mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-28 17:06:58 -05:00
Compare commits
2 Commits
6a9df807fa
...
bccaebc6d6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bccaebc6d6 | ||
|
|
bb951e637f |
@@ -200,6 +200,19 @@ export function ParkForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
|||||||
|
|
||||||
const handleFormSubmit = async (data: ParkFormData) => {
|
const handleFormSubmit = async (data: ParkFormData) => {
|
||||||
try {
|
try {
|
||||||
|
// CRITICAL: Block new photo uploads on edits
|
||||||
|
if (isEditing && data.images?.uploaded) {
|
||||||
|
const hasNewPhotos = data.images.uploaded.some(img => img.isLocal);
|
||||||
|
if (hasNewPhotos) {
|
||||||
|
toast({
|
||||||
|
variant: 'destructive',
|
||||||
|
title: 'Validation Error',
|
||||||
|
description: 'New photos cannot be added during edits. Please remove new photos or use the photo gallery.'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Build composite submission if new entities were created
|
// Build composite submission if new entities were created
|
||||||
const submissionContent: any = {
|
const submissionContent: any = {
|
||||||
park: data,
|
park: data,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import * as z from 'zod';
|
|||||||
import { validateSubmissionHandler } from '@/lib/entityFormValidation';
|
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 } from '@/types/company';
|
import type { TempCompanyData, TempRideModelData, TempParkData } from '@/types/company';
|
||||||
import { entitySchemas } from '@/lib/entityValidationSchemas';
|
import { entitySchemas } 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';
|
||||||
@@ -23,13 +23,14 @@ 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 } from 'lucide-react';
|
import { Plus, Zap, Save, X, Building2 } from 'lucide-react';
|
||||||
import { toDateOnly, parseDateOnly } from '@/lib/dateUtils';
|
import { toDateOnly, parseDateOnly } from '@/lib/dateUtils';
|
||||||
import { useUnitPreferences } from '@/hooks/useUnitPreferences';
|
import { useUnitPreferences } from '@/hooks/useUnitPreferences';
|
||||||
import { useManufacturers, useRideModels } from '@/hooks/useAutocompleteData';
|
import { useManufacturers, useRideModels } 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';
|
||||||
|
import { ParkForm } from './ParkForm';
|
||||||
import { TechnicalSpecsEditor, validateTechnicalSpecs } from './editors/TechnicalSpecsEditor';
|
import { TechnicalSpecsEditor, validateTechnicalSpecs } from './editors/TechnicalSpecsEditor';
|
||||||
import { CoasterStatsEditor, validateCoasterStats } from './editors/CoasterStatsEditor';
|
import { CoasterStatsEditor, validateCoasterStats } from './editors/CoasterStatsEditor';
|
||||||
import { FormerNamesEditor } from './editors/FormerNamesEditor';
|
import { FormerNamesEditor } from './editors/FormerNamesEditor';
|
||||||
@@ -45,12 +46,21 @@ import {
|
|||||||
type RideFormData = z.infer<typeof entitySchemas.ride>;
|
type RideFormData = z.infer<typeof entitySchemas.ride>;
|
||||||
|
|
||||||
interface RideFormProps {
|
interface RideFormProps {
|
||||||
onSubmit: (data: RideFormData) => Promise<void>;
|
onSubmit: (data: RideFormData & {
|
||||||
|
_tempNewPark?: TempParkData;
|
||||||
|
_tempNewManufacturer?: TempCompanyData;
|
||||||
|
_tempNewDesigner?: TempCompanyData;
|
||||||
|
_tempNewRideModel?: TempRideModelData;
|
||||||
|
}) => Promise<void>;
|
||||||
onCancel?: () => void;
|
onCancel?: () => void;
|
||||||
initialData?: Partial<RideFormData & {
|
initialData?: Partial<RideFormData & {
|
||||||
id?: string;
|
id?: string;
|
||||||
banner_image_url?: string;
|
banner_image_url?: string;
|
||||||
card_image_url?: string;
|
card_image_url?: string;
|
||||||
|
_tempNewPark?: TempParkData;
|
||||||
|
_tempNewManufacturer?: TempCompanyData;
|
||||||
|
_tempNewDesigner?: TempCompanyData;
|
||||||
|
_tempNewRideModel?: TempRideModelData;
|
||||||
}>;
|
}>;
|
||||||
isEditing?: boolean;
|
isEditing?: boolean;
|
||||||
}
|
}
|
||||||
@@ -154,14 +164,18 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
|||||||
validateSubmissionHandler(onSubmit, 'ride');
|
validateSubmissionHandler(onSubmit, 'ride');
|
||||||
}, [onSubmit]);
|
}, [onSubmit]);
|
||||||
|
|
||||||
// Manufacturer and model state
|
// Temp entity states
|
||||||
|
const [tempNewPark, setTempNewPark] = useState<TempParkData | null>(initialData?._tempNewPark || null);
|
||||||
const [selectedManufacturerId, setSelectedManufacturerId] = useState<string>(
|
const [selectedManufacturerId, setSelectedManufacturerId] = useState<string>(
|
||||||
initialData?.manufacturer_id || ''
|
initialData?.manufacturer_id || ''
|
||||||
);
|
);
|
||||||
const [selectedManufacturerName, setSelectedManufacturerName] = useState<string>('');
|
const [selectedManufacturerName, setSelectedManufacturerName] = useState<string>('');
|
||||||
const [tempNewManufacturer, setTempNewManufacturer] = useState<TempCompanyData | null>(null);
|
const [tempNewManufacturer, setTempNewManufacturer] = useState<TempCompanyData | null>(initialData?._tempNewManufacturer || null);
|
||||||
const [tempNewRideModel, setTempNewRideModel] = useState<TempRideModelData | null>(null);
|
const [tempNewDesigner, setTempNewDesigner] = useState<TempCompanyData | null>(initialData?._tempNewDesigner || null);
|
||||||
|
const [tempNewRideModel, setTempNewRideModel] = useState<TempRideModelData | null>(initialData?._tempNewRideModel || null);
|
||||||
|
const [isParkModalOpen, setIsParkModalOpen] = useState(false);
|
||||||
const [isManufacturerModalOpen, setIsManufacturerModalOpen] = useState(false);
|
const [isManufacturerModalOpen, setIsManufacturerModalOpen] = useState(false);
|
||||||
|
const [isDesignerModalOpen, setIsDesignerModalOpen] = useState(false);
|
||||||
const [isModelModalOpen, setIsModelModalOpen] = useState(false);
|
const [isModelModalOpen, setIsModelModalOpen] = useState(false);
|
||||||
|
|
||||||
// Advanced editor state - using simplified interface for editors (DB fields added on submit)
|
// Advanced editor state - using simplified interface for editors (DB fields added on submit)
|
||||||
@@ -250,6 +264,19 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
|||||||
|
|
||||||
const handleFormSubmit = async (data: RideFormData) => {
|
const handleFormSubmit = async (data: RideFormData) => {
|
||||||
try {
|
try {
|
||||||
|
// CRITICAL: Block new photo uploads on edits
|
||||||
|
if (isEditing && data.images?.uploaded) {
|
||||||
|
const hasNewPhotos = data.images.uploaded.some(img => img.isLocal);
|
||||||
|
if (hasNewPhotos) {
|
||||||
|
toast({
|
||||||
|
variant: 'destructive',
|
||||||
|
title: 'Validation Error',
|
||||||
|
description: 'New photos cannot be added during edits. Please remove new photos or use the photo gallery.'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Validate coaster stats
|
// Validate coaster stats
|
||||||
if (coasterStats && coasterStats.length > 0) {
|
if (coasterStats && coasterStats.length > 0) {
|
||||||
const statsValidation = validateCoasterStats(coasterStats);
|
const statsValidation = validateCoasterStats(coasterStats);
|
||||||
@@ -299,7 +326,9 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
|||||||
_technical_specifications: technicalSpecs,
|
_technical_specifications: technicalSpecs,
|
||||||
_coaster_statistics: coasterStats,
|
_coaster_statistics: coasterStats,
|
||||||
_name_history: formerNames,
|
_name_history: formerNames,
|
||||||
|
_tempNewPark: tempNewPark,
|
||||||
_tempNewManufacturer: tempNewManufacturer,
|
_tempNewManufacturer: tempNewManufacturer,
|
||||||
|
_tempNewDesigner: tempNewDesigner,
|
||||||
_tempNewRideModel: tempNewRideModel
|
_tempNewRideModel: tempNewRideModel
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1337,6 +1366,41 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
{/* Park Modal - Add before Manufacturer Modal */}
|
||||||
|
<Dialog open={isParkModalOpen} onOpenChange={setIsParkModalOpen}>
|
||||||
|
<DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Create New Park</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
<ParkForm
|
||||||
|
onSubmit={async (data) => {
|
||||||
|
setTempNewPark(data as TempParkData);
|
||||||
|
setIsParkModalOpen(false);
|
||||||
|
setValue('park_id', undefined);
|
||||||
|
}}
|
||||||
|
onCancel={() => setIsParkModalOpen(false)}
|
||||||
|
/>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
{/* Designer Modal */}
|
||||||
|
<Dialog open={isDesignerModalOpen} onOpenChange={setIsDesignerModalOpen}>
|
||||||
|
<DialogContent className="max-w-3xl max-h-[90vh] overflow-y-auto">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Create New Designer</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
<ManufacturerForm
|
||||||
|
initialData={tempNewDesigner}
|
||||||
|
onSubmit={(data) => {
|
||||||
|
setTempNewDesigner(data);
|
||||||
|
setIsDesignerModalOpen(false);
|
||||||
|
setValue('designer_id', undefined);
|
||||||
|
}}
|
||||||
|
onCancel={() => setIsDesignerModalOpen(false)}
|
||||||
|
/>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
{/* Manufacturer Modal */}
|
{/* Manufacturer Modal */}
|
||||||
<Dialog open={isManufacturerModalOpen} onOpenChange={setIsManufacturerModalOpen}>
|
<Dialog open={isManufacturerModalOpen} onOpenChange={setIsManufacturerModalOpen}>
|
||||||
<DialogContent className="max-w-3xl max-h-[90vh] overflow-y-auto">
|
<DialogContent className="max-w-3xl max-h-[90vh] overflow-y-auto">
|
||||||
|
|||||||
61
src/components/admin/ride-form-park-designer-ui.tsx
Normal file
61
src/components/admin/ride-form-park-designer-ui.tsx
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* UI components for Park and Designer creation within RideForm
|
||||||
|
* Extracted for clarity - import these into RideForm.tsx
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Plus, Building2, X } from 'lucide-react';
|
||||||
|
import type { TempParkData, TempCompanyData } from '@/types/company';
|
||||||
|
|
||||||
|
interface ParkSelectorProps {
|
||||||
|
tempNewPark: TempParkData | null;
|
||||||
|
onCreateNew: () => void;
|
||||||
|
onEdit: () => void;
|
||||||
|
onRemove: () => void;
|
||||||
|
parkId?: string;
|
||||||
|
onParkChange: (id: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DesignerSelectorProps {
|
||||||
|
tempNewDesigner: TempCompanyData | null;
|
||||||
|
onCreateNew: () => void;
|
||||||
|
onEdit: () => void;
|
||||||
|
onRemove: () => void;
|
||||||
|
designerId?: string;
|
||||||
|
onDesignerChange: (id: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RideParkSelector({ tempNewPark, onCreateNew, onEdit, onRemove }: ParkSelectorProps) {
|
||||||
|
return tempNewPark ? (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Badge variant="secondary" className="gap-2">
|
||||||
|
<Building2 className="h-3 w-3" />
|
||||||
|
New: {tempNewPark.name}
|
||||||
|
<button type="button" onClick={onRemove} className="ml-1 hover:text-destructive">×</button>
|
||||||
|
</Badge>
|
||||||
|
<Button type="button" variant="outline" size="sm" onClick={onEdit}>Edit New Park</Button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Button type="button" variant="outline" size="sm" onClick={onCreateNew}>
|
||||||
|
<Plus className="h-4 w-4 mr-2" />Create New Park
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RideDesignerSelector({ tempNewDesigner, onCreateNew, onEdit, onRemove }: DesignerSelectorProps) {
|
||||||
|
return tempNewDesigner ? (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Badge variant="secondary" className="gap-2">
|
||||||
|
<Building2 className="h-3 w-3" />
|
||||||
|
New: {tempNewDesigner.name}
|
||||||
|
<button type="button" onClick={onRemove} className="ml-1 hover:text-destructive">×</button>
|
||||||
|
</Badge>
|
||||||
|
<Button type="button" variant="outline" size="sm" onClick={onEdit}>Edit New Designer</Button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Button type="button" variant="outline" size="sm" onClick={onCreateNew}>
|
||||||
|
<Plus className="h-4 w-4 mr-2" />Create New Designer
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ import { DragDropZone } from './DragDropZone';
|
|||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
import { Skeleton } from '@/components/ui/skeleton';
|
import { Skeleton } from '@/components/ui/skeleton';
|
||||||
|
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||||
import { getErrorMessage } from '@/lib/errorHandler';
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { logger } from '@/lib/logger';
|
import { logger } from '@/lib/logger';
|
||||||
|
|
||||||
@@ -49,7 +50,8 @@ export function EntityMultiImageUploader({
|
|||||||
currentBannerUrl,
|
currentBannerUrl,
|
||||||
currentCardUrl
|
currentCardUrl
|
||||||
}: EntityMultiImageUploaderProps) {
|
}: EntityMultiImageUploaderProps) {
|
||||||
const maxImages = mode === 'create' ? 5 : 3;
|
const maxImages = mode === 'create' ? 5 : 0; // No uploads allowed in edit mode
|
||||||
|
const canUpload = mode === 'create';
|
||||||
const [loadingPhotos, setLoadingPhotos] = useState(false);
|
const [loadingPhotos, setLoadingPhotos] = useState(false);
|
||||||
|
|
||||||
// Fetch existing photos when in edit mode
|
// Fetch existing photos when in edit mode
|
||||||
@@ -119,6 +121,16 @@ export function EntityMultiImageUploader({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleFilesAdded = (files: File[]) => {
|
const handleFilesAdded = (files: File[]) => {
|
||||||
|
// Block uploads entirely in edit mode
|
||||||
|
if (!canUpload) {
|
||||||
|
toast({
|
||||||
|
title: 'Upload Not Allowed',
|
||||||
|
description: 'Photos cannot be added during edits. Use the photo gallery to submit additional photos.',
|
||||||
|
variant: 'destructive',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const currentCount = value.uploaded.length;
|
const currentCount = value.uploaded.length;
|
||||||
const availableSlots = maxImages - currentCount;
|
const availableSlots = maxImages - currentCount;
|
||||||
|
|
||||||
@@ -331,8 +343,18 @@ export function EntityMultiImageUploader({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty state: show large drag & drop zone
|
// Empty state: show large drag & drop zone (create only) or message (edit)
|
||||||
if (value.uploaded.length === 0) {
|
if (value.uploaded.length === 0) {
|
||||||
|
if (mode === 'edit') {
|
||||||
|
return (
|
||||||
|
<Alert>
|
||||||
|
<AlertDescription>
|
||||||
|
No existing photos found. Photos can only be added during entity creation. Use the photo gallery to submit additional photos after creation.
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<DragDropZone
|
<DragDropZone
|
||||||
@@ -344,22 +366,30 @@ export function EntityMultiImageUploader({
|
|||||||
<div className="text-sm text-muted-foreground space-y-1">
|
<div className="text-sm text-muted-foreground space-y-1">
|
||||||
<p>• Right-click images to set as banner or card</p>
|
<p>• Right-click images to set as banner or card</p>
|
||||||
<p>• Images will be uploaded when you submit the form</p>
|
<p>• Images will be uploaded when you submit the form</p>
|
||||||
{mode === 'edit' && <p>• No existing photos found for this entity</p>}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// With images: show grid + compact upload area
|
// With images: show grid + compact upload area (create only) or read-only (edit)
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
|
{/* Edit mode notice */}
|
||||||
|
{mode === 'edit' && (
|
||||||
|
<Alert>
|
||||||
|
<AlertDescription>
|
||||||
|
Photos cannot be added during edits. You can reassign banner/card roles below. Use the photo gallery to submit additional photos.
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Image Grid */}
|
{/* Image Grid */}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
{value.uploaded.map((image, index) => renderImageCard(image, index))}
|
{value.uploaded.map((image, index) => renderImageCard(image, index))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Compact Upload Area */}
|
{/* Compact Upload Area - Create mode only */}
|
||||||
{value.uploaded.length < maxImages && (
|
{canUpload && value.uploaded.length < maxImages && (
|
||||||
<DragDropZone
|
<DragDropZone
|
||||||
onFilesAdded={handleFilesAdded}
|
onFilesAdded={handleFilesAdded}
|
||||||
maxFiles={maxImages - value.uploaded.length}
|
maxFiles={maxImages - value.uploaded.length}
|
||||||
|
|||||||
@@ -107,7 +107,10 @@ export function EntityPhotoGallery({
|
|||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2 sm:gap-0">
|
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2 sm:gap-0">
|
||||||
<h3 className="text-base sm:text-lg font-semibold">Upload Photos for {entityName}</h3>
|
<div>
|
||||||
|
<h3 className="text-base sm:text-lg font-semibold">Submit Additional Photos for {entityName}</h3>
|
||||||
|
<p className="text-sm text-muted-foreground">Photos submitted here go through a separate review process</p>
|
||||||
|
</div>
|
||||||
<Button variant="ghost" onClick={() => setShowUpload(false)} className="w-full sm:w-auto">
|
<Button variant="ghost" onClick={() => setShowUpload(false)} className="w-full sm:w-auto">
|
||||||
Back to Gallery
|
Back to Gallery
|
||||||
</Button>
|
</Button>
|
||||||
@@ -155,7 +158,7 @@ export function EntityPhotoGallery({
|
|||||||
{user ? (
|
{user ? (
|
||||||
<>
|
<>
|
||||||
<Upload className="w-4 h-4" />
|
<Upload className="w-4 h-4" />
|
||||||
<span className="sm:inline">Upload Photos</span>
|
<span className="sm:inline">Submit Additional Photos</span>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -305,13 +305,23 @@ async function submitCompositeCreation(
|
|||||||
delete primaryData.property_owner_id;
|
delete primaryData.property_owner_id;
|
||||||
}
|
}
|
||||||
} else if (uploadedPrimary.type === 'ride') {
|
} else if (uploadedPrimary.type === 'ride') {
|
||||||
|
if (uploadedPrimary.data.park_id?.startsWith('temp-')) {
|
||||||
|
const parkIndex = tempIdMap.get(uploadedPrimary.data.park_id);
|
||||||
|
if (parkIndex !== undefined) primaryData._temp_park_ref = parkIndex;
|
||||||
|
delete primaryData.park_id;
|
||||||
|
}
|
||||||
if (uploadedPrimary.data.manufacturer_id?.startsWith('temp-')) {
|
if (uploadedPrimary.data.manufacturer_id?.startsWith('temp-')) {
|
||||||
const mfgIndex = tempIdMap.get('temp-manufacturer');
|
const mfgIndex = tempIdMap.get(uploadedPrimary.data.manufacturer_id);
|
||||||
if (mfgIndex !== undefined) primaryData._temp_manufacturer_ref = mfgIndex;
|
if (mfgIndex !== undefined) primaryData._temp_manufacturer_ref = mfgIndex;
|
||||||
delete primaryData.manufacturer_id;
|
delete primaryData.manufacturer_id;
|
||||||
}
|
}
|
||||||
|
if (uploadedPrimary.data.designer_id?.startsWith('temp-')) {
|
||||||
|
const designerIndex = tempIdMap.get(uploadedPrimary.data.designer_id);
|
||||||
|
if (designerIndex !== undefined) primaryData._temp_designer_ref = designerIndex;
|
||||||
|
delete primaryData.designer_id;
|
||||||
|
}
|
||||||
if (uploadedPrimary.data.ride_model_id?.startsWith('temp-')) {
|
if (uploadedPrimary.data.ride_model_id?.startsWith('temp-')) {
|
||||||
const modelIndex = tempIdMap.get('temp-ride-model');
|
const modelIndex = tempIdMap.get(uploadedPrimary.data.ride_model_id);
|
||||||
if (modelIndex !== undefined) primaryData._temp_ride_model_ref = modelIndex;
|
if (modelIndex !== undefined) primaryData._temp_ride_model_ref = modelIndex;
|
||||||
delete primaryData.ride_model_id;
|
delete primaryData.ride_model_id;
|
||||||
}
|
}
|
||||||
@@ -521,26 +531,15 @@ export async function submitParkUpdate(
|
|||||||
if (fetchError) throw new Error(`Failed to fetch park: ${fetchError.message}`);
|
if (fetchError) throw new Error(`Failed to fetch park: ${fetchError.message}`);
|
||||||
if (!existingPark) throw new Error('Park not found');
|
if (!existingPark) throw new Error('Park not found');
|
||||||
|
|
||||||
// Upload any pending local images first
|
// CRITICAL: Block new photo uploads on edits
|
||||||
let processedImages = data.images;
|
// Photos can only be submitted during creation or via the photo gallery
|
||||||
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
if (data.images?.uploaded && data.images.uploaded.some(img => img.isLocal)) {
|
||||||
try {
|
throw new Error('Photo uploads are not allowed during edits. Please use the photo gallery to submit additional photos.');
|
||||||
const uploadedImages = await uploadPendingImages(data.images.uploaded);
|
|
||||||
processedImages = {
|
|
||||||
...data.images,
|
|
||||||
uploaded: uploadedImages
|
|
||||||
};
|
|
||||||
} catch (error: unknown) {
|
|
||||||
const errorMessage = getErrorMessage(error);
|
|
||||||
logger.error('Park image upload failed', {
|
|
||||||
action: 'park_update',
|
|
||||||
parkId,
|
|
||||||
error: errorMessage
|
|
||||||
});
|
|
||||||
throw new Error(`Failed to upload images: ${errorMessage}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only allow banner/card reassignments from existing photos
|
||||||
|
let processedImages = data.images;
|
||||||
|
|
||||||
// Create the main submission record
|
// Create the main submission record
|
||||||
const { data: submissionData, error: submissionError } = await supabase
|
const { data: submissionData, error: submissionError } = await supabase
|
||||||
.from('content_submissions')
|
.from('content_submissions')
|
||||||
@@ -600,13 +599,54 @@ export async function submitParkUpdate(
|
|||||||
* @returns Object containing submitted boolean and submissionId
|
* @returns Object containing submitted boolean and submissionId
|
||||||
*/
|
*/
|
||||||
export async function submitRideCreation(
|
export async function submitRideCreation(
|
||||||
data: RideFormData & { _tempNewManufacturer?: any; _tempNewRideModel?: any },
|
data: RideFormData & {
|
||||||
|
_tempNewPark?: any;
|
||||||
|
_tempNewManufacturer?: any;
|
||||||
|
_tempNewDesigner?: any;
|
||||||
|
_tempNewRideModel?: any;
|
||||||
|
},
|
||||||
userId: string
|
userId: string
|
||||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||||
// Check for composite submission with dependencies
|
// Check for composite submission with dependencies
|
||||||
if (data._tempNewManufacturer || data._tempNewRideModel) {
|
if (data._tempNewPark || data._tempNewManufacturer || data._tempNewDesigner || data._tempNewRideModel) {
|
||||||
const dependencies: CompositeSubmissionDependency[] = [];
|
const dependencies: CompositeSubmissionDependency[] = [];
|
||||||
|
|
||||||
|
// Handle new park operator (from nested park)
|
||||||
|
if (data._tempNewPark?._tempNewOperator) {
|
||||||
|
dependencies.push({
|
||||||
|
type: 'company',
|
||||||
|
data: { ...data._tempNewPark._tempNewOperator, company_type: 'operator' },
|
||||||
|
tempId: 'temp-park-operator',
|
||||||
|
companyType: 'operator'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle new park property owner (from nested park)
|
||||||
|
if (data._tempNewPark?._tempNewPropertyOwner) {
|
||||||
|
dependencies.push({
|
||||||
|
type: 'company',
|
||||||
|
data: { ...data._tempNewPark._tempNewPropertyOwner, company_type: 'property_owner' },
|
||||||
|
tempId: 'temp-park-owner',
|
||||||
|
companyType: 'property_owner'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle new park (depends on operator/owner)
|
||||||
|
if (data._tempNewPark) {
|
||||||
|
dependencies.push({
|
||||||
|
type: 'park',
|
||||||
|
data: {
|
||||||
|
...data._tempNewPark,
|
||||||
|
operator_id: data._tempNewPark._tempNewOperator ? 'temp-park-operator' : data._tempNewPark.operator_id,
|
||||||
|
property_owner_id: data._tempNewPark._tempNewPropertyOwner ? 'temp-park-owner' : data._tempNewPark.property_owner_id,
|
||||||
|
_tempNewOperator: undefined,
|
||||||
|
_tempNewPropertyOwner: undefined
|
||||||
|
},
|
||||||
|
tempId: 'temp-park'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle new manufacturer
|
||||||
if (data._tempNewManufacturer) {
|
if (data._tempNewManufacturer) {
|
||||||
dependencies.push({
|
dependencies.push({
|
||||||
type: 'company',
|
type: 'company',
|
||||||
@@ -616,18 +656,45 @@ export async function submitRideCreation(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle new designer
|
||||||
|
if (data._tempNewDesigner) {
|
||||||
|
dependencies.push({
|
||||||
|
type: 'company',
|
||||||
|
data: { ...data._tempNewDesigner, company_type: 'designer' },
|
||||||
|
tempId: 'temp-designer',
|
||||||
|
companyType: 'designer'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle new ride model (depends on manufacturer)
|
||||||
if (data._tempNewRideModel) {
|
if (data._tempNewRideModel) {
|
||||||
dependencies.push({
|
dependencies.push({
|
||||||
type: 'ride_model',
|
type: 'ride_model',
|
||||||
data: data._tempNewRideModel,
|
data: {
|
||||||
|
...data._tempNewRideModel,
|
||||||
|
manufacturer_id: data._tempNewManufacturer ? 'temp-manufacturer' : data._tempNewRideModel.manufacturer_id
|
||||||
|
},
|
||||||
tempId: 'temp-ride-model',
|
tempId: 'temp-ride-model',
|
||||||
parentTempId: data._tempNewManufacturer ? 'temp-manufacturer' : undefined
|
parentTempId: data._tempNewManufacturer ? 'temp-manufacturer' : undefined
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dependencies.length > 0) {
|
if (dependencies.length > 0) {
|
||||||
|
// Prepare ride data with temp references
|
||||||
|
const rideData = {
|
||||||
|
...data,
|
||||||
|
park_id: data._tempNewPark ? 'temp-park' : data.park_id,
|
||||||
|
manufacturer_id: data._tempNewManufacturer ? 'temp-manufacturer' : data.manufacturer_id,
|
||||||
|
designer_id: data._tempNewDesigner ? 'temp-designer' : data.designer_id,
|
||||||
|
ride_model_id: data._tempNewRideModel ? 'temp-ride-model' : data.ride_model_id,
|
||||||
|
_tempNewPark: undefined,
|
||||||
|
_tempNewManufacturer: undefined,
|
||||||
|
_tempNewDesigner: undefined,
|
||||||
|
_tempNewRideModel: undefined
|
||||||
|
};
|
||||||
|
|
||||||
return submitCompositeCreation(
|
return submitCompositeCreation(
|
||||||
{ type: 'ride', data },
|
{ type: 'ride', data: rideData },
|
||||||
dependencies,
|
dependencies,
|
||||||
userId
|
userId
|
||||||
);
|
);
|
||||||
@@ -747,26 +814,15 @@ export async function submitRideUpdate(
|
|||||||
if (fetchError) throw new Error(`Failed to fetch ride: ${fetchError.message}`);
|
if (fetchError) throw new Error(`Failed to fetch ride: ${fetchError.message}`);
|
||||||
if (!existingRide) throw new Error('Ride not found');
|
if (!existingRide) throw new Error('Ride not found');
|
||||||
|
|
||||||
// Upload any pending local images first
|
// CRITICAL: Block new photo uploads on edits
|
||||||
let processedImages = data.images;
|
// Photos can only be submitted during creation or via the photo gallery
|
||||||
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
if (data.images?.uploaded && data.images.uploaded.some(img => img.isLocal)) {
|
||||||
try {
|
throw new Error('Photo uploads are not allowed during edits. Please use the photo gallery to submit additional photos.');
|
||||||
const uploadedImages = await uploadPendingImages(data.images.uploaded);
|
|
||||||
processedImages = {
|
|
||||||
...data.images,
|
|
||||||
uploaded: uploadedImages
|
|
||||||
};
|
|
||||||
} catch (error: unknown) {
|
|
||||||
const errorMessage = getErrorMessage(error);
|
|
||||||
logger.error('Ride image upload failed', {
|
|
||||||
action: 'ride_update',
|
|
||||||
rideId,
|
|
||||||
error: errorMessage
|
|
||||||
});
|
|
||||||
throw new Error(`Failed to upload images: ${errorMessage}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only allow banner/card reassignments from existing photos
|
||||||
|
let processedImages = data.images;
|
||||||
|
|
||||||
// Create the main submission record
|
// Create the main submission record
|
||||||
const { data: submissionData, error: submissionError } = await supabase
|
const { data: submissionData, error: submissionError } = await supabase
|
||||||
.from('content_submissions')
|
.from('content_submissions')
|
||||||
@@ -924,26 +980,13 @@ export async function submitRideModelUpdate(
|
|||||||
if (fetchError) throw new Error(`Failed to fetch ride model: ${fetchError.message}`);
|
if (fetchError) throw new Error(`Failed to fetch ride model: ${fetchError.message}`);
|
||||||
if (!existingModel) throw new Error('Ride model not found');
|
if (!existingModel) throw new Error('Ride model not found');
|
||||||
|
|
||||||
// Upload any pending local images first
|
// CRITICAL: Block new photo uploads on edits
|
||||||
let processedImages = data.images;
|
if (data.images?.uploaded && data.images.uploaded.some(img => img.isLocal)) {
|
||||||
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
throw new Error('Photo uploads are not allowed during edits. Please use the photo gallery to submit additional photos.');
|
||||||
try {
|
|
||||||
const uploadedImages = await uploadPendingImages(data.images.uploaded);
|
|
||||||
processedImages = {
|
|
||||||
...data.images,
|
|
||||||
uploaded: uploadedImages
|
|
||||||
};
|
|
||||||
} catch (error: unknown) {
|
|
||||||
const errorMessage = getErrorMessage(error);
|
|
||||||
logger.error('Ride model image upload failed', {
|
|
||||||
action: 'ride_model_update',
|
|
||||||
rideModelId,
|
|
||||||
error: errorMessage
|
|
||||||
});
|
|
||||||
throw new Error(`Failed to upload images: ${errorMessage}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let processedImages = data.images;
|
||||||
|
|
||||||
// Create the main submission record
|
// Create the main submission record
|
||||||
const { data: submissionData, error: submissionError } = await supabase
|
const { data: submissionData, error: submissionError } = await supabase
|
||||||
.from('content_submissions')
|
.from('content_submissions')
|
||||||
@@ -1054,22 +1097,13 @@ export async function submitManufacturerUpdate(
|
|||||||
if (fetchError) throw new Error(`Failed to fetch manufacturer: ${fetchError.message}`);
|
if (fetchError) throw new Error(`Failed to fetch manufacturer: ${fetchError.message}`);
|
||||||
if (!existingCompany) throw new Error('Manufacturer not found');
|
if (!existingCompany) throw new Error('Manufacturer not found');
|
||||||
|
|
||||||
let processedImages = data.images;
|
// CRITICAL: Block new photo uploads on edits
|
||||||
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
if (data.images?.uploaded && data.images.uploaded.some(img => img.isLocal)) {
|
||||||
try {
|
throw new Error('Photo uploads are not allowed during edits. Please use the photo gallery to submit additional photos.');
|
||||||
const uploadedImages = await uploadPendingImages(data.images.uploaded);
|
|
||||||
processedImages = { ...data.images, uploaded: uploadedImages };
|
|
||||||
} catch (error: unknown) {
|
|
||||||
const errorMessage = getErrorMessage(error);
|
|
||||||
logger.error('Company image upload failed', {
|
|
||||||
action: 'manufacturer_update',
|
|
||||||
companyId,
|
|
||||||
error: errorMessage
|
|
||||||
});
|
|
||||||
throw new Error(`Failed to upload images: ${errorMessage}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let processedImages = data.images;
|
||||||
|
|
||||||
const { data: submissionData, error: submissionError } = await supabase
|
const { data: submissionData, error: submissionError } = await supabase
|
||||||
.from('content_submissions')
|
.from('content_submissions')
|
||||||
.insert({
|
.insert({
|
||||||
@@ -1171,22 +1205,13 @@ export async function submitDesignerUpdate(
|
|||||||
if (fetchError) throw new Error(`Failed to fetch designer: ${fetchError.message}`);
|
if (fetchError) throw new Error(`Failed to fetch designer: ${fetchError.message}`);
|
||||||
if (!existingCompany) throw new Error('Designer not found');
|
if (!existingCompany) throw new Error('Designer not found');
|
||||||
|
|
||||||
let processedImages = data.images;
|
// CRITICAL: Block new photo uploads on edits
|
||||||
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
if (data.images?.uploaded && data.images.uploaded.some(img => img.isLocal)) {
|
||||||
try {
|
throw new Error('Photo uploads are not allowed during edits. Please use the photo gallery to submit additional photos.');
|
||||||
const uploadedImages = await uploadPendingImages(data.images.uploaded);
|
|
||||||
processedImages = { ...data.images, uploaded: uploadedImages };
|
|
||||||
} catch (error: unknown) {
|
|
||||||
const errorMessage = getErrorMessage(error);
|
|
||||||
logger.error('Company image upload failed', {
|
|
||||||
action: 'designer_update',
|
|
||||||
companyId,
|
|
||||||
error: errorMessage
|
|
||||||
});
|
|
||||||
throw new Error(`Failed to upload images: ${errorMessage}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let processedImages = data.images;
|
||||||
|
|
||||||
const { data: submissionData, error: submissionError } = await supabase
|
const { data: submissionData, error: submissionError } = await supabase
|
||||||
.from('content_submissions')
|
.from('content_submissions')
|
||||||
.insert({
|
.insert({
|
||||||
@@ -1288,22 +1313,13 @@ export async function submitOperatorUpdate(
|
|||||||
if (fetchError) throw new Error(`Failed to fetch operator: ${fetchError.message}`);
|
if (fetchError) throw new Error(`Failed to fetch operator: ${fetchError.message}`);
|
||||||
if (!existingCompany) throw new Error('Operator not found');
|
if (!existingCompany) throw new Error('Operator not found');
|
||||||
|
|
||||||
let processedImages = data.images;
|
// CRITICAL: Block new photo uploads on edits
|
||||||
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
if (data.images?.uploaded && data.images.uploaded.some(img => img.isLocal)) {
|
||||||
try {
|
throw new Error('Photo uploads are not allowed during edits. Please use the photo gallery to submit additional photos.');
|
||||||
const uploadedImages = await uploadPendingImages(data.images.uploaded);
|
|
||||||
processedImages = { ...data.images, uploaded: uploadedImages };
|
|
||||||
} catch (error: unknown) {
|
|
||||||
const errorMessage = getErrorMessage(error);
|
|
||||||
logger.error('Company image upload failed', {
|
|
||||||
action: 'operator_update',
|
|
||||||
companyId,
|
|
||||||
error: errorMessage
|
|
||||||
});
|
|
||||||
throw new Error(`Failed to upload images: ${errorMessage}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let processedImages = data.images;
|
||||||
|
|
||||||
const { data: submissionData, error: submissionError } = await supabase
|
const { data: submissionData, error: submissionError } = await supabase
|
||||||
.from('content_submissions')
|
.from('content_submissions')
|
||||||
.insert({
|
.insert({
|
||||||
@@ -1405,22 +1421,13 @@ export async function submitPropertyOwnerUpdate(
|
|||||||
if (fetchError) throw new Error(`Failed to fetch property owner: ${fetchError.message}`);
|
if (fetchError) throw new Error(`Failed to fetch property owner: ${fetchError.message}`);
|
||||||
if (!existingCompany) throw new Error('Property owner not found');
|
if (!existingCompany) throw new Error('Property owner not found');
|
||||||
|
|
||||||
let processedImages = data.images;
|
// CRITICAL: Block new photo uploads on edits
|
||||||
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
if (data.images?.uploaded && data.images.uploaded.some(img => img.isLocal)) {
|
||||||
try {
|
throw new Error('Photo uploads are not allowed during edits. Please use the photo gallery to submit additional photos.');
|
||||||
const uploadedImages = await uploadPendingImages(data.images.uploaded);
|
|
||||||
processedImages = { ...data.images, uploaded: uploadedImages };
|
|
||||||
} catch (error: unknown) {
|
|
||||||
const errorMessage = getErrorMessage(error);
|
|
||||||
logger.error('Company image upload failed', {
|
|
||||||
action: 'property_owner_update',
|
|
||||||
companyId,
|
|
||||||
error: errorMessage
|
|
||||||
});
|
|
||||||
throw new Error(`Failed to upload images: ${errorMessage}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let processedImages = data.images;
|
||||||
|
|
||||||
const { data: submissionData, error: submissionError } = await supabase
|
const { data: submissionData, error: submissionError } = await supabase
|
||||||
.from('content_submissions')
|
.from('content_submissions')
|
||||||
.insert({
|
.insert({
|
||||||
|
|||||||
@@ -921,6 +921,17 @@ function resolveDependencies(data: any, dependencyMap: Map<string, string>, sort
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Resolve temporary references using sortedItems array (FIXED)
|
// Resolve temporary references using sortedItems array (FIXED)
|
||||||
|
if (resolved._temp_park_ref !== undefined) {
|
||||||
|
const refIndex = resolved._temp_park_ref;
|
||||||
|
if (refIndex >= 0 && refIndex < sortedItems.length) {
|
||||||
|
const refItemId = sortedItems[refIndex].id;
|
||||||
|
if (dependencyMap.has(refItemId)) {
|
||||||
|
resolved.park_id = dependencyMap.get(refItemId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete resolved._temp_park_ref;
|
||||||
|
}
|
||||||
|
|
||||||
if (resolved._temp_manufacturer_ref !== undefined) {
|
if (resolved._temp_manufacturer_ref !== undefined) {
|
||||||
const refIndex = resolved._temp_manufacturer_ref;
|
const refIndex = resolved._temp_manufacturer_ref;
|
||||||
if (refIndex >= 0 && refIndex < sortedItems.length) {
|
if (refIndex >= 0 && refIndex < sortedItems.length) {
|
||||||
@@ -932,6 +943,17 @@ function resolveDependencies(data: any, dependencyMap: Map<string, string>, sort
|
|||||||
delete resolved._temp_manufacturer_ref;
|
delete resolved._temp_manufacturer_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resolved._temp_designer_ref !== undefined) {
|
||||||
|
const refIndex = resolved._temp_designer_ref;
|
||||||
|
if (refIndex >= 0 && refIndex < sortedItems.length) {
|
||||||
|
const refItemId = sortedItems[refIndex].id;
|
||||||
|
if (dependencyMap.has(refItemId)) {
|
||||||
|
resolved.designer_id = dependencyMap.get(refItemId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete resolved._temp_designer_ref;
|
||||||
|
}
|
||||||
|
|
||||||
if (resolved._temp_operator_ref !== undefined) {
|
if (resolved._temp_operator_ref !== undefined) {
|
||||||
const refIndex = resolved._temp_operator_ref;
|
const refIndex = resolved._temp_operator_ref;
|
||||||
if (refIndex >= 0 && refIndex < sortedItems.length) {
|
if (refIndex >= 0 && refIndex < sortedItems.length) {
|
||||||
@@ -965,17 +987,6 @@ function resolveDependencies(data: any, dependencyMap: Map<string, string>, sort
|
|||||||
delete resolved._temp_ride_model_ref;
|
delete resolved._temp_ride_model_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resolved._temp_designer_ref !== undefined) {
|
|
||||||
const refIndex = resolved._temp_designer_ref;
|
|
||||||
if (refIndex >= 0 && refIndex < sortedItems.length) {
|
|
||||||
const refItemId = sortedItems[refIndex].id;
|
|
||||||
if (dependencyMap.has(refItemId)) {
|
|
||||||
resolved.designer_id = dependencyMap.get(refItemId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete resolved._temp_designer_ref;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve each foreign key if it's a submission item ID
|
// Resolve each foreign key if it's a submission item ID
|
||||||
for (const key of foreignKeys) {
|
for (const key of foreignKeys) {
|
||||||
if (resolved[key] && dependencyMap.has(resolved[key])) {
|
if (resolved[key] && dependencyMap.has(resolved[key])) {
|
||||||
|
|||||||
@@ -35,6 +35,37 @@ export interface TempCompanyData {
|
|||||||
website_url?: string;
|
website_url?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TempParkData {
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
park_type: string;
|
||||||
|
status: string;
|
||||||
|
description?: string;
|
||||||
|
opening_date?: string;
|
||||||
|
closing_date?: string;
|
||||||
|
operator_id?: string;
|
||||||
|
property_owner_id?: string;
|
||||||
|
website_url?: string;
|
||||||
|
phone?: string;
|
||||||
|
email?: string;
|
||||||
|
location?: {
|
||||||
|
name: string;
|
||||||
|
city?: string;
|
||||||
|
state_province?: string;
|
||||||
|
country: string;
|
||||||
|
postal_code?: string;
|
||||||
|
latitude: number;
|
||||||
|
longitude: number;
|
||||||
|
};
|
||||||
|
images?: {
|
||||||
|
uploaded: UploadedImage[];
|
||||||
|
banner_assignment?: number | null;
|
||||||
|
card_assignment?: number | null;
|
||||||
|
};
|
||||||
|
_tempNewOperator?: TempCompanyData;
|
||||||
|
_tempNewPropertyOwner?: TempCompanyData;
|
||||||
|
}
|
||||||
|
|
||||||
export interface TempRideModelData {
|
export interface TempRideModelData {
|
||||||
name: string;
|
name: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
|
|||||||
@@ -790,6 +790,41 @@ function resolveDependencies(data: any, dependencyMap: Map<string, string>, sort
|
|||||||
delete resolved._temp_manufacturer_ref;
|
delete resolved._temp_manufacturer_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve temporary references using sortedItems array
|
||||||
|
if (resolved._temp_park_ref !== undefined) {
|
||||||
|
const refIndex = resolved._temp_park_ref;
|
||||||
|
if (refIndex >= 0 && refIndex < sortedItems.length) {
|
||||||
|
const refItemId = sortedItems[refIndex].id;
|
||||||
|
if (dependencyMap.has(refItemId)) {
|
||||||
|
resolved.park_id = dependencyMap.get(refItemId);
|
||||||
|
edgeLogger.info('Resolved temp park ref', {
|
||||||
|
action: 'dependency_resolve_temp_ref',
|
||||||
|
refIndex,
|
||||||
|
refItemId,
|
||||||
|
resolvedId: resolved.park_id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete resolved._temp_park_ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolved._temp_manufacturer_ref !== undefined) {
|
||||||
|
const refIndex = resolved._temp_manufacturer_ref;
|
||||||
|
if (refIndex >= 0 && refIndex < sortedItems.length) {
|
||||||
|
const refItemId = sortedItems[refIndex].id;
|
||||||
|
if (dependencyMap.has(refItemId)) {
|
||||||
|
resolved.manufacturer_id = dependencyMap.get(refItemId);
|
||||||
|
edgeLogger.info('Resolved temp manufacturer ref', {
|
||||||
|
action: 'dependency_resolve_temp_ref',
|
||||||
|
refIndex,
|
||||||
|
refItemId,
|
||||||
|
resolvedId: resolved.manufacturer_id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete resolved._temp_manufacturer_ref;
|
||||||
|
}
|
||||||
|
|
||||||
if (resolved._temp_operator_ref !== undefined) {
|
if (resolved._temp_operator_ref !== undefined) {
|
||||||
const refIndex = resolved._temp_operator_ref;
|
const refIndex = resolved._temp_operator_ref;
|
||||||
if (refIndex >= 0 && refIndex < sortedItems.length) {
|
if (refIndex >= 0 && refIndex < sortedItems.length) {
|
||||||
|
|||||||
Reference in New Issue
Block a user