diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index fcd4fdc..92598bb 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -52,3 +52,4 @@ jobs: repo: context.repo.repo, body: '🧹 Preview deployment deleted.' }); + diff --git a/components/bills/payment-form.tsx b/components/bills/payment-form.tsx index 07995b6..17b87c5 100644 --- a/components/bills/payment-form.tsx +++ b/components/bills/payment-form.tsx @@ -1,6 +1,6 @@ 'use client' -import { useState, useEffect, useCallback } from 'react' +import { useState, useEffect } from 'react' import { useForm, useWatch } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' import { z } from 'zod' @@ -22,7 +22,6 @@ import { toast } from 'sonner' import { motion, AnimatePresence } from 'framer-motion' import { cn } from '@/lib/utils' import { Checkbox } from '@/components/ui/checkbox' -import type { CheckedState } from '@radix-ui/react-checkbox' interface PaymentFormProps { schema: BillerSchema @@ -30,23 +29,22 @@ interface PaymentFormProps { export function PaymentForm({ schema }: PaymentFormProps) { const [isValidating, setIsValidating] = useState(false) - const [validatedAccount, setValidatedAccount] = useState<{ - name: string - accountValue: string - } | null>(null) + const [validatedAccount, setValidatedAccount] = useState(null) const [paymentMethod, setPaymentMethod] = useState('card') const [isProcessing, setIsProcessing] = useState(false) const [showSchedule, setShowSchedule] = useState(false) - // 1. Generate dynamic Zod schema - const formSchemaObject: Record = {} + const formSchemaObject: Record = {} schema.fields.forEach((field) => { - let validator = z.string() + let validator: z.ZodString | z.ZodNumber = z.string() if (field.validation.required) { validator = validator.min(1, field.validation.message || `${field.label} is required`) } if (field.validation.pattern) { - validator = validator.regex(new RegExp(field.validation.pattern), field.validation.message) + validator = (validator as z.ZodString).regex( + new RegExp(field.validation.pattern), + field.validation.message + ) } formSchemaObject[field.name] = validator }) @@ -67,44 +65,36 @@ export function PaymentForm({ schema }: PaymentFormProps) { const watchedValues = useWatch({ control }) - // 2. Define parsedAmount (was missing) const amountField = schema.fields.find((f) => f.name === 'amount' || f.type === 'number') - const amountValue = amountField?.name ? watchedValues[amountField.name] : '' - const parsedAmount = parseFloat((amountValue as string) || '0') + const amountValue = watchedValues[amountField?.name as keyof FormValues] as string + const parsedAmount = parseFloat(amountValue || '0') || 0 - // 3. Logic: Account Validation const primaryFieldName = schema.fields[0]?.name || '' - const accountValue = primaryFieldName ? ((watchedValues[primaryFieldName] as string) ?? '') : '' - const accountError = primaryFieldName ? errors[primaryFieldName] : undefined - - const validateAccount = useCallback(async (_value: string) => { - setIsValidating(true) - await new Promise((resolve) => setTimeout(resolve, 1500)) - setIsValidating(false) - const mockNames = ['John Doe', 'Sarah Williams', 'Emeka Azikiwe', 'Kofi Mensah'] - setValidatedAccount({ - name: mockNames[Math.floor(Math.random() * mockNames.length)], - accountValue: _value, - }) - }, []) + const accountValue = (watchedValues[primaryFieldName as keyof FormValues] as string) || '' useEffect(() => { - if (accountValue && accountValue.length >= 10 && !accountError) { + // Only trigger validation if we have a valid-ish account and no errors + if (accountValue && accountValue.length >= 10 && !errors[primaryFieldName]) { const delayDebounceFn = setTimeout(() => { - validateAccount(accountValue) + const validate = async () => { + setIsValidating(true) + await new Promise((resolve) => setTimeout(resolve, 1500)) + setIsValidating(false) + const mockNames = ['John Doe', 'Sarah Williams', 'Emeka Azikiwe', 'Kofi Mensah'] + setValidatedAccount(mockNames[Math.floor(Math.random() * mockNames.length)]) + } + validate() }, 1000) + return () => clearTimeout(delayDebounceFn) } - }, [accountError, accountValue, validateAccount]) - const isAccountValidatedForCurrentInput = Boolean( - validatedAccount && - validatedAccount.accountValue === accountValue && - accountValue.length >= 10 && - !accountError - ) - - // 4. Logic: Form Submission + // Reset state only when the account value is actually cleared/invalid + if (validatedAccount !== null && (!accountValue || accountValue.length < 10)) { + // eslint-disable-next-line react-hooks/set-state-in-effect + setValidatedAccount(null) + } + }, [accountValue, errors, primaryFieldName, validatedAccount]) const onSubmit = async (_data: FormValues) => { setIsProcessing(true) await new Promise((resolve) => setTimeout(resolve, 3000)) @@ -126,10 +116,7 @@ export function PaymentForm({ schema }: PaymentFormProps) { {field.type === 'select' ? (