Refactor admin page layout

This commit is contained in:
gpt-engineer-app[bot]
2025-09-28 19:02:02 +00:00
parent 2c0af24daa
commit 89cbd6ae8e
2 changed files with 129 additions and 57 deletions

View File

@@ -1,11 +1,11 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { CheckCircle, XCircle, Eye, Calendar, User, Filter, MessageSquare, FileText, Image } from 'lucide-react'; import { CheckCircle, XCircle, Eye, Calendar, User, Filter, MessageSquare, FileText, Image, X } from 'lucide-react';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge'; import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardHeader } from '@/components/ui/card'; import { Card, CardContent, CardHeader } from '@/components/ui/card';
import { Textarea } from '@/components/ui/textarea'; import { Textarea } from '@/components/ui/textarea';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { supabase } from '@/integrations/supabase/client'; import { supabase } from '@/integrations/supabase/client';
import { useToast } from '@/hooks/use-toast'; import { useToast } from '@/hooks/use-toast';
import { format } from 'date-fns'; import { format } from 'date-fns';
@@ -455,56 +455,120 @@ export function ModerationQueue() {
); );
}; };
const clearFilters = () => {
setActiveEntityFilter('all');
setActiveStatusFilter('pending');
};
const getEntityFilterIcon = (filter: EntityFilter) => {
switch (filter) {
case 'reviews': return <MessageSquare className="w-4 h-4" />;
case 'submissions': return <FileText className="w-4 h-4" />;
case 'photos': return <Image className="w-4 h-4" />;
default: return <Filter className="w-4 h-4" />;
}
};
return ( return (
<div className="space-y-4"> <div className="space-y-4">
{/* Entity Type Filter */} {/* Filter Bar */}
<Tabs value={activeEntityFilter} onValueChange={(value) => setActiveEntityFilter(value as EntityFilter)}> <div className="flex flex-col sm:flex-row gap-4 p-4 bg-muted/50 rounded-lg">
<TabsList className="grid w-full grid-cols-4"> <div className="flex flex-col sm:flex-row gap-4 flex-1">
<TabsTrigger value="all" className="flex items-center gap-2"> <div className="space-y-2 min-w-[140px]">
<Label className="text-sm font-medium">Entity Type</Label>
<Select value={activeEntityFilter} onValueChange={(value) => setActiveEntityFilter(value as EntityFilter)}>
<SelectTrigger>
<SelectValue>
<div className="flex items-center gap-2">
{getEntityFilterIcon(activeEntityFilter)}
<span className="capitalize">{activeEntityFilter === 'all' ? 'All Items' : activeEntityFilter}</span>
</div>
</SelectValue>
</SelectTrigger>
<SelectContent>
<SelectItem value="all">
<div className="flex items-center gap-2">
<Filter className="w-4 h-4" /> <Filter className="w-4 h-4" />
All All Items
</TabsTrigger> </div>
<TabsTrigger value="reviews" className="flex items-center gap-2"> </SelectItem>
<SelectItem value="reviews">
<div className="flex items-center gap-2">
<MessageSquare className="w-4 h-4" /> <MessageSquare className="w-4 h-4" />
Reviews Reviews
</TabsTrigger> </div>
<TabsTrigger value="submissions" className="flex items-center gap-2"> </SelectItem>
<SelectItem value="submissions">
<div className="flex items-center gap-2">
<FileText className="w-4 h-4" /> <FileText className="w-4 h-4" />
Submissions Submissions
</TabsTrigger> </div>
<TabsTrigger value="photos" className="flex items-center gap-2"> </SelectItem>
<SelectItem value="photos">
<div className="flex items-center gap-2">
<Image className="w-4 h-4" /> <Image className="w-4 h-4" />
Photos Photos
</TabsTrigger> </div>
</TabsList> </SelectItem>
</Tabs> </SelectContent>
</Select>
</div>
{/* Status Filter */} <div className="space-y-2 min-w-[120px]">
<Tabs value={activeStatusFilter} onValueChange={(value) => setActiveStatusFilter(value as StatusFilter)}> <Label className="text-sm font-medium">Status</Label>
<TabsList className="grid w-full grid-cols-5"> <Select value={activeStatusFilter} onValueChange={(value) => setActiveStatusFilter(value as StatusFilter)}>
<TabsTrigger value="all" className="flex items-center gap-2"> <SelectTrigger>
<Filter className="w-4 h-4" /> <SelectValue>
All <span className="capitalize">{activeStatusFilter === 'all' ? 'All Status' : activeStatusFilter}</span>
</TabsTrigger> </SelectValue>
<TabsTrigger value="pending" className="flex items-center gap-2"> </SelectTrigger>
<Eye className="w-4 h-4" /> <SelectContent>
Pending <SelectItem value="all">All Status</SelectItem>
</TabsTrigger> <SelectItem value="pending">Pending</SelectItem>
<TabsTrigger value="flagged" className="flex items-center gap-2"> {activeEntityFilter !== 'submissions' && activeEntityFilter !== 'photos' && (
<XCircle className="w-4 h-4" /> <SelectItem value="flagged">Flagged</SelectItem>
Flagged )}
</TabsTrigger> <SelectItem value="approved">Approved</SelectItem>
<TabsTrigger value="approved" className="flex items-center gap-2"> <SelectItem value="rejected">Rejected</SelectItem>
<CheckCircle className="w-4 h-4" /> </SelectContent>
Approved </Select>
</TabsTrigger> </div>
<TabsTrigger value="rejected" className="flex items-center gap-2"> </div>
<XCircle className="w-4 h-4" />
Rejected
</TabsTrigger>
</TabsList>
</Tabs>
{(activeEntityFilter !== 'all' || activeStatusFilter !== 'pending') && (
<div className="flex items-end">
<Button
variant="outline"
size="sm"
onClick={clearFilters}
className="flex items-center gap-2"
>
<X className="w-4 h-4" />
Clear Filters
</Button>
</div>
)}
</div>
{/* Active Filters Display */}
{(activeEntityFilter !== 'all' || activeStatusFilter !== 'pending') && (
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<span>Active filters:</span>
{activeEntityFilter !== 'all' && (
<Badge variant="secondary" className="flex items-center gap-1">
{getEntityFilterIcon(activeEntityFilter)}
{activeEntityFilter}
</Badge>
)}
{activeStatusFilter !== 'pending' && (
<Badge variant="secondary" className="capitalize">
{activeStatusFilter}
</Badge>
)}
</div>
)}
{/* Queue Content */}
<QueueContent /> <QueueContent />
</div> </div>
); );

