Skip to content

Commit e26b080

Browse files
fix(payments): pre-populate all edit dialog fields using react-hook-form and zod schema validation
1 parent 6a5053a commit e26b080

2 files changed

Lines changed: 104 additions & 9 deletions

File tree

app/(merchant)/payments/page.tsx

Lines changed: 93 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
"use client";
22

3-
import { useState, memo, useMemo } from 'react';
3+
import { useState, memo, useMemo, useEffect } from 'react';
4+
import { useForm } from 'react-hook-form';
5+
import { zodResolver } from '@hookform/resolvers/zod';
6+
import { editPaymentLinkSchema, type EditPaymentLinkFormValues } from '@/lib/utils/validation';
47
import { Card, CardContent, CardHeader, CardTitle, CardDescription, Button, Input, Label } from '@/components/ui';
58
import { CopyAddress, EmptyState, ErrorDisplay } from '@/components/shared';
69
import { PageHeader } from '@/components/shared/PageHeader';
@@ -166,8 +169,24 @@ export default function PaymentsPage() {
166169
resetForm();
167170
};
168171

169-
const handleEditSubmit = (e: React.FormEvent) => {
170-
e.preventDefault();
172+
const { register: registerEdit, handleSubmit: handleEditSubmitForm, reset: resetEditForm, formState: { errors: editErrors } } = useForm<EditPaymentLinkFormValues>({
173+
resolver: zodResolver(editPaymentLinkSchema),
174+
});
175+
176+
useEffect(() => {
177+
if (editingLink) {
178+
resetEditForm({
179+
label: editingLink.source ?? '',
180+
amount: editingLink.amountUsdc ? String(editingLink.amountUsdc) : '',
181+
currency: editingLink.amountUsdc ? 'USDC' : 'XLM',
182+
expiry: '',
183+
redirectUrl: '',
184+
reference: '',
185+
});
186+
}
187+
}, [editingLink, resetEditForm]);
188+
189+
const handleEditSubmit = (data: EditPaymentLinkFormValues) => {
171190
notifySuccess('Payment link updated successfully');
172191
setEditingLink(null);
173192
};
@@ -471,21 +490,86 @@ export default function PaymentsPage() {
471490

472491
{/* Edit Dialog */}
473492
<Dialog open={!!editingLink} onOpenChange={(open) => !open && setEditingLink(null)}>
474-
<DialogContent className="sm:max-w-[425px] bg-card border-border/50">
493+
<DialogContent className="sm:max-w-[425px] bg-card border-border/50 max-h-[85dvh] overflow-y-auto">
475494
<DialogHeader>
476495
<DialogTitle>Edit Payment Link</DialogTitle>
477496
<DialogDescription>Update details for {editingLink?.source}</DialogDescription>
478497
</DialogHeader>
479-
<form onSubmit={handleEditSubmit} className="space-y-4 py-2">
498+
<form onSubmit={handleEditSubmitForm(handleEditSubmit)} className="space-y-4 py-2">
480499
<div className="space-y-2">
481500
<Label htmlFor="edit-title">Title / Label</Label>
482-
<Input id="edit-title" defaultValue={editingLink?.source ?? ''} />
501+
<Input
502+
id="edit-title"
503+
className="bg-background/50 border-border/50"
504+
{...registerEdit('label')}
505+
/>
506+
{editErrors.label && (
507+
<p className="text-xs text-destructive mt-1">{editErrors.label.message}</p>
508+
)}
509+
</div>
510+
511+
<div className="grid grid-cols-2 gap-3">
512+
<div className="space-y-2">
513+
<Label htmlFor="edit-amount">Amount (Optional)</Label>
514+
<Input
515+
id="edit-amount"
516+
type="number"
517+
placeholder="0.00"
518+
className="bg-background/50 border-border/50"
519+
{...registerEdit('amount')}
520+
/>
521+
{editErrors.amount && (
522+
<p className="text-xs text-destructive mt-1">{editErrors.amount.message}</p>
523+
)}
524+
</div>
525+
<div className="space-y-2">
526+
<Label htmlFor="edit-currency">Currency</Label>
527+
<select
528+
id="edit-currency"
529+
className="flex h-10 w-full rounded-md border border-input border-border/50 bg-background/50 px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
530+
{...registerEdit('currency')}
531+
>
532+
<option value="USDC">USDC</option>
533+
<option value="XLM">XLM</option>
534+
<option value="USDT">USDT</option>
535+
</select>
536+
</div>
537+
</div>
538+
539+
<div className="space-y-2">
540+
<Label htmlFor="edit-reference">Internal Reference</Label>
541+
<Input
542+
id="edit-reference"
543+
placeholder="e.g. INV-2026-001"
544+
className="bg-background/50 border-border/50"
545+
{...registerEdit('reference')}
546+
/>
547+
</div>
548+
549+
<div className="space-y-2">
550+
<Label htmlFor="edit-expiry">Expiry Date</Label>
551+
<Input
552+
id="edit-expiry"
553+
type="date"
554+
className="bg-background/50 border-border/50"
555+
{...registerEdit('expiry')}
556+
/>
483557
</div>
558+
484559
<div className="space-y-2">
485-
<Label htmlFor="edit-amount">Amount (USDC)</Label>
486-
<Input id="edit-amount" type="number" defaultValue={editingLink?.amountUsdc ?? 0} />
560+
<Label htmlFor="edit-redirect">Redirect URL (On success)</Label>
561+
<Input
562+
id="edit-redirect"
563+
placeholder="https://yourstore.com/thank-you"
564+
className="bg-background/50 border-border/50"
565+
{...registerEdit('redirectUrl')}
566+
/>
567+
{editErrors.redirectUrl && (
568+
<p className="text-xs text-destructive mt-1">{editErrors.redirectUrl.message}</p>
569+
)}
487570
</div>
488-
<DialogFooter>
571+
572+
<DialogFooter className="pt-4">
489573
<Button type="button" variant="ghost" onClick={() => setEditingLink(null)}>Cancel</Button>
490574
<Button type="submit">Save Changes</Button>
491575
</DialogFooter>

lib/utils/validation.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,14 @@ export const merchantProfileSchema = z.object({
3333
});
3434

3535
export type MerchantProfileFormValues = z.infer<typeof merchantProfileSchema>;
36+
37+
export const editPaymentLinkSchema = z.object({
38+
label: z.string().min(1, 'Label is required'),
39+
amount: z.string().optional(),
40+
currency: z.enum(['USDC', 'XLM', 'USDT']).default('USDC'),
41+
expiry: z.string().optional(),
42+
redirectUrl: z.string().url('Invalid URL').or(z.literal('')).optional(),
43+
reference: z.string().optional(),
44+
});
45+
46+
export type EditPaymentLinkFormValues = z.infer<typeof editPaymentLinkSchema>;

0 commit comments

Comments
 (0)