mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-28 10:46:59 -05:00
Compare commits
2 Commits
e21e4990ad
...
34fcd841ee
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34fcd841ee | ||
|
|
a51f37bf8a |
@@ -779,8 +779,13 @@ export async function submitRideCreation(
|
|||||||
|
|
||||||
if (submissionError) throw submissionError;
|
if (submissionError) throw submissionError;
|
||||||
|
|
||||||
// Extract images for assignment
|
// ✅ FIXED: Get image URLs/IDs from processed images using assignments
|
||||||
const changedFields = extractChangedFields(data, {});
|
const uploadedImages = processedImages?.uploaded || [];
|
||||||
|
const bannerIndex = processedImages?.banner_assignment;
|
||||||
|
const cardIndex = processedImages?.card_assignment;
|
||||||
|
|
||||||
|
const bannerImage = (bannerIndex !== null && bannerIndex !== undefined) ? uploadedImages[bannerIndex] : null;
|
||||||
|
const cardImage = (cardIndex !== null && cardIndex !== undefined) ? uploadedImages[cardIndex] : null;
|
||||||
|
|
||||||
// Insert into relational ride_submissions table
|
// Insert into relational ride_submissions table
|
||||||
const { data: rideSubmission, error: rideSubmissionError } = await supabase
|
const { data: rideSubmission, error: rideSubmissionError } = await supabase
|
||||||
@@ -812,10 +817,10 @@ export async function submitRideCreation(
|
|||||||
coaster_type: data.coaster_type || null,
|
coaster_type: data.coaster_type || null,
|
||||||
seating_type: data.seating_type || null,
|
seating_type: data.seating_type || null,
|
||||||
intensity_level: data.intensity_level || null,
|
intensity_level: data.intensity_level || null,
|
||||||
banner_image_url: changedFields.banner_image_url as string || null,
|
banner_image_url: bannerImage?.url || data.banner_image_url || null,
|
||||||
banner_image_id: changedFields.banner_image_id as string || null,
|
banner_image_id: bannerImage?.cloudflare_id || data.banner_image_id || null,
|
||||||
card_image_url: changedFields.card_image_url as string || null,
|
card_image_url: cardImage?.url || data.card_image_url || null,
|
||||||
card_image_id: changedFields.card_image_id as string || null,
|
card_image_id: cardImage?.cloudflare_id || data.card_image_id || null,
|
||||||
image_url: null
|
image_url: null
|
||||||
} as any)
|
} as any)
|
||||||
.select('id')
|
.select('id')
|
||||||
@@ -1006,7 +1011,11 @@ export async function submitRideModelCreation(
|
|||||||
item_type: 'ride_model',
|
item_type: 'ride_model',
|
||||||
action_type: 'create',
|
action_type: 'create',
|
||||||
item_data: {
|
item_data: {
|
||||||
...extractChangedFields(data, {}),
|
// ✅ FIXED: Don't use extractChangedFields for CREATE - include ALL data
|
||||||
|
...(() => {
|
||||||
|
const { images, ...dataWithoutImages } = data;
|
||||||
|
return dataWithoutImages;
|
||||||
|
})(),
|
||||||
images: processedImages as unknown as Json
|
images: processedImages as unknown as Json
|
||||||
},
|
},
|
||||||
status: 'pending' as const,
|
status: 'pending' as const,
|
||||||
@@ -1138,7 +1147,11 @@ export async function submitManufacturerCreation(
|
|||||||
item_type: 'manufacturer',
|
item_type: 'manufacturer',
|
||||||
action_type: 'create',
|
action_type: 'create',
|
||||||
item_data: {
|
item_data: {
|
||||||
...extractChangedFields(data, {}),
|
// ✅ FIXED: Don't use extractChangedFields for CREATE - include ALL data
|
||||||
|
...(() => {
|
||||||
|
const { images, ...dataWithoutImages } = data;
|
||||||
|
return dataWithoutImages;
|
||||||
|
})(),
|
||||||
company_type: 'manufacturer',
|
company_type: 'manufacturer',
|
||||||
images: processedImages as unknown as Json
|
images: processedImages as unknown as Json
|
||||||
},
|
},
|
||||||
@@ -1244,7 +1257,11 @@ export async function submitDesignerCreation(
|
|||||||
item_type: 'designer',
|
item_type: 'designer',
|
||||||
action_type: 'create',
|
action_type: 'create',
|
||||||
item_data: {
|
item_data: {
|
||||||
...extractChangedFields(data, {}),
|
// ✅ FIXED: Don't use extractChangedFields for CREATE - include ALL data
|
||||||
|
...(() => {
|
||||||
|
const { images, ...dataWithoutImages } = data;
|
||||||
|
return dataWithoutImages;
|
||||||
|
})(),
|
||||||
company_type: 'designer',
|
company_type: 'designer',
|
||||||
images: processedImages as unknown as Json
|
images: processedImages as unknown as Json
|
||||||
},
|
},
|
||||||
@@ -1350,7 +1367,11 @@ export async function submitOperatorCreation(
|
|||||||
item_type: 'operator',
|
item_type: 'operator',
|
||||||
action_type: 'create',
|
action_type: 'create',
|
||||||
item_data: {
|
item_data: {
|
||||||
...extractChangedFields(data, {}),
|
// ✅ FIXED: Don't use extractChangedFields for CREATE - include ALL data
|
||||||
|
...(() => {
|
||||||
|
const { images, ...dataWithoutImages } = data;
|
||||||
|
return dataWithoutImages;
|
||||||
|
})(),
|
||||||
company_type: 'operator',
|
company_type: 'operator',
|
||||||
images: processedImages as unknown as Json
|
images: processedImages as unknown as Json
|
||||||
},
|
},
|
||||||
@@ -1456,7 +1477,11 @@ export async function submitPropertyOwnerCreation(
|
|||||||
item_type: 'property_owner',
|
item_type: 'property_owner',
|
||||||
action_type: 'create',
|
action_type: 'create',
|
||||||
item_data: {
|
item_data: {
|
||||||
...extractChangedFields(data, {}),
|
// ✅ FIXED: Don't use extractChangedFields for CREATE - include ALL data
|
||||||
|
...(() => {
|
||||||
|
const { images, ...dataWithoutImages } = data;
|
||||||
|
return dataWithoutImages;
|
||||||
|
})(),
|
||||||
company_type: 'property_owner',
|
company_type: 'property_owner',
|
||||||
images: processedImages as unknown as Json
|
images: processedImages as unknown as Json
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,230 @@
|
|||||||
|
-- Add comprehensive validation and error handling to create_submission_with_items
|
||||||
|
-- This prevents silent failures and ensures proper transaction rollback
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION public.create_submission_with_items(
|
||||||
|
p_user_id uuid,
|
||||||
|
p_submission_type text,
|
||||||
|
p_content jsonb, -- Keep for backward compatibility
|
||||||
|
p_items jsonb[]
|
||||||
|
)
|
||||||
|
RETURNS uuid
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
SECURITY DEFINER
|
||||||
|
SET search_path TO 'public'
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
v_submission_id UUID;
|
||||||
|
v_item JSONB;
|
||||||
|
v_item_data JSONB;
|
||||||
|
v_item_type TEXT;
|
||||||
|
v_action_type TEXT;
|
||||||
|
v_park_submission_id UUID;
|
||||||
|
v_company_submission_id UUID;
|
||||||
|
v_ride_submission_id UUID;
|
||||||
|
v_ride_model_submission_id UUID;
|
||||||
|
v_photo_submission_id UUID;
|
||||||
|
BEGIN
|
||||||
|
-- Create main submission
|
||||||
|
INSERT INTO content_submissions (user_id, submission_type, status, approval_mode)
|
||||||
|
VALUES (p_user_id, p_submission_type, 'pending', 'full')
|
||||||
|
RETURNING id INTO v_submission_id;
|
||||||
|
|
||||||
|
-- Validate items array
|
||||||
|
IF array_length(p_items, 1) IS NULL OR array_length(p_items, 1) = 0 THEN
|
||||||
|
RAISE EXCEPTION 'Cannot create submission without items';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Process each item
|
||||||
|
FOREACH v_item IN ARRAY p_items
|
||||||
|
LOOP
|
||||||
|
v_item_type := (v_item->>'item_type')::TEXT;
|
||||||
|
v_action_type := (v_item->>'action_type')::TEXT;
|
||||||
|
v_item_data := v_item->'item_data';
|
||||||
|
|
||||||
|
-- Reset IDs for this iteration
|
||||||
|
v_park_submission_id := (v_item->>'park_submission_id')::UUID;
|
||||||
|
v_company_submission_id := (v_item->>'company_submission_id')::UUID;
|
||||||
|
v_ride_submission_id := (v_item->>'ride_submission_id')::UUID;
|
||||||
|
v_ride_model_submission_id := (v_item->>'ride_model_submission_id')::UUID;
|
||||||
|
v_photo_submission_id := (v_item->>'photo_submission_id')::UUID;
|
||||||
|
|
||||||
|
-- Create specialized submission if item_data exists (for new entities)
|
||||||
|
IF v_item_data IS NOT NULL AND jsonb_typeof(v_item_data) = 'object' THEN
|
||||||
|
|
||||||
|
IF v_item_type = 'park' THEN
|
||||||
|
-- ✅ VALIDATE REQUIRED FIELDS BEFORE INSERT
|
||||||
|
IF v_item_data->>'name' IS NULL THEN
|
||||||
|
RAISE EXCEPTION 'Park submission missing required field: name';
|
||||||
|
END IF;
|
||||||
|
IF v_item_data->>'slug' IS NULL THEN
|
||||||
|
RAISE EXCEPTION 'Park submission missing required field: slug (name="%")', v_item_data->>'name';
|
||||||
|
END IF;
|
||||||
|
IF v_item_data->>'park_type' IS NULL THEN
|
||||||
|
RAISE EXCEPTION 'Park submission missing required field: park_type (name="%")', v_item_data->>'name';
|
||||||
|
END IF;
|
||||||
|
IF v_item_data->>'status' IS NULL THEN
|
||||||
|
RAISE EXCEPTION 'Park submission missing required field: status (name="%")', v_item_data->>'name';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
INSERT INTO park_submissions (
|
||||||
|
submission_id, name, slug, description, park_type, status,
|
||||||
|
opening_date, closing_date, opening_date_precision, closing_date_precision,
|
||||||
|
website_url, phone, email, location_id,
|
||||||
|
operator_id, property_owner_id,
|
||||||
|
banner_image_url, banner_image_id, card_image_url, card_image_id
|
||||||
|
) VALUES (
|
||||||
|
v_submission_id,
|
||||||
|
v_item_data->>'name',
|
||||||
|
v_item_data->>'slug',
|
||||||
|
v_item_data->>'description',
|
||||||
|
v_item_data->>'park_type',
|
||||||
|
v_item_data->>'status',
|
||||||
|
(v_item_data->>'opening_date')::DATE,
|
||||||
|
(v_item_data->>'closing_date')::DATE,
|
||||||
|
v_item_data->>'opening_date_precision',
|
||||||
|
v_item_data->>'closing_date_precision',
|
||||||
|
v_item_data->>'website_url',
|
||||||
|
v_item_data->>'phone',
|
||||||
|
v_item_data->>'email',
|
||||||
|
(v_item_data->>'location_id')::UUID,
|
||||||
|
(v_item_data->>'operator_id')::UUID,
|
||||||
|
(v_item_data->>'property_owner_id')::UUID,
|
||||||
|
v_item_data->>'banner_image_url',
|
||||||
|
v_item_data->>'banner_image_id',
|
||||||
|
v_item_data->>'card_image_url',
|
||||||
|
v_item_data->>'card_image_id'
|
||||||
|
) RETURNING id INTO v_park_submission_id;
|
||||||
|
|
||||||
|
ELSIF v_item_type IN ('operator', 'property_owner', 'manufacturer', 'designer') THEN
|
||||||
|
-- ✅ VALIDATE REQUIRED FIELDS BEFORE INSERT
|
||||||
|
IF v_item_data->>'name' IS NULL THEN
|
||||||
|
RAISE EXCEPTION 'Company submission missing required field: name (type="%")', v_item_type;
|
||||||
|
END IF;
|
||||||
|
IF v_item_data->>'slug' IS NULL THEN
|
||||||
|
RAISE EXCEPTION 'Company submission missing required field: slug (type="%", name="%")', v_item_type, v_item_data->>'name';
|
||||||
|
END IF;
|
||||||
|
IF v_item_data->>'company_type' IS NULL THEN
|
||||||
|
RAISE EXCEPTION 'Company submission missing required field: company_type (name="%")', v_item_data->>'name';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
INSERT INTO company_submissions (
|
||||||
|
submission_id, name, slug, description, company_type, person_type,
|
||||||
|
founded_year, founded_date, founded_date_precision,
|
||||||
|
headquarters_location, website_url,
|
||||||
|
logo_url, banner_image_url, banner_image_id,
|
||||||
|
card_image_url, card_image_id
|
||||||
|
) VALUES (
|
||||||
|
v_submission_id,
|
||||||
|
v_item_data->>'name',
|
||||||
|
v_item_data->>'slug',
|
||||||
|
v_item_data->>'description',
|
||||||
|
v_item_data->>'company_type',
|
||||||
|
v_item_data->>'person_type',
|
||||||
|
(v_item_data->>'founded_year')::INTEGER,
|
||||||
|
(v_item_data->>'founded_date')::DATE,
|
||||||
|
v_item_data->>'founded_date_precision',
|
||||||
|
v_item_data->>'headquarters_location',
|
||||||
|
v_item_data->>'website_url',
|
||||||
|
v_item_data->>'logo_url',
|
||||||
|
v_item_data->>'banner_image_url',
|
||||||
|
v_item_data->>'banner_image_id',
|
||||||
|
v_item_data->>'card_image_url',
|
||||||
|
v_item_data->>'card_image_id'
|
||||||
|
) RETURNING id INTO v_company_submission_id;
|
||||||
|
|
||||||
|
ELSIF v_item_type = 'ride' THEN
|
||||||
|
-- ✅ VALIDATE REQUIRED FIELDS BEFORE INSERT
|
||||||
|
IF v_item_data->>'name' IS NULL THEN
|
||||||
|
RAISE EXCEPTION 'Ride submission missing required field: name';
|
||||||
|
END IF;
|
||||||
|
IF v_item_data->>'slug' IS NULL THEN
|
||||||
|
RAISE EXCEPTION 'Ride submission missing required field: slug (name="%")', v_item_data->>'name';
|
||||||
|
END IF;
|
||||||
|
IF v_item_data->>'category' IS NULL THEN
|
||||||
|
RAISE EXCEPTION 'Ride submission missing required field: category (name="%")', v_item_data->>'name';
|
||||||
|
END IF;
|
||||||
|
IF v_item_data->>'status' IS NULL THEN
|
||||||
|
RAISE EXCEPTION 'Ride submission missing required field: status (name="%")', v_item_data->>'name';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
INSERT INTO ride_submissions (
|
||||||
|
submission_id, name, slug, description, category, status,
|
||||||
|
park_id, manufacturer_id, designer_id, ride_model_id,
|
||||||
|
opening_date, closing_date, opening_date_precision, closing_date_precision,
|
||||||
|
height_requirement_cm, age_requirement,
|
||||||
|
max_speed_kmh, duration_seconds, capacity_per_hour,
|
||||||
|
gforce_max, inversions_count,
|
||||||
|
length_meters, height_meters, drop_meters,
|
||||||
|
banner_image_url, banner_image_id, card_image_url, card_image_id
|
||||||
|
) VALUES (
|
||||||
|
v_submission_id,
|
||||||
|
v_item_data->>'name',
|
||||||
|
v_item_data->>'slug',
|
||||||
|
v_item_data->>'description',
|
||||||
|
v_item_data->>'category',
|
||||||
|
v_item_data->>'status',
|
||||||
|
(v_item_data->>'park_id')::UUID,
|
||||||
|
(v_item_data->>'manufacturer_id')::UUID,
|
||||||
|
(v_item_data->>'designer_id')::UUID,
|
||||||
|
(v_item_data->>'ride_model_id')::UUID,
|
||||||
|
(v_item_data->>'opening_date')::DATE,
|
||||||
|
(v_item_data->>'closing_date')::DATE,
|
||||||
|
v_item_data->>'opening_date_precision',
|
||||||
|
v_item_data->>'closing_date_precision',
|
||||||
|
(v_item_data->>'height_requirement_cm')::INTEGER,
|
||||||
|
(v_item_data->>'age_requirement')::INTEGER,
|
||||||
|
(v_item_data->>'max_speed_kmh')::NUMERIC,
|
||||||
|
(v_item_data->>'duration_seconds')::INTEGER,
|
||||||
|
(v_item_data->>'capacity_per_hour')::INTEGER,
|
||||||
|
(v_item_data->>'gforce_max')::NUMERIC,
|
||||||
|
(v_item_data->>'inversions_count')::INTEGER,
|
||||||
|
(v_item_data->>'length_meters')::NUMERIC,
|
||||||
|
(v_item_data->>'height_meters')::NUMERIC,
|
||||||
|
(v_item_data->>'drop_meters')::NUMERIC,
|
||||||
|
v_item_data->>'banner_image_url',
|
||||||
|
v_item_data->>'banner_image_id',
|
||||||
|
v_item_data->>'card_image_url',
|
||||||
|
v_item_data->>'card_image_id'
|
||||||
|
) RETURNING id INTO v_ride_submission_id;
|
||||||
|
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Insert submission_item with proper foreign key linkage
|
||||||
|
INSERT INTO submission_items (
|
||||||
|
submission_id,
|
||||||
|
item_type,
|
||||||
|
action_type,
|
||||||
|
park_submission_id,
|
||||||
|
company_submission_id,
|
||||||
|
ride_submission_id,
|
||||||
|
ride_model_submission_id,
|
||||||
|
photo_submission_id,
|
||||||
|
status,
|
||||||
|
order_index,
|
||||||
|
depends_on
|
||||||
|
) VALUES (
|
||||||
|
v_submission_id,
|
||||||
|
v_item_type,
|
||||||
|
v_action_type,
|
||||||
|
v_park_submission_id,
|
||||||
|
v_company_submission_id,
|
||||||
|
v_ride_submission_id,
|
||||||
|
v_ride_model_submission_id,
|
||||||
|
v_photo_submission_id,
|
||||||
|
'pending',
|
||||||
|
COALESCE((v_item->>'order_index')::INTEGER, 0),
|
||||||
|
(v_item->>'depends_on')::UUID
|
||||||
|
);
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
RETURN v_submission_id;
|
||||||
|
|
||||||
|
EXCEPTION
|
||||||
|
-- ✅ PROPER ERROR HANDLING: Log and re-raise to ensure full rollback
|
||||||
|
WHEN OTHERS THEN
|
||||||
|
RAISE NOTICE 'Submission creation failed for user % (type=%): %', p_user_id, p_submission_type, SQLERRM;
|
||||||
|
-- Re-raise the exception to rollback the entire transaction
|
||||||
|
RAISE;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
Reference in New Issue
Block a user