import type { Route } from './+types' import { isValidCPF } from '@brazilian-utils/brazilian-utils' import { zodResolver } from '@hookform/resolvers/zod' import { useForm } from 'react-hook-form' import { PatternFormat } from 'react-number-format' import { Link, useFetcher } from 'react-router' import { toast } from 'sonner' import { adjectives, colors, NumberDictionary, uniqueNamesGenerator } from 'unique-names-generator' import { z } from 'zod' import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from '@repo/ui/components/ui/breadcrumb' import { Button } from '@repo/ui/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@repo/ui/components/ui/card' import { Checkbox } from '@repo/ui/components/ui/checkbox' import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@repo/ui/components/ui/form' import { Input } from '@repo/ui/components/ui/input' import { Spinner } from '@repo/ui/components/ui/spinner' import { useWorksapce } from '@/components/workspace-switcher' import { HttpMethod, request as req } from '@repo/util/request' import { useEffect } from 'react' const isName = (name: string) => name && name.includes(' ') function randomEmail() { const numberDict = NumberDictionary.generate({ min: 100, max: 999 }) const randomName: string = uniqueNamesGenerator({ dictionaries: [adjectives, colors, numberDict], length: 3, separator: '-' }) return `${randomName}@users.noreply.saladeaula.digital` } export const formSchema = z .object({ name: z .string() .trim() .nonempty('Digite um nome') .refine(isName, { message: 'Nome inválido' }), email: z.string().trim().toLowerCase().optional(), cpf: z .string('CPF obrigatório') .refine(isValidCPF, { message: 'CPF inválido' }), given_email: z.coerce.boolean() }) .refine( ({ given_email, email }) => { if (given_email) { return true } return email && z.email().safeParse(email).success }, { message: 'Email inválido', path: ['email'] } ) .transform((data) => { if (data.given_email) { return { ...data, email: randomEmail() } } return data }) export type Schema = z.infer export function meta({}: Route.MetaArgs) { return [{ title: 'Adicionar colaborador' }] } export async function action({ params, request, context }: Route.ActionArgs) { const { orgid } = params const body = await request.json() const r = await req({ url: `orgs/${orgid}/users`, headers: new Headers({ 'Content-Type': 'application/json' }), method: HttpMethod.POST, body: JSON.stringify(body), request, context }) if (!r.ok) { const error = await r.json().catch(() => ({})) return { ok: false, error } } return { ok: true } } export default function Route() { const fetcher = useFetcher() const { activeWorkspace } = useWorksapce() const form = useForm({ resolver: zodResolver(formSchema) }) const { handleSubmit, control, formState, reset, watch, setValue } = form const givenEmail = watch('given_email') as boolean const onSubmit = async (user: Schema) => { await fetcher.submit(JSON.stringify({ user, org: activeWorkspace }), { method: 'post', encType: 'application/json' }) } useEffect(() => { if (fetcher.data?.ok) { toast.success('O colaborador foi adicionado') return reset() } switch (fetcher.data?.error?.type) { case 'UserConflictError': toast.error('O colaborador já foi vinculado anteriormente') } }, [fetcher.data]) useEffect(() => { if (givenEmail) { setValue('email', '', { shouldValidate: true }) } }, [givenEmail, setValue]) return (
Colaboradores Adicionar colaborador
Adicionar colaborador Siga os passos abaixo para cadastrar um novo colaborador ( Nome )} />
( Email )} /> ( Usar um email fornecido pela plataforma. )} />
( CPF { onChange(value) }} {...props} /> )} />
) }