mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 11:31:11 -05:00
Fix submission flow issues
This commit is contained in:
@@ -223,10 +223,23 @@ export function ParkForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
|||||||
submissionContent.park.property_owner_id = null;
|
submissionContent.park.property_owner_id = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const finalOperatorId = tempNewOperator ? undefined : (selectedOperatorId || undefined);
|
// Determine final IDs to pass
|
||||||
const finalPropertyOwnerId = operatorIsOwner
|
// When creating new entities via composite submission, IDs should be undefined
|
||||||
? finalOperatorId
|
// When using existing entities, pass their IDs directly
|
||||||
: (tempNewPropertyOwner ? undefined : (selectedPropertyOwnerId || undefined));
|
let finalOperatorId: string | undefined;
|
||||||
|
let finalPropertyOwnerId: string | undefined;
|
||||||
|
|
||||||
|
if (tempNewOperator) {
|
||||||
|
// New operator being created via composite submission
|
||||||
|
finalOperatorId = undefined;
|
||||||
|
finalPropertyOwnerId = operatorIsOwner ? undefined :
|
||||||
|
(tempNewPropertyOwner ? undefined : selectedPropertyOwnerId);
|
||||||
|
} else {
|
||||||
|
// Using existing operator
|
||||||
|
finalOperatorId = selectedOperatorId || undefined;
|
||||||
|
finalPropertyOwnerId = operatorIsOwner ? finalOperatorId :
|
||||||
|
(tempNewPropertyOwner ? undefined : selectedPropertyOwnerId);
|
||||||
|
}
|
||||||
|
|
||||||
await onSubmit({
|
await onSubmit({
|
||||||
...data,
|
...data,
|
||||||
|
|||||||
@@ -185,24 +185,25 @@ export async function approveSubmissionItems(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Create the entity based on type with dependency resolution
|
// Create the entity based on type with dependency resolution
|
||||||
|
// PASS sortedItems to enable correct index-based resolution
|
||||||
switch (item.item_type) {
|
switch (item.item_type) {
|
||||||
case 'park':
|
case 'park':
|
||||||
entityId = await createPark(item.item_data, dependencyMap);
|
entityId = await createPark(item.item_data, dependencyMap, sortedItems);
|
||||||
break;
|
break;
|
||||||
case 'ride':
|
case 'ride':
|
||||||
entityId = await createRide(item.item_data, dependencyMap);
|
entityId = await createRide(item.item_data, dependencyMap, sortedItems);
|
||||||
break;
|
break;
|
||||||
case 'manufacturer':
|
case 'manufacturer':
|
||||||
case 'operator':
|
case 'operator':
|
||||||
case 'property_owner':
|
case 'property_owner':
|
||||||
case 'designer':
|
case 'designer':
|
||||||
entityId = await createCompany(item.item_data, item.item_type, dependencyMap);
|
entityId = await createCompany(item.item_data, item.item_type, dependencyMap, sortedItems);
|
||||||
break;
|
break;
|
||||||
case 'ride_model':
|
case 'ride_model':
|
||||||
entityId = await createRideModel(item.item_data, dependencyMap);
|
entityId = await createRideModel(item.item_data, dependencyMap, sortedItems);
|
||||||
break;
|
break;
|
||||||
case 'photo':
|
case 'photo':
|
||||||
entityId = await approvePhotos(item.item_data, dependencyMap, userId, item.submission_id);
|
entityId = await approvePhotos(item.item_data, dependencyMap, userId, item.submission_id, sortedItems);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,7 +344,7 @@ function extractImageAssignments(images: any) {
|
|||||||
/**
|
/**
|
||||||
* Helper functions to create entities with dependency resolution
|
* Helper functions to create entities with dependency resolution
|
||||||
*/
|
*/
|
||||||
async function createPark(data: any, dependencyMap: Map<string, string>): Promise<string> {
|
async function createPark(data: any, dependencyMap: Map<string, string>, sortedItems: SubmissionItemWithDeps[]): Promise<string> {
|
||||||
const { transformParkData, validateSubmissionData } = await import('./entityTransformers');
|
const { transformParkData, validateSubmissionData } = await import('./entityTransformers');
|
||||||
const { ensureUniqueSlug } = await import('./slugUtils');
|
const { ensureUniqueSlug } = await import('./slugUtils');
|
||||||
|
|
||||||
@@ -352,7 +353,7 @@ async function createPark(data: any, dependencyMap: Map<string, string>): Promis
|
|||||||
|
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
// Handle park edit
|
// Handle park edit
|
||||||
const resolvedData = resolveDependencies(data, dependencyMap);
|
const resolvedData = resolveDependencies(data, dependencyMap, sortedItems);
|
||||||
|
|
||||||
// Resolve location_id if location data is provided
|
// Resolve location_id if location data is provided
|
||||||
let locationId = resolvedData.location_id;
|
let locationId = resolvedData.location_id;
|
||||||
@@ -401,7 +402,7 @@ async function createPark(data: any, dependencyMap: Map<string, string>): Promis
|
|||||||
|
|
||||||
// Handle park creation
|
// Handle park creation
|
||||||
validateSubmissionData(data, 'Park');
|
validateSubmissionData(data, 'Park');
|
||||||
const resolvedData = resolveDependencies(data, dependencyMap);
|
const resolvedData = resolveDependencies(data, dependencyMap, sortedItems);
|
||||||
|
|
||||||
// Resolve location_id if location data is provided
|
// Resolve location_id if location data is provided
|
||||||
let locationId = resolvedData.location_id;
|
let locationId = resolvedData.location_id;
|
||||||
@@ -498,7 +499,7 @@ async function resolveLocationId(locationData: any): Promise<string | null> {
|
|||||||
return newLocation.id;
|
return newLocation.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createRide(data: any, dependencyMap: Map<string, string>): Promise<string> {
|
async function createRide(data: any, dependencyMap: Map<string, string>, sortedItems: SubmissionItemWithDeps[]): Promise<string> {
|
||||||
const { transformRideData, validateSubmissionData } = await import('./entityTransformers');
|
const { transformRideData, validateSubmissionData } = await import('./entityTransformers');
|
||||||
const { ensureUniqueSlug } = await import('./slugUtils');
|
const { ensureUniqueSlug } = await import('./slugUtils');
|
||||||
|
|
||||||
@@ -507,7 +508,7 @@ async function createRide(data: any, dependencyMap: Map<string, string>): Promis
|
|||||||
|
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
// Handle ride edit
|
// Handle ride edit
|
||||||
const resolvedData = resolveDependencies(data, dependencyMap);
|
const resolvedData = resolveDependencies(data, dependencyMap, sortedItems);
|
||||||
|
|
||||||
// Extract image assignments from ImageAssignments structure
|
// Extract image assignments from ImageAssignments structure
|
||||||
const imageData = extractImageAssignments(resolvedData.images);
|
const imageData = extractImageAssignments(resolvedData.images);
|
||||||
@@ -556,7 +557,7 @@ async function createRide(data: any, dependencyMap: Map<string, string>): Promis
|
|||||||
|
|
||||||
// Handle ride creation
|
// Handle ride creation
|
||||||
validateSubmissionData(data, 'Ride');
|
validateSubmissionData(data, 'Ride');
|
||||||
const resolvedData = resolveDependencies(data, dependencyMap);
|
const resolvedData = resolveDependencies(data, dependencyMap, sortedItems);
|
||||||
|
|
||||||
if (!resolvedData.park_id) {
|
if (!resolvedData.park_id) {
|
||||||
throw new Error('Ride must be associated with a park');
|
throw new Error('Ride must be associated with a park');
|
||||||
@@ -588,7 +589,8 @@ async function createRide(data: any, dependencyMap: Map<string, string>): Promis
|
|||||||
async function createCompany(
|
async function createCompany(
|
||||||
data: any,
|
data: any,
|
||||||
companyType: string,
|
companyType: string,
|
||||||
dependencyMap: Map<string, string>
|
dependencyMap: Map<string, string>,
|
||||||
|
sortedItems: SubmissionItemWithDeps[]
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const { transformCompanyData, validateSubmissionData } = await import('./entityTransformers');
|
const { transformCompanyData, validateSubmissionData } = await import('./entityTransformers');
|
||||||
const { ensureUniqueSlug } = await import('./slugUtils');
|
const { ensureUniqueSlug } = await import('./slugUtils');
|
||||||
@@ -598,7 +600,7 @@ async function createCompany(
|
|||||||
|
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
// Handle company edit
|
// Handle company edit
|
||||||
const resolvedData = resolveDependencies(data, dependencyMap);
|
const resolvedData = resolveDependencies(data, dependencyMap, sortedItems);
|
||||||
|
|
||||||
// Extract image assignments from ImageAssignments structure
|
// Extract image assignments from ImageAssignments structure
|
||||||
const imageData = extractImageAssignments(resolvedData.images);
|
const imageData = extractImageAssignments(resolvedData.images);
|
||||||
@@ -630,7 +632,7 @@ async function createCompany(
|
|||||||
|
|
||||||
// Handle company creation
|
// Handle company creation
|
||||||
validateSubmissionData(data, 'Company');
|
validateSubmissionData(data, 'Company');
|
||||||
const resolvedData = resolveDependencies(data, dependencyMap);
|
const resolvedData = resolveDependencies(data, dependencyMap, sortedItems);
|
||||||
|
|
||||||
const uniqueSlug = await ensureUniqueSlug(resolvedData.slug, 'companies');
|
const uniqueSlug = await ensureUniqueSlug(resolvedData.slug, 'companies');
|
||||||
resolvedData.slug = uniqueSlug;
|
resolvedData.slug = uniqueSlug;
|
||||||
@@ -663,7 +665,7 @@ async function createCompany(
|
|||||||
return company.id;
|
return company.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createRideModel(data: any, dependencyMap: Map<string, string>): Promise<string> {
|
async function createRideModel(data: any, dependencyMap: Map<string, string>, sortedItems: SubmissionItemWithDeps[]): Promise<string> {
|
||||||
const { transformRideModelData, validateSubmissionData } = await import('./entityTransformers');
|
const { transformRideModelData, validateSubmissionData } = await import('./entityTransformers');
|
||||||
const { ensureUniqueSlug } = await import('./slugUtils');
|
const { ensureUniqueSlug } = await import('./slugUtils');
|
||||||
|
|
||||||
@@ -672,7 +674,7 @@ async function createRideModel(data: any, dependencyMap: Map<string, string>): P
|
|||||||
|
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
// Handle ride model edit
|
// Handle ride model edit
|
||||||
const resolvedData = resolveDependencies(data, dependencyMap);
|
const resolvedData = resolveDependencies(data, dependencyMap, sortedItems);
|
||||||
|
|
||||||
// Extract image assignments from ImageAssignments structure
|
// Extract image assignments from ImageAssignments structure
|
||||||
const imageData = extractImageAssignments(resolvedData.images);
|
const imageData = extractImageAssignments(resolvedData.images);
|
||||||
@@ -704,7 +706,7 @@ async function createRideModel(data: any, dependencyMap: Map<string, string>): P
|
|||||||
|
|
||||||
// Handle ride model creation
|
// Handle ride model creation
|
||||||
validateSubmissionData(data, 'Ride Model');
|
validateSubmissionData(data, 'Ride Model');
|
||||||
const resolvedData = resolveDependencies(data, dependencyMap);
|
const resolvedData = resolveDependencies(data, dependencyMap, sortedItems);
|
||||||
|
|
||||||
// Validate manufacturer_id is present (required for ride models)
|
// Validate manufacturer_id is present (required for ride models)
|
||||||
if (!resolvedData.manufacturer_id) {
|
if (!resolvedData.manufacturer_id) {
|
||||||
@@ -739,10 +741,10 @@ async function createRideModel(data: any, dependencyMap: Map<string, string>): P
|
|||||||
return model.id;
|
return model.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function approvePhotos(data: any, dependencyMap: Map<string, string>, userId: string, submissionId: string): Promise<string> {
|
async function approvePhotos(data: any, dependencyMap: Map<string, string>, userId: string, submissionId: string, sortedItems: SubmissionItemWithDeps[]): Promise<string> {
|
||||||
// Photos are already uploaded to Cloudflare
|
// Photos are already uploaded to Cloudflare
|
||||||
// Resolve dependencies for entity associations
|
// Resolve dependencies for entity associations
|
||||||
const resolvedData = resolveDependencies(data, dependencyMap);
|
const resolvedData = resolveDependencies(data, dependencyMap, sortedItems);
|
||||||
|
|
||||||
if (!resolvedData.photos || !Array.isArray(resolvedData.photos) || resolvedData.photos.length === 0) {
|
if (!resolvedData.photos || !Array.isArray(resolvedData.photos) || resolvedData.photos.length === 0) {
|
||||||
throw new Error('No photos found in submission');
|
throw new Error('No photos found in submission');
|
||||||
@@ -900,8 +902,11 @@ async function updateEntityFeaturedImage(
|
|||||||
/**
|
/**
|
||||||
* Resolve dependency references in item_data by looking up approved entity IDs
|
* Resolve dependency references in item_data by looking up approved entity IDs
|
||||||
* Replaces temporary references (_temp_*_ref) with actual database entity IDs
|
* Replaces temporary references (_temp_*_ref) with actual database entity IDs
|
||||||
|
*
|
||||||
|
* FIXED: Now uses sortedItems array for stable index-based resolution
|
||||||
|
* instead of unreliable Array.from(dependencyMap.keys())[refIndex]
|
||||||
*/
|
*/
|
||||||
function resolveDependencies(data: any, dependencyMap: Map<string, string>): any {
|
function resolveDependencies(data: any, dependencyMap: Map<string, string>, sortedItems: SubmissionItemWithDeps[]): any {
|
||||||
const resolved = { ...data };
|
const resolved = { ...data };
|
||||||
|
|
||||||
// List of foreign key fields that may need resolution
|
// List of foreign key fields that may need resolution
|
||||||
@@ -915,43 +920,62 @@ function resolveDependencies(data: any, dependencyMap: Map<string, string>): any
|
|||||||
'location_id',
|
'location_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
// Resolve temporary references first
|
// Resolve temporary references using sortedItems array (FIXED)
|
||||||
if (resolved._temp_manufacturer_ref !== undefined) {
|
if (resolved._temp_manufacturer_ref !== undefined) {
|
||||||
const refIndex = resolved._temp_manufacturer_ref;
|
const refIndex = resolved._temp_manufacturer_ref;
|
||||||
const refItemId = Array.from(dependencyMap.keys())[refIndex];
|
if (refIndex >= 0 && refIndex < sortedItems.length) {
|
||||||
if (refItemId && dependencyMap.has(refItemId)) {
|
const refItemId = sortedItems[refIndex].id;
|
||||||
resolved.manufacturer_id = dependencyMap.get(refItemId);
|
if (dependencyMap.has(refItemId)) {
|
||||||
|
resolved.manufacturer_id = dependencyMap.get(refItemId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
delete resolved._temp_manufacturer_ref;
|
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;
|
||||||
const refItemId = Array.from(dependencyMap.keys())[refIndex];
|
if (refIndex >= 0 && refIndex < sortedItems.length) {
|
||||||
if (refItemId && dependencyMap.has(refItemId)) {
|
const refItemId = sortedItems[refIndex].id;
|
||||||
resolved.operator_id = dependencyMap.get(refItemId);
|
if (dependencyMap.has(refItemId)) {
|
||||||
|
resolved.operator_id = dependencyMap.get(refItemId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
delete resolved._temp_operator_ref;
|
delete resolved._temp_operator_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resolved._temp_property_owner_ref !== undefined) {
|
if (resolved._temp_property_owner_ref !== undefined) {
|
||||||
const refIndex = resolved._temp_property_owner_ref;
|
const refIndex = resolved._temp_property_owner_ref;
|
||||||
const refItemId = Array.from(dependencyMap.keys())[refIndex];
|
if (refIndex >= 0 && refIndex < sortedItems.length) {
|
||||||
if (refItemId && dependencyMap.has(refItemId)) {
|
const refItemId = sortedItems[refIndex].id;
|
||||||
resolved.property_owner_id = dependencyMap.get(refItemId);
|
if (dependencyMap.has(refItemId)) {
|
||||||
|
resolved.property_owner_id = dependencyMap.get(refItemId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
delete resolved._temp_property_owner_ref;
|
delete resolved._temp_property_owner_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resolved._temp_ride_model_ref !== undefined) {
|
if (resolved._temp_ride_model_ref !== undefined) {
|
||||||
const refIndex = resolved._temp_ride_model_ref;
|
const refIndex = resolved._temp_ride_model_ref;
|
||||||
const refItemId = Array.from(dependencyMap.keys())[refIndex];
|
if (refIndex >= 0 && refIndex < sortedItems.length) {
|
||||||
if (refItemId && dependencyMap.has(refItemId)) {
|
const refItemId = sortedItems[refIndex].id;
|
||||||
resolved.ride_model_id = dependencyMap.get(refItemId);
|
if (dependencyMap.has(refItemId)) {
|
||||||
|
resolved.ride_model_id = dependencyMap.get(refItemId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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])) {
|
||||||
|
|||||||
@@ -1301,6 +1301,15 @@ async function createRideModel(supabase: any, data: any): Promise<string> {
|
|||||||
if (error) throw new Error(`Failed to update ride model: ${error.message}`);
|
if (error) throw new Error(`Failed to update ride model: ${error.message}`);
|
||||||
} else {
|
} else {
|
||||||
console.log('Creating new ride model');
|
console.log('Creating new ride model');
|
||||||
|
|
||||||
|
// Validate required fields
|
||||||
|
if (!data.manufacturer_id) {
|
||||||
|
throw new Error('Ride model must be associated with a manufacturer');
|
||||||
|
}
|
||||||
|
if (!data.name || !data.slug) {
|
||||||
|
throw new Error('Ride model must have a name and slug');
|
||||||
|
}
|
||||||
|
|
||||||
const sanitizedData = sanitizeDateFields(data);
|
const sanitizedData = sanitizeDateFields(data);
|
||||||
const filteredData = filterDatabaseFields(sanitizedData, RIDE_MODEL_FIELDS);
|
const filteredData = filterDatabaseFields(sanitizedData, RIDE_MODEL_FIELDS);
|
||||||
const { data: model, error } = await supabase
|
const { data: model, error } = await supabase
|
||||||
|
|||||||
Reference in New Issue
Block a user