import { useRequest, useToggle } from 'ahooks' import { PatternFormat } from 'react-number-format' import { ExternalLinkIcon, PencilIcon, SearchIcon } from 'lucide-react' import { Controller, useForm } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' import { formatCEP } from '@brazilian-utils/brazilian-utils' import { z } from 'zod' import valid from 'card-validator' import { Currency } from '@repo/ui/components/currency' import { Button } from '@repo/ui/components/ui/button' import { Separator } from '@repo/ui/components/ui/separator' import { Spinner } from '@repo/ui/components/ui/spinner' import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow } from '@repo/ui/components/ui/table' import { Item, ItemActions, ItemContent, ItemDescription, ItemGroup, ItemTitle } from '@repo/ui/components/ui/item' import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from '@repo/ui/components/ui/dialog' import { paymentMethods } from '@repo/ui/routes/orders/data' import { useWizard } from '@/components/wizard' import { Field, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldSet } from '@repo/ui/components/ui/field' import { Input } from '@repo/ui/components/ui/input' import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from '@repo/ui/components/ui/input-group' import { useWizardStore } from './store' import { useParams } from 'react-router' import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyTitle } from '@repo/ui/components/ui/empty' type ReviewProps = { onSubmit: () => void | Promise } export function Review({ onSubmit }: ReviewProps) { const wizard = useWizard() const { items, summary, address } = useWizardStore() const { subtotal, discount, interest_amount, total } = summary() const [loading, { set }] = useToggle() return ( <>
{ e.preventDefault() set(true) await onSubmit() }} className="space-y-4" > Curso Quantidade Valor unit. Total {items?.map(({ course, quantity }, index) => { return ( {course.name} {quantity} {course.unit_price} {course.unit_price * quantity} ) })} {/* Summary */} Subtotal {subtotal} {/* Discount */} Descontos {discount} {/* Interest */} {interest_amount ? ( Juros {interest_amount} ) : ( <> )} {/* Total */} Total {total}
) } export function Summary() { const { summary, credit_card, payment_method, installments, address } = useWizardStore() const { total } = summary() const numberValidation = valid.number(credit_card?.number) return ( {address ? ( Endereço de cobrança
    {address?.address1} {address?.address2 ? <>, {address?.address2} : null}
    {address?.neighborhood}
    {address?.city}, {address?.state}
    {formatCEP(address?.postcode)}
) : ( Nenhum endereço ainda Você ainda não cadastrou nenhum endereço. )} Forma de pagamento {credit_card ? ( <> {numberValidation.card?.niceType} (Crédito) ****{' '} {credit_card.number.slice(-4)}
{installments}x{' '} {total / Number(installments)} ) : ( <> {payment_method ? paymentMethods[payment_method] : payment_method} )}
) } const formSchema = z.object({ postcode: z.string().min(1, 'Digite um CEP'), address1: z.string().min(1, 'Digite um endereço'), address2: z.string().optional(), neighborhood: z.string().min(1, 'Digite o bairro'), city: z.string().min(1, 'Digite a cidade'), state: z.string().min(1, 'Digite o estado') }) export type Address = z.infer export function AddressDialog({ children }) { const { update, address } = useWizardStore() const { orgid } = useParams() const { runAsync } = useRequest( async (address: Address) => { await fetch(`/~/api/orgs/${orgid}/address`, { method: 'POST', body: JSON.stringify({ address }), headers: new Headers({ 'Content-Type': 'application/json' }) }) }, { manual: true } ) const { handleSubmit, control, reset, formState } = useForm({ defaultValues: address, resolver: zodResolver(formSchema) }) const [open, { toggle, set: setOpen }] = useToggle(address === undefined) const onSubmit = async (address: Address) => { await runAsync(address) setOpen(false) update({ address }) } return ( {children} Editar endereço Este endereço será utilizado para a emissão da NFS-e.
( Endereço {fieldState.invalid && ( )} )} /> ( Complemento{' '} (opcional) {fieldState.invalid && ( )} )} /> {/* Neighborhood */} ( Bairro {fieldState.invalid && ( )} )} /> {/* City */} ( Cidade {fieldState.invalid && ( )} )} /> {/* State */} ( Estado {fieldState.invalid && ( )} )} />
) } type PostcodeFormProps = { onChange: (value: Address) => void } function PostcodeForm({ onChange }: PostcodeFormProps) { const formSchema = z.object({ postcode: z.string().min(1, 'Digite um CEP') }) type Schema = z.infer const { address } = useWizardStore() const { control, handleSubmit, setError, formState } = useForm({ resolver: zodResolver(formSchema), defaultValues: address }) const { runAsync, loading } = useRequest( async (cep: string) => { return await fetch(`/~/api/cep/${cep}.json`) }, { manual: true } ) const onSubmit = async ({ postcode }: Schema) => { const r = await runAsync(postcode) if (r.ok) { onChange?.((await r.json()) as Address) return } setError('postcode', { message: 'CEP não encontrado' }) } return (
( {/* CEP */} CEP { onChange(value) }} {...field} /> {loading ? : } {fieldState.invalid && } Não sei o CEP )} />
) }