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:
@@ -160,6 +160,8 @@ export function GenericGatewayForm({ gateway, onSave, onCancel, hideFooter = fal
|
|||||||
);
|
);
|
||||||
|
|
||||||
case 'select':
|
case 'select':
|
||||||
|
// Ensure select has a value - use current value, saved value, or default
|
||||||
|
const selectValue = (value || field.value || field.default) as string;
|
||||||
return (
|
return (
|
||||||
<div key={field.id} className="space-y-2">
|
<div key={field.id} className="space-y-2">
|
||||||
<Label htmlFor={field.id}>
|
<Label htmlFor={field.id}>
|
||||||
@@ -173,7 +175,7 @@ export function GenericGatewayForm({ gateway, onSave, onCancel, hideFooter = fal
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Select
|
<Select
|
||||||
value={value as string}
|
value={selectValue}
|
||||||
onValueChange={(val) => handleFieldChange(field.id, val)}
|
onValueChange={(val) => handleFieldChange(field.id, val)}
|
||||||
>
|
>
|
||||||
<SelectTrigger id={field.id}>
|
<SelectTrigger id={field.id}>
|
||||||
|
|||||||
@@ -6,7 +6,16 @@ import { formatRelativeOrDate } from '@/lib/dates';
|
|||||||
import { formatMoney } from '@/lib/currency';
|
import { formatMoney } from '@/lib/currency';
|
||||||
import { ArrowLeft, Printer, ExternalLink, Loader2, Ticket, FileText, Pencil, RefreshCw } from 'lucide-react';
|
import { ArrowLeft, Printer, ExternalLink, Loader2, Ticket, FileText, Pencil, RefreshCw } from 'lucide-react';
|
||||||
import { Select, SelectTrigger, SelectContent, SelectItem, SelectValue } from '@/components/ui/select';
|
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 { Button } from '@/components/ui/button';
|
||||||
import { showErrorToast, showSuccessToast, getPageLoadErrorMessage } from '@/lib/errorHandling';
|
import { showErrorToast, showSuccessToast, getPageLoadErrorMessage } from '@/lib/errorHandling';
|
||||||
import { ErrorCard } from '@/components/ErrorCard';
|
import { ErrorCard } from '@/components/ErrorCard';
|
||||||
@@ -254,33 +263,33 @@ export default function OrderShow() {
|
|||||||
{__('Retry Payment')}
|
{__('Retry Payment')}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<Dialog open={showRetryDialog} onOpenChange={setShowRetryDialog}>
|
<AlertDialog open={showRetryDialog} onOpenChange={setShowRetryDialog}>
|
||||||
<DialogContent>
|
<AlertDialogContent>
|
||||||
<DialogHeader>
|
<AlertDialogHeader>
|
||||||
<DialogTitle>{__('Retry Payment')}</DialogTitle>
|
<AlertDialogTitle>{__('Retry Payment')}</AlertDialogTitle>
|
||||||
<DialogDescription>
|
<AlertDialogDescription>
|
||||||
{__('Are you sure you want to retry payment processing for this order?')}
|
{__('Are you sure you want to retry payment processing for this order?')}
|
||||||
<br />
|
<br />
|
||||||
<span className="text-amber-600 font-medium">
|
<span className="text-amber-600 font-medium">
|
||||||
{__('This will create a new payment transaction.')}
|
{__('This will create a new payment transaction.')}
|
||||||
</span>
|
</span>
|
||||||
</DialogDescription>
|
</AlertDialogDescription>
|
||||||
</DialogHeader>
|
</AlertDialogHeader>
|
||||||
<DialogFooter>
|
<AlertDialogFooter>
|
||||||
<Button variant="outline" onClick={() => setShowRetryDialog(false)}>
|
<AlertDialogCancel onClick={() => setShowRetryDialog(false)}>
|
||||||
{__('Cancel')}
|
{__('Cancel')}
|
||||||
</Button>
|
</AlertDialogCancel>
|
||||||
<Button onClick={confirmRetryPayment} disabled={retryPaymentMutation.isPending}>
|
<AlertDialogAction onClick={confirmRetryPayment} disabled={retryPaymentMutation.isPending}>
|
||||||
{retryPaymentMutation.isPending ? (
|
{retryPaymentMutation.isPending ? (
|
||||||
<Loader2 className="w-4 h-4 animate-spin mr-2" />
|
<Loader2 className="w-4 h-4 animate-spin mr-2" />
|
||||||
) : (
|
) : (
|
||||||
<RefreshCw className="w-4 h-4 mr-2" />
|
<RefreshCw className="w-4 h-4 mr-2" />
|
||||||
)}
|
)}
|
||||||
{__('Retry Payment')}
|
{__('Retry Payment')}
|
||||||
</Button>
|
</AlertDialogAction>
|
||||||
</DialogFooter>
|
</AlertDialogFooter>
|
||||||
</DialogContent>
|
</AlertDialogContent>
|
||||||
</Dialog>
|
</AlertDialog>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,7 +6,16 @@ import { ErrorCard } from '@/components/ErrorCard';
|
|||||||
import { getPageLoadErrorMessage } from '@/lib/errorHandling';
|
import { getPageLoadErrorMessage } from '@/lib/errorHandling';
|
||||||
import { __ } from '@/lib/i18n';
|
import { __ } from '@/lib/i18n';
|
||||||
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card';
|
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 { Button } from '@/components/ui/button';
|
||||||
import { Checkbox } from '@/components/ui/checkbox';
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
@@ -435,34 +444,33 @@ export default function Orders() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Delete Confirmation Dialog */}
|
{/* Delete Confirmation Dialog */}
|
||||||
<Dialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
|
<AlertDialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
|
||||||
<DialogContent>
|
<AlertDialogContent>
|
||||||
<DialogHeader>
|
<AlertDialogHeader>
|
||||||
<DialogTitle>{__('Delete Orders')}</DialogTitle>
|
<AlertDialogTitle>{__('Delete Orders')}</AlertDialogTitle>
|
||||||
<DialogDescription>
|
<AlertDialogDescription>
|
||||||
{__('Are you sure you want to delete')} {selectedIds.length} {selectedIds.length === 1 ? __('order') : __('orders')}?
|
{__('Are you sure you want to delete')} {selectedIds.length} {selectedIds.length === 1 ? __('order') : __('orders')}?
|
||||||
<br />
|
<br />
|
||||||
<span className="text-red-600 font-medium">{__('This action cannot be undone.')}</span>
|
<span className="text-red-600 font-medium">{__('This action cannot be undone.')}</span>
|
||||||
</DialogDescription>
|
</AlertDialogDescription>
|
||||||
</DialogHeader>
|
</AlertDialogHeader>
|
||||||
<DialogFooter>
|
<AlertDialogFooter>
|
||||||
<Button
|
<AlertDialogCancel
|
||||||
variant="outline"
|
|
||||||
onClick={() => setShowDeleteDialog(false)}
|
onClick={() => setShowDeleteDialog(false)}
|
||||||
disabled={deleteMutation.isPending}
|
disabled={deleteMutation.isPending}
|
||||||
>
|
>
|
||||||
{__('Cancel')}
|
{__('Cancel')}
|
||||||
</Button>
|
</AlertDialogCancel>
|
||||||
<Button
|
<AlertDialogAction
|
||||||
variant="destructive"
|
|
||||||
onClick={confirmDelete}
|
onClick={confirmDelete}
|
||||||
disabled={deleteMutation.isPending}
|
disabled={deleteMutation.isPending}
|
||||||
|
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||||
>
|
>
|
||||||
{deleteMutation.isPending ? __('Deleting...') : __('Delete')}
|
{deleteMutation.isPending ? __('Deleting...') : __('Delete')}
|
||||||
</Button>
|
</AlertDialogAction>
|
||||||
</DialogFooter>
|
</AlertDialogFooter>
|
||||||
</DialogContent>
|
</AlertDialogContent>
|
||||||
</Dialog>
|
</AlertDialog>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user