import { useForm, Controller, useWatch, type Control } from 'react-hook-form' import { PatternFormat } from 'react-number-format' import { zodResolver } from '@hookform/resolvers/zod' import { ErrorMessage } from '@hookform/error-message' import { z } from 'zod' import { ArrowRightIcon, CircleQuestionMarkIcon } from 'lucide-react' import valid from 'card-validator' import { Button } from '@repo/ui/components/ui/button' import { Kbd } from '@repo/ui/components/ui/kbd' import { Label } from '@repo/ui/components/ui/label' import { RadioGroup, RadioGroupItem } from '@repo/ui/components/ui/radio-group' import { Separator } from '@repo/ui/components/ui/separator' import { Input } from '@repo/ui/components/ui/input' import { Card, CardContent } from '@repo/ui/components/ui/card' import { HoverCard, HoverCardContent, HoverCardTrigger } from '@repo/ui/components/ui/hover-card' import { Field, FieldError, FieldGroup, FieldLabel, FieldSet } from '@repo/ui/components/ui/field' import { NativeSelect, NativeSelectOption } from '@repo/ui/components/ui/native-select' import { Currency } from '@repo/ui/components/currency' import { useWizard } from '@/components/wizard' import { isName } from '../_.$orgid.users.add/data' import { applyDiscount } from './discount' import { useWizardStore } from './store' const creditCard = z.object({ holder_name: z .string() .trim() .nonempty('Digite um nome') .refine(isName, { message: 'Nome inválido' }), number: z.string().refine( (value) => { const numberValidation = valid.number(value) return numberValidation.isValid }, { error: 'Número do cartão inválido' } ), exp_month: z.string().min(2), exp_year: z.string().min(4), cvv: z.string().min(3).max(4) }) const formSchema = z.discriminatedUnion( 'payment_method', [ z.object({ payment_method: z.literal('PIX') }), z.object({ payment_method: z.literal('BANK_SLIP') }), z.object({ payment_method: z.literal('MANUAL') }), z.object({ payment_method: z.literal('CREDIT_CARD'), credit_card: creditCard, installments: z.coerce.number().int().min(1).max(12) }) ], { error: 'Escolha uma forma de pagamento' } ) type Schema = z.input export type CreditCard = z.infer export function Payment({}) { const wizard = useWizard() const { update, summary, ...state } = useWizardStore() const { subtotal, discount } = summary() const { control, handleSubmit } = useForm({ defaultValues: { payment_method: state.payment_method, installments: state.installments, credit_card: state.credit_card }, resolver: zodResolver(formSchema) }) const paymentMethod = useWatch({ control, name: 'payment_method' }) const onSubmit = async ({ payment_method, ...data }: Schema) => { if (payment_method === 'CREDIT_CARD') { // @ts-ignore update({ payment_method, ...data }) } else { update({ payment_method, installments: undefined, credit_card: undefined }) } wizard('review') } return (
(
(

{message}

)} />
)} /> {paymentMethod === 'CREDIT_CARD' ? ( ) : null}
) } export function CreditCard({ total, control }: { total: number control: Control }) { const currentYear = new Date().getFullYear() const years = Array.from({ length: 10 }, (_, i) => currentYear + i) return (
{/* Credir card number */} ( Número do cartão { onChange(value) }} {...field} /> {fieldState.invalid && ( )} )} /> {/* Holder name */} ( Nome do titular {fieldState.invalid && ( )} )} />
( Mês Selecione {Array.from({ length: 12 }, (_, i) => { const v = String(i + 1).padStart(2, '0') return ( {v} ) })} )} /> ( Ano Selecione {years.map((year) => ( {year} ))} )} /> ( CVC

O CVC é o código de segurança do cartão de crédito.

Ele fica no verso do cartão e geralmente possui{' '} 3 dígitos (ou 4 dígitos na frente, no caso do American Express).

)} />
( Parcelas {Array.from({ length: 12 }, (_, index) => { const installment = index + 1 // 1 -> 12 if (installment === 1) { return ( {total} à vista ) } const value = installment > 1 ? calcInterest(total, installment) / installment : total return ( {installment}x {value} com juros ) })} )} />
) } export const calcInterest = (total: number, installment: number) => { const rate2to6 = 0.055 const rate7to12 = 0.0608 const rate = installment >= 7 ? rate7to12 : rate2to6 return total * ((1 - 0.0382) / (1 - rate)) }