mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 11:51:14 -05:00
Fix: Approve database migration
This commit is contained in:
@@ -15,6 +15,7 @@ import { DatePicker } from '@/components/ui/date-picker';
|
|||||||
import { FlexibleDateInput, type DatePrecision } from '@/components/ui/flexible-date-input';
|
import { FlexibleDateInput, type DatePrecision } from '@/components/ui/flexible-date-input';
|
||||||
import { SlugField } from '@/components/ui/slug-field';
|
import { SlugField } from '@/components/ui/slug-field';
|
||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { MapPin, Save, X, Plus } from 'lucide-react';
|
import { MapPin, Save, X, Plus } from 'lucide-react';
|
||||||
import { toDateOnly } from '@/lib/dateUtils';
|
import { toDateOnly } from '@/lib/dateUtils';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
@@ -192,10 +193,11 @@ export function ParkForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
|||||||
? "The park information has been updated successfully."
|
? "The park information has been updated successfully."
|
||||||
: "The new park has been created successfully."
|
: "The new park has been created successfully."
|
||||||
});
|
});
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
toast({
|
toast({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
description: error.message || "Failed to save park information.",
|
description: errorMsg,
|
||||||
variant: "destructive"
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } f
|
|||||||
import { Combobox } from '@/components/ui/combobox';
|
import { Combobox } from '@/components/ui/combobox';
|
||||||
import { SlugField } from '@/components/ui/slug-field';
|
import { SlugField } from '@/components/ui/slug-field';
|
||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { Plus, Zap, Save, X } from 'lucide-react';
|
import { Plus, Zap, Save, X } from 'lucide-react';
|
||||||
import { toDateOnly } from '@/lib/dateUtils';
|
import { toDateOnly } from '@/lib/dateUtils';
|
||||||
import { useUnitPreferences } from '@/hooks/useUnitPreferences';
|
import { useUnitPreferences } from '@/hooks/useUnitPreferences';
|
||||||
@@ -263,10 +264,11 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
|||||||
? "Ride, manufacturer, and model submitted for review"
|
? "Ride, manufacturer, and model submitted for review"
|
||||||
: "Ride submitted for review"
|
: "Ride submitted for review"
|
||||||
});
|
});
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
toast({
|
toast({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
description: error.message || "Failed to save ride information.",
|
description: errorMsg,
|
||||||
variant: "destructive"
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { useAuth } from '@/hooks/useAuth';
|
|||||||
import { useProfile } from '@/hooks/useProfile';
|
import { useProfile } from '@/hooks/useProfile';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
import { useAuthModal } from '@/hooks/useAuthModal';
|
import { useAuthModal } from '@/hooks/useAuthModal';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
|
|
||||||
export function AuthButtons() {
|
export function AuthButtons() {
|
||||||
const { user, loading: authLoading, signOut } = useAuth();
|
const { user, loading: authLoading, signOut } = useAuth();
|
||||||
@@ -25,11 +26,12 @@ export function AuthButtons() {
|
|||||||
description: "You've been signed out successfully."
|
description: "You've been signed out successfully."
|
||||||
});
|
});
|
||||||
navigate('/');
|
navigate('/');
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
toast({
|
toast({
|
||||||
variant: "destructive",
|
variant: "destructive",
|
||||||
title: "Error signing out",
|
title: "Error signing out",
|
||||||
description: error.message
|
description: errorMsg
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setLoggingOut(false);
|
setLoggingOut(false);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { AlertCircle } from 'lucide-react';
|
|||||||
import { type DependencyConflict, type SubmissionItemWithDeps } from '@/lib/submissionItemsService';
|
import { type DependencyConflict, type SubmissionItemWithDeps } from '@/lib/submissionItemsService';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
import { useAuth } from '@/hooks/useAuth';
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
|
|
||||||
interface ConflictResolutionDialogProps {
|
interface ConflictResolutionDialogProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@@ -67,10 +68,11 @@ export function ConflictResolutionDialog({
|
|||||||
|
|
||||||
onResolve();
|
onResolve();
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
toast({
|
toast({
|
||||||
title: 'Error',
|
title: 'Error',
|
||||||
description: error.message || 'Failed to resolve conflicts',
|
description: errorMsg,
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { Textarea } from '@/components/ui/textarea';
|
|||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
import { useIsMobile } from '@/hooks/use-mobile';
|
import { useIsMobile } from '@/hooks/use-mobile';
|
||||||
import { useUserRole } from '@/hooks/useUserRole';
|
import { useUserRole } from '@/hooks/useUserRole';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { useAuth } from '@/hooks/useAuth';
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
import { editSubmissionItem, type SubmissionItemWithDeps } from '@/lib/submissionItemsService';
|
import { editSubmissionItem, type SubmissionItemWithDeps } from '@/lib/submissionItemsService';
|
||||||
import { ParkForm } from '@/components/admin/ParkForm';
|
import { ParkForm } from '@/components/admin/ParkForm';
|
||||||
@@ -58,10 +59,11 @@ export function ItemEditDialog({ item, open, onOpenChange, onComplete }: ItemEdi
|
|||||||
|
|
||||||
onComplete();
|
onComplete();
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
toast({
|
toast({
|
||||||
title: 'Error',
|
title: 'Error',
|
||||||
description: error.message || 'Failed to save changes',
|
description: errorMsg,
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { supabase } from '@/integrations/supabase/client';
|
|||||||
import { PhotoGrid } from '@/components/common/PhotoGrid';
|
import { PhotoGrid } from '@/components/common/PhotoGrid';
|
||||||
import type { PhotoSubmissionItem } from '@/types/photo-submissions';
|
import type { PhotoSubmissionItem } from '@/types/photo-submissions';
|
||||||
import type { PhotoItem } from '@/types/photos';
|
import type { PhotoItem } from '@/types/photos';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
|
|
||||||
interface PhotoSubmissionDisplayProps {
|
interface PhotoSubmissionDisplayProps {
|
||||||
submissionId: string;
|
submissionId: string;
|
||||||
@@ -81,10 +82,11 @@ export function PhotoSubmissionDisplay({ submissionId }: PhotoSubmissionDisplayP
|
|||||||
|
|
||||||
setPhotos(data || []);
|
setPhotos(data || []);
|
||||||
console.log(`✅ Successfully loaded ${data?.length || 0} photos`);
|
console.log(`✅ Successfully loaded ${data?.length || 0} photos`);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
console.error('❌ PhotoSubmissionDisplay error:', error);
|
const errorMsg = getErrorMessage(error);
|
||||||
|
console.error('❌ PhotoSubmissionDisplay error:', errorMsg);
|
||||||
setPhotos([]);
|
setPhotos([]);
|
||||||
setError(error.message || 'Failed to load photos');
|
setError(errorMsg);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
} from '@/components/ui/select';
|
} from '@/components/ui/select';
|
||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
|
|
||||||
interface Moderator {
|
interface Moderator {
|
||||||
user_id: string;
|
user_id: string;
|
||||||
@@ -87,8 +88,9 @@ export function ReassignDialog({
|
|||||||
});
|
});
|
||||||
|
|
||||||
setModerators(moderatorsList);
|
setModerators(moderatorsList);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
console.error('Error fetching moderators:', error);
|
const errorMsg = getErrorMessage(error);
|
||||||
|
console.error('Error fetching moderators:', errorMsg);
|
||||||
toast({
|
toast({
|
||||||
title: 'Error',
|
title: 'Error',
|
||||||
description: 'Failed to load moderators list',
|
description: 'Failed to load moderators list',
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
|
|||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
import { useAuth } from '@/hooks/useAuth';
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { ActivityCard } from './ActivityCard';
|
import { ActivityCard } from './ActivityCard';
|
||||||
import { Skeleton } from '@/components/ui/skeleton';
|
import { Skeleton } from '@/components/ui/skeleton';
|
||||||
import { Activity as ActivityIcon } from 'lucide-react';
|
import { Activity as ActivityIcon } from 'lucide-react';
|
||||||
@@ -150,8 +151,9 @@ export const RecentActivity = forwardRef<RecentActivityRef>((props, ref) => {
|
|||||||
// Full replacement for non-silent refreshes or 'replace' strategy
|
// Full replacement for non-silent refreshes or 'replace' strategy
|
||||||
setActivities(recentActivities);
|
setActivities(recentActivities);
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
console.error('Error fetching recent activity:', error);
|
const errorMsg = getErrorMessage(error);
|
||||||
|
console.error('Error fetching recent activity:', errorMsg);
|
||||||
toast({
|
toast({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
description: "Failed to load recent activity",
|
description: "Failed to load recent activity",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { UserX } from 'lucide-react';
|
|||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
import { useAuth } from '@/hooks/useAuth';
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
|
|
||||||
interface UserBlockButtonProps {
|
interface UserBlockButtonProps {
|
||||||
targetUserId: string;
|
targetUserId: string;
|
||||||
@@ -42,8 +43,9 @@ export function UserBlockButton({ targetUserId, targetUsername, variant = 'outli
|
|||||||
});
|
});
|
||||||
|
|
||||||
setReason('');
|
setReason('');
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
console.error('Error blocking user:', error);
|
const errorMsg = getErrorMessage(error);
|
||||||
|
console.error('Error blocking user:', errorMsg);
|
||||||
toast({
|
toast({
|
||||||
title: 'Error',
|
title: 'Error',
|
||||||
description: 'Failed to block user',
|
description: 'Failed to block user',
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { supabase } from '@/integrations/supabase/client';
|
|||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
import { AlertTriangle, Loader2 } from 'lucide-react';
|
import { AlertTriangle, Loader2 } from 'lucide-react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
|
|
||||||
interface DeletionStatusBannerProps {
|
interface DeletionStatusBannerProps {
|
||||||
scheduledDate: string;
|
scheduledDate: string;
|
||||||
@@ -37,11 +38,12 @@ export function DeletionStatusBanner({ scheduledDate, onCancelled }: DeletionSta
|
|||||||
});
|
});
|
||||||
|
|
||||||
onCancelled();
|
onCancelled();
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
toast({
|
toast({
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
title: 'Error',
|
title: 'Error',
|
||||||
description: error.message || 'Failed to cancel deletion',
|
description: errorMsg,
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
} from '@/components/ui/form';
|
} from '@/components/ui/form';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { handleError, handleSuccess, AppError } from '@/lib/errorHandler';
|
import { handleError, handleSuccess, AppError, getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { logger } from '@/lib/logger';
|
import { logger } from '@/lib/logger';
|
||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
import { Loader2, Mail, CheckCircle2, AlertCircle } from 'lucide-react';
|
import { Loader2, Mail, CheckCircle2, AlertCircle } from 'lucide-react';
|
||||||
@@ -185,13 +185,12 @@ export function EmailChangeDialog({ open, onOpenChange, currentEmail, userId }:
|
|||||||
);
|
);
|
||||||
|
|
||||||
setStep('success');
|
setStep('success');
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
logger.error('Email change failed', {
|
logger.error('Email change failed', {
|
||||||
userId,
|
userId,
|
||||||
action: 'email_change',
|
action: 'email_change',
|
||||||
error: error instanceof Error ? error.message : String(error),
|
error: errorMsg,
|
||||||
errorCode: error.code,
|
|
||||||
errorStatus: error.status
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (error.message?.includes('rate limit') || error.status === 429) {
|
if (error.message?.includes('rate limit') || error.status === 429) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { useQuery } from '@tanstack/react-query';
|
|||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
import { useAuth } from '@/hooks/useAuth';
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { deleteTimelineEvent } from '@/lib/entitySubmissionHelpers';
|
import { deleteTimelineEvent } from '@/lib/entitySubmissionHelpers';
|
||||||
import type { EntityType, TimelineEvent } from '@/types/timeline';
|
import type { EntityType, TimelineEvent } from '@/types/timeline';
|
||||||
|
|
||||||
@@ -113,10 +114,11 @@ export function EntityTimelineManager({
|
|||||||
toast.success('Event deleted', {
|
toast.success('Event deleted', {
|
||||||
description: 'Your timeline event has been deleted successfully.'
|
description: 'Your timeline event has been deleted successfully.'
|
||||||
});
|
});
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
console.error('Delete error:', error);
|
const errorMsg = getErrorMessage(error);
|
||||||
|
console.error('Delete error:', errorMsg);
|
||||||
toast.error('Failed to delete event', {
|
toast.error('Failed to delete event', {
|
||||||
description: error.message || 'Please try again.'
|
description: errorMsg
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import { Loader2, Trash } from 'lucide-react';
|
|||||||
import { useAuth } from '@/hooks/useAuth';
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
import { submitTimelineEvent, submitTimelineEventUpdate, deleteTimelineEvent } from '@/lib/entitySubmissionHelpers';
|
import { submitTimelineEvent, submitTimelineEventUpdate, deleteTimelineEvent } from '@/lib/entitySubmissionHelpers';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import type {
|
import type {
|
||||||
EntityType,
|
EntityType,
|
||||||
TimelineEventFormData,
|
TimelineEventFormData,
|
||||||
@@ -195,11 +196,12 @@ export function TimelineEventEditorDialog({
|
|||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
setShowDeleteConfirm(false);
|
setShowDeleteConfirm(false);
|
||||||
form.reset();
|
form.reset();
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
console.error('Delete error:', error);
|
const errorMsg = getErrorMessage(error);
|
||||||
|
console.error('Delete error:', errorMsg);
|
||||||
toast({
|
toast({
|
||||||
title: 'Failed to delete event',
|
title: 'Failed to delete event',
|
||||||
description: error.message || 'Please try again.',
|
description: errorMsg,
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
FileImage
|
FileImage
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
|
|
||||||
interface PhotoUploadProps {
|
interface PhotoUploadProps {
|
||||||
@@ -266,11 +267,11 @@ export function PhotoUpload({
|
|||||||
}
|
}
|
||||||
|
|
||||||
setUploadProgress(100);
|
setUploadProgress(100);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
previewUrls.forEach(url => revokeObjectUrl(url));
|
previewUrls.forEach(url => revokeObjectUrl(url));
|
||||||
const errorMessage = error.message || 'Upload failed';
|
const errorMsg = getErrorMessage(error);
|
||||||
setError(errorMessage);
|
setError(errorMsg);
|
||||||
onError?.(errorMessage);
|
onError?.(errorMsg);
|
||||||
} finally {
|
} finally {
|
||||||
setUploading(false);
|
setUploading(false);
|
||||||
setUploadProgress(0);
|
setUploadProgress(0);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { supabase } from '@/integrations/supabase/client';
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { updateSubmissionItem, type SubmissionItemWithDeps, type DependencyConflict } from './submissionItemsService';
|
import { updateSubmissionItem, type SubmissionItemWithDeps, type DependencyConflict } from './submissionItemsService';
|
||||||
|
|
||||||
export interface ResolutionResult {
|
export interface ResolutionResult {
|
||||||
@@ -83,11 +83,12 @@ export async function resolveConflicts(
|
|||||||
success: true,
|
success: true,
|
||||||
updatedSelections,
|
updatedSelections,
|
||||||
};
|
};
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
console.error('Conflict resolution error:', error);
|
const errorMsg = getErrorMessage(error);
|
||||||
|
console.error('Conflict resolution error:', errorMsg);
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: error.message || 'Failed to resolve conflicts',
|
error: errorMsg,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -346,40 +346,29 @@ async function checkSlugUniqueness(
|
|||||||
try {
|
try {
|
||||||
console.log(`Checking slug uniqueness for "${slug}" in ${tableName}, excludeId: ${excludeId}`);
|
console.log(`Checking slug uniqueness for "${slug}" in ${tableName}, excludeId: ${excludeId}`);
|
||||||
|
|
||||||
// Type-safe queries for each table
|
// Query with explicit table name - use simple approach to avoid type instantiation issues
|
||||||
type ValidTableName = 'parks' | 'rides' | 'companies' | 'ride_models' | 'photos';
|
let result;
|
||||||
|
|
||||||
// Validate table name
|
switch (tableName) {
|
||||||
const validTables: ValidTableName[] = ['parks', 'rides', 'companies', 'ride_models', 'photos'];
|
case 'parks':
|
||||||
if (!validTables.includes(tableName as ValidTableName)) {
|
result = await supabase.from('parks').select('id').eq('slug', slug).limit(1);
|
||||||
console.error(`Invalid table name: ${tableName}`);
|
break;
|
||||||
return true; // Assume unique on invalid table
|
case 'rides':
|
||||||
}
|
result = await supabase.from('rides').select('id').eq('slug', slug).limit(1);
|
||||||
|
break;
|
||||||
// Query with explicit table name
|
case 'companies':
|
||||||
let data, error;
|
result = await supabase.from('companies').select('id').eq('slug', slug).limit(1);
|
||||||
if (tableName === 'parks') {
|
break;
|
||||||
const result = await supabase.from('parks').select('id').eq('slug', slug).limit(1);
|
case 'ride_models':
|
||||||
data = result.data;
|
result = await supabase.from('ride_models').select('id').eq('slug', slug).limit(1);
|
||||||
error = result.error;
|
break;
|
||||||
} else if (tableName === 'rides') {
|
default:
|
||||||
const result = await supabase.from('rides').select('id').eq('slug', slug).limit(1);
|
console.error(`Invalid table name: ${tableName}`);
|
||||||
data = result.data;
|
return true; // Assume unique on invalid table
|
||||||
error = result.error;
|
|
||||||
} else if (tableName === 'companies') {
|
|
||||||
const result = await supabase.from('companies').select('id').eq('slug', slug).limit(1);
|
|
||||||
data = result.data;
|
|
||||||
error = result.error;
|
|
||||||
} else if (tableName === 'ride_models') {
|
|
||||||
const result = await supabase.from('ride_models').select('id').eq('slug', slug).limit(1);
|
|
||||||
data = result.data;
|
|
||||||
error = result.error;
|
|
||||||
} else {
|
|
||||||
const result = await supabase.from('photos').select('id').eq('slug', slug).limit(1);
|
|
||||||
data = result.data;
|
|
||||||
error = result.error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { data, error } = result;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error(`Slug uniqueness check failed for ${entityType}:`, error);
|
console.error(`Slug uniqueness check failed for ${entityType}:`, error);
|
||||||
return true; // Assume unique on error to avoid blocking
|
return true; // Assume unique on error to avoid blocking
|
||||||
|
|||||||
@@ -23,10 +23,11 @@ export async function getUserIdentities(): Promise<UserIdentity[]> {
|
|||||||
if (error) throw error;
|
if (error) throw error;
|
||||||
|
|
||||||
return (data?.identities || []) as UserIdentity[];
|
return (data?.identities || []) as UserIdentity[];
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
logger.error('Failed to get user identities', {
|
logger.error('Failed to get user identities', {
|
||||||
action: 'get_identities',
|
action: 'get_identities',
|
||||||
error: error.message
|
error: errorMsg
|
||||||
});
|
});
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -127,15 +128,16 @@ export async function disconnectIdentity(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
logger.error('Failed to disconnect identity', {
|
logger.error('Failed to disconnect identity', {
|
||||||
action: 'identity_disconnect',
|
action: 'identity_disconnect',
|
||||||
provider,
|
provider,
|
||||||
error: error.message
|
error: errorMsg
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: error.message || 'Failed to disconnect identity'
|
error: errorMsg
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,15 +161,16 @@ export async function connectIdentity(
|
|||||||
if (error) throw error;
|
if (error) throw error;
|
||||||
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
logger.error('Failed to connect identity', {
|
logger.error('Failed to connect identity', {
|
||||||
action: 'identity_connect',
|
action: 'identity_connect',
|
||||||
provider,
|
provider,
|
||||||
error: error.message
|
error: errorMsg
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: error.message || `Failed to connect ${provider} account`
|
error: errorMsg
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,14 +232,15 @@ export async function addPasswordToAccount(): Promise<IdentityOperationResult> {
|
|||||||
needsEmailConfirmation: true,
|
needsEmailConfirmation: true,
|
||||||
email: userEmail
|
email: userEmail
|
||||||
};
|
};
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
logger.error('Failed to initiate password setup', {
|
logger.error('Failed to initiate password setup', {
|
||||||
action: 'password_setup',
|
action: 'password_setup',
|
||||||
error: error.message
|
error: errorMsg
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: error.message || 'Failed to send password reset email'
|
error: errorMsg
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -224,16 +224,17 @@ export async function approveSubmissionItems(
|
|||||||
// Add to dependency map for child items
|
// Add to dependency map for child items
|
||||||
dependencyMap.set(item.id, entityId);
|
dependencyMap.set(item.id, entityId);
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
console.error(`Error approving ${item.item_type} item ${item.id}:`, error);
|
const errorMsg = getErrorMessage(error);
|
||||||
|
console.error(`Error approving ${item.item_type} item ${item.id}:`, errorMsg);
|
||||||
|
|
||||||
// Update item with error status
|
// Update item with error status
|
||||||
await updateSubmissionItem(item.id, {
|
await updateSubmissionItem(item.id, {
|
||||||
status: 'rejected',
|
status: 'rejected',
|
||||||
rejection_reason: `Failed to create entity: ${error.message}`,
|
rejection_reason: `Failed to create entity: ${errorMsg}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
throw new Error(`Failed to approve ${item.item_type}: ${error.message}`);
|
throw new Error(`Failed to approve ${item.item_type}: ${errorMsg}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@/com
|
|||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
|
|
||||||
export default function AuthCallback() {
|
export default function AuthCallback() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -124,14 +125,15 @@ export default function AuthCallback() {
|
|||||||
navigate('/');
|
navigate('/');
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
console.error('[AuthCallback] Error:', error);
|
const errorMsg = getErrorMessage(error);
|
||||||
|
console.error('[AuthCallback] Error:', errorMsg);
|
||||||
setStatus('error');
|
setStatus('error');
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
title: 'Sign in error',
|
title: 'Sign in error',
|
||||||
description: error.message || 'An error occurred during sign in. Please try again.',
|
description: errorMsg,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Redirect to auth page after error
|
// Redirect to auth page after error
|
||||||
@@ -183,12 +185,13 @@ export default function AuthCallback() {
|
|||||||
navigate('/auth');
|
navigate('/auth');
|
||||||
}, 1500);
|
}, 1500);
|
||||||
|
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
console.error('[AuthCallback] Password reset error:', error);
|
const errorMsg = getErrorMessage(error);
|
||||||
|
console.error('[AuthCallback] Password reset error:', errorMsg);
|
||||||
toast({
|
toast({
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
title: 'Failed to set password',
|
title: 'Failed to set password',
|
||||||
description: error.message || 'Please try again.',
|
description: errorMsg,
|
||||||
});
|
});
|
||||||
setSettingPassword(false);
|
setSettingPassword(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { DesignerPhotoGallery } from '@/components/companies/DesignerPhotoGaller
|
|||||||
import { useAuth } from '@/hooks/useAuth';
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
import { useUserRole } from '@/hooks/useUserRole';
|
import { useUserRole } from '@/hooks/useUserRole';
|
||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { submitCompanyUpdate } from '@/lib/companyHelpers';
|
import { submitCompanyUpdate } from '@/lib/companyHelpers';
|
||||||
import { VersionIndicator } from '@/components/versioning/VersionIndicator';
|
import { VersionIndicator } from '@/components/versioning/VersionIndicator';
|
||||||
import { EntityHistoryTabs } from '@/components/history/EntityHistoryTabs';
|
import { EntityHistoryTabs } from '@/components/history/EntityHistoryTabs';
|
||||||
@@ -109,10 +110,11 @@ export default function DesignerDetail() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
setIsEditModalOpen(false);
|
setIsEditModalOpen(false);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
toast({
|
toast({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
description: error.message || "Failed to submit edit.",
|
description: errorMsg,
|
||||||
variant: "destructive"
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { useUserRole } from '@/hooks/useUserRole';
|
|||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
import { submitCompanyCreation } from '@/lib/companyHelpers';
|
import { submitCompanyCreation } from '@/lib/companyHelpers';
|
||||||
import { useAuthModal } from '@/hooks/useAuthModal';
|
import { useAuthModal } from '@/hooks/useAuthModal';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
|
|
||||||
export default function Designers() {
|
export default function Designers() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -36,8 +37,9 @@ export default function Designers() {
|
|||||||
description: "Your submission has been sent for review."
|
description: "Your submission has been sent for review."
|
||||||
});
|
});
|
||||||
setIsCreateModalOpen(false);
|
setIsCreateModalOpen(false);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
toast({ title: "Error", description: error.message || "Failed to submit designer.", variant: "destructive" });
|
const errorMsg = getErrorMessage(error);
|
||||||
|
toast({ title: "Error", description: errorMsg, variant: "destructive" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { ManufacturerPhotoGallery } from '@/components/companies/ManufacturerPho
|
|||||||
import { useAuth } from '@/hooks/useAuth';
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
import { useUserRole } from '@/hooks/useUserRole';
|
import { useUserRole } from '@/hooks/useUserRole';
|
||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { submitCompanyUpdate } from '@/lib/companyHelpers';
|
import { submitCompanyUpdate } from '@/lib/companyHelpers';
|
||||||
import { VersionIndicator } from '@/components/versioning/VersionIndicator';
|
import { VersionIndicator } from '@/components/versioning/VersionIndicator';
|
||||||
import { EntityHistoryTabs } from '@/components/history/EntityHistoryTabs';
|
import { EntityHistoryTabs } from '@/components/history/EntityHistoryTabs';
|
||||||
@@ -119,10 +120,11 @@ export default function ManufacturerDetail() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
setIsEditModalOpen(false);
|
setIsEditModalOpen(false);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
toast({
|
toast({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
description: error.message || "Failed to submit edit.",
|
description: errorMsg,
|
||||||
variant: "destructive"
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { useUserRole } from '@/hooks/useUserRole';
|
|||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
import { submitCompanyCreation } from '@/lib/companyHelpers';
|
import { submitCompanyCreation } from '@/lib/companyHelpers';
|
||||||
import { useAuthModal } from '@/hooks/useAuthModal';
|
import { useAuthModal } from '@/hooks/useAuthModal';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
|
|
||||||
export default function Manufacturers() {
|
export default function Manufacturers() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -80,10 +81,11 @@ export default function Manufacturers() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
setIsCreateModalOpen(false);
|
setIsCreateModalOpen(false);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
toast({
|
toast({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
description: error.message || "Failed to submit manufacturer.",
|
description: errorMsg,
|
||||||
variant: "destructive"
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { ParkCard } from '@/components/parks/ParkCard';
|
|||||||
import { useAuth } from '@/hooks/useAuth';
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
import { useUserRole } from '@/hooks/useUserRole';
|
import { useUserRole } from '@/hooks/useUserRole';
|
||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { submitCompanyUpdate } from '@/lib/companyHelpers';
|
import { submitCompanyUpdate } from '@/lib/companyHelpers';
|
||||||
import { VersionIndicator } from '@/components/versioning/VersionIndicator';
|
import { VersionIndicator } from '@/components/versioning/VersionIndicator';
|
||||||
import { EntityHistoryTabs } from '@/components/history/EntityHistoryTabs';
|
import { EntityHistoryTabs } from '@/components/history/EntityHistoryTabs';
|
||||||
@@ -154,10 +155,11 @@ export default function OperatorDetail() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
setIsEditModalOpen(false);
|
setIsEditModalOpen(false);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
toast({
|
toast({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
description: error.message || "Failed to submit edit.",
|
description: errorMsg,
|
||||||
variant: "destructive"
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { useUserRole } from '@/hooks/useUserRole';
|
|||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
import { submitCompanyCreation } from '@/lib/companyHelpers';
|
import { submitCompanyCreation } from '@/lib/companyHelpers';
|
||||||
import { useAuthModal } from '@/hooks/useAuthModal';
|
import { useAuthModal } from '@/hooks/useAuthModal';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
|
|
||||||
const Operators = () => {
|
const Operators = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -73,10 +74,11 @@ const Operators = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
setIsCreateModalOpen(false);
|
setIsCreateModalOpen(false);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
toast({
|
toast({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
description: error.message || "Failed to submit operator.",
|
description: errorMsg,
|
||||||
variant: "destructive"
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } f
|
|||||||
import { RideForm } from '@/components/admin/RideForm';
|
import { RideForm } from '@/components/admin/RideForm';
|
||||||
import { ParkForm } from '@/components/admin/ParkForm';
|
import { ParkForm } from '@/components/admin/ParkForm';
|
||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { useUserRole } from '@/hooks/useUserRole';
|
import { useUserRole } from '@/hooks/useUserRole';
|
||||||
import { Edit } from 'lucide-react';
|
import { Edit } from 'lucide-react';
|
||||||
import { VersionIndicator } from '@/components/versioning/VersionIndicator';
|
import { VersionIndicator } from '@/components/versioning/VersionIndicator';
|
||||||
@@ -149,10 +150,11 @@ export default function ParkDetail() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
setIsAddRideModalOpen(false);
|
setIsAddRideModalOpen(false);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
toast({
|
toast({
|
||||||
title: "Submission Failed",
|
title: "Submission Failed",
|
||||||
description: error.message || "Failed to submit ride for review.",
|
description: errorMsg,
|
||||||
variant: "destructive"
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -175,10 +177,11 @@ export default function ParkDetail() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
setIsEditParkModalOpen(false);
|
setIsEditParkModalOpen(false);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
toast({
|
toast({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
description: error.message || "Failed to submit park edit.",
|
description: errorMsg,
|
||||||
variant: "destructive"
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { useUserRole } from '@/hooks/useUserRole';
|
|||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
import { submitCompanyCreation } from '@/lib/companyHelpers';
|
import { submitCompanyCreation } from '@/lib/companyHelpers';
|
||||||
import { useAuthModal } from '@/hooks/useAuthModal';
|
import { useAuthModal } from '@/hooks/useAuthModal';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
|
|
||||||
const ParkOwners = () => {
|
const ParkOwners = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -73,10 +74,11 @@ const ParkOwners = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
setIsCreateModalOpen(false);
|
setIsCreateModalOpen(false);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
toast({
|
toast({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
description: error.message || "Failed to submit property owner.",
|
description: errorMsg,
|
||||||
variant: "destructive"
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { RideSubmissionData } from '@/types/submission-data';
|
|||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
import { useAuth } from '@/hooks/useAuth';
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
|
import { getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { useAuthModal } from '@/hooks/useAuthModal';
|
import { useAuthModal } from '@/hooks/useAuthModal';
|
||||||
|
|
||||||
export default function ParkRides() {
|
export default function ParkRides() {
|
||||||
@@ -130,10 +131,11 @@ export default function ParkRides() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
setIsCreateModalOpen(false);
|
setIsCreateModalOpen(false);
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
|
const errorMsg = getErrorMessage(error);
|
||||||
toast({
|
toast({
|
||||||
title: "Submission Failed",
|
title: "Submission Failed",
|
||||||
description: error.message || "Failed to submit ride.",
|
description: errorMsg,
|
||||||
variant: "destructive"
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
-- Add check constraints to enforce metric-only units in statistics tables
|
||||||
|
-- This ensures data integrity and compliance with the custom knowledge requirement:
|
||||||
|
-- "Unit Conversion Rules: Storage: Always metric in DB (km/h, m, cm, kg)"
|
||||||
|
|
||||||
|
-- Add constraint to ride_coaster_stats table
|
||||||
|
ALTER TABLE ride_coaster_stats
|
||||||
|
ADD CONSTRAINT ride_coaster_stats_metric_unit_check
|
||||||
|
CHECK (
|
||||||
|
unit IS NULL OR
|
||||||
|
unit IN ('km/h', 'm', 'cm', 'kg', 'g', 'G', 'celsius', 'seconds', 'minutes', 'hours', 'count', '%')
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Add constraint to ride_technical_specifications table
|
||||||
|
ALTER TABLE ride_technical_specifications
|
||||||
|
ADD CONSTRAINT ride_tech_specs_metric_unit_check
|
||||||
|
CHECK (
|
||||||
|
unit IS NULL OR
|
||||||
|
unit IN ('km/h', 'm', 'cm', 'kg', 'g', 'G', 'celsius', 'seconds', 'minutes', 'hours', 'count', '%')
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Add constraint to ride_model_technical_specifications table
|
||||||
|
ALTER TABLE ride_model_technical_specifications
|
||||||
|
ADD CONSTRAINT ride_model_tech_specs_metric_unit_check
|
||||||
|
CHECK (
|
||||||
|
unit IS NULL OR
|
||||||
|
unit IN ('km/h', 'm', 'cm', 'kg', 'g', 'G', 'celsius', 'seconds', 'minutes', 'hours', 'count', '%')
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user