mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 08:51:13 -05:00
133 lines
4.7 KiB
TypeScript
133 lines
4.7 KiB
TypeScript
import { useState } from 'react';
|
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/dialog';
|
|
import { Button } from '@/components/ui/button';
|
|
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
|
import { Label } from '@/components/ui/label';
|
|
import { Alert, AlertDescription } from '@/components/ui/alert';
|
|
import { AlertCircle } from 'lucide-react';
|
|
import { type DependencyConflict, type SubmissionItemWithDeps } from '@/lib/submissionItemsService';
|
|
import { useAuth } from '@/hooks/useAuth';
|
|
import { handleError, handleSuccess } from '@/lib/errorHandler';
|
|
|
|
interface ConflictResolutionDialogProps {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
conflicts: DependencyConflict[];
|
|
items: SubmissionItemWithDeps[];
|
|
onResolve: () => void;
|
|
}
|
|
|
|
export function ConflictResolutionDialog({
|
|
open,
|
|
onOpenChange,
|
|
conflicts,
|
|
items,
|
|
onResolve,
|
|
}: ConflictResolutionDialogProps) {
|
|
const [resolutions, setResolutions] = useState<Record<string, string>>({});
|
|
const { user } = useAuth();
|
|
|
|
const handleResolutionChange = (itemId: string, action: string) => {
|
|
setResolutions(prev => ({ ...prev, [itemId]: action }));
|
|
};
|
|
|
|
const allConflictsResolved = conflicts.every(
|
|
conflict => resolutions[conflict.itemId]
|
|
);
|
|
|
|
const handleApply = async () => {
|
|
if (!user?.id) {
|
|
handleError(new Error('Authentication required'), {
|
|
action: 'Resolve Conflicts',
|
|
metadata: { conflictCount: conflicts.length }
|
|
});
|
|
return;
|
|
}
|
|
|
|
const { resolveConflicts } = await import('@/lib/conflictResolutionService');
|
|
|
|
try {
|
|
const result = await resolveConflicts(conflicts, resolutions, items, user.id);
|
|
|
|
if (!result.success) {
|
|
handleError(new Error(result.error || 'Failed to resolve conflicts'), {
|
|
action: 'Resolve Conflicts',
|
|
userId: user.id,
|
|
metadata: { conflictCount: conflicts.length }
|
|
});
|
|
return;
|
|
}
|
|
|
|
handleSuccess('Conflicts Resolved', 'All conflicts have been resolved successfully');
|
|
onResolve();
|
|
onOpenChange(false);
|
|
} catch (error: unknown) {
|
|
handleError(error, {
|
|
action: 'Resolve Conflicts',
|
|
userId: user.id,
|
|
metadata: { conflictCount: conflicts.length }
|
|
});
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent className="max-w-2xl max-h-[80vh] overflow-y-auto">
|
|
<DialogHeader>
|
|
<DialogTitle>Resolve Dependency Conflicts</DialogTitle>
|
|
<DialogDescription>
|
|
{conflicts.length} conflict(s) found. Choose how to resolve each one.
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div className="space-y-6 py-4">
|
|
{conflicts.map((conflict) => {
|
|
const item = items.find(i => i.id === conflict.itemId);
|
|
|
|
return (
|
|
<div key={conflict.itemId} className="space-y-3">
|
|
<Alert variant="destructive">
|
|
<AlertCircle className="h-4 w-4" />
|
|
<AlertDescription>
|
|
<p className="font-medium">
|
|
{item?.item_type.replace('_', ' ').toUpperCase()}: {
|
|
item && typeof item.item_data === 'object' && item.item_data !== null && !Array.isArray(item.item_data) && 'name' in item.item_data
|
|
? String((item.item_data as Record<string, unknown>).name)
|
|
: 'Unnamed'
|
|
}
|
|
</p>
|
|
<p className="text-sm mt-1">{conflict.message}</p>
|
|
</AlertDescription>
|
|
</Alert>
|
|
|
|
<RadioGroup
|
|
value={resolutions[conflict.itemId] || ''}
|
|
onValueChange={(value) => handleResolutionChange(conflict.itemId, value)}
|
|
>
|
|
{conflict.suggestions.map((suggestion, idx) => (
|
|
<div key={idx} className="flex items-center space-x-2">
|
|
<RadioGroupItem value={suggestion.action} id={`${conflict.itemId}-${idx}`} />
|
|
<Label htmlFor={`${conflict.itemId}-${idx}`} className="cursor-pointer">
|
|
{suggestion.label}
|
|
</Label>
|
|
</div>
|
|
))}
|
|
</RadioGroup>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
<DialogFooter>
|
|
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
|
Cancel
|
|
</Button>
|
|
<Button onClick={handleApply} disabled={!allConflictsResolved}>
|
|
Apply & Approve
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|