mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-28 14:06:58 -05:00
Compare commits
4 Commits
dfd17e8244
...
7476fbd5da
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7476fbd5da | ||
|
|
34300a89c4 | ||
|
|
caa6c788df | ||
|
|
6c5b5363c0 |
@@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
|
|||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import * as z from 'zod';
|
import * as z from 'zod';
|
||||||
import { entitySchemas } from '@/lib/entityValidationSchemas';
|
import { entitySchemas, validateRequiredFields } from '@/lib/entityValidationSchemas';
|
||||||
import { validateSubmissionHandler } from '@/lib/entityFormValidation';
|
import { validateSubmissionHandler } from '@/lib/entityFormValidation';
|
||||||
import { getErrorMessage } from '@/lib/errorHandler';
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
@@ -17,7 +17,7 @@ import { FlexibleDateInput, type DatePrecision } from '@/components/ui/flexible-
|
|||||||
import { SlugField } from '@/components/ui/slug-field';
|
import { SlugField } from '@/components/ui/slug-field';
|
||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
import { handleError } from '@/lib/errorHandler';
|
import { handleError } from '@/lib/errorHandler';
|
||||||
import { MapPin, Save, X, Plus } from 'lucide-react';
|
import { MapPin, Save, X, Plus, AlertCircle } from 'lucide-react';
|
||||||
import { toDateOnly, parseDateOnly, toDateWithPrecision } from '@/lib/dateUtils';
|
import { toDateOnly, parseDateOnly, toDateWithPrecision } from '@/lib/dateUtils';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Combobox } from '@/components/ui/combobox';
|
import { Combobox } from '@/components/ui/combobox';
|
||||||
@@ -167,6 +167,7 @@ export function ParkForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
|||||||
handleSubmit,
|
handleSubmit,
|
||||||
setValue,
|
setValue,
|
||||||
watch,
|
watch,
|
||||||
|
trigger,
|
||||||
formState: { errors }
|
formState: { errors }
|
||||||
} = useForm<ParkFormData>({
|
} = useForm<ParkFormData>({
|
||||||
resolver: zodResolver(entitySchemas.park),
|
resolver: zodResolver(entitySchemas.park),
|
||||||
@@ -202,6 +203,20 @@ export function ParkForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
|||||||
const handleFormSubmit = async (data: ParkFormData) => {
|
const handleFormSubmit = async (data: ParkFormData) => {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
try {
|
try {
|
||||||
|
// Pre-submission validation for required fields
|
||||||
|
const { valid, errors: validationErrors } = validateRequiredFields('park', data);
|
||||||
|
if (!valid) {
|
||||||
|
validationErrors.forEach(error => {
|
||||||
|
toast({
|
||||||
|
variant: 'destructive',
|
||||||
|
title: 'Missing Required Fields',
|
||||||
|
description: error
|
||||||
|
});
|
||||||
|
});
|
||||||
|
setIsSubmitting(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// CRITICAL: Block new photo uploads on edits
|
// CRITICAL: Block new photo uploads on edits
|
||||||
if (isEditing && data.images?.uploaded) {
|
if (isEditing && data.images?.uploaded) {
|
||||||
const hasNewPhotos = data.images.uploaded.some(img => img.isLocal);
|
const hasNewPhotos = data.images.uploaded.some(img => img.isLocal);
|
||||||
@@ -405,16 +420,29 @@ export function ParkForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
|||||||
|
|
||||||
{/* Location */}
|
{/* Location */}
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label>Location</Label>
|
<Label className="flex items-center gap-1">
|
||||||
|
Location
|
||||||
|
<span className="text-destructive">*</span>
|
||||||
|
</Label>
|
||||||
<LocationSearch
|
<LocationSearch
|
||||||
onLocationSelect={(location) => {
|
onLocationSelect={(location) => {
|
||||||
setValue('location', location);
|
setValue('location', location);
|
||||||
|
// Manually trigger validation for the location field
|
||||||
|
trigger('location');
|
||||||
}}
|
}}
|
||||||
initialLocationId={watch('location_id')}
|
initialLocationId={watch('location_id')}
|
||||||
/>
|
/>
|
||||||
<p className="text-sm text-muted-foreground">
|
{errors.location && (
|
||||||
Search for the park's location using OpenStreetMap. Location will be created when submission is approved.
|
<p className="text-sm text-destructive flex items-center gap-1">
|
||||||
</p>
|
<AlertCircle className="w-4 h-4" />
|
||||||
|
{errors.location.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
{!errors.location && (
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Search for the park's location using OpenStreetMap. Location will be created when submission is approved.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Operator & Property Owner Selection */}
|
{/* Operator & Property Owner Selection */}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { validateSubmissionHandler } from '@/lib/entityFormValidation';
|
|||||||
import { getErrorMessage } from '@/lib/errorHandler';
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import type { RideTechnicalSpec, RideCoasterStat, RideNameHistory } from '@/types/database';
|
import type { RideTechnicalSpec, RideCoasterStat, RideNameHistory } from '@/types/database';
|
||||||
import type { TempCompanyData, TempRideModelData, TempParkData } from '@/types/company';
|
import type { TempCompanyData, TempRideModelData, TempParkData } from '@/types/company';
|
||||||
import { entitySchemas } from '@/lib/entityValidationSchemas';
|
import { entitySchemas, validateRequiredFields } from '@/lib/entityValidationSchemas';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
@@ -23,10 +23,10 @@ import { SlugField } from '@/components/ui/slug-field';
|
|||||||
import { Checkbox } from '@/components/ui/checkbox';
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
import { handleError } from '@/lib/errorHandler';
|
import { handleError } from '@/lib/errorHandler';
|
||||||
import { Plus, Zap, Save, X, Building2 } from 'lucide-react';
|
import { Plus, Zap, Save, X, Building2, AlertCircle } from 'lucide-react';
|
||||||
import { toDateOnly, parseDateOnly, toDateWithPrecision } from '@/lib/dateUtils';
|
import { toDateOnly, parseDateOnly, toDateWithPrecision } from '@/lib/dateUtils';
|
||||||
import { useUnitPreferences } from '@/hooks/useUnitPreferences';
|
import { useUnitPreferences } from '@/hooks/useUnitPreferences';
|
||||||
import { useManufacturers, useRideModels } from '@/hooks/useAutocompleteData';
|
import { useManufacturers, useRideModels, useParks } from '@/hooks/useAutocompleteData';
|
||||||
import { useUserRole } from '@/hooks/useUserRole';
|
import { useUserRole } from '@/hooks/useUserRole';
|
||||||
import { ManufacturerForm } from './ManufacturerForm';
|
import { ManufacturerForm } from './ManufacturerForm';
|
||||||
import { RideModelForm } from './RideModelForm';
|
import { RideModelForm } from './RideModelForm';
|
||||||
@@ -208,12 +208,14 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
|||||||
// Fetch data
|
// Fetch data
|
||||||
const { manufacturers, loading: manufacturersLoading } = useManufacturers();
|
const { manufacturers, loading: manufacturersLoading } = useManufacturers();
|
||||||
const { rideModels, loading: modelsLoading } = useRideModels(selectedManufacturerId);
|
const { rideModels, loading: modelsLoading } = useRideModels(selectedManufacturerId);
|
||||||
|
const { parks, loading: parksLoading } = useParks();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
setValue,
|
setValue,
|
||||||
watch,
|
watch,
|
||||||
|
trigger,
|
||||||
formState: { errors }
|
formState: { errors }
|
||||||
} = useForm<RideFormData>({
|
} = useForm<RideFormData>({
|
||||||
resolver: zodResolver(entitySchemas.ride),
|
resolver: zodResolver(entitySchemas.ride),
|
||||||
@@ -256,16 +258,32 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
|||||||
ride_model_id: initialData?.ride_model_id || undefined,
|
ride_model_id: initialData?.ride_model_id || undefined,
|
||||||
source_url: initialData?.source_url || '',
|
source_url: initialData?.source_url || '',
|
||||||
submission_notes: initialData?.submission_notes || '',
|
submission_notes: initialData?.submission_notes || '',
|
||||||
images: { uploaded: [] }
|
images: { uploaded: [] },
|
||||||
|
park_id: initialData?.park_id || undefined
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectedCategory = watch('category');
|
const selectedCategory = watch('category');
|
||||||
|
const isParkPreselected = !!initialData?.park_id; // Coming from park detail page
|
||||||
|
|
||||||
|
|
||||||
const handleFormSubmit = async (data: RideFormData) => {
|
const handleFormSubmit = async (data: RideFormData) => {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
try {
|
try {
|
||||||
|
// Pre-submission validation for required fields
|
||||||
|
const { valid, errors: validationErrors } = validateRequiredFields('ride', data);
|
||||||
|
if (!valid) {
|
||||||
|
validationErrors.forEach(error => {
|
||||||
|
toast({
|
||||||
|
variant: 'destructive',
|
||||||
|
title: 'Missing Required Fields',
|
||||||
|
description: error
|
||||||
|
});
|
||||||
|
});
|
||||||
|
setIsSubmitting(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// CRITICAL: Block new photo uploads on edits
|
// CRITICAL: Block new photo uploads on edits
|
||||||
if (isEditing && data.images?.uploaded) {
|
if (isEditing && data.images?.uploaded) {
|
||||||
const hasNewPhotos = data.images.uploaded.some(img => img.isLocal);
|
const hasNewPhotos = data.images.uploaded.some(img => img.isLocal);
|
||||||
@@ -405,6 +423,96 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Park Selection */}
|
||||||
|
<div className="space-y-4">
|
||||||
|
<h3 className="text-lg font-semibold">Park Information</h3>
|
||||||
|
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="flex items-center gap-1">
|
||||||
|
Park
|
||||||
|
<span className="text-destructive">*</span>
|
||||||
|
</Label>
|
||||||
|
|
||||||
|
{tempNewPark ? (
|
||||||
|
// Show temp park badge
|
||||||
|
<div className="flex items-center gap-2 p-3 border rounded-md bg-green-50 dark:bg-green-950">
|
||||||
|
<Badge variant="secondary">New</Badge>
|
||||||
|
<span className="font-medium">{tempNewPark.name}</span>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => {
|
||||||
|
setTempNewPark(null);
|
||||||
|
}}
|
||||||
|
disabled={isParkPreselected}
|
||||||
|
>
|
||||||
|
<X className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => setIsParkModalOpen(true)}
|
||||||
|
disabled={isParkPreselected}
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
// Show combobox for existing parks
|
||||||
|
<Combobox
|
||||||
|
options={parks}
|
||||||
|
value={watch('park_id') || undefined}
|
||||||
|
onValueChange={(value) => {
|
||||||
|
setValue('park_id', value);
|
||||||
|
trigger('park_id');
|
||||||
|
}}
|
||||||
|
placeholder={isParkPreselected ? "Park pre-selected" : "Select a park"}
|
||||||
|
searchPlaceholder="Search parks..."
|
||||||
|
emptyText="No parks found"
|
||||||
|
loading={parksLoading}
|
||||||
|
disabled={isParkPreselected}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Validation error display */}
|
||||||
|
{errors.park_id && (
|
||||||
|
<p className="text-sm text-destructive flex items-center gap-1">
|
||||||
|
<AlertCircle className="w-4 h-4" />
|
||||||
|
{errors.park_id.message}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Create New Park Button */}
|
||||||
|
{!tempNewPark && !isParkPreselected && (
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
className="w-full"
|
||||||
|
onClick={() => setIsParkModalOpen(true)}
|
||||||
|
>
|
||||||
|
<Plus className="w-4 h-4 mr-2" />
|
||||||
|
Create New Park
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Help text */}
|
||||||
|
{isParkPreselected ? (
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Park is pre-selected from the park detail page and cannot be changed.
|
||||||
|
</p>
|
||||||
|
) : (
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
{tempNewPark
|
||||||
|
? "New park will be created when submission is approved"
|
||||||
|
: "Select the park where this ride is located"}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Category and Status */}
|
{/* Category and Status */}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
|
|||||||
@@ -301,4 +301,46 @@ export function usePropertyOwners() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return { propertyOwners, loading };
|
return { propertyOwners, loading };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to fetch all parks for autocomplete
|
||||||
|
* Returns parks as combobox options
|
||||||
|
*/
|
||||||
|
export function useParks() {
|
||||||
|
const [parks, setParks] = useState<ComboboxOption[]>([]);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function fetchParks() {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const { data, error } = await supabase
|
||||||
|
.from('parks')
|
||||||
|
.select('id, name, slug')
|
||||||
|
.order('name');
|
||||||
|
|
||||||
|
if (error) throw error;
|
||||||
|
|
||||||
|
setParks(
|
||||||
|
(data || []).map(park => ({
|
||||||
|
label: park.name,
|
||||||
|
value: park.id
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
handleNonCriticalError(error, { action: 'Fetch parks' });
|
||||||
|
toast.error('Failed to load parks', {
|
||||||
|
description: 'Please refresh the page and try again.',
|
||||||
|
});
|
||||||
|
setParks([]);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchParks();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return { parks, loading };
|
||||||
}
|
}
|
||||||
@@ -39,6 +39,17 @@ export const parkValidationSchema = z.object({
|
|||||||
closing_date: z.string().nullish().transform(val => val ?? undefined),
|
closing_date: z.string().nullish().transform(val => val ?? undefined),
|
||||||
closing_date_precision: z.enum(['day', 'month', 'year']).nullable().optional(),
|
closing_date_precision: z.enum(['day', 'month', 'year']).nullable().optional(),
|
||||||
location_id: z.string().uuid().optional().nullable(),
|
location_id: z.string().uuid().optional().nullable(),
|
||||||
|
location: z.object({
|
||||||
|
name: z.string(),
|
||||||
|
city: z.string().optional().nullable(),
|
||||||
|
state_province: z.string().optional().nullable(),
|
||||||
|
country: z.string(),
|
||||||
|
postal_code: z.string().optional().nullable(),
|
||||||
|
latitude: z.number(),
|
||||||
|
longitude: z.number(),
|
||||||
|
timezone: z.string().optional().nullable(),
|
||||||
|
display_name: z.string(),
|
||||||
|
}).optional(),
|
||||||
website_url: z.string().trim().nullish().transform(val => val ?? undefined).refine((val) => {
|
website_url: z.string().trim().nullish().transform(val => val ?? undefined).refine((val) => {
|
||||||
if (!val || val === '') return true;
|
if (!val || val === '') return true;
|
||||||
return z.string().url().safeParse(val).success;
|
return z.string().url().safeParse(val).success;
|
||||||
@@ -83,6 +94,12 @@ export const parkValidationSchema = z.object({
|
|||||||
}, {
|
}, {
|
||||||
message: 'Closing date must be after opening date',
|
message: 'Closing date must be after opening date',
|
||||||
path: ['closing_date'],
|
path: ['closing_date'],
|
||||||
|
}).refine((data) => {
|
||||||
|
// Either location object OR location_id must be provided
|
||||||
|
return !!(data.location || data.location_id);
|
||||||
|
}, {
|
||||||
|
message: 'Location is required. Please search and select a location for the park.',
|
||||||
|
path: ['location']
|
||||||
});
|
});
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
@@ -269,6 +286,12 @@ export const rideValidationSchema = z.object({
|
|||||||
.max(1000, 'Submission notes must be less than 1000 characters')
|
.max(1000, 'Submission notes must be less than 1000 characters')
|
||||||
.nullish()
|
.nullish()
|
||||||
.transform(val => val ?? undefined),
|
.transform(val => val ?? undefined),
|
||||||
|
}).refine((data) => {
|
||||||
|
// park_id is required (either real UUID or temp- reference)
|
||||||
|
return !!(data.park_id && data.park_id.trim().length > 0);
|
||||||
|
}, {
|
||||||
|
message: 'Park is required. Please select or create a park for this ride.',
|
||||||
|
path: ['park_id']
|
||||||
});
|
});
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
@@ -763,3 +786,31 @@ export async function validateMultipleItems(
|
|||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate required fields before submission
|
||||||
|
* Returns user-friendly error messages
|
||||||
|
*/
|
||||||
|
export function validateRequiredFields(
|
||||||
|
entityType: keyof typeof entitySchemas,
|
||||||
|
data: any
|
||||||
|
): { valid: boolean; errors: string[] } {
|
||||||
|
const errors: string[] = [];
|
||||||
|
|
||||||
|
if (entityType === 'park') {
|
||||||
|
if (!data.location && !data.location_id) {
|
||||||
|
errors.push('Location is required. Please search and select a location for the park.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entityType === 'ride') {
|
||||||
|
if (!data.park_id || data.park_id.trim().length === 0) {
|
||||||
|
errors.push('Park is required. Please select or create a park for this ride.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
valid: errors.length === 0,
|
||||||
|
errors
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -1309,6 +1309,88 @@ export async function editSubmissionItem(
|
|||||||
|
|
||||||
if (updateError) throw updateError;
|
if (updateError) throw updateError;
|
||||||
|
|
||||||
|
// Update relational table with new data based on item type
|
||||||
|
if (currentItem.item_type === 'park') {
|
||||||
|
// For parks, store location in temp_location_data if provided
|
||||||
|
const updateData: any = { ...newData };
|
||||||
|
|
||||||
|
// If location object is provided, store it in temp_location_data
|
||||||
|
if (newData.location) {
|
||||||
|
updateData.temp_location_data = {
|
||||||
|
name: newData.location.name,
|
||||||
|
city: newData.location.city || null,
|
||||||
|
state_province: newData.location.state_province || null,
|
||||||
|
country: newData.location.country,
|
||||||
|
latitude: newData.location.latitude,
|
||||||
|
longitude: newData.location.longitude,
|
||||||
|
timezone: newData.location.timezone || null,
|
||||||
|
postal_code: newData.location.postal_code || null,
|
||||||
|
display_name: newData.location.display_name
|
||||||
|
};
|
||||||
|
delete updateData.location; // Remove the nested object
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update park_submissions table
|
||||||
|
const { error: parkUpdateError } = await supabase
|
||||||
|
.from('park_submissions')
|
||||||
|
.update(updateData)
|
||||||
|
.eq('submission_id', currentItem.submission_id);
|
||||||
|
|
||||||
|
if (parkUpdateError) throw parkUpdateError;
|
||||||
|
|
||||||
|
} else if (currentItem.item_type === 'ride') {
|
||||||
|
const { error: rideUpdateError } = await supabase
|
||||||
|
.from('ride_submissions')
|
||||||
|
.update(newData)
|
||||||
|
.eq('submission_id', currentItem.submission_id);
|
||||||
|
|
||||||
|
if (rideUpdateError) throw rideUpdateError;
|
||||||
|
|
||||||
|
} else if (currentItem.item_type === 'manufacturer') {
|
||||||
|
const { error: manufacturerUpdateError } = await supabase
|
||||||
|
.from('company_submissions')
|
||||||
|
.update(newData)
|
||||||
|
.eq('submission_id', currentItem.submission_id)
|
||||||
|
.eq('company_type', 'manufacturer');
|
||||||
|
|
||||||
|
if (manufacturerUpdateError) throw manufacturerUpdateError;
|
||||||
|
|
||||||
|
} else if (currentItem.item_type === 'designer') {
|
||||||
|
const { error: designerUpdateError } = await supabase
|
||||||
|
.from('company_submissions')
|
||||||
|
.update(newData)
|
||||||
|
.eq('submission_id', currentItem.submission_id)
|
||||||
|
.eq('company_type', 'designer');
|
||||||
|
|
||||||
|
if (designerUpdateError) throw designerUpdateError;
|
||||||
|
|
||||||
|
} else if (currentItem.item_type === 'operator') {
|
||||||
|
const { error: operatorUpdateError } = await supabase
|
||||||
|
.from('company_submissions')
|
||||||
|
.update(newData)
|
||||||
|
.eq('submission_id', currentItem.submission_id)
|
||||||
|
.eq('company_type', 'operator');
|
||||||
|
|
||||||
|
if (operatorUpdateError) throw operatorUpdateError;
|
||||||
|
|
||||||
|
} else if (currentItem.item_type === 'property_owner') {
|
||||||
|
const { error: ownerUpdateError } = await supabase
|
||||||
|
.from('company_submissions')
|
||||||
|
.update(newData)
|
||||||
|
.eq('submission_id', currentItem.submission_id)
|
||||||
|
.eq('company_type', 'property_owner');
|
||||||
|
|
||||||
|
if (ownerUpdateError) throw ownerUpdateError;
|
||||||
|
|
||||||
|
} else if (currentItem.item_type === 'ride_model') {
|
||||||
|
const { error: modelUpdateError } = await supabase
|
||||||
|
.from('ride_model_submissions')
|
||||||
|
.update(newData)
|
||||||
|
.eq('submission_id', currentItem.submission_id);
|
||||||
|
|
||||||
|
if (modelUpdateError) throw modelUpdateError;
|
||||||
|
}
|
||||||
|
|
||||||
// Phase 4: Record edit history
|
// Phase 4: Record edit history
|
||||||
const { data: historyData, error: historyError } = await supabase
|
const { data: historyData, error: historyError } = await supabase
|
||||||
.from('item_edit_history')
|
.from('item_edit_history')
|
||||||
|
|||||||
Reference in New Issue
Block a user