mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 06:11:11 -05:00
Fix orphaned submission data
This commit is contained in:
@@ -8,6 +8,13 @@ import type { CompanyDatabaseRecord, TimelineEventDatabaseRecord } from '@/types
|
||||
import { logger } from './logger';
|
||||
import { handleError } from './errorHandler';
|
||||
import type { TimelineEventFormData, EntityType } from '@/types/timeline';
|
||||
import {
|
||||
validateParkCreateFields,
|
||||
validateRideCreateFields,
|
||||
validateCompanyCreateFields,
|
||||
validateRideModelCreateFields,
|
||||
assertValid
|
||||
} from './submissionValidation';
|
||||
|
||||
// ============================================
|
||||
// COMPOSITE SUBMISSION TYPES
|
||||
@@ -382,6 +389,9 @@ export async function submitParkCreation(
|
||||
data: ParkFormData & { _compositeSubmission?: any },
|
||||
userId: string
|
||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||
// Validate required fields client-side
|
||||
assertValid(validateParkCreateFields(data));
|
||||
|
||||
// Check for composite submission with dependencies
|
||||
if (data._compositeSubmission) {
|
||||
const dependencies: CompositeSubmissionDependency[] = [];
|
||||
@@ -640,6 +650,9 @@ export async function submitRideCreation(
|
||||
},
|
||||
userId: string
|
||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||
// Validate required fields client-side
|
||||
assertValid(validateRideCreateFields(data));
|
||||
|
||||
// Check for composite submission with dependencies
|
||||
if (data._tempNewPark || data._tempNewManufacturer || data._tempNewDesigner || data._tempNewRideModel) {
|
||||
const dependencies: CompositeSubmissionDependency[] = [];
|
||||
@@ -959,6 +972,9 @@ export async function submitRideModelCreation(
|
||||
data: RideModelFormData,
|
||||
userId: string
|
||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||
// Validate required fields client-side
|
||||
assertValid(validateRideModelCreateFields(data));
|
||||
|
||||
// Check if user is banned
|
||||
const { data: profile } = await supabase
|
||||
.from('profiles')
|
||||
@@ -1114,6 +1130,9 @@ export async function submitManufacturerCreation(
|
||||
data: CompanyFormData,
|
||||
userId: string
|
||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||
// Validate required fields client-side
|
||||
assertValid(validateCompanyCreateFields({ ...data, company_type: 'manufacturer' }));
|
||||
|
||||
let processedImages = data.images;
|
||||
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
||||
try {
|
||||
@@ -1224,6 +1243,9 @@ export async function submitDesignerCreation(
|
||||
data: CompanyFormData,
|
||||
userId: string
|
||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||
// Validate required fields client-side
|
||||
assertValid(validateCompanyCreateFields({ ...data, company_type: 'designer' }));
|
||||
|
||||
let processedImages = data.images;
|
||||
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
||||
try {
|
||||
@@ -1334,6 +1356,9 @@ export async function submitOperatorCreation(
|
||||
data: CompanyFormData,
|
||||
userId: string
|
||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||
// Validate required fields client-side
|
||||
assertValid(validateCompanyCreateFields({ ...data, company_type: 'operator' }));
|
||||
|
||||
let processedImages = data.images;
|
||||
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
||||
try {
|
||||
@@ -1444,6 +1469,9 @@ export async function submitPropertyOwnerCreation(
|
||||
data: CompanyFormData,
|
||||
userId: string
|
||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||
// Validate required fields client-side
|
||||
assertValid(validateCompanyCreateFields({ ...data, company_type: 'property_owner' }));
|
||||
|
||||
let processedImages = data.images;
|
||||
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
||||
try {
|
||||
|
||||
106
src/lib/submissionValidation.ts
Normal file
106
src/lib/submissionValidation.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Client-side validation for entity submissions
|
||||
* Prevents missing required fields before database calls
|
||||
*/
|
||||
|
||||
export interface ValidationResult {
|
||||
valid: boolean;
|
||||
missingFields: string[];
|
||||
errorMessage?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates required fields for park creation
|
||||
*/
|
||||
export function validateParkCreateFields(data: any): ValidationResult {
|
||||
const missingFields: string[] = [];
|
||||
|
||||
if (!data.name?.trim()) missingFields.push('name');
|
||||
if (!data.slug?.trim()) missingFields.push('slug');
|
||||
if (!data.park_type) missingFields.push('park_type');
|
||||
if (!data.status) missingFields.push('status');
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
return {
|
||||
valid: false,
|
||||
missingFields,
|
||||
errorMessage: `Missing required fields for park creation: ${missingFields.join(', ')}`
|
||||
};
|
||||
}
|
||||
|
||||
return { valid: true, missingFields: [] };
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates required fields for ride creation
|
||||
*/
|
||||
export function validateRideCreateFields(data: any): ValidationResult {
|
||||
const missingFields: string[] = [];
|
||||
|
||||
if (!data.name?.trim()) missingFields.push('name');
|
||||
if (!data.slug?.trim()) missingFields.push('slug');
|
||||
if (!data.category) missingFields.push('category');
|
||||
if (!data.status) missingFields.push('status');
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
return {
|
||||
valid: false,
|
||||
missingFields,
|
||||
errorMessage: `Missing required fields for ride creation: ${missingFields.join(', ')}`
|
||||
};
|
||||
}
|
||||
|
||||
return { valid: true, missingFields: [] };
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates required fields for company creation
|
||||
*/
|
||||
export function validateCompanyCreateFields(data: any): ValidationResult {
|
||||
const missingFields: string[] = [];
|
||||
|
||||
if (!data.name?.trim()) missingFields.push('name');
|
||||
if (!data.slug?.trim()) missingFields.push('slug');
|
||||
if (!data.company_type) missingFields.push('company_type');
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
return {
|
||||
valid: false,
|
||||
missingFields,
|
||||
errorMessage: `Missing required fields for company creation: ${missingFields.join(', ')}`
|
||||
};
|
||||
}
|
||||
|
||||
return { valid: true, missingFields: [] };
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates required fields for ride model creation
|
||||
*/
|
||||
export function validateRideModelCreateFields(data: any): ValidationResult {
|
||||
const missingFields: string[] = [];
|
||||
|
||||
if (!data.name?.trim()) missingFields.push('name');
|
||||
if (!data.slug?.trim()) missingFields.push('slug');
|
||||
if (!data.manufacturer_id) missingFields.push('manufacturer_id');
|
||||
if (!data.category) missingFields.push('category');
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
return {
|
||||
valid: false,
|
||||
missingFields,
|
||||
errorMessage: `Missing required fields for ride model creation: ${missingFields.join(', ')}`
|
||||
};
|
||||
}
|
||||
|
||||
return { valid: true, missingFields: [] };
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to throw validation error if validation fails
|
||||
*/
|
||||
export function assertValid(result: ValidationResult): void {
|
||||
if (!result.valid) {
|
||||
throw new Error(result.errorMessage);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
-- Clean up orphaned data from broken submission
|
||||
DELETE FROM submission_items
|
||||
WHERE submission_id = '4ace4a83-1642-48d0-b8b9-586981284e8c';
|
||||
|
||||
DELETE FROM content_submissions
|
||||
WHERE id = '4ace4a83-1642-48d0-b8b9-586981284e8c';
|
||||
Reference in New Issue
Block a user