Fix submission flow issues

This commit is contained in:
gpt-engineer-app[bot]
2025-11-02 20:21:10 +00:00
parent 4aa0c02769
commit 6a9df807fa
3 changed files with 83 additions and 37 deletions

View File

@@ -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,

View File

@@ -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])) {

View File

@@ -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