From 2be277a42e3b9845bcb9e07b7c36ea030018b0e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Rafael=20Siqueira?= Date: Tue, 16 Dec 2025 14:54:18 -0300 Subject: [PATCH] update profile --- .../app/routes/_.$orgid.scheduled/route.tsx | 1 + .../_.$orgid.users.$id._index/route.tsx | 100 +++++++++++++++--- .../app/routes/_.$orgid.users.$id/route.tsx | 10 +- .../app/routes/settings/profile.tsx | 9 +- 4 files changed, 96 insertions(+), 24 deletions(-) diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid.scheduled/route.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid.scheduled/route.tsx index ee72933..bfe9916 100644 --- a/apps/admin.saladeaula.digital/app/routes/_.$orgid.scheduled/route.tsx +++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid.scheduled/route.tsx @@ -387,6 +387,7 @@ function Failed({ items = [] }) { {datetime.format(new Date(created_at))} + {cause?.type === 'DeduplicationConflictError' ? (
  • diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid.users.$id._index/route.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid.users.$id._index/route.tsx index 47acc2e..0d2602f 100644 --- a/apps/admin.saladeaula.digital/app/routes/_.$orgid.users.$id._index/route.tsx +++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid.users.$id._index/route.tsx @@ -1,9 +1,12 @@ import type { Route } from './+types/route' +import { useEffect } from 'react' import { zodResolver } from '@hookform/resolvers/zod' import { PatternFormat } from 'react-number-format' -import { Link, useOutletContext } from 'react-router' +import { useFetcher, Link, useOutletContext } from 'react-router' +import { AlertCircleIcon } from 'lucide-react' import { useForm } from 'react-hook-form' +import { toast } from 'sonner' import { Button } from '@repo/ui/components/ui/button' import { @@ -24,24 +27,79 @@ import { import { Input } from '@repo/ui/components/ui/input' import { Spinner } from '@repo/ui/components/ui/spinner' import { type User } from '@repo/ui/routes/users/data' +import { + Alert, + AlertDescription, + AlertTitle +} from '@repo/ui/components/ui/alert' +import { request as req, HttpMethod } from '@repo/util/request' import { formSchema, type Schema } from '../_.$orgid.users.add/data' +export async function action({ params, request, context }: Route.ActionArgs) { + const body = await request.json() + const r = await req({ + url: `/users/${params.id}`, + method: HttpMethod.PATCH, + headers: new Headers({ 'Content-Type': 'application/json' }), + body: JSON.stringify(body), + request, + context + }) + + if (r.ok) { + return { ok: true } + } + + return { ok: false, error: await r.json() } +} + export default function Route({}: Route.ComponentProps) { const { user } = useOutletContext() as { user: User } + const fetcher = useFetcher() const form = useForm({ defaultValues: { ...user, given_email: false }, resolver: zodResolver(formSchema) }) - const { handleSubmit, control, formState } = form + const { handleSubmit, control, formState, setError } = form const onSubmit = async (data: Schema) => { - console.log(data) + await fetcher.submit(JSON.stringify({ id: user.id, ...data }), { + method: 'post', + encType: 'application/json' + }) } + useEffect(() => { + if (fetcher.data?.ok) { + toast.success('O colaborador foi atualizado.') + return + } + + switch (fetcher.data?.error?.type) { + case 'RateLimitExceededError': + toast.error('Seu limite diário de atualizações foi atingido.') + case 'CPFConflictError': + setError('cpf', { message: 'CPF já está em uso' }) + } + + console.log(fetcher.data?.error) + }, [fetcher.data, setError]) + return (
    + {user?.rate_limit_exceeded && ( + + + Limite diário de atualizações atingido. + + Tente novamente a partir de{' '} + {getDaysRemaining(user.rate_limit_exceeded.ttl)} + + + )} + Editar colaborador @@ -115,20 +173,34 @@ export default function Route({}: Route.ComponentProps) { )} /> + + - -
    - -
    ) } + +function getDaysRemaining(ttl: number) { + const date = new Date(ttl * 1000) + + const day = date.toLocaleDateString('pt-BR', { + day: '2-digit', + month: '2-digit' + }) + + const time = date.toLocaleTimeString('pt-BR', { + hour: '2-digit', + minute: '2-digit' + }) + + return `${day} às ${time}` +} diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid.users.$id/route.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid.users.$id/route.tsx index fab0996..c447298 100644 --- a/apps/admin.saladeaula.digital/app/routes/_.$orgid.users.$id/route.tsx +++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid.users.$id/route.tsx @@ -20,6 +20,11 @@ import { Tabs, TabsList, TabsTrigger } from '@repo/ui/components/ui/tabs' import { initials } from '@repo/ui/lib/utils' import { request as req } from '@repo/util/request' +const links = [ + { to: '', title: 'Perfil', end: true }, + { to: 'emails', title: 'Emails' } +] + export function meta() { return [ { @@ -51,11 +56,6 @@ export function shouldRevalidate({ return currentParams.id !== nextParams.id } -const links = [ - { to: '', title: 'Perfil', end: true }, - { to: 'emails', title: 'Emails' } -] - export default function Route({ loaderData: { data: user } }: Route.ComponentProps) { diff --git a/apps/saladeaula.digital/app/routes/settings/profile.tsx b/apps/saladeaula.digital/app/routes/settings/profile.tsx index b2aaaed..b14e9ff 100644 --- a/apps/saladeaula.digital/app/routes/settings/profile.tsx +++ b/apps/saladeaula.digital/app/routes/settings/profile.tsx @@ -1,8 +1,9 @@ import type { Route } from './+types/profile' +import { useEffect } from 'react' import { AlertCircleIcon } from 'lucide-react' import { useForm } from 'react-hook-form' -import { Link, useOutletContext } from 'react-router' +import { Link, useOutletContext, useFetcher } from 'react-router' import { PatternFormat } from 'react-number-format' import { zodResolver } from '@hookform/resolvers/zod' import { toast } from 'sonner' @@ -27,16 +28,14 @@ import { Input } from '@repo/ui/components/ui/input' import { Spinner } from '@repo/ui/components/ui/spinner' import { type User } from '@repo/ui/routes/users/data' import { request as req, HttpMethod } from '@repo/util/request' - -import { formSchema, type Schema } from './emails/data' -import { useFetcher } from 'react-router' import { userContext } from '@repo/auth/context' import { Alert, AlertDescription, AlertTitle } from '@repo/ui/components/ui/alert' -import { useEffect } from 'react' + +import { formSchema, type Schema } from './emails/data' export async function action({ request, context }: Route.ActionArgs) { const body = await request.json()