Refactor code structure and remove redundant changes

This commit is contained in:
pacnpal
2025-11-09 16:31:34 -05:00
parent 2884bc23ce
commit eb68cf40c6
1080 changed files with 27361 additions and 56687 deletions

View File

@@ -0,0 +1,152 @@
import { useEffect, useState } from 'react';
import { Helmet } from 'react-helmet-async';
import { MetaTagsProps, MetaTags as MetaTagsType, StructuredData } from './types';
const API_BASE_URL = import.meta.env.VITE_DJANGO_API_URL || 'http://localhost:8000/api/v1';
/**
* MetaTags Component
*
* Fetches and renders SEO meta tags from Django API.
* Includes OpenGraph tags for social sharing and optional JSON-LD structured data.
*/
export function MetaTags({
entityType,
entitySlug,
parkSlug,
includeStructuredData = true
}: MetaTagsProps) {
const [metaTags, setMetaTags] = useState<MetaTagsType | null>(null);
const [structuredData, setStructuredData] = useState<StructuredData | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchMetaTags = async () => {
setLoading(true);
try {
// Build the appropriate endpoint URL
let metaUrl = `${API_BASE_URL}/seo/meta/`;
let structuredDataUrl = '';
switch (entityType) {
case 'home':
metaUrl += 'home';
break;
case 'park':
if (!entitySlug) throw new Error('Park slug is required');
metaUrl += `park/${entitySlug}`;
if (includeStructuredData) {
structuredDataUrl = `${API_BASE_URL}/seo/structured-data/park/${entitySlug}`;
}
break;
case 'ride':
if (!parkSlug || !entitySlug) throw new Error('Park slug and ride slug are required');
metaUrl += `ride/${parkSlug}/${entitySlug}`;
if (includeStructuredData) {
structuredDataUrl = `${API_BASE_URL}/seo/structured-data/ride/${parkSlug}/${entitySlug}`;
}
break;
case 'company':
if (!entitySlug) throw new Error('Company slug is required');
metaUrl += `company/${entitySlug}`;
break;
case 'ride-model':
if (!entitySlug) throw new Error('Ride model slug is required');
metaUrl += `ride-model/${entitySlug}`;
break;
}
// Fetch meta tags
const metaResponse = await fetch(metaUrl);
if (!metaResponse.ok) {
throw new Error(`Failed to fetch meta tags: ${metaResponse.status}`);
}
const metaData = await metaResponse.json();
setMetaTags(metaData);
// Fetch structured data if available and requested
if (structuredDataUrl) {
try {
const structuredResponse = await fetch(structuredDataUrl);
if (structuredResponse.ok) {
const data = await structuredResponse.json();
setStructuredData(data);
}
} catch (error) {
// eslint-disable-next-line no-console
console.warn('Failed to fetch structured data:', error);
// Don't fail the entire component if structured data fails
}
}
} catch (error) {
// eslint-disable-next-line no-console
console.error('Error fetching meta tags:', error);
// Set fallback meta tags
setMetaTags({
title: 'ThrillWiki - Theme Park & Roller Coaster Database',
description: 'Explore the world\'s most comprehensive database of theme parks, roller coasters, and thrill rides.',
keywords: 'theme parks, roller coasters, thrill rides, amusement parks',
canonical: window.location.href,
'og:title': 'ThrillWiki',
'og:description': 'Explore the world\'s most comprehensive database of theme parks, roller coasters, and thrill rides.',
'og:type': 'website',
'og:url': window.location.href,
'og:image': `${window.location.origin}/og-image.png`,
'og:image:width': '1200',
'og:image:height': '630',
'og:site_name': 'ThrillWiki',
'og:locale': 'en_US',
'twitter:card': 'summary_large_image',
'twitter:site': '@thrillwiki',
'twitter:title': 'ThrillWiki',
'twitter:description': 'Explore the world\'s most comprehensive database of theme parks, roller coasters, and thrill rides.',
'twitter:image': `${window.location.origin}/og-image.png`,
});
} finally {
setLoading(false);
}
};
fetchMetaTags();
}, [entityType, entitySlug, parkSlug, includeStructuredData]);
// Don't render anything while loading to avoid flash of default tags
if (loading || !metaTags) {
return null;
}
return (
<Helmet>
{/* Basic SEO */}
<title>{metaTags.title}</title>
<meta name="description" content={metaTags.description} />
<meta name="keywords" content={metaTags.keywords} />
<link rel="canonical" href={metaTags.canonical} />
{/* OpenGraph tags for Facebook, LinkedIn, Discord */}
<meta property="og:title" content={metaTags['og:title']} />
<meta property="og:description" content={metaTags['og:description']} />
<meta property="og:type" content={metaTags['og:type']} />
<meta property="og:url" content={metaTags['og:url']} />
<meta property="og:image" content={metaTags['og:image']} />
<meta property="og:image:width" content={metaTags['og:image:width']} />
<meta property="og:image:height" content={metaTags['og:image:height']} />
<meta property="og:site_name" content={metaTags['og:site_name']} />
<meta property="og:locale" content={metaTags['og:locale']} />
{/* Twitter Card tags */}
<meta name="twitter:card" content={metaTags['twitter:card']} />
<meta name="twitter:site" content={metaTags['twitter:site']} />
<meta name="twitter:title" content={metaTags['twitter:title']} />
<meta name="twitter:description" content={metaTags['twitter:description']} />
<meta name="twitter:image" content={metaTags['twitter:image']} />
{/* JSON-LD Structured Data */}
{structuredData && (
<script type="application/ld+json">
{JSON.stringify(structuredData)}
</script>
)}
</Helmet>
);
}

View File

@@ -0,0 +1,2 @@
export { MetaTags } from './MetaTags';
export type { MetaTagsProps, EntityType, MetaTags as MetaTagsType, StructuredData } from './types';

View File

@@ -0,0 +1,54 @@
/**
* SEO Meta Tags Types
*
* Types for SEO meta tags returned by Django API endpoints
*/
/**
* Meta tags returned from Django SEO API endpoints
*/
export interface MetaTags {
// Basic SEO
title: string;
description: string;
keywords: string;
canonical: string;
// OpenGraph (for Facebook, LinkedIn, Discord)
'og:title': string;
'og:description': string;
'og:type': 'website' | 'article';
'og:url': string;
'og:image': string;
'og:image:width': string;
'og:image:height': string;
'og:site_name': string;
'og:locale': string;
// Twitter Cards
'twitter:card': 'summary_large_image' | 'summary';
'twitter:site': string;
'twitter:title': string;
'twitter:description': string;
'twitter:image': string;
}
/**
* JSON-LD Structured Data (Schema.org)
*/
export type StructuredData = Record<string, unknown>;
/**
* Entity types for MetaTags component
*/
export type EntityType = 'home' | 'park' | 'ride' | 'company' | 'ride-model';
/**
* Props for MetaTags component
*/
export interface MetaTagsProps {
entityType: EntityType;
entitySlug?: string;
parkSlug?: string; // Required for rides
includeStructuredData?: boolean;
}