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 { logger } from './logger';
|
||||||
import { handleError } from './errorHandler';
|
import { handleError } from './errorHandler';
|
||||||
import type { TimelineEventFormData, EntityType } from '@/types/timeline';
|
import type { TimelineEventFormData, EntityType } from '@/types/timeline';
|
||||||
|
import {
|
||||||
|
validateParkCreateFields,
|
||||||
|
validateRideCreateFields,
|
||||||
|
validateCompanyCreateFields,
|
||||||
|
validateRideModelCreateFields,
|
||||||
|
assertValid
|
||||||
|
} from './submissionValidation';
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// COMPOSITE SUBMISSION TYPES
|
// COMPOSITE SUBMISSION TYPES
|
||||||
@@ -382,6 +389,9 @@ export async function submitParkCreation(
|
|||||||
data: ParkFormData & { _compositeSubmission?: any },
|
data: ParkFormData & { _compositeSubmission?: any },
|
||||||
userId: string
|
userId: string
|
||||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||||
|
// Validate required fields client-side
|
||||||
|
assertValid(validateParkCreateFields(data));
|
||||||
|
|
||||||
// Check for composite submission with dependencies
|
// Check for composite submission with dependencies
|
||||||
if (data._compositeSubmission) {
|
if (data._compositeSubmission) {
|
||||||
const dependencies: CompositeSubmissionDependency[] = [];
|
const dependencies: CompositeSubmissionDependency[] = [];
|
||||||
@@ -640,6 +650,9 @@ export async function submitRideCreation(
|
|||||||
},
|
},
|
||||||
userId: string
|
userId: string
|
||||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||||
|
// Validate required fields client-side
|
||||||
|
assertValid(validateRideCreateFields(data));
|
||||||
|
|
||||||
// Check for composite submission with dependencies
|
// Check for composite submission with dependencies
|
||||||
if (data._tempNewPark || data._tempNewManufacturer || data._tempNewDesigner || data._tempNewRideModel) {
|
if (data._tempNewPark || data._tempNewManufacturer || data._tempNewDesigner || data._tempNewRideModel) {
|
||||||
const dependencies: CompositeSubmissionDependency[] = [];
|
const dependencies: CompositeSubmissionDependency[] = [];
|
||||||
@@ -959,6 +972,9 @@ export async function submitRideModelCreation(
|
|||||||
data: RideModelFormData,
|
data: RideModelFormData,
|
||||||
userId: string
|
userId: string
|
||||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||||
|
// Validate required fields client-side
|
||||||
|
assertValid(validateRideModelCreateFields(data));
|
||||||
|
|
||||||
// Check if user is banned
|
// Check if user is banned
|
||||||
const { data: profile } = await supabase
|
const { data: profile } = await supabase
|
||||||
.from('profiles')
|
.from('profiles')
|
||||||
@@ -1114,6 +1130,9 @@ export async function submitManufacturerCreation(
|
|||||||
data: CompanyFormData,
|
data: CompanyFormData,
|
||||||
userId: string
|
userId: string
|
||||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||||
|
// Validate required fields client-side
|
||||||
|
assertValid(validateCompanyCreateFields({ ...data, company_type: 'manufacturer' }));
|
||||||
|
|
||||||
let processedImages = data.images;
|
let processedImages = data.images;
|
||||||
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
||||||
try {
|
try {
|
||||||
@@ -1224,6 +1243,9 @@ export async function submitDesignerCreation(
|
|||||||
data: CompanyFormData,
|
data: CompanyFormData,
|
||||||
userId: string
|
userId: string
|
||||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||||
|
// Validate required fields client-side
|
||||||
|
assertValid(validateCompanyCreateFields({ ...data, company_type: 'designer' }));
|
||||||
|
|
||||||
let processedImages = data.images;
|
let processedImages = data.images;
|
||||||
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
||||||
try {
|
try {
|
||||||
@@ -1334,6 +1356,9 @@ export async function submitOperatorCreation(
|
|||||||
data: CompanyFormData,
|
data: CompanyFormData,
|
||||||
userId: string
|
userId: string
|
||||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||||
|
// Validate required fields client-side
|
||||||
|
assertValid(validateCompanyCreateFields({ ...data, company_type: 'operator' }));
|
||||||
|
|
||||||
let processedImages = data.images;
|
let processedImages = data.images;
|
||||||
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
||||||
try {
|
try {
|
||||||
@@ -1444,6 +1469,9 @@ export async function submitPropertyOwnerCreation(
|
|||||||
data: CompanyFormData,
|
data: CompanyFormData,
|
||||||
userId: string
|
userId: string
|
||||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||||
|
// Validate required fields client-side
|
||||||
|
assertValid(validateCompanyCreateFields({ ...data, company_type: 'property_owner' }));
|
||||||
|
|
||||||
let processedImages = data.images;
|
let processedImages = data.images;
|
||||||
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
if (data.images?.uploaded && data.images.uploaded.length > 0) {
|
||||||
try {
|
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