From 1138eea02402867553f051cb98e4a2df6703aa38 Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 21 Oct 2025 12:18:38 +0000 Subject: [PATCH] Implement all phases sequentially --- src/components/admin/ParkForm.tsx | 43 +++++++++++++++++----- src/components/admin/RideForm.tsx | 53 +++++++++++++--------------- src/lib/companyHelpers.ts | 8 ++--- src/lib/conflictResolutionService.ts | 6 ++-- src/lib/entityValidationSchemas.ts | 4 +-- src/lib/moderation/actions.ts | 4 +-- src/lib/runtimeValidation.ts | 4 +-- src/pages/RideDetail.tsx | 2 +- src/types/database.ts | 4 +-- src/types/submissions.ts | 3 +- 10 files changed, 77 insertions(+), 54 deletions(-) diff --git a/src/components/admin/ParkForm.tsx b/src/components/admin/ParkForm.tsx index 51ef6a59..2df5b05d 100644 --- a/src/components/admin/ParkForm.tsx +++ b/src/components/admin/ParkForm.tsx @@ -101,13 +101,32 @@ const parkTypes = [ const statusOptions = [ 'Operating', - 'Seasonal', 'Closed Temporarily', 'Closed Permanently', 'Under Construction', - 'Planned' + 'Planned', + 'Abandoned' ]; +// Status mappings +const STATUS_DISPLAY_TO_DB: Record = { + 'Operating': 'operating', + 'Closed Temporarily': 'closed_temporarily', + 'Closed Permanently': 'closed_permanently', + 'Under Construction': 'under_construction', + 'Planned': 'planned', + 'Abandoned': 'abandoned' +}; + +const STATUS_DB_TO_DISPLAY: Record = { + 'operating': 'Operating', + 'closed_temporarily': 'Closed Temporarily', + 'closed_permanently': 'Closed Permanently', + 'under_construction': 'Under Construction', + 'planned': 'Planned', + 'abandoned': 'Abandoned' +}; + export function ParkForm({ onSubmit, onCancel, initialData, isEditing = false }: ParkFormProps) { const { isModerator } = useUserRole(); const [submitting, setSubmitting] = useState(false); @@ -146,7 +165,7 @@ export function ParkForm({ onSubmit, onCancel, initialData, isEditing = false }: slug: initialData?.slug || '', description: initialData?.description || '', park_type: initialData?.park_type || '', - status: initialData?.status || 'Operating', + status: initialData?.status || 'operating' as const, // Store DB value opening_date: initialData?.opening_date || '', closing_date: initialData?.closing_date || '', location_id: initialData?.location_id || undefined, @@ -275,16 +294,22 @@ export function ParkForm({ onSubmit, onCancel, initialData, isEditing = false }:
- setValue('status', value as any)} + defaultValue={initialData?.status || 'operating'} + > - {statusOptions.map((status) => ( - - {status} - - ))} + {statusOptions.map((displayStatus) => { + const dbValue = STATUS_DISPLAY_TO_DB[displayStatus]; + return ( + + {displayStatus} + + ); + })} {errors.status && ( diff --git a/src/components/admin/RideForm.tsx b/src/components/admin/RideForm.tsx index 1e256a92..dc0d6e0d 100644 --- a/src/components/admin/RideForm.tsx +++ b/src/components/admin/RideForm.tsx @@ -64,12 +64,12 @@ const categories = [ const statusOptions = [ 'Operating', - 'Seasonal', 'Closed Temporarily', 'Closed Permanently', 'Under Construction', - 'Planned', - 'SBNO' // Standing But Not Operating + 'Relocated', + 'Stored', + 'Demolished' ]; const coasterTypes = [ @@ -99,20 +99,22 @@ const intensityLevels = [ // Status value mappings between display (form) and database values const STATUS_DISPLAY_TO_DB: Record = { 'Operating': 'operating', - 'Seasonal': 'operating', - 'Closed Temporarily': 'maintenance', - 'Closed Permanently': 'closed', + 'Closed Temporarily': 'closed_temporarily', + 'Closed Permanently': 'closed_permanently', 'Under Construction': 'under_construction', - 'Planned': 'under_construction', - 'SBNO': 'sbno' + 'Relocated': 'relocated', + 'Stored': 'stored', + 'Demolished': 'demolished' }; const STATUS_DB_TO_DISPLAY: Record = { 'operating': 'Operating', - 'closed': 'Closed Permanently', + 'closed_permanently': 'Closed Permanently', + 'closed_temporarily': 'Closed Temporarily', 'under_construction': 'Under Construction', - 'maintenance': 'Closed Temporarily', - 'sbno': 'SBNO' + 'relocated': 'Relocated', + 'stored': 'Stored', + 'demolished': 'Demolished' }; export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }: RideFormProps) { @@ -180,9 +182,7 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }: description: initialData?.description || '', category: initialData?.category || '', ride_sub_type: initialData?.ride_sub_type || '', - status: initialData?.status - ? STATUS_DB_TO_DISPLAY[initialData.status] || 'Operating' - : 'Operating', + status: initialData?.status || 'operating' as const, // Store DB value directly opening_date: initialData?.opening_date || '', opening_date_precision: initialData?.opening_date_precision || 'day', closing_date: initialData?.closing_date || '', @@ -223,13 +223,10 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }: const handleFormSubmit = async (data: RideFormData) => { setSubmitting(true); try { - // Transform status from display value to DB value - const dbStatus = STATUS_DISPLAY_TO_DB[data.status] || 'operating'; - // Convert form values back to metric for storage const metricData = { ...data, - status: dbStatus, + // Status is already in DB format height_requirement: data.height_requirement ? convertValueToMetric(data.height_requirement, getDisplayUnit('cm', measurementSystem)) : undefined, @@ -354,21 +351,21 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }:
{errors.status && ( diff --git a/src/lib/companyHelpers.ts b/src/lib/companyHelpers.ts index bd3a6d09..cd9990ff 100644 --- a/src/lib/companyHelpers.ts +++ b/src/lib/companyHelpers.ts @@ -40,7 +40,7 @@ export async function submitCompanyCreation( content: { action: 'create' }, - status: 'pending' + status: 'pending' as const }) .select() .single(); @@ -64,7 +64,7 @@ export async function submitCompanyCreation( company_type: companyType, images: processedImages as unknown as Json }, - status: 'pending', + status: 'pending' as const, order_index: 0 }); @@ -118,7 +118,7 @@ export async function submitCompanyUpdate( action: 'edit', company_id: companyId }, - status: 'pending' + status: 'pending' as const }) .select() .single(); @@ -143,7 +143,7 @@ export async function submitCompanyUpdate( images: processedImages as unknown as Json }, original_data: JSON.parse(JSON.stringify(existingCompany)), - status: 'pending', + status: 'pending' as const, order_index: 0 }); diff --git a/src/lib/conflictResolutionService.ts b/src/lib/conflictResolutionService.ts index c0eb07de..32c95aa0 100644 --- a/src/lib/conflictResolutionService.ts +++ b/src/lib/conflictResolutionService.ts @@ -105,7 +105,7 @@ export async function resolveConflicts( async function linkToExistingEntity(itemId: string, entityId: string): Promise { await updateSubmissionItem(itemId, { approved_entity_id: entityId, - status: 'approved', + status: 'approved' as const, }); } @@ -135,7 +135,7 @@ async function cascadeRejectDependents( // Reject all collected dependents for (const depId of toReject) { await updateSubmissionItem(depId, { - status: 'rejected', + status: 'rejected' as const, rejection_reason: 'Parent dependency was rejected', }); } @@ -152,7 +152,7 @@ async function escalateForAdminReview( const { error } = await supabase .from('content_submissions') .update({ - status: 'pending', + status: 'pending' as const, escalation_reason: reason, escalated_by: userId, updated_at: new Date().toISOString(), diff --git a/src/lib/entityValidationSchemas.ts b/src/lib/entityValidationSchemas.ts index 397e3b3e..66537270 100644 --- a/src/lib/entityValidationSchemas.ts +++ b/src/lib/entityValidationSchemas.ts @@ -27,7 +27,7 @@ export const parkValidationSchema = z.object({ slug: z.string().trim().min(1, 'Slug is required').regex(/^[a-z0-9-]+$/, 'Slug must contain only lowercase letters, numbers, and hyphens'), description: z.string().trim().max(2000, 'Description must be less than 2000 characters').optional().or(z.literal('')), park_type: z.string().min(1, 'Park type is required'), - status: z.string().min(1, 'Status is required'), + status: z.enum(['operating', 'closed_permanently', 'closed_temporarily', 'under_construction', 'planned', 'abandoned']), opening_date: z.string().optional().or(z.literal('')).refine((val) => { if (!val) return true; const date = new Date(val); @@ -73,7 +73,7 @@ export const rideValidationSchema = z.object({ description: z.string().trim().max(2000, 'Description must be less than 2000 characters').optional().or(z.literal('')), category: z.string().min(1, 'Category is required'), ride_sub_type: z.string().trim().max(100, 'Sub type must be less than 100 characters').optional().or(z.literal('')), - status: z.string().min(1, 'Status is required'), + status: z.enum(['operating', 'closed_permanently', 'closed_temporarily', 'under_construction', 'relocated', 'stored', 'demolished']), park_id: z.string().uuid().optional().nullable(), designer_id: z.string().uuid().optional().nullable(), opening_date: z.string().optional().or(z.literal('')), diff --git a/src/lib/moderation/actions.ts b/src/lib/moderation/actions.ts index acdeb9df..875f3374 100644 --- a/src/lib/moderation/actions.ts +++ b/src/lib/moderation/actions.ts @@ -136,7 +136,7 @@ export async function approvePhotoSubmission( const { error: updateError } = await supabase .from('content_submissions') .update({ - status: 'approved', + status: 'approved' as const, reviewer_id: config.moderatorId, reviewed_at: new Date().toISOString(), reviewer_notes: config.moderatorNotes, @@ -239,7 +239,7 @@ export async function rejectSubmissionItems( const { error: rejectError } = await supabase .from('submission_items') .update({ - status: 'rejected', + status: 'rejected' as const, rejection_reason: rejectionReason || 'Parent submission rejected', updated_at: new Date().toISOString(), }) diff --git a/src/lib/runtimeValidation.ts b/src/lib/runtimeValidation.ts index 06fbeceb..11976f1a 100644 --- a/src/lib/runtimeValidation.ts +++ b/src/lib/runtimeValidation.ts @@ -18,7 +18,7 @@ export const parkRuntimeSchema = z.object({ slug: z.string(), description: z.string().nullable().optional(), park_type: z.string(), - status: z.string(), + status: z.enum(['operating', 'closed_permanently', 'closed_temporarily', 'under_construction', 'planned', 'abandoned']), opening_date: z.string().nullable().optional(), opening_date_precision: z.string().nullable().optional(), closing_date: z.string().nullable().optional(), @@ -51,7 +51,7 @@ export const rideRuntimeSchema = z.object({ description: z.string().nullable().optional(), category: z.string(), ride_sub_type: z.string().nullable().optional(), - status: z.string(), + status: z.enum(['operating', 'closed_permanently', 'closed_temporarily', 'under_construction', 'relocated', 'stored', 'demolished']), park_id: z.string().uuid().nullable().optional(), manufacturer_id: z.string().uuid().nullable().optional(), designer_id: z.string().uuid().nullable().optional(), diff --git a/src/pages/RideDetail.tsx b/src/pages/RideDetail.tsx index 620e147e..24551a07 100644 --- a/src/pages/RideDetail.tsx +++ b/src/pages/RideDetail.tsx @@ -738,7 +738,7 @@ export default function RideDetail() { description: ride.description, category: ride.category, ride_sub_type: ride.ride_sub_type, - status: ride.status, + status: ride.status as any, // Type assertion for DB status opening_date: ride.opening_date, closing_date: ride.closing_date, height_requirement: ride.height_requirement, diff --git a/src/types/database.ts b/src/types/database.ts index e5e3c0d1..db245861 100644 --- a/src/types/database.ts +++ b/src/types/database.ts @@ -211,7 +211,7 @@ export interface AccountDeletionRequest { scheduled_deletion_at: string; confirmation_code: string; confirmation_code_sent_at?: string; - status: 'pending' | 'confirmed' | 'cancelled' | 'completed'; + status: 'pending' | 'confirmed' | 'cancelled' | 'completed'; // Account deletion specific status cancelled_at?: string; completed_at?: string; cancellation_reason?: string; @@ -232,7 +232,7 @@ export interface Review { photos?: any; helpful_votes: number; total_votes: number; - moderation_status: 'pending' | 'approved' | 'rejected' | 'flagged'; + moderation_status: 'pending' | 'approved' | 'rejected' | 'flagged'; // Review moderation status created_at: string; updated_at: string; } diff --git a/src/types/submissions.ts b/src/types/submissions.ts index e8c4d607..acfb9f55 100644 --- a/src/types/submissions.ts +++ b/src/types/submissions.ts @@ -33,9 +33,10 @@ export interface SubmissionItemData { id: string; submission_id: string; item_type: EntityType | 'photo' | 'ride_model'; + action_type: 'create' | 'edit' | 'delete'; item_data: Record; original_data?: Record; - status: 'pending' | 'approved' | 'rejected'; + status: 'pending' | 'approved' | 'rejected' | 'flagged' | 'skipped'; // Use ReviewStatus type depends_on: string | null; order_index: number; approved_entity_id: string | null;