From 337552224bb411214bc92fd339a73da94d25119c Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 14:16:59 +0000 Subject: [PATCH] feat: Implement item editing capability --- src/components/moderation/ItemEditDialog.tsx | 276 ++++++++++++++++++ src/components/moderation/ItemReviewCard.tsx | 5 + .../moderation/SubmissionReviewManager.tsx | 23 +- src/lib/submissionItemsService.ts | 82 ++++++ 4 files changed, 385 insertions(+), 1 deletion(-) create mode 100644 src/components/moderation/ItemEditDialog.tsx diff --git a/src/components/moderation/ItemEditDialog.tsx b/src/components/moderation/ItemEditDialog.tsx new file mode 100644 index 00000000..d1f65dbf --- /dev/null +++ b/src/components/moderation/ItemEditDialog.tsx @@ -0,0 +1,276 @@ +import { useState } from 'react'; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog'; +import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription } from '@/components/ui/sheet'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { Textarea } from '@/components/ui/textarea'; +import { toast } from '@/hooks/use-toast'; +import { useIsMobile } from '@/hooks/use-mobile'; +import { useUserRole } from '@/hooks/useUserRole'; +import { useAuth } from '@/hooks/useAuth'; +import { editSubmissionItem, type SubmissionItemWithDeps } from '@/lib/submissionItemsService'; +import { ParkForm } from '@/components/admin/ParkForm'; +import { RideForm } from '@/components/admin/RideForm'; +import { ManufacturerForm } from '@/components/admin/ManufacturerForm'; +import { DesignerForm } from '@/components/admin/DesignerForm'; +import { OperatorForm } from '@/components/admin/OperatorForm'; +import { PropertyOwnerForm } from '@/components/admin/PropertyOwnerForm'; +import { RideModelForm } from '@/components/admin/RideModelForm'; +import { Save, X, Edit } from 'lucide-react'; + +interface ItemEditDialogProps { + item: SubmissionItemWithDeps | null; + open: boolean; + onOpenChange: (open: boolean) => void; + onComplete: () => void; +} + +export function ItemEditDialog({ item, open, onOpenChange, onComplete }: ItemEditDialogProps) { + const [submitting, setSubmitting] = useState(false); + const isMobile = useIsMobile(); + const { isModerator } = useUserRole(); + const { user } = useAuth(); + const Container = isMobile ? Sheet : Dialog; + + if (!item) return null; + + const handleSubmit = async (data: any) => { + if (!user?.id) { + toast({ + title: 'Authentication Required', + description: 'You must be logged in to edit items', + variant: 'destructive', + }); + return; + } + + setSubmitting(true); + try { + await editSubmissionItem(item.id, data, user.id); + + toast({ + title: isModerator() ? 'Item Updated' : 'Edit Submitted', + description: isModerator() + ? 'The item has been updated successfully.' + : 'Your edit has been submitted and will be reviewed by a moderator.', + }); + + onComplete(); + onOpenChange(false); + } catch (error: any) { + toast({ + title: 'Error', + description: error.message || 'Failed to save changes', + variant: 'destructive', + }); + } finally { + setSubmitting(false); + } + }; + + const handlePhotoSubmit = async (caption: string, credit: string) => { + const photoData = { + ...item.item_data, + photos: item.item_data.photos?.map((photo: any) => ({ + ...photo, + caption, + credit, + })), + }; + await handleSubmit(photoData); + }; + + const renderEditForm = () => { + const data = item.item_data; + + switch (item.item_type) { + case 'park': + return ( + onOpenChange(false)} + initialData={data} + isEditing + /> + ); + + case 'ride': + return ( + onOpenChange(false)} + initialData={data} + isEditing + /> + ); + + case 'manufacturer': + return ( + onOpenChange(false)} + initialData={data} + /> + ); + + case 'designer': + return ( + onOpenChange(false)} + initialData={data} + /> + ); + + case 'operator': + return ( + onOpenChange(false)} + initialData={data} + /> + ); + + case 'property_owner': + return ( + onOpenChange(false)} + initialData={data} + /> + ); + + case 'ride_model': + return ( + onOpenChange(false)} + initialData={data} + /> + ); + + case 'photo': + return ( + onOpenChange(false)} + submitting={submitting} + /> + ); + + default: + return ( +
+ No edit form available for this item type +
+ ); + } + }; + + return ( + + {isMobile ? ( + + + + + Edit {item.item_type.replace('_', ' ')} + + + Make changes to this submission item + + +
+ {renderEditForm()} +
+
+ ) : ( + + + + + Edit {item.item_type.replace('_', ' ')} + + + Make changes to this submission item + + +
+ {renderEditForm()} +
+
+ )} +
+ ); +} + +// Simple photo editing form for caption and credit +function PhotoEditForm({ + photos, + onSubmit, + onCancel, + submitting +}: { + photos: any[]; + onSubmit: (caption: string, credit: string) => void; + onCancel: () => void; + submitting: boolean; +}) { + const [caption, setCaption] = useState(photos[0]?.caption || ''); + const [credit, setCredit] = useState(photos[0]?.credit || ''); + + return ( +
+ {/* Photo Preview */} +
+ {photos.slice(0, 3).map((photo, idx) => ( + {photo.caption + ))} +
+ + {/* Caption */} +
+ +