mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-28 13:26:58 -05:00
Compare commits
3 Commits
07420a67bf
...
3c13b7a9f4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c13b7a9f4 | ||
|
|
88403f04f5 | ||
|
|
516f7c4c41 |
@@ -56,7 +56,7 @@ export const performanceTestSuite: TestSuite = {
|
|||||||
|
|
||||||
// Set performance thresholds (in milliseconds)
|
// Set performance thresholds (in milliseconds)
|
||||||
const threshold = 1000; // 1 second
|
const threshold = 1000; // 1 second
|
||||||
const warnings = [];
|
const warnings: string[] = [];
|
||||||
|
|
||||||
if (parksDuration > threshold) {
|
if (parksDuration > threshold) {
|
||||||
warnings.push(`Parks query slow: ${parksDuration}ms`);
|
warnings.push(`Parks query slow: ${parksDuration}ms`);
|
||||||
@@ -229,7 +229,7 @@ export const performanceTestSuite: TestSuite = {
|
|||||||
|
|
||||||
// Performance threshold: 200ms for simple functions
|
// Performance threshold: 200ms for simple functions
|
||||||
const threshold = 200;
|
const threshold = 200;
|
||||||
const warnings = [];
|
const warnings: string[] = [];
|
||||||
|
|
||||||
if (modDuration > threshold) {
|
if (modDuration > threshold) {
|
||||||
warnings.push(`is_moderator slow: ${modDuration}ms`);
|
warnings.push(`is_moderator slow: ${modDuration}ms`);
|
||||||
|
|||||||
@@ -347,7 +347,7 @@ export const submissionTestSuite: TestSuite = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify version was created with images
|
// Verify version was created with images
|
||||||
let version = null;
|
let version: any = null;
|
||||||
const pollStart = Date.now();
|
const pollStart = Date.now();
|
||||||
while (!version && Date.now() - pollStart < 5000) {
|
while (!version && Date.now() - pollStart < 5000) {
|
||||||
const { data } = await supabase
|
const { data } = await supabase
|
||||||
|
|||||||
@@ -72,16 +72,16 @@ export const unitConversionTestSuite: TestSuite = {
|
|||||||
// Validate values are stored in metric
|
// Validate values are stored in metric
|
||||||
const tolerance = 0.01; // Allow small floating point differences
|
const tolerance = 0.01; // Allow small floating point differences
|
||||||
|
|
||||||
if (Math.abs(ride.max_speed_kmh - testData.max_speed_kmh) > tolerance) {
|
if (Math.abs((ride.max_speed_kmh ?? 0) - testData.max_speed_kmh) > tolerance) {
|
||||||
throw new Error(`max_speed_kmh mismatch: expected ${testData.max_speed_kmh}, got ${ride.max_speed_kmh}`);
|
throw new Error(`max_speed_kmh mismatch: expected ${testData.max_speed_kmh}, got ${ride.max_speed_kmh}`);
|
||||||
}
|
}
|
||||||
if (Math.abs(ride.max_height_meters - testData.max_height_meters) > tolerance) {
|
if (Math.abs((ride.max_height_meters ?? 0) - testData.max_height_meters) > tolerance) {
|
||||||
throw new Error(`max_height_meters mismatch: expected ${testData.max_height_meters}, got ${ride.max_height_meters}`);
|
throw new Error(`max_height_meters mismatch: expected ${testData.max_height_meters}, got ${ride.max_height_meters}`);
|
||||||
}
|
}
|
||||||
if (Math.abs(ride.length_meters - testData.length_meters) > tolerance) {
|
if (Math.abs((ride.length_meters ?? 0) - testData.length_meters) > tolerance) {
|
||||||
throw new Error(`length_meters mismatch: expected ${testData.length_meters}, got ${ride.length_meters}`);
|
throw new Error(`length_meters mismatch: expected ${testData.length_meters}, got ${ride.length_meters}`);
|
||||||
}
|
}
|
||||||
if (Math.abs(ride.height_requirement - testData.height_requirement) > tolerance) {
|
if (Math.abs((ride.height_requirement ?? 0) - testData.height_requirement) > tolerance) {
|
||||||
throw new Error(`height_requirement mismatch: expected ${testData.height_requirement} cm, got ${ride.height_requirement}`);
|
throw new Error(`height_requirement mismatch: expected ${testData.height_requirement} cm, got ${ride.height_requirement}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ export const unitConversionTestSuite: TestSuite = {
|
|||||||
tracker.track('rides', rideId);
|
tracker.track('rides', rideId);
|
||||||
|
|
||||||
// Poll for version creation
|
// Poll for version creation
|
||||||
let version = null;
|
let version: any = null;
|
||||||
const pollStart = Date.now();
|
const pollStart = Date.now();
|
||||||
while (!version && Date.now() - pollStart < 5000) {
|
while (!version && Date.now() - pollStart < 5000) {
|
||||||
const { data } = await supabase
|
const { data } = await supabase
|
||||||
@@ -193,13 +193,13 @@ export const unitConversionTestSuite: TestSuite = {
|
|||||||
|
|
||||||
// Validate version has metric units
|
// Validate version has metric units
|
||||||
const tolerance = 0.01;
|
const tolerance = 0.01;
|
||||||
if (Math.abs(version.max_speed_kmh - 120.0) > tolerance) {
|
if (Math.abs((version.max_speed_kmh ?? 0) - 120.0) > tolerance) {
|
||||||
throw new Error(`Version max_speed_kmh mismatch: expected 120.0, got ${version.max_speed_kmh}`);
|
throw new Error(`Version max_speed_kmh mismatch: expected 120.0, got ${version.max_speed_kmh}`);
|
||||||
}
|
}
|
||||||
if (Math.abs(version.height_meters - 60.0) > tolerance) {
|
if (Math.abs((version.height_meters ?? 0) - 60.0) > tolerance) {
|
||||||
throw new Error(`Version height_meters mismatch: expected 60.0, got ${version.height_meters}`);
|
throw new Error(`Version height_meters mismatch: expected 60.0, got ${version.height_meters}`);
|
||||||
}
|
}
|
||||||
if (Math.abs(version.height_requirement_cm - 140) > tolerance) {
|
if (Math.abs((version.height_requirement_cm ?? 0) - 140) > tolerance) {
|
||||||
throw new Error(`Version height_requirement_cm mismatch: expected 140, got ${version.height_requirement_cm}`);
|
throw new Error(`Version height_requirement_cm mismatch: expected 140, got ${version.height_requirement_cm}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export const versioningTestSuite: TestSuite = {
|
|||||||
parkId = park.id;
|
parkId = park.id;
|
||||||
|
|
||||||
// Poll for version creation
|
// Poll for version creation
|
||||||
let v1 = null;
|
let v1: any = null;
|
||||||
const pollStart = Date.now();
|
const pollStart = Date.now();
|
||||||
while (!v1 && Date.now() - pollStart < 5000) {
|
while (!v1 && Date.now() - pollStart < 5000) {
|
||||||
const { data } = await supabase
|
const { data } = await supabase
|
||||||
@@ -243,7 +243,7 @@ export const versioningTestSuite: TestSuite = {
|
|||||||
parkId = park.id;
|
parkId = park.id;
|
||||||
|
|
||||||
// Poll for version creation
|
// Poll for version creation
|
||||||
let v1 = null;
|
let v1: any = null;
|
||||||
const pollStart = Date.now();
|
const pollStart = Date.now();
|
||||||
while (!v1 && Date.now() - pollStart < 5000) {
|
while (!v1 && Date.now() - pollStart < 5000) {
|
||||||
const { data } = await supabase
|
const { data } = await supabase
|
||||||
|
|||||||
@@ -347,8 +347,8 @@ class NotificationService {
|
|||||||
return (data || []).map(t => ({
|
return (data || []).map(t => ({
|
||||||
...t,
|
...t,
|
||||||
is_active: t.is_active ?? true,
|
is_active: t.is_active ?? true,
|
||||||
description: t.description || undefined,
|
description: t.description || null,
|
||||||
novu_workflow_id: t.novu_workflow_id || undefined
|
novu_workflow_id: t.novu_workflow_id || null,
|
||||||
}));
|
}));
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
logger.error('Error fetching notification templates', {
|
logger.error('Error fetching notification templates', {
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ async function logRequestMetadata(metadata: RequestMetadata): Promise<void> {
|
|||||||
// Safe cast - RPC function exists in database
|
// Safe cast - RPC function exists in database
|
||||||
const { error } = await supabase.rpc('log_request_metadata' as 'log_request_metadata', {
|
const { error } = await supabase.rpc('log_request_metadata' as 'log_request_metadata', {
|
||||||
p_request_id: metadata.requestId,
|
p_request_id: metadata.requestId,
|
||||||
p_user_id: metadata.userId || null,
|
p_user_id: metadata.userId ?? undefined,
|
||||||
p_endpoint: metadata.endpoint,
|
p_endpoint: metadata.endpoint,
|
||||||
p_method: metadata.method,
|
p_method: metadata.method,
|
||||||
p_status_code: metadata.statusCode,
|
p_status_code: metadata.statusCode,
|
||||||
|
|||||||
@@ -1450,7 +1450,7 @@ export async function checkSubmissionConflict(
|
|||||||
},
|
},
|
||||||
serverVersion: {
|
serverVersion: {
|
||||||
last_modified_at: data.last_modified_at,
|
last_modified_at: data.last_modified_at,
|
||||||
last_modified_by: data.last_modified_by,
|
last_modified_by: (data.last_modified_by ?? undefined) as string,
|
||||||
modified_by_profile: data.profiles as any,
|
modified_by_profile: data.profiles as any,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
22
src/lib/typeAssertions.ts
Normal file
22
src/lib/typeAssertions.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* Type assertion helpers for TypeScript strict mode compatibility
|
||||||
|
* These help bridge database types (null) with application types (undefined)
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function nullToUndefined<T>(value: T | null): T | undefined {
|
||||||
|
return value === null ? undefined : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertNullsToUndefined<T extends Record<string, any>>(obj: T): { [K in keyof T]: T[K] extends (infer U | null) ? (U | undefined) : T[K] } {
|
||||||
|
const result: any = {};
|
||||||
|
for (const key in obj) {
|
||||||
|
const value = obj[key];
|
||||||
|
result[key] = value === null ? undefined : value;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type guard for checking if value is not null/undefined
|
||||||
|
export function isDefined<T>(value: T | null | undefined): value is T {
|
||||||
|
return value !== null && value !== undefined;
|
||||||
|
}
|
||||||
@@ -197,7 +197,7 @@ export default function AdminDashboard() {
|
|||||||
onRefresh={handleRefresh}
|
onRefresh={handleRefresh}
|
||||||
refreshMode={refreshMode}
|
refreshMode={refreshMode}
|
||||||
pollInterval={pollInterval}
|
pollInterval={pollInterval}
|
||||||
lastUpdated={lastUpdated}
|
lastUpdated={lastUpdated ?? undefined}
|
||||||
isRefreshing={isRefreshing}
|
isRefreshing={isRefreshing}
|
||||||
>
|
>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export default function AdminModeration() {
|
|||||||
onRefresh={handleRefresh}
|
onRefresh={handleRefresh}
|
||||||
refreshMode={refreshMode}
|
refreshMode={refreshMode}
|
||||||
pollInterval={pollInterval}
|
pollInterval={pollInterval}
|
||||||
lastUpdated={lastUpdated}
|
lastUpdated={lastUpdated ?? undefined}
|
||||||
>
|
>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div>
|
<div>
|
||||||
@@ -70,7 +70,7 @@ export default function AdminModeration() {
|
|||||||
onRefresh={handleRefresh}
|
onRefresh={handleRefresh}
|
||||||
refreshMode={refreshMode}
|
refreshMode={refreshMode}
|
||||||
pollInterval={pollInterval}
|
pollInterval={pollInterval}
|
||||||
lastUpdated={lastUpdated}
|
lastUpdated={lastUpdated ?? undefined}
|
||||||
>
|
>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export default function AdminReports() {
|
|||||||
onRefresh={handleRefresh}
|
onRefresh={handleRefresh}
|
||||||
refreshMode={refreshMode}
|
refreshMode={refreshMode}
|
||||||
pollInterval={pollInterval}
|
pollInterval={pollInterval}
|
||||||
lastUpdated={lastUpdated}
|
lastUpdated={lastUpdated ?? undefined}
|
||||||
>
|
>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div>
|
<div>
|
||||||
@@ -71,7 +71,7 @@ export default function AdminReports() {
|
|||||||
onRefresh={handleRefresh}
|
onRefresh={handleRefresh}
|
||||||
refreshMode={refreshMode}
|
refreshMode={refreshMode}
|
||||||
pollInterval={pollInterval}
|
pollInterval={pollInterval}
|
||||||
lastUpdated={lastUpdated}
|
lastUpdated={lastUpdated ?? undefined}
|
||||||
>
|
>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ export default function Auth() {
|
|||||||
const { handlePostAuthFlow } = await import('@/lib/authService');
|
const { handlePostAuthFlow } = await import('@/lib/authService');
|
||||||
const postAuthResult = await handlePostAuthFlow(data.session, 'password');
|
const postAuthResult = await handlePostAuthFlow(data.session, 'password');
|
||||||
|
|
||||||
if (postAuthResult.success && postAuthResult.data.shouldRedirect) {
|
if (postAuthResult.success && postAuthResult.data?.shouldRedirect) {
|
||||||
// Get the TOTP factor ID
|
// Get the TOTP factor ID
|
||||||
const { data: factors } = await supabase.auth.mfa.listFactors();
|
const { data: factors } = await supabase.auth.mfa.listFactors();
|
||||||
const totpFactor = factors?.totp?.find(f => f.status === 'verified');
|
const totpFactor = factors?.totp?.find(f => f.status === 'verified');
|
||||||
@@ -189,7 +189,7 @@ export default function Auth() {
|
|||||||
errorMessage = 'Invalid email or password. Please try again.';
|
errorMessage = 'Invalid email or password. Please try again.';
|
||||||
} else if (errorMsg.includes('Email not confirmed')) {
|
} else if (errorMsg.includes('Email not confirmed')) {
|
||||||
errorMessage = 'Please confirm your email address before signing in.';
|
errorMessage = 'Please confirm your email address before signing in.';
|
||||||
} else if (error.message.includes('Too many requests')) {
|
} else if (error instanceof Error && error.message.includes('Too many requests')) {
|
||||||
errorMessage = 'Too many login attempts. Please wait a few minutes and try again.';
|
errorMessage = 'Too many login attempts. Please wait a few minutes and try again.';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ export default function BlogIndex() {
|
|||||||
description: searchQuery
|
description: searchQuery
|
||||||
? `Search results for "${searchQuery}" in ThrillWiki Blog`
|
? `Search results for "${searchQuery}" in ThrillWiki Blog`
|
||||||
: 'News, updates, and stories from the world of theme parks and roller coasters',
|
: 'News, updates, and stories from the world of theme parks and roller coasters',
|
||||||
imageUrl: data?.posts?.[0]?.featured_image_url,
|
imageUrl: data?.posts?.[0]?.featured_image_url ?? undefined,
|
||||||
imageId: data?.posts?.[0]?.featured_image_id,
|
imageId: data?.posts?.[0]?.featured_image_id ?? undefined,
|
||||||
type: 'website',
|
type: 'website',
|
||||||
enabled: !isLoading
|
enabled: !isLoading
|
||||||
});
|
});
|
||||||
@@ -97,14 +97,14 @@ export default function BlogIndex() {
|
|||||||
slug={post.slug}
|
slug={post.slug}
|
||||||
title={post.title}
|
title={post.title}
|
||||||
content={post.content}
|
content={post.content}
|
||||||
featuredImageId={post.featured_image_id}
|
featuredImageId={post.featured_image_id ?? undefined}
|
||||||
author={{
|
author={{
|
||||||
username: post.profiles.username,
|
username: post.profiles.username,
|
||||||
displayName: post.profiles.display_name,
|
displayName: post.profiles.display_name ?? undefined,
|
||||||
avatarUrl: post.profiles.avatar_url,
|
avatarUrl: post.profiles.avatar_url ?? undefined,
|
||||||
}}
|
}}
|
||||||
publishedAt={post.published_at!}
|
publishedAt={post.published_at!}
|
||||||
viewCount={post.view_count}
|
viewCount={post.view_count ?? 0}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export default function BlogPost() {
|
|||||||
const query = supabase
|
const query = supabase
|
||||||
.from('blog_posts')
|
.from('blog_posts')
|
||||||
.select('*, profiles!inner(username, display_name, avatar_url, avatar_image_id)')
|
.select('*, profiles!inner(username, display_name, avatar_url, avatar_image_id)')
|
||||||
.eq('slug', slug)
|
.eq('slug', slug || '')
|
||||||
.eq('status', 'published')
|
.eq('status', 'published')
|
||||||
.single();
|
.single();
|
||||||
|
|
||||||
@@ -41,8 +41,8 @@ export default function BlogPost() {
|
|||||||
useOpenGraph({
|
useOpenGraph({
|
||||||
title: post?.title || '',
|
title: post?.title || '',
|
||||||
description: post?.content?.substring(0, 160),
|
description: post?.content?.substring(0, 160),
|
||||||
imageUrl: post?.featured_image_url,
|
imageUrl: post?.featured_image_url ?? undefined,
|
||||||
imageId: post?.featured_image_id,
|
imageId: post?.featured_image_id ?? undefined,
|
||||||
type: 'article',
|
type: 'article',
|
||||||
enabled: !!post
|
enabled: !!post
|
||||||
});
|
});
|
||||||
@@ -106,14 +106,14 @@ export default function BlogPost() {
|
|||||||
<div className="flex items-center justify-between mb-8 pb-6 border-b">
|
<div className="flex items-center justify-between mb-8 pb-6 border-b">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<Avatar className="w-12 h-12">
|
<Avatar className="w-12 h-12">
|
||||||
<AvatarImage src={post.profiles.avatar_url} />
|
<AvatarImage src={post.profiles.avatar_url ?? undefined} />
|
||||||
<AvatarFallback>
|
<AvatarFallback>
|
||||||
{post.profiles.display_name?.[0] || post.profiles.username[0]}
|
{post.profiles.display_name?.[0] || post.profiles.username[0]}
|
||||||
</AvatarFallback>
|
</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<div>
|
<div>
|
||||||
<p className="font-medium">
|
<p className="font-medium">
|
||||||
{post.profiles.display_name || post.profiles.username}
|
{post.profiles.display_name ?? post.profiles.username}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex items-center gap-3 text-sm text-muted-foreground">
|
<div className="flex items-center gap-3 text-sm text-muted-foreground">
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
|
|||||||
@@ -46,9 +46,9 @@ export default function DesignerDetail() {
|
|||||||
// Update Open Graph meta tags
|
// Update Open Graph meta tags
|
||||||
useOpenGraph({
|
useOpenGraph({
|
||||||
title: designer?.name || '',
|
title: designer?.name || '',
|
||||||
description: designer?.description || (designer ? `${designer.name} - Ride Designer${designer.headquarters_location ? ` based in ${designer.headquarters_location}` : ''}` : ''),
|
description: designer?.description ?? (designer ? `${designer.name} - Ride Designer${designer.headquarters_location ? ` based in ${designer.headquarters_location}` : ''}` : ''),
|
||||||
imageUrl: designer?.banner_image_url,
|
imageUrl: designer?.banner_image_url ?? undefined,
|
||||||
imageId: designer?.banner_image_id,
|
imageId: designer?.banner_image_id ?? undefined,
|
||||||
type: 'profile',
|
type: 'profile',
|
||||||
enabled: !!designer
|
enabled: !!designer
|
||||||
});
|
});
|
||||||
@@ -71,7 +71,7 @@ export default function DesignerDetail() {
|
|||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
.from('companies')
|
.from('companies')
|
||||||
.select('*')
|
.select('*')
|
||||||
.eq('slug', slug)
|
.eq('slug', slug || '')
|
||||||
.eq('company_type', 'designer')
|
.eq('company_type', 'designer')
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
|
|
||||||
@@ -197,10 +197,10 @@ export default function DesignerDetail() {
|
|||||||
<picture>
|
<picture>
|
||||||
<source
|
<source
|
||||||
media="(max-width: 768px)"
|
media="(max-width: 768px)"
|
||||||
srcSet={getBannerUrls(designer.banner_image_id).mobile || designer.banner_image_url}
|
srcSet={(getBannerUrls(designer.banner_image_id ?? undefined).mobile || designer.banner_image_url) ?? undefined}
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
src={getBannerUrls(designer.banner_image_id).desktop || designer.banner_image_url}
|
src={(getBannerUrls(designer.banner_image_id ?? undefined).desktop || designer.banner_image_url) ?? undefined}
|
||||||
alt={designer.name}
|
alt={designer.name}
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
loading="eager"
|
loading="eager"
|
||||||
@@ -244,12 +244,12 @@ export default function DesignerDetail() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{designer.average_rating > 0 && (
|
{(designer.average_rating ?? 0) > 0 && (
|
||||||
<div className="bg-black/30 backdrop-blur-md rounded-lg p-6 text-center">
|
<div className="bg-black/30 backdrop-blur-md rounded-lg p-6 text-center">
|
||||||
<div className="flex items-center gap-2 text-white mb-2">
|
<div className="flex items-center gap-2 text-white mb-2">
|
||||||
<Star className="w-6 h-6 fill-yellow-400 text-yellow-400" />
|
<Star className="w-6 h-6 fill-yellow-400 text-yellow-400" />
|
||||||
<span className="text-3xl font-bold">
|
<span className="text-3xl font-bold">
|
||||||
{designer.average_rating.toFixed(1)}
|
{(designer.average_rating ?? 0).toFixed(1)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-white/90 text-sm">
|
<div className="text-white/90 text-sm">
|
||||||
@@ -361,14 +361,14 @@ export default function DesignerDetail() {
|
|||||||
id: designer.id,
|
id: designer.id,
|
||||||
name: designer.name,
|
name: designer.name,
|
||||||
slug: designer.slug,
|
slug: designer.slug,
|
||||||
description: designer.description,
|
description: designer.description ?? undefined,
|
||||||
company_type: 'designer',
|
company_type: 'designer',
|
||||||
person_type: (designer.person_type || 'company') as 'company' | 'individual' | 'firm' | 'organization',
|
person_type: (designer.person_type || 'company') as 'company' | 'individual' | 'firm' | 'organization',
|
||||||
website_url: designer.website_url,
|
website_url: designer.website_url ?? undefined,
|
||||||
founded_year: designer.founded_year,
|
founded_year: designer.founded_year ?? undefined,
|
||||||
headquarters_location: designer.headquarters_location,
|
headquarters_location: designer.headquarters_location ?? undefined,
|
||||||
banner_image_url: designer.banner_image_url,
|
banner_image_url: designer.banner_image_url ?? undefined,
|
||||||
card_image_url: designer.card_image_url
|
card_image_url: designer.card_image_url ?? undefined
|
||||||
}}
|
}}
|
||||||
onSubmit={handleEditSubmit}
|
onSubmit={handleEditSubmit}
|
||||||
onCancel={() => setIsEditModalOpen(false)}
|
onCancel={() => setIsEditModalOpen(false)}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export default function DesignerRides() {
|
|||||||
const { data: designerData, error: designerError } = await supabase
|
const { data: designerData, error: designerError } = await supabase
|
||||||
.from('companies')
|
.from('companies')
|
||||||
.select('*')
|
.select('*')
|
||||||
.eq('slug', designerSlug)
|
.eq('slug', designerSlug || '')
|
||||||
.eq('company_type', 'designer')
|
.eq('company_type', 'designer')
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ export default function DesignerRides() {
|
|||||||
|
|
||||||
const { data: ridesData, error: ridesError } = await query;
|
const { data: ridesData, error: ridesError } = await query;
|
||||||
if (ridesError) throw ridesError;
|
if (ridesError) throw ridesError;
|
||||||
setRides(ridesData || []);
|
setRides((ridesData || []) as any);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching data:', error);
|
console.error('Error fetching data:', error);
|
||||||
@@ -110,8 +110,8 @@ export default function DesignerRides() {
|
|||||||
description: designer
|
description: designer
|
||||||
? `Explore ${filteredRides.length} rides designed by ${designer.name}`
|
? `Explore ${filteredRides.length} rides designed by ${designer.name}`
|
||||||
: undefined,
|
: undefined,
|
||||||
imageUrl: designer?.banner_image_url || filteredRides[0]?.banner_image_url,
|
imageUrl: designer?.banner_image_url ?? filteredRides[0]?.banner_image_url ?? undefined,
|
||||||
imageId: designer?.banner_image_id || filteredRides[0]?.banner_image_id,
|
imageId: designer?.banner_image_id ?? filteredRides[0]?.banner_image_id ?? undefined,
|
||||||
type: 'website',
|
type: 'website',
|
||||||
enabled: !!designer && !loading
|
enabled: !!designer && !loading
|
||||||
});
|
});
|
||||||
@@ -129,11 +129,12 @@ export default function DesignerRides() {
|
|||||||
|
|
||||||
const submissionData: RideSubmissionData = {
|
const submissionData: RideSubmissionData = {
|
||||||
...data,
|
...data,
|
||||||
|
description: data.description ?? undefined,
|
||||||
designer_id: designer.id,
|
designer_id: designer.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { submitRideCreation } = await import('@/lib/entitySubmissionHelpers');
|
const { submitRideCreation } = await import('@/lib/entitySubmissionHelpers');
|
||||||
await submitRideCreation(submissionData, user.id);
|
await submitRideCreation(submissionData as any, user!.id);
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: "Ride Submitted",
|
title: "Ride Submitted",
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export default function Designers() {
|
|||||||
|
|
||||||
const handleCreateSubmit = async (data: any) => {
|
const handleCreateSubmit = async (data: any) => {
|
||||||
try {
|
try {
|
||||||
await submitCompanyCreation(data, 'designer', user.id);
|
await submitCompanyCreation(data, 'designer', user!.id);
|
||||||
toast({
|
toast({
|
||||||
title: "Designer Submitted",
|
title: "Designer Submitted",
|
||||||
description: "Your submission has been sent for review."
|
description: "Your submission has been sent for review."
|
||||||
@@ -168,8 +168,8 @@ export default function Designers() {
|
|||||||
useOpenGraph({
|
useOpenGraph({
|
||||||
title: 'Ride Designers - ThrillWiki',
|
title: 'Ride Designers - ThrillWiki',
|
||||||
description: `Browse ${filteredCompanies.length} ride designers worldwide`,
|
description: `Browse ${filteredCompanies.length} ride designers worldwide`,
|
||||||
imageUrl: filteredCompanies[0]?.banner_image_url,
|
imageUrl: filteredCompanies[0]?.banner_image_url ?? undefined,
|
||||||
imageId: filteredCompanies[0]?.banner_image_id,
|
imageId: filteredCompanies[0]?.banner_image_id ?? undefined,
|
||||||
type: 'website',
|
type: 'website',
|
||||||
enabled: !loading
|
enabled: !loading
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -47,9 +47,9 @@ export default function ManufacturerDetail() {
|
|||||||
// Update Open Graph meta tags
|
// Update Open Graph meta tags
|
||||||
useOpenGraph({
|
useOpenGraph({
|
||||||
title: manufacturer?.name || '',
|
title: manufacturer?.name || '',
|
||||||
description: manufacturer?.description || (manufacturer ? `${manufacturer.name} - Ride Manufacturer${manufacturer.headquarters_location ? ` based in ${manufacturer.headquarters_location}` : ''}` : ''),
|
description: manufacturer?.description ?? (manufacturer ? `${manufacturer.name} - Ride Manufacturer${manufacturer.headquarters_location ? ` based in ${manufacturer.headquarters_location}` : ''}` : ''),
|
||||||
imageUrl: manufacturer?.banner_image_url,
|
imageUrl: manufacturer?.banner_image_url ?? undefined,
|
||||||
imageId: manufacturer?.banner_image_id,
|
imageId: manufacturer?.banner_image_id ?? undefined,
|
||||||
type: 'profile',
|
type: 'profile',
|
||||||
enabled: !!manufacturer
|
enabled: !!manufacturer
|
||||||
});
|
});
|
||||||
@@ -72,7 +72,7 @@ export default function ManufacturerDetail() {
|
|||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
.from('companies')
|
.from('companies')
|
||||||
.select('*')
|
.select('*')
|
||||||
.eq('slug', slug)
|
.eq('slug', slug || '')
|
||||||
.eq('company_type', 'manufacturer')
|
.eq('company_type', 'manufacturer')
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
|
|
||||||
@@ -209,10 +209,10 @@ export default function ManufacturerDetail() {
|
|||||||
<picture>
|
<picture>
|
||||||
<source
|
<source
|
||||||
media="(max-width: 768px)"
|
media="(max-width: 768px)"
|
||||||
srcSet={getBannerUrls(manufacturer.banner_image_id).mobile || manufacturer.banner_image_url}
|
srcSet={(getBannerUrls(manufacturer.banner_image_id ?? undefined).mobile || manufacturer.banner_image_url) ?? undefined}
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
src={getBannerUrls(manufacturer.banner_image_id).desktop || manufacturer.banner_image_url}
|
src={(getBannerUrls(manufacturer.banner_image_id ?? undefined).desktop || manufacturer.banner_image_url) ?? undefined}
|
||||||
alt={manufacturer.name}
|
alt={manufacturer.name}
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
loading="eager"
|
loading="eager"
|
||||||
@@ -256,12 +256,12 @@ export default function ManufacturerDetail() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{manufacturer.average_rating > 0 && (
|
{(manufacturer.average_rating ?? 0) > 0 && (
|
||||||
<div className="bg-black/30 backdrop-blur-md rounded-lg p-6 text-center">
|
<div className="bg-black/30 backdrop-blur-md rounded-lg p-6 text-center">
|
||||||
<div className="flex items-center gap-2 text-white mb-2">
|
<div className="flex items-center gap-2 text-white mb-2">
|
||||||
<Star className="w-6 h-6 fill-yellow-400 text-yellow-400" />
|
<Star className="w-6 h-6 fill-yellow-400 text-yellow-400" />
|
||||||
<span className="text-3xl font-bold">
|
<span className="text-3xl font-bold">
|
||||||
{manufacturer.average_rating.toFixed(1)}
|
{(manufacturer.average_rating ?? 0).toFixed(1)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-white/90 text-sm">
|
<div className="text-white/90 text-sm">
|
||||||
@@ -395,14 +395,14 @@ export default function ManufacturerDetail() {
|
|||||||
id: manufacturer.id,
|
id: manufacturer.id,
|
||||||
name: manufacturer.name,
|
name: manufacturer.name,
|
||||||
slug: manufacturer.slug,
|
slug: manufacturer.slug,
|
||||||
description: manufacturer.description,
|
description: manufacturer.description ?? undefined,
|
||||||
company_type: 'manufacturer',
|
company_type: 'manufacturer',
|
||||||
person_type: (manufacturer.person_type || 'company') as 'company' | 'individual' | 'firm' | 'organization',
|
person_type: (manufacturer.person_type || 'company') as 'company' | 'individual' | 'firm' | 'organization',
|
||||||
website_url: manufacturer.website_url,
|
website_url: manufacturer.website_url ?? undefined,
|
||||||
founded_year: manufacturer.founded_year,
|
founded_year: manufacturer.founded_year ?? undefined,
|
||||||
headquarters_location: manufacturer.headquarters_location,
|
headquarters_location: manufacturer.headquarters_location ?? undefined,
|
||||||
banner_image_url: manufacturer.banner_image_url,
|
banner_image_url: manufacturer.banner_image_url ?? undefined,
|
||||||
card_image_url: manufacturer.card_image_url
|
card_image_url: manufacturer.card_image_url ?? undefined
|
||||||
}}
|
}}
|
||||||
onSubmit={handleEditSubmit}
|
onSubmit={handleEditSubmit}
|
||||||
onCancel={() => setIsEditModalOpen(false)}
|
onCancel={() => setIsEditModalOpen(false)}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export default function ManufacturerModels() {
|
|||||||
const { data: manufacturerData, error: manufacturerError } = await supabase
|
const { data: manufacturerData, error: manufacturerError } = await supabase
|
||||||
.from('companies')
|
.from('companies')
|
||||||
.select('*')
|
.select('*')
|
||||||
.eq('slug', manufacturerSlug)
|
.eq('slug', manufacturerSlug || '')
|
||||||
.eq('company_type', 'manufacturer')
|
.eq('company_type', 'manufacturer')
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
|
|
||||||
@@ -127,10 +127,11 @@ export default function ManufacturerModels() {
|
|||||||
const submissionData: RideModelSubmissionData = {
|
const submissionData: RideModelSubmissionData = {
|
||||||
...data,
|
...data,
|
||||||
manufacturer_id: manufacturer.id,
|
manufacturer_id: manufacturer.id,
|
||||||
|
ride_type: data.ride_type ?? undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { submitRideModelCreation } = await import('@/lib/entitySubmissionHelpers');
|
const { submitRideModelCreation } = await import('@/lib/entitySubmissionHelpers');
|
||||||
await submitRideModelCreation(submissionData, user.id);
|
await submitRideModelCreation(submissionData as any, user!.id);
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: "Ride Model Submitted",
|
title: "Ride Model Submitted",
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export default function ManufacturerRides() {
|
|||||||
const { data: manufacturerData, error: manufacturerError } = await supabase
|
const { data: manufacturerData, error: manufacturerError } = await supabase
|
||||||
.from('companies')
|
.from('companies')
|
||||||
.select('*')
|
.select('*')
|
||||||
.eq('slug', manufacturerSlug)
|
.eq('slug', manufacturerSlug || '')
|
||||||
.eq('company_type', 'manufacturer')
|
.eq('company_type', 'manufacturer')
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ export default function ManufacturerRides() {
|
|||||||
|
|
||||||
const { data: ridesData, error: ridesError } = await query;
|
const { data: ridesData, error: ridesError } = await query;
|
||||||
if (ridesError) throw ridesError;
|
if (ridesError) throw ridesError;
|
||||||
setRides(ridesData || []);
|
setRides(ridesData as any || []);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching data:', error);
|
console.error('Error fetching data:', error);
|
||||||
@@ -110,8 +110,8 @@ export default function ManufacturerRides() {
|
|||||||
description: manufacturer
|
description: manufacturer
|
||||||
? `Explore ${filteredRides.length} rides manufactured by ${manufacturer.name}`
|
? `Explore ${filteredRides.length} rides manufactured by ${manufacturer.name}`
|
||||||
: undefined,
|
: undefined,
|
||||||
imageUrl: manufacturer?.banner_image_url || filteredRides[0]?.banner_image_url,
|
imageUrl: manufacturer?.banner_image_url ?? filteredRides[0]?.banner_image_url ?? undefined,
|
||||||
imageId: manufacturer?.banner_image_id || filteredRides[0]?.banner_image_id,
|
imageId: manufacturer?.banner_image_id ?? filteredRides[0]?.banner_image_id ?? undefined,
|
||||||
type: 'website',
|
type: 'website',
|
||||||
enabled: !!manufacturer && !loading
|
enabled: !!manufacturer && !loading
|
||||||
});
|
});
|
||||||
@@ -130,10 +130,11 @@ export default function ManufacturerRides() {
|
|||||||
const submissionData: RideSubmissionData = {
|
const submissionData: RideSubmissionData = {
|
||||||
...data,
|
...data,
|
||||||
manufacturer_id: manufacturer.id,
|
manufacturer_id: manufacturer.id,
|
||||||
|
description: data.description ?? undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { submitRideCreation } = await import('@/lib/entitySubmissionHelpers');
|
const { submitRideCreation } = await import('@/lib/entitySubmissionHelpers');
|
||||||
await submitRideCreation(submissionData, user.id);
|
await submitRideCreation(submissionData as any, user!.id);
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: "Ride Submitted",
|
title: "Ride Submitted",
|
||||||
|
|||||||
@@ -155,8 +155,8 @@ export default function Manufacturers() {
|
|||||||
useOpenGraph({
|
useOpenGraph({
|
||||||
title: 'Ride Manufacturers - ThrillWiki',
|
title: 'Ride Manufacturers - ThrillWiki',
|
||||||
description: `Browse ${filteredCompanies.length} ride manufacturers worldwide`,
|
description: `Browse ${filteredCompanies.length} ride manufacturers worldwide`,
|
||||||
imageUrl: filteredCompanies[0]?.banner_image_url,
|
imageUrl: filteredCompanies[0]?.banner_image_url ?? undefined,
|
||||||
imageId: filteredCompanies[0]?.banner_image_id,
|
imageId: filteredCompanies[0]?.banner_image_id ?? undefined,
|
||||||
type: 'website',
|
type: 'website',
|
||||||
enabled: !loading
|
enabled: !loading
|
||||||
});
|
});
|
||||||
@@ -166,7 +166,7 @@ export default function Manufacturers() {
|
|||||||
await submitCompanyCreation(
|
await submitCompanyCreation(
|
||||||
data,
|
data,
|
||||||
'manufacturer',
|
'manufacturer',
|
||||||
user.id
|
user!.id
|
||||||
);
|
);
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ export default function OperatorDetail() {
|
|||||||
// Update Open Graph meta tags
|
// Update Open Graph meta tags
|
||||||
useOpenGraph({
|
useOpenGraph({
|
||||||
title: operator?.name || '',
|
title: operator?.name || '',
|
||||||
description: operator?.description || (operator ? `${operator.name} - Park Operator${operator.headquarters_location ? ` based in ${operator.headquarters_location}` : ''}` : ''),
|
description: operator?.description ?? (operator ? `${operator.name} - Park Operator${operator.headquarters_location ? ` based in ${operator.headquarters_location}` : ''}` : undefined),
|
||||||
imageUrl: operator?.banner_image_url,
|
imageUrl: operator?.banner_image_url ?? undefined,
|
||||||
imageId: operator?.banner_image_id,
|
imageId: operator?.banner_image_id ?? undefined,
|
||||||
type: 'profile',
|
type: 'profile',
|
||||||
enabled: !!operator
|
enabled: !!operator
|
||||||
});
|
});
|
||||||
@@ -75,7 +75,7 @@ export default function OperatorDetail() {
|
|||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
.from('companies')
|
.from('companies')
|
||||||
.select('*')
|
.select('*')
|
||||||
.eq('slug', slug)
|
.eq('slug', slug || '')
|
||||||
.eq('company_type', 'operator')
|
.eq('company_type', 'operator')
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
|
|
||||||
@@ -242,10 +242,10 @@ export default function OperatorDetail() {
|
|||||||
<picture>
|
<picture>
|
||||||
<source
|
<source
|
||||||
media="(max-width: 768px)"
|
media="(max-width: 768px)"
|
||||||
srcSet={getBannerUrls(operator.banner_image_id).mobile || operator.banner_image_url}
|
srcSet={getBannerUrls(operator.banner_image_id ?? undefined).mobile ?? operator.banner_image_url ?? undefined}
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
src={getBannerUrls(operator.banner_image_id).desktop || operator.banner_image_url}
|
src={getBannerUrls(operator.banner_image_id ?? undefined).desktop ?? operator.banner_image_url ?? undefined}
|
||||||
alt={operator.name}
|
alt={operator.name}
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
loading="eager"
|
loading="eager"
|
||||||
@@ -289,12 +289,12 @@ export default function OperatorDetail() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{operator.average_rating > 0 && (
|
{(operator.average_rating ?? 0) > 0 && (
|
||||||
<div className="bg-black/30 backdrop-blur-md rounded-lg p-6 text-center">
|
<div className="bg-black/30 backdrop-blur-md rounded-lg p-6 text-center">
|
||||||
<div className="flex items-center gap-2 text-white mb-2">
|
<div className="flex items-center gap-2 text-white mb-2">
|
||||||
<Star className="w-6 h-6 fill-yellow-400 text-yellow-400" />
|
<Star className="w-6 h-6 fill-yellow-400 text-yellow-400" />
|
||||||
<span className="text-3xl font-bold">
|
<span className="text-3xl font-bold">
|
||||||
{operator.average_rating.toFixed(1)}
|
{(operator.average_rating ?? 0).toFixed(1)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-white/90 text-sm">
|
<div className="text-white/90 text-sm">
|
||||||
@@ -447,14 +447,14 @@ export default function OperatorDetail() {
|
|||||||
id: operator.id,
|
id: operator.id,
|
||||||
name: operator.name,
|
name: operator.name,
|
||||||
slug: operator.slug,
|
slug: operator.slug,
|
||||||
description: operator.description,
|
description: operator.description ?? undefined,
|
||||||
company_type: 'operator',
|
company_type: 'operator',
|
||||||
person_type: (operator.person_type || 'company') as 'company' | 'individual' | 'firm' | 'organization',
|
person_type: (operator.person_type || 'company') as 'company' | 'individual' | 'firm' | 'organization',
|
||||||
website_url: operator.website_url,
|
website_url: operator.website_url ?? undefined,
|
||||||
founded_year: operator.founded_year,
|
founded_year: operator.founded_year ?? undefined,
|
||||||
headquarters_location: operator.headquarters_location,
|
headquarters_location: operator.headquarters_location ?? undefined,
|
||||||
banner_image_url: operator.banner_image_url,
|
banner_image_url: operator.banner_image_url ?? undefined,
|
||||||
card_image_url: operator.card_image_url
|
card_image_url: operator.card_image_url ?? undefined
|
||||||
}}
|
}}
|
||||||
onSubmit={handleEditSubmit}
|
onSubmit={handleEditSubmit}
|
||||||
onCancel={() => setIsEditModalOpen(false)}
|
onCancel={() => setIsEditModalOpen(false)}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export default function OperatorParks() {
|
|||||||
const { data: operatorData, error: operatorError } = await supabase
|
const { data: operatorData, error: operatorError } = await supabase
|
||||||
.from('companies')
|
.from('companies')
|
||||||
.select('*')
|
.select('*')
|
||||||
.eq('slug', operatorSlug)
|
.eq('slug', operatorSlug || '')
|
||||||
.eq('company_type', 'operator')
|
.eq('company_type', 'operator')
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
|
|
||||||
@@ -151,8 +151,8 @@ export default function OperatorParks() {
|
|||||||
description: operator
|
description: operator
|
||||||
? `Explore ${filteredAndSortedParks.length} theme parks operated by ${operator.name}`
|
? `Explore ${filteredAndSortedParks.length} theme parks operated by ${operator.name}`
|
||||||
: undefined,
|
: undefined,
|
||||||
imageUrl: operator?.banner_image_url || filteredAndSortedParks[0]?.banner_image_url,
|
imageUrl: operator?.banner_image_url ?? filteredAndSortedParks[0]?.banner_image_url ?? undefined,
|
||||||
imageId: operator?.banner_image_id || filteredAndSortedParks[0]?.banner_image_id,
|
imageId: operator?.banner_image_id ?? filteredAndSortedParks[0]?.banner_image_id ?? undefined,
|
||||||
type: 'website',
|
type: 'website',
|
||||||
enabled: !!operator && !loading
|
enabled: !!operator && !loading
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ const Operators = () => {
|
|||||||
.from('parks')
|
.from('parks')
|
||||||
.select('operator_id')
|
.select('operator_id')
|
||||||
.not('operator_id', 'is', null)
|
.not('operator_id', 'is', null)
|
||||||
.then(({ data }) => data?.map(park => park.operator_id) || [])
|
.then(({ data }) => data?.map(park => park.operator_id).filter((id): id is string => id !== null) || [])
|
||||||
)
|
)
|
||||||
.order('name');
|
.order('name');
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ const Operators = () => {
|
|||||||
await submitCompanyCreation(
|
await submitCompanyCreation(
|
||||||
data,
|
data,
|
||||||
'operator',
|
'operator',
|
||||||
user.id
|
user!.id
|
||||||
);
|
);
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
@@ -186,8 +186,8 @@ const Operators = () => {
|
|||||||
useOpenGraph({
|
useOpenGraph({
|
||||||
title: 'Park Operators - ThrillWiki',
|
title: 'Park Operators - ThrillWiki',
|
||||||
description: `Browse ${filteredAndSortedOperators.length} theme park operators worldwide`,
|
description: `Browse ${filteredAndSortedOperators.length} theme park operators worldwide`,
|
||||||
imageUrl: filteredAndSortedOperators[0]?.banner_image_url,
|
imageUrl: filteredAndSortedOperators[0]?.banner_image_url ?? undefined,
|
||||||
imageId: filteredAndSortedOperators[0]?.banner_image_id,
|
imageId: filteredAndSortedOperators[0]?.banner_image_id ?? undefined,
|
||||||
type: 'website',
|
type: 'website',
|
||||||
enabled: !isLoading
|
enabled: !isLoading
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -59,10 +59,10 @@ export default function OwnerParks() {
|
|||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
// Fetch owner
|
// Fetch owner
|
||||||
const { data: ownerData, error: ownerError } = await supabase
|
const { data: ownerData, error: ownerError} = await supabase
|
||||||
.from('companies')
|
.from('companies')
|
||||||
.select('*')
|
.select('*')
|
||||||
.eq('slug', ownerSlug)
|
.eq('slug', ownerSlug || '')
|
||||||
.eq('company_type', 'property_owner')
|
.eq('company_type', 'property_owner')
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
|
|
||||||
@@ -151,8 +151,8 @@ export default function OwnerParks() {
|
|||||||
description: owner
|
description: owner
|
||||||
? `Explore ${filteredAndSortedParks.length} theme parks owned by ${owner.name}`
|
? `Explore ${filteredAndSortedParks.length} theme parks owned by ${owner.name}`
|
||||||
: undefined,
|
: undefined,
|
||||||
imageUrl: owner?.banner_image_url || filteredAndSortedParks[0]?.banner_image_url,
|
imageUrl: owner?.banner_image_url ?? filteredAndSortedParks[0]?.banner_image_url ?? undefined,
|
||||||
imageId: owner?.banner_image_id || filteredAndSortedParks[0]?.banner_image_id,
|
imageId: owner?.banner_image_id ?? filteredAndSortedParks[0]?.banner_image_id ?? undefined,
|
||||||
type: 'website',
|
type: 'website',
|
||||||
enabled: !!owner && !loading
|
enabled: !!owner && !loading
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -58,9 +58,9 @@ export default function ParkDetail() {
|
|||||||
// Update Open Graph meta tags
|
// Update Open Graph meta tags
|
||||||
useOpenGraph({
|
useOpenGraph({
|
||||||
title: park?.name || '',
|
title: park?.name || '',
|
||||||
description: park?.description || (park ? `${park.name} - A theme park${park.location ? ` in ${park.location.city}, ${park.location.country}` : ''}` : ''),
|
description: park?.description ?? (park ? `${park.name} - A theme park${park.location ? ` in ${park.location.city}, ${park.location.country}` : ''}` : undefined),
|
||||||
imageUrl: park?.banner_image_url,
|
imageUrl: park?.banner_image_url ?? undefined,
|
||||||
imageId: park?.banner_image_id,
|
imageId: park?.banner_image_id ?? undefined,
|
||||||
type: 'website',
|
type: 'website',
|
||||||
enabled: !!park
|
enabled: !!park
|
||||||
});
|
});
|
||||||
@@ -110,7 +110,7 @@ export default function ParkDetail() {
|
|||||||
...rideData,
|
...rideData,
|
||||||
park_id: park?.id
|
park_id: park?.id
|
||||||
},
|
},
|
||||||
user.id
|
user!.id
|
||||||
);
|
);
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
@@ -212,10 +212,10 @@ export default function ParkDetail() {
|
|||||||
<picture>
|
<picture>
|
||||||
<source
|
<source
|
||||||
media="(max-width: 768px)"
|
media="(max-width: 768px)"
|
||||||
srcSet={getBannerUrls(park.banner_image_id).mobile || park.banner_image_url}
|
srcSet={getBannerUrls(park.banner_image_id ?? undefined).mobile ?? park.banner_image_url ?? undefined}
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
src={getBannerUrls(park.banner_image_id).desktop || park.banner_image_url}
|
src={getBannerUrls(park.banner_image_id ?? undefined).desktop ?? park.banner_image_url ?? undefined}
|
||||||
alt={park.name}
|
alt={park.name}
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
loading="eager"
|
loading="eager"
|
||||||
@@ -258,10 +258,10 @@ export default function ParkDetail() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{park.average_rating > 0 && <div className="bg-black/20 backdrop-blur-sm rounded-lg p-4 text-center">
|
{(park.average_rating ?? 0) > 0 && <div className="bg-black/20 backdrop-blur-sm rounded-lg p-4 text-center">
|
||||||
<div className="flex items-center gap-2 text-white mb-1">
|
<div className="flex items-center gap-2 text-white mb-1">
|
||||||
<Star className="w-5 h-5 fill-yellow-400 text-yellow-400" />
|
<Star className="w-5 h-5 fill-yellow-400 text-yellow-400" />
|
||||||
<span className="text-2xl font-bold">{park.average_rating.toFixed(1)}</span>
|
<span className="text-2xl font-bold">{(park.average_rating ?? 0).toFixed(1)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-white/70 text-sm">
|
<div className="text-white/70 text-sm">
|
||||||
{park.review_count} reviews
|
{park.review_count} reviews
|
||||||
@@ -319,10 +319,10 @@ export default function ParkDetail() {
|
|||||||
{park.review_count}
|
{park.review_count}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs font-medium text-muted-foreground">Reviews</div>
|
<div className="text-xs font-medium text-muted-foreground">Reviews</div>
|
||||||
{park.average_rating > 0 && <div className="flex items-center justify-center gap-1 mt-1">
|
{(park.average_rating ?? 0) > 0 && <div className="flex items-center justify-center gap-1 mt-1">
|
||||||
<Star className="w-3 h-3 fill-yellow-400 text-yellow-400" />
|
<Star className="w-3 h-3 fill-yellow-400 text-yellow-400" />
|
||||||
<span className="text-xs font-medium text-yellow-500">
|
<span className="text-xs font-medium text-yellow-500">
|
||||||
{park.average_rating.toFixed(1)}
|
{(park.average_rating ?? 0).toFixed(1)}
|
||||||
</span>
|
</span>
|
||||||
</div>}
|
</div>}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
@@ -356,7 +356,7 @@ export default function ParkDetail() {
|
|||||||
Rides {rides.length > 0 && `(${rides.length})`}
|
Rides {rides.length > 0 && `(${rides.length})`}
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger value="reviews">
|
<TabsTrigger value="reviews">
|
||||||
Reviews {park.review_count > 0 && `(${park.review_count})`}
|
Reviews {(park.review_count ?? 0) > 0 && `(${park.review_count})`}
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
<TabsTrigger value="photos">
|
<TabsTrigger value="photos">
|
||||||
Photos {!statsLoading && photoCount > 0 && `(${photoCount})`}
|
Photos {!statsLoading && photoCount > 0 && `(${photoCount})`}
|
||||||
@@ -580,7 +580,7 @@ export default function ParkDetail() {
|
|||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="reviews" className="mt-6">
|
<TabsContent value="reviews" className="mt-6">
|
||||||
<ReviewsSection entityType="park" entityId={park.id} entityName={park.name} averageRating={park.average_rating} reviewCount={park.review_count} />
|
<ReviewsSection entityType="park" entityId={park.id} entityName={park.name} averageRating={park.average_rating ?? 0} reviewCount={park.review_count ?? 0} />
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="photos" className="mt-6">
|
<TabsContent value="photos" className="mt-6">
|
||||||
@@ -635,18 +635,18 @@ export default function ParkDetail() {
|
|||||||
id: park?.id,
|
id: park?.id,
|
||||||
name: park?.name,
|
name: park?.name,
|
||||||
slug: park?.slug,
|
slug: park?.slug,
|
||||||
description: park?.description,
|
description: park?.description ?? undefined,
|
||||||
park_type: park?.park_type,
|
park_type: park?.park_type,
|
||||||
status: park?.status,
|
status: park?.status,
|
||||||
opening_date: park?.opening_date,
|
opening_date: park?.opening_date ?? undefined,
|
||||||
closing_date: park?.closing_date,
|
closing_date: park?.closing_date ?? undefined,
|
||||||
website_url: park?.website_url,
|
website_url: park?.website_url ?? undefined,
|
||||||
phone: park?.phone,
|
phone: park?.phone ?? undefined,
|
||||||
email: park?.email,
|
email: park?.email ?? undefined,
|
||||||
operator_id: park?.operator?.id,
|
operator_id: park?.operator?.id,
|
||||||
property_owner_id: park?.property_owner?.id,
|
property_owner_id: park?.property_owner?.id,
|
||||||
banner_image_url: park?.banner_image_url,
|
banner_image_url: park?.banner_image_url ?? undefined,
|
||||||
card_image_url: park?.card_image_url
|
card_image_url: park?.card_image_url ?? undefined
|
||||||
}}
|
}}
|
||||||
isEditing={true}
|
isEditing={true}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user