mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 17:31:13 -05:00
179 lines
5.1 KiB
TypeScript
179 lines
5.1 KiB
TypeScript
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 '@/lib/supabaseClient';
|
|
import { handleError, getErrorMessage } from '@/lib/errorHandler';
|
|
import { logger } from '@/lib/logger';
|
|
|
|
interface Moderator {
|
|
user_id: string;
|
|
username: string;
|
|
display_name?: string | null;
|
|
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);
|
|
|
|
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);
|
|
|
|
let profiles: Array<{ user_id: string; username: string; display_name?: string | null }> | null = null;
|
|
const { data: allProfiles, error: rpcError } = await supabase
|
|
.rpc('get_users_with_emails');
|
|
|
|
if (rpcError) {
|
|
// Fall back to basic profiles
|
|
const { data: basicProfiles } = await supabase
|
|
.from('profiles')
|
|
.select('user_id, username, display_name')
|
|
.in('user_id', userIds);
|
|
profiles = basicProfiles as typeof profiles;
|
|
} else {
|
|
profiles = allProfiles?.filter(p => userIds.includes(p.user_id)) || null;
|
|
}
|
|
|
|
|
|
|
|
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: unknown) {
|
|
handleError(error, {
|
|
action: 'Load Moderators List',
|
|
metadata: { submissionType }
|
|
});
|
|
} 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>
|
|
);
|
|
}
|