mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 10:11:13 -05:00
Fix entity submission pipelines
Refactor park updates, ride updates, and timeline event submissions to use dedicated relational tables instead of JSON blobs in `submission_items.item_data`. This enforces the "NO JSON IN SQL" rule, improving queryability, data integrity, and consistency across the pipeline.
This commit is contained in:
@@ -91,7 +91,9 @@ export interface ParkFormData {
|
||||
park_type: string;
|
||||
status: string;
|
||||
opening_date?: string;
|
||||
opening_date_precision?: string;
|
||||
closing_date?: string;
|
||||
closing_date_precision?: string;
|
||||
website_url?: string;
|
||||
phone?: string;
|
||||
email?: string;
|
||||
@@ -131,7 +133,9 @@ export interface RideFormData {
|
||||
designer_id?: string;
|
||||
ride_model_id?: string;
|
||||
opening_date?: string;
|
||||
opening_date_precision?: string;
|
||||
closing_date?: string;
|
||||
closing_date_precision?: string;
|
||||
max_speed_kmh?: number;
|
||||
max_height_meters?: number;
|
||||
length_meters?: number;
|
||||
@@ -890,21 +894,72 @@ export async function submitParkUpdate(
|
||||
|
||||
if (submissionError) throw submissionError;
|
||||
|
||||
// Create the submission item with actual park data AND original data
|
||||
// Extract changed fields
|
||||
const changedFields = extractChangedFields(data, existingPark as any);
|
||||
|
||||
// Handle location data properly
|
||||
let tempLocationData: any = null;
|
||||
if (data.location) {
|
||||
tempLocationData = {
|
||||
name: data.location.name,
|
||||
street_address: data.location.street_address || null,
|
||||
city: data.location.city || null,
|
||||
state_province: data.location.state_province || null,
|
||||
country: data.location.country,
|
||||
latitude: data.location.latitude,
|
||||
longitude: data.location.longitude,
|
||||
timezone: data.location.timezone || null,
|
||||
postal_code: data.location.postal_code || null,
|
||||
display_name: data.location.display_name
|
||||
};
|
||||
}
|
||||
|
||||
// ✅ FIXED: Insert into park_submissions table (relational pattern)
|
||||
const { data: parkSubmission, error: parkSubmissionError } = await supabase
|
||||
.from('park_submissions')
|
||||
.insert({
|
||||
submission_id: submissionData.id,
|
||||
name: changedFields.name ?? existingPark.name,
|
||||
slug: changedFields.slug ?? existingPark.slug,
|
||||
description: changedFields.description !== undefined ? changedFields.description : existingPark.description,
|
||||
park_type: changedFields.park_type ?? existingPark.park_type,
|
||||
status: changedFields.status ?? existingPark.status,
|
||||
opening_date: changedFields.opening_date !== undefined ? changedFields.opening_date : existingPark.opening_date,
|
||||
opening_date_precision: changedFields.opening_date_precision !== undefined ? changedFields.opening_date_precision : existingPark.opening_date_precision,
|
||||
closing_date: changedFields.closing_date !== undefined ? changedFields.closing_date : existingPark.closing_date,
|
||||
closing_date_precision: changedFields.closing_date_precision !== undefined ? changedFields.closing_date_precision : existingPark.closing_date_precision,
|
||||
website_url: changedFields.website_url !== undefined ? changedFields.website_url : existingPark.website_url,
|
||||
phone: changedFields.phone !== undefined ? changedFields.phone : existingPark.phone,
|
||||
email: changedFields.email !== undefined ? changedFields.email : existingPark.email,
|
||||
operator_id: changedFields.operator_id !== undefined ? changedFields.operator_id : existingPark.operator_id,
|
||||
property_owner_id: changedFields.property_owner_id !== undefined ? changedFields.property_owner_id : existingPark.property_owner_id,
|
||||
location_id: changedFields.location_id !== undefined ? changedFields.location_id : existingPark.location_id,
|
||||
temp_location_data: tempLocationData,
|
||||
banner_image_url: changedFields.banner_image_url !== undefined ? changedFields.banner_image_url : existingPark.banner_image_url,
|
||||
banner_image_id: changedFields.banner_image_id !== undefined ? changedFields.banner_image_id : existingPark.banner_image_id,
|
||||
card_image_url: changedFields.card_image_url !== undefined ? changedFields.card_image_url : existingPark.card_image_url,
|
||||
card_image_id: changedFields.card_image_id !== undefined ? changedFields.card_image_id : existingPark.card_image_id,
|
||||
})
|
||||
.select('id')
|
||||
.single();
|
||||
|
||||
if (parkSubmissionError) throw parkSubmissionError;
|
||||
|
||||
// ✅ Create submission_items referencing park_submission (no JSON data)
|
||||
const { error: itemError } = await supabase
|
||||
.from('submission_items')
|
||||
.insert({
|
||||
submission_id: submissionData.id,
|
||||
item_type: 'park',
|
||||
action_type: 'edit',
|
||||
item_data: JSON.parse(JSON.stringify({
|
||||
...extractChangedFields(data, existingPark as any),
|
||||
park_id: parkId, // Always include for relational integrity
|
||||
images: processedImages
|
||||
})) as Json,
|
||||
item_data: {
|
||||
park_id: parkId, // Only reference IDs
|
||||
images: processedImages as unknown as Json
|
||||
},
|
||||
original_data: JSON.parse(JSON.stringify(existingPark)),
|
||||
status: 'pending' as const,
|
||||
order_index: 0
|
||||
order_index: 0,
|
||||
park_submission_id: parkSubmission.id
|
||||
});
|
||||
|
||||
if (itemError) throw itemError;
|
||||
@@ -1440,7 +1495,52 @@ export async function submitRideUpdate(
|
||||
|
||||
if (submissionError) throw submissionError;
|
||||
|
||||
// Create the submission item with actual ride data AND original data
|
||||
// Extract changed fields
|
||||
const changedFields = extractChangedFields(data, existingRide as any);
|
||||
|
||||
// ✅ FIXED: Insert into ride_submissions table (relational pattern)
|
||||
const { data: rideSubmission, error: rideSubmissionError } = await supabase
|
||||
.from('ride_submissions')
|
||||
.insert({
|
||||
submission_id: submissionData.id,
|
||||
name: changedFields.name ?? existingRide.name,
|
||||
slug: changedFields.slug ?? existingRide.slug,
|
||||
description: changedFields.description !== undefined ? changedFields.description : existingRide.description,
|
||||
category: changedFields.category ?? existingRide.category,
|
||||
status: changedFields.status ?? existingRide.status,
|
||||
park_id: changedFields.park_id !== undefined ? changedFields.park_id : existingRide.park_id,
|
||||
manufacturer_id: changedFields.manufacturer_id !== undefined ? changedFields.manufacturer_id : existingRide.manufacturer_id,
|
||||
designer_id: changedFields.designer_id !== undefined ? changedFields.designer_id : existingRide.designer_id,
|
||||
ride_model_id: changedFields.ride_model_id !== undefined ? changedFields.ride_model_id : existingRide.ride_model_id,
|
||||
opening_date: changedFields.opening_date !== undefined ? changedFields.opening_date : existingRide.opening_date,
|
||||
opening_date_precision: changedFields.opening_date_precision !== undefined ? changedFields.opening_date_precision : existingRide.opening_date_precision,
|
||||
closing_date: changedFields.closing_date !== undefined ? changedFields.closing_date : existingRide.closing_date,
|
||||
closing_date_precision: changedFields.closing_date_precision !== undefined ? changedFields.closing_date_precision : existingRide.closing_date_precision,
|
||||
max_speed_kmh: changedFields.max_speed_kmh !== undefined ? changedFields.max_speed_kmh : existingRide.max_speed_kmh,
|
||||
max_height_meters: changedFields.max_height_meters !== undefined ? changedFields.max_height_meters : existingRide.max_height_meters,
|
||||
length_meters: changedFields.length_meters !== undefined ? changedFields.length_meters : existingRide.length_meters,
|
||||
duration_seconds: changedFields.duration_seconds !== undefined ? changedFields.duration_seconds : existingRide.duration_seconds,
|
||||
capacity_per_hour: changedFields.capacity_per_hour !== undefined ? changedFields.capacity_per_hour : existingRide.capacity_per_hour,
|
||||
height_requirement: changedFields.height_requirement !== undefined ? changedFields.height_requirement : existingRide.height_requirement,
|
||||
age_requirement: changedFields.age_requirement !== undefined ? changedFields.age_requirement : existingRide.age_requirement,
|
||||
inversions: changedFields.inversions !== undefined ? changedFields.inversions : existingRide.inversions,
|
||||
drop_height_meters: changedFields.drop_height_meters !== undefined ? changedFields.drop_height_meters : existingRide.drop_height_meters,
|
||||
max_g_force: changedFields.max_g_force !== undefined ? changedFields.max_g_force : existingRide.max_g_force,
|
||||
intensity_level: changedFields.intensity_level !== undefined ? changedFields.intensity_level : existingRide.intensity_level,
|
||||
coaster_type: changedFields.coaster_type !== undefined ? changedFields.coaster_type : existingRide.coaster_type,
|
||||
seating_type: changedFields.seating_type !== undefined ? changedFields.seating_type : existingRide.seating_type,
|
||||
ride_sub_type: changedFields.ride_sub_type !== undefined ? changedFields.ride_sub_type : existingRide.ride_sub_type,
|
||||
banner_image_url: changedFields.banner_image_url !== undefined ? changedFields.banner_image_url : existingRide.banner_image_url,
|
||||
banner_image_id: changedFields.banner_image_id !== undefined ? changedFields.banner_image_id : existingRide.banner_image_id,
|
||||
card_image_url: changedFields.card_image_url !== undefined ? changedFields.card_image_url : existingRide.card_image_url,
|
||||
card_image_id: changedFields.card_image_id !== undefined ? changedFields.card_image_id : existingRide.card_image_id,
|
||||
})
|
||||
.select('id')
|
||||
.single();
|
||||
|
||||
if (rideSubmissionError) throw rideSubmissionError;
|
||||
|
||||
// ✅ Create submission_items referencing ride_submission (no JSON data)
|
||||
const { error: itemError } = await supabase
|
||||
.from('submission_items')
|
||||
.insert({
|
||||
@@ -1448,13 +1548,13 @@ export async function submitRideUpdate(
|
||||
item_type: 'ride',
|
||||
action_type: 'edit',
|
||||
item_data: {
|
||||
...extractChangedFields(data, existingRide as any),
|
||||
ride_id: rideId, // Always include for relational integrity
|
||||
ride_id: rideId, // Only reference IDs
|
||||
images: processedImages as unknown as Json
|
||||
},
|
||||
original_data: JSON.parse(JSON.stringify(existingRide)),
|
||||
status: 'pending' as const,
|
||||
order_index: 0
|
||||
order_index: 0,
|
||||
ride_submission_id: rideSubmission.id
|
||||
});
|
||||
|
||||
if (itemError) throw itemError;
|
||||
@@ -2248,16 +2348,30 @@ export async function submitTimelineEvent(
|
||||
throw new Error('User ID is required for timeline event submission');
|
||||
}
|
||||
|
||||
// Create submission content (minimal reference data only)
|
||||
const content: Json = {
|
||||
action: 'create',
|
||||
entity_type: entityType,
|
||||
entity_id: entityId,
|
||||
};
|
||||
|
||||
// Create the main submission record
|
||||
// Use atomic RPC function to create submission + items in transaction
|
||||
const itemData: Record<string, any> = {
|
||||
const { data: submissionData, error: submissionError } = await supabase
|
||||
.from('content_submissions')
|
||||
.insert({
|
||||
user_id: userId,
|
||||
submission_type: 'timeline_event',
|
||||
status: 'pending' as const
|
||||
})
|
||||
.select('id')
|
||||
.single();
|
||||
|
||||
if (submissionError) {
|
||||
handleError(submissionError, {
|
||||
action: 'Submit timeline event',
|
||||
userId,
|
||||
});
|
||||
throw new Error('Failed to create timeline event submission');
|
||||
}
|
||||
|
||||
// ✅ FIXED: Insert into timeline_event_submissions table (relational pattern)
|
||||
const { data: timelineSubmission, error: timelineSubmissionError } = await supabase
|
||||
.from('timeline_event_submissions')
|
||||
.insert({
|
||||
submission_id: submissionData.id,
|
||||
entity_type: entityType,
|
||||
entity_id: entityId,
|
||||
event_type: data.event_type,
|
||||
@@ -2272,34 +2386,45 @@ export async function submitTimelineEvent(
|
||||
from_location_id: data.from_location_id,
|
||||
to_location_id: data.to_location_id,
|
||||
is_public: true,
|
||||
};
|
||||
})
|
||||
.select('id')
|
||||
.single();
|
||||
|
||||
const items = [{
|
||||
item_type: 'timeline_event',
|
||||
action_type: 'create',
|
||||
item_data: itemData,
|
||||
order_index: 0,
|
||||
}];
|
||||
|
||||
const { data: submissionId, error } = await supabase
|
||||
.rpc('create_submission_with_items', {
|
||||
p_user_id: userId,
|
||||
p_submission_type: 'timeline_event',
|
||||
p_content: content,
|
||||
p_items: items as unknown as Json[],
|
||||
});
|
||||
|
||||
if (error || !submissionId) {
|
||||
handleError(error || new Error('No submission ID returned'), {
|
||||
action: 'Submit timeline event',
|
||||
if (timelineSubmissionError) {
|
||||
handleError(timelineSubmissionError, {
|
||||
action: 'Submit timeline event data',
|
||||
userId,
|
||||
});
|
||||
throw new Error('Failed to submit timeline event for review');
|
||||
}
|
||||
|
||||
// ✅ Create submission_items referencing timeline_event_submission (no JSON data)
|
||||
const { error: itemError } = await supabase
|
||||
.from('submission_items')
|
||||
.insert({
|
||||
submission_id: submissionData.id,
|
||||
item_type: 'timeline_event',
|
||||
action_type: 'create',
|
||||
item_data: {
|
||||
entity_type: entityType,
|
||||
entity_id: entityId
|
||||
} as Json,
|
||||
status: 'pending' as const,
|
||||
order_index: 0,
|
||||
timeline_event_submission_id: timelineSubmission.id
|
||||
});
|
||||
|
||||
if (itemError) {
|
||||
handleError(itemError, {
|
||||
action: 'Create timeline event submission item',
|
||||
userId,
|
||||
});
|
||||
throw new Error('Failed to link timeline event submission');
|
||||
}
|
||||
|
||||
return {
|
||||
submitted: true,
|
||||
submissionId: submissionId,
|
||||
submissionId: submissionData.id,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2332,49 +2457,85 @@ export async function submitTimelineEventUpdate(
|
||||
// Extract only changed fields from form data
|
||||
const changedFields = extractChangedFields(data, originalEvent as Partial<Record<string, unknown>>);
|
||||
|
||||
const itemData: Record<string, unknown> = {
|
||||
...changedFields,
|
||||
// Always include entity reference (for FK integrity)
|
||||
// Create the main submission record
|
||||
const { data: submissionData, error: submissionError } = await supabase
|
||||
.from('content_submissions')
|
||||
.insert({
|
||||
user_id: userId,
|
||||
submission_type: 'timeline_event',
|
||||
status: 'pending' as const
|
||||
})
|
||||
.select('id')
|
||||
.single();
|
||||
|
||||
if (submissionError) {
|
||||
handleError(submissionError, {
|
||||
action: 'Update timeline event',
|
||||
metadata: { eventId },
|
||||
});
|
||||
throw new Error('Failed to create timeline event update submission');
|
||||
}
|
||||
|
||||
// ✅ FIXED: Insert into timeline_event_submissions table (relational pattern)
|
||||
const { data: timelineSubmission, error: timelineSubmissionError } = await supabase
|
||||
.from('timeline_event_submissions')
|
||||
.insert({
|
||||
submission_id: submissionData.id,
|
||||
entity_type: originalEvent.entity_type,
|
||||
entity_id: originalEvent.entity_id,
|
||||
event_type: changedFields.event_type !== undefined ? changedFields.event_type : originalEvent.event_type,
|
||||
event_date: changedFields.event_date !== undefined ? (typeof changedFields.event_date === 'string' ? changedFields.event_date : changedFields.event_date.toISOString().split('T')[0]) : originalEvent.event_date,
|
||||
event_date_precision: (changedFields.event_date_precision !== undefined ? changedFields.event_date_precision : originalEvent.event_date_precision) || 'day',
|
||||
title: changedFields.title !== undefined ? changedFields.title : originalEvent.title,
|
||||
description: changedFields.description !== undefined ? changedFields.description : originalEvent.description,
|
||||
from_value: changedFields.from_value !== undefined ? changedFields.from_value : originalEvent.from_value,
|
||||
to_value: changedFields.to_value !== undefined ? changedFields.to_value : originalEvent.to_value,
|
||||
from_entity_id: changedFields.from_entity_id !== undefined ? changedFields.from_entity_id : originalEvent.from_entity_id,
|
||||
to_entity_id: changedFields.to_entity_id !== undefined ? changedFields.to_entity_id : originalEvent.to_entity_id,
|
||||
from_location_id: changedFields.from_location_id !== undefined ? changedFields.from_location_id : originalEvent.from_location_id,
|
||||
to_location_id: changedFields.to_location_id !== undefined ? changedFields.to_location_id : originalEvent.to_location_id,
|
||||
is_public: true,
|
||||
};
|
||||
})
|
||||
.select('id')
|
||||
.single();
|
||||
|
||||
// Use atomic RPC function to create submission and item together
|
||||
const { data: result, error: rpcError } = await supabase.rpc(
|
||||
'create_submission_with_items',
|
||||
{
|
||||
p_user_id: userId,
|
||||
p_submission_type: 'timeline_event',
|
||||
p_content: {
|
||||
action: 'edit',
|
||||
event_id: eventId,
|
||||
entity_type: originalEvent.entity_type,
|
||||
} as unknown as Json,
|
||||
p_items: [
|
||||
{
|
||||
item_type: 'timeline_event',
|
||||
action_type: 'edit',
|
||||
item_data: itemData,
|
||||
original_data: originalEvent,
|
||||
status: 'pending' as const,
|
||||
order_index: 0,
|
||||
}
|
||||
] as unknown as Json[],
|
||||
}
|
||||
);
|
||||
|
||||
if (rpcError || !result) {
|
||||
handleError(rpcError || new Error('No result returned'), {
|
||||
action: 'Update timeline event',
|
||||
if (timelineSubmissionError) {
|
||||
handleError(timelineSubmissionError, {
|
||||
action: 'Update timeline event data',
|
||||
metadata: { eventId },
|
||||
});
|
||||
throw new Error('Failed to submit timeline event update');
|
||||
}
|
||||
|
||||
// ✅ Create submission_items referencing timeline_event_submission (no JSON data)
|
||||
const { error: itemError } = await supabase
|
||||
.from('submission_items')
|
||||
.insert({
|
||||
submission_id: submissionData.id,
|
||||
item_type: 'timeline_event',
|
||||
action_type: 'edit',
|
||||
item_data: {
|
||||
event_id: eventId,
|
||||
entity_type: originalEvent.entity_type,
|
||||
entity_id: originalEvent.entity_id
|
||||
} as Json,
|
||||
original_data: JSON.parse(JSON.stringify(originalEvent)),
|
||||
status: 'pending' as const,
|
||||
order_index: 0,
|
||||
timeline_event_submission_id: timelineSubmission.id
|
||||
});
|
||||
|
||||
if (itemError) {
|
||||
handleError(itemError, {
|
||||
action: 'Create timeline event update submission item',
|
||||
metadata: { eventId },
|
||||
});
|
||||
throw new Error('Failed to link timeline event update submission');
|
||||
}
|
||||
|
||||
return {
|
||||
submitted: true,
|
||||
submissionId: result,
|
||||
submissionId: submissionData.id,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1653,6 +1653,37 @@ async function createPark(supabase: any, data: any): Promise<string> {
|
||||
parkId = data.park_id;
|
||||
delete data.park_id; // Remove ID from update data
|
||||
|
||||
// ✅ FIXED: Handle location updates from temp_location_data
|
||||
if (data.temp_location_data && !data.location_id) {
|
||||
edgeLogger.info('Creating location from temp data for update', {
|
||||
action: 'approval_create_location_update',
|
||||
locationName: data.temp_location_data.name
|
||||
});
|
||||
|
||||
const { data: newLocation, error: locationError } = await supabase
|
||||
.from('locations')
|
||||
.insert({
|
||||
name: data.temp_location_data.name,
|
||||
street_address: data.temp_location_data.street_address || null,
|
||||
city: data.temp_location_data.city,
|
||||
state_province: data.temp_location_data.state_province,
|
||||
country: data.temp_location_data.country,
|
||||
latitude: data.temp_location_data.latitude,
|
||||
longitude: data.temp_location_data.longitude,
|
||||
timezone: data.temp_location_data.timezone,
|
||||
postal_code: data.temp_location_data.postal_code
|
||||
})
|
||||
.select('id')
|
||||
.single();
|
||||
|
||||
if (locationError) {
|
||||
throw new Error(`Failed to create location: ${locationError.message}`);
|
||||
}
|
||||
|
||||
data.location_id = newLocation.id;
|
||||
}
|
||||
delete data.temp_location_data;
|
||||
|
||||
const normalizedData = normalizeParkTypeValue(normalizeStatusValue(data));
|
||||
const sanitizedData = sanitizeDateFields(normalizedData);
|
||||
const filteredData = filterDatabaseFields(sanitizedData, PARK_FIELDS);
|
||||
@@ -1764,6 +1795,89 @@ async function createRide(supabase: any, data: any): Promise<string> {
|
||||
|
||||
if (error) throw new Error(`Failed to update ride: ${error.message}`);
|
||||
|
||||
// ✅ FIXED: Handle nested data updates (technical specs, coaster stats, name history)
|
||||
// For updates, we typically replace all related data rather than merge
|
||||
// Delete existing and insert new
|
||||
if (technicalSpecifications.length > 0) {
|
||||
// Delete existing specs
|
||||
await supabase
|
||||
.from('ride_technical_specifications')
|
||||
.delete()
|
||||
.eq('ride_id', rideId);
|
||||
|
||||
// Insert new specs
|
||||
const techSpecsToInsert = technicalSpecifications.map((spec: any) => ({
|
||||
ride_id: rideId,
|
||||
spec_name: spec.spec_name,
|
||||
spec_value: spec.spec_value,
|
||||
spec_unit: spec.spec_unit || null,
|
||||
category: spec.category || null,
|
||||
display_order: spec.display_order || 0
|
||||
}));
|
||||
|
||||
const { error: techSpecError } = await supabase
|
||||
.from('ride_technical_specifications')
|
||||
.insert(techSpecsToInsert);
|
||||
|
||||
if (techSpecError) {
|
||||
edgeLogger.error('Failed to update technical specifications', { action: 'approval_update_specs', error: techSpecError.message, rideId });
|
||||
}
|
||||
}
|
||||
|
||||
if (coasterStatistics.length > 0) {
|
||||
// Delete existing stats
|
||||
await supabase
|
||||
.from('ride_coaster_stats')
|
||||
.delete()
|
||||
.eq('ride_id', rideId);
|
||||
|
||||
// Insert new stats
|
||||
const statsToInsert = coasterStatistics.map((stat: any) => ({
|
||||
ride_id: rideId,
|
||||
stat_name: stat.stat_name,
|
||||
stat_value: stat.stat_value,
|
||||
unit: stat.unit || null,
|
||||
category: stat.category || null,
|
||||
description: stat.description || null,
|
||||
display_order: stat.display_order || 0
|
||||
}));
|
||||
|
||||
const { error: statsError } = await supabase
|
||||
.from('ride_coaster_stats')
|
||||
.insert(statsToInsert);
|
||||
|
||||
if (statsError) {
|
||||
edgeLogger.error('Failed to update coaster statistics', { action: 'approval_update_stats', error: statsError.message, rideId });
|
||||
}
|
||||
}
|
||||
|
||||
if (nameHistory.length > 0) {
|
||||
// Delete existing name history
|
||||
await supabase
|
||||
.from('ride_name_history')
|
||||
.delete()
|
||||
.eq('ride_id', rideId);
|
||||
|
||||
// Insert new name history
|
||||
const namesToInsert = nameHistory.map((name: any) => ({
|
||||
ride_id: rideId,
|
||||
former_name: name.former_name,
|
||||
date_changed: name.date_changed || null,
|
||||
reason: name.reason || null,
|
||||
from_year: name.from_year || null,
|
||||
to_year: name.to_year || null,
|
||||
order_index: name.order_index || 0
|
||||
}));
|
||||
|
||||
const { error: namesError } = await supabase
|
||||
.from('ride_name_history')
|
||||
.insert(namesToInsert);
|
||||
|
||||
if (namesError) {
|
||||
edgeLogger.error('Failed to update name history', { action: 'approval_update_names', error: namesError.message, rideId });
|
||||
}
|
||||
}
|
||||
|
||||
// Update park ride counts after successful ride update
|
||||
if (parkId) {
|
||||
edgeLogger.info('Updating ride counts for park', { action: 'approval_update_counts', parkId });
|
||||
|
||||
Reference in New Issue
Block a user