diff --git a/src/components/moderation/ItemLevelApprovalHistory.tsx b/src/components/moderation/ItemLevelApprovalHistory.tsx new file mode 100644 index 00000000..4d033cec --- /dev/null +++ b/src/components/moderation/ItemLevelApprovalHistory.tsx @@ -0,0 +1,125 @@ +import { memo } from 'react'; +import { formatDistanceToNow } from 'date-fns'; +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; +import { Badge } from '@/components/ui/badge'; +import { CheckCircle2, User } from 'lucide-react'; +import type { SubmissionItem } from '@/types/moderation'; + +interface ItemLevelApprovalHistoryProps { + items: SubmissionItem[]; + reviewerProfile?: { + user_id: string; + username: string; + display_name?: string | null; + avatar_url?: string | null; + } | null; +} + +export const ItemLevelApprovalHistory = memo(({ + items, + reviewerProfile, +}: ItemLevelApprovalHistoryProps) => { + // Filter to only approved items with timestamps + const approvedItems = items.filter( + item => item.status === 'approved' && (item as any).approved_at + ); + + if (approvedItems.length === 0) { + return null; + } + + // Sort by approval time (newest first) + const sortedItems = [...approvedItems].sort((a, b) => { + const timeA = new Date((a as any).approved_at).getTime(); + const timeB = new Date((b as any).approved_at).getTime(); + return timeB - timeA; + }); + + // Helper to get item display name + const getItemName = (item: SubmissionItem): string => { + const entityData = item.entity_data || item.item_data; + if (entityData && typeof entityData === 'object' && 'name' in entityData) { + return String(entityData.name); + } + return `${item.item_type} #${item.order_index}`; + }; + + // Helper to get action label + const getActionLabel = (actionType: string): string => { + switch (actionType) { + case 'create': return 'Created'; + case 'edit': return 'Edited'; + case 'delete': return 'Deleted'; + default: return 'Modified'; + } + }; + + return ( +