fix: Select defaults + confirm responsive pattern + convert to AlertDialog

1. Fixed Select Field Default Value 
   Problem: Select shows empty even with default/saved value
   Solution: Ensure select always has value

   const selectValue = (value || field.value || field.default) as string;
   <Select value={selectValue}>

   Priority: current > saved > default
   Result:  Select always shows correct value

2. Confirmed Responsive Pattern 
   ResponsiveDialog already working correctly:
   - Desktop (≥768px): Dialog component
   - Mobile (<768px): Drawer component
   - useMediaQuery hook detects screen size

    No changes needed - already correct!

3. Converted to AlertDialog 

   A. Orders/Detail.tsx - Retry Payment
      - Was: Dialog (can dismiss by clicking outside)
      - Now: AlertDialog (must choose action)
      - Better for critical payment retry action

   B. Orders/index.tsx - Delete Orders
      - Was: Dialog (can dismiss by clicking outside)
      - Now: AlertDialog (must choose action)
      - Better for destructive delete action

   Benefits:
   -  No close button (forces decision)
   -  Can't dismiss by clicking outside
   -  User must explicitly choose Cancel or Confirm
   -  Better UX for critical/destructive actions

Component Usage Summary:
- Dialog: Forms, settings, content display
- Drawer: Mobile bottom sheet (auto via ResponsiveDialog)
- AlertDialog: Confirmations, destructive actions

Files Modified:
- GenericGatewayForm.tsx: Select default value fix
- Orders/Detail.tsx: Dialog → AlertDialog
- Orders/index.tsx: Dialog → AlertDialog
This commit is contained in:
dwindown
2025-11-06 10:28:04 +07:00
parent 108155db50
commit f9161b49f4
3 changed files with 54 additions and 35 deletions

View File

@@ -160,6 +160,8 @@ export function GenericGatewayForm({ gateway, onSave, onCancel, hideFooter = fal
);
case 'select':
// Ensure select has a value - use current value, saved value, or default
const selectValue = (value || field.value || field.default) as string;
return (
<div key={field.id} className="space-y-2">
<Label htmlFor={field.id}>
@@ -173,7 +175,7 @@ export function GenericGatewayForm({ gateway, onSave, onCancel, hideFooter = fal
/>
)}
<Select
value={value as string}
value={selectValue}
onValueChange={(val) => handleFieldChange(field.id, val)}
>
<SelectTrigger id={field.id}>

View File

@@ -6,7 +6,16 @@ import { formatRelativeOrDate } from '@/lib/dates';
import { formatMoney } from '@/lib/currency';
import { ArrowLeft, Printer, ExternalLink, Loader2, Ticket, FileText, Pencil, RefreshCw } from 'lucide-react';
import { Select, SelectTrigger, SelectContent, SelectItem, SelectValue } from '@/components/ui/select';
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle
} from '@/components/ui/alert-dialog';
import { Button } from '@/components/ui/button';
import { showErrorToast, showSuccessToast, getPageLoadErrorMessage } from '@/lib/errorHandling';
import { ErrorCard } from '@/components/ErrorCard';
@@ -254,33 +263,33 @@ export default function OrderShow() {
{__('Retry Payment')}
</button>
<Dialog open={showRetryDialog} onOpenChange={setShowRetryDialog}>
<DialogContent>
<DialogHeader>
<DialogTitle>{__('Retry Payment')}</DialogTitle>
<DialogDescription>
<AlertDialog open={showRetryDialog} onOpenChange={setShowRetryDialog}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{__('Retry Payment')}</AlertDialogTitle>
<AlertDialogDescription>
{__('Are you sure you want to retry payment processing for this order?')}
<br />
<span className="text-amber-600 font-medium">
{__('This will create a new payment transaction.')}
</span>
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button variant="outline" onClick={() => setShowRetryDialog(false)}>
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel onClick={() => setShowRetryDialog(false)}>
{__('Cancel')}
</Button>
<Button onClick={confirmRetryPayment} disabled={retryPaymentMutation.isPending}>
</AlertDialogCancel>
<AlertDialogAction onClick={confirmRetryPayment} disabled={retryPaymentMutation.isPending}>
{retryPaymentMutation.isPending ? (
<Loader2 className="w-4 h-4 animate-spin mr-2" />
) : (
<RefreshCw className="w-4 h-4 mr-2" />
)}
{__('Retry Payment')}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</>
)}
</div>

View File

@@ -6,7 +6,16 @@ import { ErrorCard } from '@/components/ErrorCard';
import { getPageLoadErrorMessage } from '@/lib/errorHandling';
import { __ } from '@/lib/i18n';
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card';
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle
} from '@/components/ui/alert-dialog';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { toast } from 'sonner';
@@ -435,34 +444,33 @@ export default function Orders() {
</div>
{/* Delete Confirmation Dialog */}
<Dialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
<DialogContent>
<DialogHeader>
<DialogTitle>{__('Delete Orders')}</DialogTitle>
<DialogDescription>
<AlertDialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{__('Delete Orders')}</AlertDialogTitle>
<AlertDialogDescription>
{__('Are you sure you want to delete')} {selectedIds.length} {selectedIds.length === 1 ? __('order') : __('orders')}?
<br />
<span className="text-red-600 font-medium">{__('This action cannot be undone.')}</span>
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button
variant="outline"
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel
onClick={() => setShowDeleteDialog(false)}
disabled={deleteMutation.isPending}
>
{__('Cancel')}
</Button>
<Button
variant="destructive"
</AlertDialogCancel>
<AlertDialogAction
onClick={confirmDelete}
disabled={deleteMutation.isPending}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
>
{deleteMutation.isPending ? __('Deleting...') : __('Delete')}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</div>
);
}