From c146523a28195120119cc0cc6df48425a332ec80 Mon Sep 17 00:00:00 2001 From: Vedant Chainani Date: Sun, 30 Nov 2025 18:37:25 +0530 Subject: [PATCH 1/5] chore: add superrefine with paths for each issue and add address schema --- src/lib/schemas/invoice.ts | 77 +++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/src/lib/schemas/invoice.ts b/src/lib/schemas/invoice.ts index 069a8313..96d98057 100644 --- a/src/lib/schemas/invoice.ts +++ b/src/lib/schemas/invoice.ts @@ -1,7 +1,10 @@ import { INVOICE_CURRENCIES } from "@/lib/constants/currencies"; -import { isEthereumAddress } from "validator"; import { z } from "zod"; +export const AddressSchema = z + .string() + .regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address"); + export const invoiceFormSchema = z .object({ invoiceNumber: z.string().min(1, "Invoice number is required"), @@ -25,51 +28,49 @@ export const invoiceFormSchema = z required_error: "Please select an invoice currency", }), paymentCurrency: z.string().min(1, "Payment currency is required"), - walletAddress: z.string().optional(), + walletAddress: AddressSchema.optional(), isRecurring: z.boolean().default(false), startDate: z.string().optional(), frequency: z.enum(["DAILY", "WEEKLY", "MONTHLY", "YEARLY"]).optional(), isCryptoToFiatAvailable: z.boolean().default(false), paymentDetailsId: z.string().optional(), }) - .refine( - (data) => { - // If invoice is recurring, startDate and frequency must be provided - if (data.isRecurring) { - return !!data.startDate && !!data.frequency; + .superRefine((data, ctx) => { + if (data.isRecurring) { + if (!data.startDate) { + ctx.addIssue({ + code: "custom", + message: "Start date is required for recurring invoices", + path: ["startDate"], + }); } - return true; - }, - { - message: "Start date and frequency are required for recurring invoices", - path: ["isRecurring"], - }, - ) - .refine( - (data) => { - // Wallet address is required when crypto-to-fiat is not enabled - if (!data.isCryptoToFiatAvailable) { - return !!data.walletAddress && isEthereumAddress(data.walletAddress); + + if (!data.frequency) { + ctx.addIssue({ + code: "custom", + message: "Frequency is required for recurring invoices", + path: ["frequency"], + }); } - return true; - }, - { - message: "Valid wallet address is required for direct crypto payments", - path: ["walletAddress"], - }, - ) - .refine( - (data) => { - // Payment details are required when crypto-to-fiat is enabled - if (data.isCryptoToFiatAvailable) { - return !!data.paymentDetailsId; + + if (!data.isCryptoToFiatAvailable) { + if (!data.walletAddress) { + ctx.addIssue({ + code: "custom", + message: "Wallet address is required for recurring invoices", + path: ["walletAddress"], + }); + } + } else { + if (!data.paymentDetailsId) { + ctx.addIssue({ + code: "custom", + message: "Payment details are required for recurring invoices", + path: ["paymentDetailsId"], + }); + } } - return true; - }, - { - message: "Please select a payment method for Crypto-to-fiat payment", - path: ["paymentDetailsId"], - }, - ); + } + }); export type InvoiceFormValues = z.infer; From 59a8a889c60648918db6d973590ecb535a6c2391 Mon Sep 17 00:00:00 2001 From: Vedant Chainani Date: Sun, 30 Nov 2025 18:51:30 +0530 Subject: [PATCH 2/5] chore: move validation to superrefine and fix some validation issues --- .../invoice/invoice-form/invoice-form.tsx | 22 +--------- src/lib/schemas/invoice.ts | 44 ++++++++++++------- 2 files changed, 29 insertions(+), 37 deletions(-) diff --git a/src/components/invoice/invoice-form/invoice-form.tsx b/src/components/invoice/invoice-form/invoice-form.tsx index ee60eee1..2fabb496 100644 --- a/src/components/invoice/invoice-form/invoice-form.tsx +++ b/src/components/invoice/invoice-form/invoice-form.tsx @@ -363,20 +363,8 @@ export function InvoiceForm({ async (data: InvoiceFormValues) => { // Prevent multiple submissions if (isSubmitting) return; - setIsSubmitting(true); - // If Crypto-to-fiat is enabled but no payment details are linked, show error - if (data.isCryptoToFiatAvailable && !data.paymentDetailsId) { - // Set form error for paymentDetailsId - form.setError("paymentDetailsId", { - type: "required", - message: "Please select a payment method for Crypto-to-fiat payment", - }); - setIsSubmitting(false); - return; - } - // Check if payment details have approved status if (data.isCryptoToFiatAvailable && data.paymentDetailsId) { const selectedPaymentDetail = linkedPaymentDetails?.find( @@ -429,13 +417,7 @@ export function InvoiceForm({ setIsSubmitting(false); } }, - [ - linkedPaymentDetails, - onSubmit, - form.setError, - isSubmitting, - handleBankAccountSuccess, - ], + [linkedPaymentDetails, onSubmit, isSubmitting, handleBankAccountSuccess], ); // Add timeout effect for pending approval modal @@ -755,7 +737,7 @@ export function InvoiceForm({
{fields.map((field, index) => ( -
+
; From 7ac720a15bb88fb726fd86b822682bb6729db511 Mon Sep 17 00:00:00 2001 From: Vedant Chainani Date: Sun, 30 Nov 2025 18:52:52 +0530 Subject: [PATCH 3/5] chore: push to /invoices after successful creation --- src/components/invoice/invoice-creator.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/invoice/invoice-creator.tsx b/src/components/invoice/invoice-creator.tsx index eb290135..93e1bcd9 100644 --- a/src/components/invoice/invoice-creator.tsx +++ b/src/components/invoice/invoice-creator.tsx @@ -49,7 +49,7 @@ export function InvoiceCreator({ } toast.success("Invoice created successfully"); await utils.invoice.getAll.invalidate(); - router.push("/dashboard"); + router.push("/invoices"); }, onError: (error) => { toast.error("Failed to create invoice", { @@ -64,7 +64,7 @@ export function InvoiceCreator({ onSuccess: async () => { toast.success("Invoice created successfully"); await utils.invoice.getAll.invalidate(); - router.push("/dashboard"); + router.push("/invoices"); }, onError: (error) => { toast.error("Failed to create invoice", { From 03aca069c2ed3e91bd4ebcef2cdfa6e069835c7b Mon Sep 17 00:00:00 2001 From: Vedant Chainani Date: Sun, 30 Nov 2025 19:17:19 +0530 Subject: [PATCH 4/5] chore: update error messages --- src/lib/schemas/invoice.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/schemas/invoice.ts b/src/lib/schemas/invoice.ts index 9b5eeaa6..6068c3c9 100644 --- a/src/lib/schemas/invoice.ts +++ b/src/lib/schemas/invoice.ts @@ -58,7 +58,7 @@ export const invoiceFormSchema = z if (!data.walletAddress) { ctx.addIssue({ code: "custom", - message: "Wallet address is required for recurring invoices", + message: "Wallet address is required", path: ["walletAddress"], }); } @@ -66,7 +66,7 @@ export const invoiceFormSchema = z if (!data.paymentDetailsId) { ctx.addIssue({ code: "custom", - message: "Payment details are required for recurring invoices", + message: "Payment details are required for crypto-to-fiat payments", path: ["paymentDetailsId"], }); } From d3f255e64b7b6cd377f88ee44757ab1bd4f6a928 Mon Sep 17 00:00:00 2001 From: Vedant Chainani Date: Mon, 8 Dec 2025 21:17:24 +0530 Subject: [PATCH 5/5] chore: add isEthereumAddress to validate addresses --- src/lib/schemas/invoice.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/schemas/invoice.ts b/src/lib/schemas/invoice.ts index 6068c3c9..d68341a3 100644 --- a/src/lib/schemas/invoice.ts +++ b/src/lib/schemas/invoice.ts @@ -1,9 +1,10 @@ import { INVOICE_CURRENCIES } from "@/lib/constants/currencies"; +import { isEthereumAddress } from "validator"; import { z } from "zod"; export const AddressSchema = z .string() - .regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address"); + .refine(isEthereumAddress, "Invalid Ethereum Address"); export const invoiceFormSchema = z .object({