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 (
)
}
+
+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()