feat: Implement complete queue system

This commit is contained in:
gpt-engineer-app[bot]
2025-10-06 14:43:31 +00:00
parent d955037990
commit 3dec0b2a97
6 changed files with 417 additions and 16 deletions

View File

@@ -0,0 +1,170 @@
import { useState, useEffect } from 'react';
import { UserCog } from 'lucide-react';
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { supabase } from '@/integrations/supabase/client';
import { useToast } from '@/hooks/use-toast';
interface Moderator {
user_id: string;
username: string;
display_name?: string;
role: string;
}
interface ReassignDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
onReassign: (moderatorId: string) => Promise<void>;
submissionType: string;
}
export function ReassignDialog({
open,
onOpenChange,
onReassign,
submissionType,
}: ReassignDialogProps) {
const [selectedModerator, setSelectedModerator] = useState<string>('');
const [moderators, setModerators] = useState<Moderator[]>([]);
const [isSubmitting, setIsSubmitting] = useState(false);
const [loading, setLoading] = useState(true);
const { toast } = useToast();
useEffect(() => {
if (open) {
fetchModerators();
}
}, [open]);
const fetchModerators = async () => {
setLoading(true);
try {
const { data: roles, error: rolesError } = await supabase
.from('user_roles')
.select('user_id, role')
.in('role', ['moderator', 'admin', 'superuser']);
if (rolesError) throw rolesError;
if (!roles || roles.length === 0) {
setModerators([]);
return;
}
const userIds = roles.map((r) => r.user_id);
const { data: profiles, error: profilesError } = await supabase
.from('profiles')
.select('user_id, username, display_name')
.in('user_id', userIds);
if (profilesError) throw profilesError;
const moderatorsList = roles.map((role) => {
const profile = profiles?.find((p) => p.user_id === role.user_id);
return {
user_id: role.user_id,
username: profile?.username || 'Unknown',
display_name: profile?.display_name,
role: role.role,
};
});
setModerators(moderatorsList);
} catch (error: any) {
console.error('Error fetching moderators:', error);
toast({
title: 'Error',
description: 'Failed to load moderators list',
variant: 'destructive',
});
} finally {
setLoading(false);
}
};
const handleReassign = async () => {
if (!selectedModerator) return;
setIsSubmitting(true);
try {
await onReassign(selectedModerator);
setSelectedModerator('');
onOpenChange(false);
} finally {
setIsSubmitting(false);
}
};
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent>
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<UserCog className="h-5 w-5" />
Reassign Submission
</DialogTitle>
<DialogDescription>
Assign this {submissionType} to another moderator. They will receive a lock for 15 minutes.
</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-4">
<div className="space-y-2">
<Label htmlFor="moderator">Select Moderator</Label>
{loading ? (
<div className="text-sm text-muted-foreground">Loading moderators...</div>
) : moderators.length === 0 ? (
<div className="text-sm text-muted-foreground">No moderators available</div>
) : (
<Select value={selectedModerator} onValueChange={setSelectedModerator}>
<SelectTrigger id="moderator">
<SelectValue placeholder="Choose a moderator" />
</SelectTrigger>
<SelectContent>
{moderators.map((mod) => (
<SelectItem key={mod.user_id} value={mod.user_id}>
{mod.display_name || mod.username} ({mod.role})
</SelectItem>
))}
</SelectContent>
</Select>
)}
</div>
</div>
<DialogFooter>
<Button
variant="outline"
onClick={() => onOpenChange(false)}
disabled={isSubmitting}
>
Cancel
</Button>
<Button
onClick={handleReassign}
disabled={!selectedModerator || isSubmitting}
>
{isSubmitting ? 'Reassigning...' : 'Reassign'}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}