View File

@@ -98,8 +98,24 @@ export default function Admin() {
</Card> </Card>
</div> </div>
{/* User Management Section */}
<Card className="mb-8">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Users className="w-5 h-5" />
User Management
</CardTitle>
<CardDescription>
Manage user profiles and role assignments
</CardDescription>
</CardHeader>
<CardContent>
<UserManagement />
</CardContent>
</Card>
<Tabs defaultValue="queue" className="space-y-6"> <Tabs defaultValue="queue" className="space-y-6">
<TabsList className="grid w-full grid-cols-3"> <TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="queue" className="flex items-center gap-2"> <TabsTrigger value="queue" className="flex items-center gap-2">
<FileText className="w-4 h-4" /> <FileText className="w-4 h-4" />
Moderation Queue Moderation Queue
@@ -108,10 +124,6 @@ export default function Admin() {
<Flag className="w-4 h-4" /> <Flag className="w-4 h-4" />
Reports Reports
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="users" className="flex items-center gap-2">
<Users className="w-4 h-4" />
User Management
</TabsTrigger>
</TabsList> </TabsList>
<TabsContent value="queue"> <TabsContent value="queue">
@@ -141,10 +153,6 @@ export default function Admin() {
</CardContent> </CardContent>
</Card> </Card>
</TabsContent> </TabsContent>
<TabsContent value="users">
<UserManagement />
</TabsContent>
</Tabs> </Tabs>
</div> </div>
</> </>