Fix: Prevent approval with blocking errors

This commit is contained in:
gpt-engineer-app[bot]
2025-10-13 20:22:34 +00:00
parent 3aa928da00
commit dc21e2a6aa
3 changed files with 49 additions and 3 deletions

View File

@@ -74,8 +74,10 @@ export function ItemReviewCard({ item, onEdit, onStatusChange, submissionId }: I
); );
}; };
const hasBlockingErrors = validationResult && validationResult.blockingErrors.length > 0;
return ( return (
<Card className="w-full"> <Card className={`w-full ${hasBlockingErrors ? 'border-destructive border-2' : ''}`}>
<CardHeader className={isMobile ? "pb-3 p-4" : "pb-3"}> <CardHeader className={isMobile ? "pb-3 p-4" : "pb-3"}>
<div className={`flex gap-2 ${isMobile ? 'flex-col' : 'items-start justify-between'}`}> <div className={`flex gap-2 ${isMobile ? 'flex-col' : 'items-start justify-between'}`}>
<div className="flex items-center gap-2 flex-wrap"> <div className="flex items-center gap-2 flex-wrap">
@@ -89,6 +91,11 @@ export function ItemReviewCard({ item, onEdit, onStatusChange, submissionId }: I
Moderator Edited Moderator Edited
</Badge> </Badge>
)} )}
{hasBlockingErrors && (
<Badge variant="destructive" className="text-xs">
Blocked
</Badge>
)}
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Badge variant={getStatusColor()} className={isMobile ? "text-xs" : ""}> <Badge variant={getStatusColor()} className={isMobile ? "text-xs" : ""}>

View File

@@ -60,6 +60,7 @@ export function SubmissionReviewManager({
const [showWarningConfirmDialog, setShowWarningConfirmDialog] = useState(false); const [showWarningConfirmDialog, setShowWarningConfirmDialog] = useState(false);
const [validationResults, setValidationResults] = useState<Map<string, ValidationResult>>(new Map()); const [validationResults, setValidationResults] = useState<Map<string, ValidationResult>>(new Map());
const [userConfirmedWarnings, setUserConfirmedWarnings] = useState(false); const [userConfirmedWarnings, setUserConfirmedWarnings] = useState(false);
const [hasBlockingErrors, setHasBlockingErrors] = useState(false);
const { toast } = useToast(); const { toast } = useToast();
const { isAdmin, isSuperuser } = useUserRole(); const { isAdmin, isSuperuser } = useUserRole();
@@ -117,6 +118,9 @@ export function SubmissionReviewManager({
} else { } else {
next.add(itemId); next.add(itemId);
} }
// Clear blocking errors when selection changes
setHasBlockingErrors(false);
setValidationResults(new Map());
return next; return next;
}); });
}; };
@@ -176,6 +180,7 @@ export function SubmissionReviewManager({
}); });
if (itemsWithBlockingErrors.length > 0 && !userConfirmedWarnings) { if (itemsWithBlockingErrors.length > 0 && !userConfirmedWarnings) {
setHasBlockingErrors(true);
setShowValidationBlockerDialog(true); setShowValidationBlockerDialog(true);
setLoading(false); setLoading(false);
return; // Block approval return; // Block approval
@@ -475,6 +480,29 @@ export function SubmissionReviewManager({
onOpenChange={setShowEditDialog} onOpenChange={setShowEditDialog}
onComplete={handleEditComplete} onComplete={handleEditComplete}
/> />
<ValidationBlockerDialog
open={showValidationBlockerDialog}
onClose={() => setShowValidationBlockerDialog(false)}
blockingErrors={Array.from(validationResults.values()).flatMap(r => r.blockingErrors)}
itemNames={items.filter(i => selectedItemIds.has(i.id)).map(i =>
i.item_data?.name || i.item_type.replace('_', ' ')
)}
/>
<WarningConfirmDialog
open={showWarningConfirmDialog}
onClose={() => setShowWarningConfirmDialog(false)}
onProceed={() => {
setUserConfirmedWarnings(true);
setShowWarningConfirmDialog(false);
handleApprove();
}}
warnings={Array.from(validationResults.values()).flatMap(r => r.warnings)}
itemNames={items.filter(i => selectedItemIds.has(i.id)).map(i =>
i.item_data?.name || i.item_type.replace('_', ' ')
)}
/>
</> </>
); );
@@ -532,11 +560,21 @@ export function SubmissionReviewManager({
</TabsContent> </TabsContent>
</Tabs> </Tabs>
{/* Blocking error alert */}
{hasBlockingErrors && (
<Alert variant="destructive">
<AlertCircle className="w-4 h-4" />
<AlertDescription>
Cannot approve: Selected items have validation errors that must be fixed first.
</AlertDescription>
</Alert>
)}
{/* Action buttons */} {/* Action buttons */}
<div className="flex flex-col sm:flex-row gap-2 pt-4 border-t"> <div className="flex flex-col sm:flex-row gap-2 pt-4 border-t">
<Button <Button
onClick={handleCheckConflicts} onClick={handleCheckConflicts}
disabled={selectedCount === 0 || loading} disabled={selectedCount === 0 || loading || hasBlockingErrors}
className="flex-1" className="flex-1"
> >
<CheckCircle2 className="w-4 h-4 mr-2" /> <CheckCircle2 className="w-4 h-4 mr-2" />

View File

@@ -33,7 +33,8 @@ export function ValidationBlockerDialog({
Cannot Approve: Validation Errors Cannot Approve: Validation Errors
</AlertDialogTitle> </AlertDialogTitle>
<AlertDialogDescription> <AlertDialogDescription>
The following items have blocking validation errors that must be fixed before approval: The following items have blocking validation errors that MUST be fixed before approval.
These items cannot be approved until the errors are resolved. Please edit or reject them.
</AlertDialogDescription> </AlertDialogDescription>
</AlertDialogHeader> </AlertDialogHeader>