Implement dynamic page titles

This commit is contained in:
gpt-engineer-app[bot]
2025-10-29 12:42:18 +00:00
parent 1cdd1f59fb
commit 2d66a4f778
43 changed files with 131 additions and 4 deletions

View File

@@ -3,12 +3,12 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>thrilltrack-explorer</title> <title>ThrillWiki - Theme Park & Roller Coaster Database</title>
<meta name="description" content="Lovable Generated Project" /> <meta name="description" content="Explore theme parks and roller coasters worldwide with ThrillWiki - the comprehensive database for enthusiasts" />
<meta name="author" content="Lovable" /> <meta name="author" content="Lovable" />
<meta property="og:title" content="thrilltrack-explorer" /> <meta property="og:title" content="ThrillWiki - Theme Park & Roller Coaster Database" />
<meta property="og:description" content="Lovable Generated Project" /> <meta property="og:description" content="Explore theme parks and roller coasters worldwide with ThrillWiki - the comprehensive database for enthusiasts" />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:image" content="https://lovable.dev/opengraph-image-p98pqg.png" /> <meta property="og:image" content="https://lovable.dev/opengraph-image-p98pqg.png" />

View File

@@ -0,0 +1,12 @@
import { useEffect } from 'react';
export function useDocumentTitle(title: string, suffix: string = 'ThrillWiki') {
useEffect(() => {
const fullTitle = title ? `${title} | ${suffix}` : suffix;
document.title = fullTitle;
return () => {
document.title = suffix;
};
}, [title, suffix]);
}

View File

@@ -13,8 +13,10 @@ import { UserManagement } from '@/components/admin/UserManagement';
import { AdminHeader } from '@/components/layout/AdminHeader'; import { AdminHeader } from '@/components/layout/AdminHeader';
import { useModerationStats } from '@/hooks/useModerationStats'; import { useModerationStats } from '@/hooks/useModerationStats';
import { useAdminSettings } from '@/hooks/useAdminSettings'; import { useAdminSettings } from '@/hooks/useAdminSettings';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function Admin() { export default function Admin() {
useDocumentTitle('Admin Panel');
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const { user, loading: authLoading } = useAuth(); const { user, loading: authLoading } = useAuth();
const { isModerator, loading: roleLoading } = useUserRole(); const { isModerator, loading: roleLoading } = useUserRole();

View File

@@ -19,6 +19,7 @@ import { extractCloudflareImageId } from '@/lib/cloudflareImageUtils';
import { Edit, Trash2, Eye, Plus } from 'lucide-react'; import { Edit, Trash2, Eye, Plus } from 'lucide-react';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { formatDistanceToNow } from 'date-fns'; import { formatDistanceToNow } from 'date-fns';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
interface BlogPost { interface BlogPost {
id: string; id: string;
@@ -34,6 +35,7 @@ interface BlogPost {
} }
export default function AdminBlog() { export default function AdminBlog() {
useDocumentTitle('Blog Management - Admin');
const { user } = useAuth(); const { user } = useAuth();
const { isAdmin, loading } = useUserRole(); const { isAdmin, loading } = useUserRole();
const navigate = useNavigate(); const navigate = useNavigate();

View File

@@ -18,8 +18,10 @@ import { supabase } from '@/integrations/supabase/client';
import { Alert, AlertDescription } from '@/components/ui/alert'; import { Alert, AlertDescription } from '@/components/ui/alert';
import { Skeleton } from '@/components/ui/skeleton'; import { Skeleton } from '@/components/ui/skeleton';
import { QueueSkeleton } from '@/components/moderation/QueueSkeleton'; import { QueueSkeleton } from '@/components/moderation/QueueSkeleton';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function AdminDashboard() { export default function AdminDashboard() {
useDocumentTitle('Dashboard - Admin');
const { user, loading: authLoading } = useAuth(); const { user, loading: authLoading } = useAuth();
const { isModerator, loading: roleLoading } = useUserRole(); const { isModerator, loading: roleLoading } = useUserRole();
const { needsEnrollment, loading: mfaLoading } = useRequireMFA(); const { needsEnrollment, loading: mfaLoading } = useRequireMFA();

View File

@@ -6,8 +6,10 @@ import { ModerationQueue, ModerationQueueRef } from '@/components/moderation/Mod
import { QueueSkeleton } from '@/components/moderation/QueueSkeleton'; import { QueueSkeleton } from '@/components/moderation/QueueSkeleton';
import { useAdminSettings } from '@/hooks/useAdminSettings'; import { useAdminSettings } from '@/hooks/useAdminSettings';
import { useModerationStats } from '@/hooks/useModerationStats'; import { useModerationStats } from '@/hooks/useModerationStats';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function AdminModeration() { export default function AdminModeration() {
useDocumentTitle('Moderation Queue - Admin');
const { isLoading, isAuthorized, needsMFA, user } = useAdminGuard(); const { isLoading, isAuthorized, needsMFA, user } = useAdminGuard();
const moderationQueueRef = useRef<ModerationQueueRef>(null); const moderationQueueRef = useRef<ModerationQueueRef>(null);

View File

@@ -6,8 +6,10 @@ import { ReportsQueue, ReportsQueueRef } from '@/components/moderation/ReportsQu
import { QueueSkeleton } from '@/components/moderation/QueueSkeleton'; import { QueueSkeleton } from '@/components/moderation/QueueSkeleton';
import { useAdminSettings } from '@/hooks/useAdminSettings'; import { useAdminSettings } from '@/hooks/useAdminSettings';
import { useModerationStats } from '@/hooks/useModerationStats'; import { useModerationStats } from '@/hooks/useModerationStats';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function AdminReports() { export default function AdminReports() {
useDocumentTitle('Reports Queue - Admin');
const { isLoading, isAuthorized, needsMFA } = useAdminGuard(); const { isLoading, isAuthorized, needsMFA } = useAdminGuard();
const reportsQueueRef = useRef<ReportsQueueRef>(null); const reportsQueueRef = useRef<ReportsQueueRef>(null);

View File

@@ -14,8 +14,10 @@ import { useAdminSettings } from '@/hooks/useAdminSettings';
import { NovuMigrationUtility } from '@/components/admin/NovuMigrationUtility'; import { NovuMigrationUtility } from '@/components/admin/NovuMigrationUtility';
import { TestDataGenerator } from '@/components/admin/TestDataGenerator'; import { TestDataGenerator } from '@/components/admin/TestDataGenerator';
import { Loader2, Save, Clock, Users, Bell, Shield, Settings, Trash2, Plug, AlertTriangle, Lock } from 'lucide-react'; import { Loader2, Save, Clock, Users, Bell, Shield, Settings, Trash2, Plug, AlertTriangle, Lock } from 'lucide-react';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function AdminSettings() { export default function AdminSettings() {
useDocumentTitle('Settings - Admin');
const { user } = useAuth(); const { user } = useAuth();
const { isSuperuser, loading: roleLoading } = useUserRole(); const { isSuperuser, loading: roleLoading } = useUserRole();
const { const {

View File

@@ -6,6 +6,7 @@ import { Skeleton } from '@/components/ui/skeleton';
import { Card, CardContent } from '@/components/ui/card'; import { Card, CardContent } from '@/components/ui/card';
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { AlertCircle } from 'lucide-react'; import { AlertCircle } from 'lucide-react';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
interface ErrorBoundaryProps { interface ErrorBoundaryProps {
children: ReactNode; children: ReactNode;
@@ -48,6 +49,7 @@ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
} }
export default function AdminSystemLog() { export default function AdminSystemLog() {
useDocumentTitle('System Activity Log - Admin');
const { isLoading, isAuthorized } = useAdminGuard(false); // No MFA required for viewing logs const { isLoading, isAuthorized } = useAdminGuard(false); // No MFA required for viewing logs
if (isLoading) { if (isLoading) {

View File

@@ -4,8 +4,10 @@ import { AdminLayout } from '@/components/layout/AdminLayout';
import { UserManagement } from '@/components/admin/UserManagement'; import { UserManagement } from '@/components/admin/UserManagement';
import { Skeleton } from '@/components/ui/skeleton'; import { Skeleton } from '@/components/ui/skeleton';
import { Card, CardContent } from '@/components/ui/card'; import { Card, CardContent } from '@/components/ui/card';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function AdminUsers() { export default function AdminUsers() {
useDocumentTitle('User Management - Admin');
const { isLoading, isAuthorized, needsMFA } = useAdminGuard(); const { isLoading, isAuthorized, needsMFA } = useAdminGuard();
if (isLoading) { if (isLoading) {

View File

@@ -19,8 +19,10 @@ import { StorageWarning } from '@/components/auth/StorageWarning';
import { MFAChallenge } from '@/components/auth/MFAChallenge'; import { MFAChallenge } from '@/components/auth/MFAChallenge';
import { verifyMfaUpgrade } from '@/lib/authService'; import { verifyMfaUpgrade } from '@/lib/authService';
import { setAuthMethod } from '@/lib/sessionFlags'; import { setAuthMethod } from '@/lib/sessionFlags';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function Auth() { export default function Auth() {
useDocumentTitle('Sign In');
const [searchParams] = useSearchParams(); const [searchParams] = useSearchParams();
const navigate = useNavigate(); const navigate = useNavigate();
const { const {

View File

@@ -13,8 +13,10 @@ import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { getErrorMessage } from '@/lib/errorHandler'; import { getErrorMessage } from '@/lib/errorHandler';
import { MFAStepUpModal } from '@/components/auth/MFAStepUpModal'; import { MFAStepUpModal } from '@/components/auth/MFAStepUpModal';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function AuthCallback() { export default function AuthCallback() {
useDocumentTitle('Sign In - Processing');
const navigate = useNavigate(); const navigate = useNavigate();
const { toast } = useToast(); const { toast } = useToast();
const [status, setStatus] = useState<'processing' | 'success' | 'error' | 'mfa_required'>('processing'); const [status, setStatus] = useState<'processing' | 'success' | 'error' | 'mfa_required'>('processing');

View File

@@ -8,10 +8,12 @@ import { Search, ChevronLeft, ChevronRight } from 'lucide-react';
import { Skeleton } from '@/components/ui/skeleton'; import { Skeleton } from '@/components/ui/skeleton';
import { Header } from '@/components/layout/Header'; import { Header } from '@/components/layout/Header';
import { Footer } from '@/components/layout/Footer'; import { Footer } from '@/components/layout/Footer';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
const POSTS_PER_PAGE = 9; const POSTS_PER_PAGE = 9;
export default function BlogIndex() { export default function BlogIndex() {
useDocumentTitle('Blog');
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
const [searchQuery, setSearchQuery] = useState(''); const [searchQuery, setSearchQuery] = useState('');

View File

@@ -11,6 +11,7 @@ import { getCloudflareImageUrl } from '@/lib/cloudflareImageUtils';
import { Skeleton } from '@/components/ui/skeleton'; import { Skeleton } from '@/components/ui/skeleton';
import { Header } from '@/components/layout/Header'; import { Header } from '@/components/layout/Header';
import { Footer } from '@/components/layout/Footer'; import { Footer } from '@/components/layout/Footer';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function BlogPost() { export default function BlogPost() {
const { slug } = useParams<{ slug: string }>(); const { slug } = useParams<{ slug: string }>();
@@ -32,6 +33,9 @@ export default function BlogPost() {
enabled: !!slug, enabled: !!slug,
}); });
// Update document title when post changes
useDocumentTitle(post?.title || 'Blog Post');
useEffect(() => { useEffect(() => {
if (slug) { if (slug) {
supabase.rpc('increment_blog_view_count', { post_slug: slug }); supabase.rpc('increment_blog_view_count', { post_slug: slug });

View File

@@ -5,8 +5,10 @@ import { ContactFAQ } from '@/components/contact/ContactFAQ';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Header } from '@/components/layout/Header'; import { Header } from '@/components/layout/Header';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function Contact() { export default function Contact() {
useDocumentTitle('Contact Us');
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<Header /> <Header />

View File

@@ -24,6 +24,7 @@ import { VersionIndicator } from '@/components/versioning/VersionIndicator';
import { EntityHistoryTabs } from '@/components/history/EntityHistoryTabs'; import { EntityHistoryTabs } from '@/components/history/EntityHistoryTabs';
import { trackPageView } from '@/lib/viewTracking'; import { trackPageView } from '@/lib/viewTracking';
import { useAuthModal } from '@/hooks/useAuthModal'; import { useAuthModal } from '@/hooks/useAuthModal';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function DesignerDetail() { export default function DesignerDetail() {
const { slug } = useParams<{ slug: string }>(); const { slug } = useParams<{ slug: string }>();
@@ -38,6 +39,9 @@ export default function DesignerDetail() {
const { isModerator } = useUserRole(); const { isModerator } = useUserRole();
const { requireAuth } = useAuthModal(); const { requireAuth } = useAuthModal();
// Update document title when designer changes
useDocumentTitle(designer?.name || 'Designer Details');
useEffect(() => { useEffect(() => {
if (slug) { if (slug) {
fetchDesignerData(); fetchDesignerData();

View File

@@ -15,6 +15,7 @@ import { AutocompleteSearch } from '@/components/search/AutocompleteSearch';
import { useAuth } from '@/hooks/useAuth'; import { useAuth } from '@/hooks/useAuth';
import { toast } from '@/hooks/use-toast'; import { toast } from '@/hooks/use-toast';
import { useAuthModal } from '@/hooks/useAuthModal'; import { useAuthModal } from '@/hooks/useAuthModal';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function DesignerRides() { export default function DesignerRides() {
const { designerSlug } = useParams<{ designerSlug: string }>(); const { designerSlug } = useParams<{ designerSlug: string }>();
@@ -28,6 +29,9 @@ export default function DesignerRides() {
const [sortBy, setSortBy] = useState('name'); const [sortBy, setSortBy] = useState('name');
const [filterCategory, setFilterCategory] = useState('all'); const [filterCategory, setFilterCategory] = useState('all');
const [filterStatus, setFilterStatus] = useState('all'); const [filterStatus, setFilterStatus] = useState('all');
// Update document title when designer changes
useDocumentTitle(designer ? `${designer.name} - Rides` : 'Designer Rides');
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
const fetchData = useCallback(async () => { const fetchData = useCallback(async () => {

View File

@@ -23,8 +23,10 @@ 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'; import { getErrorMessage } from '@/lib/errorHandler';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function Designers() { export default function Designers() {
useDocumentTitle('Designers');
const navigate = useNavigate(); const navigate = useNavigate();
const { user } = useAuth(); const { user } = useAuth();
const { isModerator } = useUserRole(); const { isModerator } = useUserRole();

View File

@@ -2,6 +2,7 @@ import { useEffect } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { supabase } from "@/integrations/supabase/client"; import { supabase } from "@/integrations/supabase/client";
import { authStorage } from "@/lib/authStorage"; import { authStorage } from "@/lib/authStorage";
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
/** /**
* ForceLogout - Hidden endpoint for completely clearing auth session * ForceLogout - Hidden endpoint for completely clearing auth session
@@ -9,6 +10,7 @@ import { authStorage } from "@/lib/authStorage";
* Not linked anywhere in the UI - for manual navigation only * Not linked anywhere in the UI - for manual navigation only
*/ */
const ForceLogout = () => { const ForceLogout = () => {
useDocumentTitle('Signing Out');
const navigate = useNavigate(); const navigate = useNavigate();
useEffect(() => { useEffect(() => {

View File

@@ -1,8 +1,11 @@
import { Header } from '@/components/layout/Header'; import { Header } from '@/components/layout/Header';
import { SimpleHeroSearch } from '@/components/homepage/SimpleHeroSearch'; import { SimpleHeroSearch } from '@/components/homepage/SimpleHeroSearch';
import { ContentTabs } from '@/components/homepage/ContentTabs'; import { ContentTabs } from '@/components/homepage/ContentTabs';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
const Index = () => { const Index = () => {
useDocumentTitle('Home');
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<Header /> <Header />

View File

@@ -24,6 +24,7 @@ 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';
import { useAuthModal } from '@/hooks/useAuthModal'; import { useAuthModal } from '@/hooks/useAuthModal';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function ManufacturerDetail() { export default function ManufacturerDetail() {
const { slug } = useParams<{ slug: string }>(); const { slug } = useParams<{ slug: string }>();
@@ -39,6 +40,9 @@ export default function ManufacturerDetail() {
const { isModerator } = useUserRole(); const { isModerator } = useUserRole();
const { requireAuth } = useAuthModal(); const { requireAuth } = useAuthModal();
// Update document title when manufacturer changes
useDocumentTitle(manufacturer?.name || 'Manufacturer Details');
useEffect(() => { useEffect(() => {
if (slug) { if (slug) {
fetchManufacturerData(); fetchManufacturerData();

View File

@@ -15,6 +15,7 @@ import { AutocompleteSearch } from '@/components/search/AutocompleteSearch';
import { useAuth } from '@/hooks/useAuth'; import { useAuth } from '@/hooks/useAuth';
import { toast } from '@/hooks/use-toast'; import { toast } from '@/hooks/use-toast';
import { useAuthModal } from '@/hooks/useAuthModal'; import { useAuthModal } from '@/hooks/useAuthModal';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
interface RideModelWithCount extends RideModel { interface RideModelWithCount extends RideModel {
ride_count: number; ride_count: number;
@@ -28,6 +29,9 @@ export default function ManufacturerModels() {
const [manufacturer, setManufacturer] = useState<Company | null>(null); const [manufacturer, setManufacturer] = useState<Company | null>(null);
const [models, setModels] = useState<RideModelWithCount[]>([]); const [models, setModels] = useState<RideModelWithCount[]>([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
// Update document title when manufacturer changes
useDocumentTitle(manufacturer ? `${manufacturer.name} - Models` : 'Manufacturer Models');
const [searchQuery, setSearchQuery] = useState(''); const [searchQuery, setSearchQuery] = useState('');
const [sortBy, setSortBy] = useState('name'); const [sortBy, setSortBy] = useState('name');
const [filterCategory, setFilterCategory] = useState('all'); const [filterCategory, setFilterCategory] = useState('all');

View File

@@ -15,6 +15,7 @@ import { AutocompleteSearch } from '@/components/search/AutocompleteSearch';
import { useAuth } from '@/hooks/useAuth'; import { useAuth } from '@/hooks/useAuth';
import { toast } from '@/hooks/use-toast'; import { toast } from '@/hooks/use-toast';
import { useAuthModal } from '@/hooks/useAuthModal'; import { useAuthModal } from '@/hooks/useAuthModal';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function ManufacturerRides() { export default function ManufacturerRides() {
const { manufacturerSlug } = useParams<{ manufacturerSlug: string }>(); const { manufacturerSlug } = useParams<{ manufacturerSlug: string }>();
@@ -28,6 +29,9 @@ export default function ManufacturerRides() {
const [sortBy, setSortBy] = useState('name'); const [sortBy, setSortBy] = useState('name');
const [filterCategory, setFilterCategory] = useState('all'); const [filterCategory, setFilterCategory] = useState('all');
const [filterStatus, setFilterStatus] = useState('all'); const [filterStatus, setFilterStatus] = useState('all');
// Update document title when manufacturer changes
useDocumentTitle(manufacturer ? `${manufacturer.name} - Rides` : 'Manufacturer Rides');
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
const fetchData = useCallback(async () => { const fetchData = useCallback(async () => {

View File

@@ -23,8 +23,10 @@ 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'; import { getErrorMessage } from '@/lib/errorHandler';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function Manufacturers() { export default function Manufacturers() {
useDocumentTitle('Manufacturers');
const navigate = useNavigate(); const navigate = useNavigate();
const { user } = useAuth(); const { user } = useAuth();
const { isModerator } = useUserRole(); const { isModerator } = useUserRole();

View File

@@ -1,7 +1,9 @@
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { useEffect } from "react"; import { useEffect } from "react";
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
const NotFound = () => { const NotFound = () => {
useDocumentTitle('404 - Page Not Found');
const location = useLocation(); const location = useLocation();
useEffect(() => { useEffect(() => {

View File

@@ -25,6 +25,7 @@ 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';
import { useAuthModal } from '@/hooks/useAuthModal'; import { useAuthModal } from '@/hooks/useAuthModal';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function OperatorDetail() { export default function OperatorDetail() {
const { slug } = useParams<{ slug: string }>(); const { slug } = useParams<{ slug: string }>();
@@ -42,6 +43,9 @@ export default function OperatorDetail() {
const { isModerator } = useUserRole(); const { isModerator } = useUserRole();
const { requireAuth } = useAuthModal(); const { requireAuth } = useAuthModal();
// Update document title when operator changes
useDocumentTitle(operator?.name || 'Operator Details');
useEffect(() => { useEffect(() => {
if (slug) { if (slug) {
fetchOperatorData(); fetchOperatorData();

View File

@@ -15,6 +15,7 @@ import { ParkFilters } from '@/components/parks/ParkFilters';
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Grid3X3, List } from 'lucide-react'; import { Grid3X3, List } from 'lucide-react';
import { FilterState, SortState } from './Parks'; import { FilterState, SortState } from './Parks';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
const initialFilters: FilterState = { const initialFilters: FilterState = {
search: '', search: '',
@@ -45,6 +46,9 @@ export default function OperatorParks() {
const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid'); const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');
const [showFilters, setShowFilters] = useState(false); const [showFilters, setShowFilters] = useState(false);
// Update document title when operator changes
useDocumentTitle(operator ? `${operator.name} - Parks` : 'Operator Parks');
useEffect(() => { useEffect(() => {
if (operatorSlug) { if (operatorSlug) {
fetchData(); fetchData();

View File

@@ -24,8 +24,10 @@ 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'; import { getErrorMessage } from '@/lib/errorHandler';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
const Operators = () => { const Operators = () => {
useDocumentTitle('Operators');
const navigate = useNavigate(); const navigate = useNavigate();
const { user } = useAuth(); const { user } = useAuth();
const { isModerator } = useUserRole(); const { isModerator } = useUserRole();

View File

@@ -15,6 +15,7 @@ import { ParkFilters } from '@/components/parks/ParkFilters';
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Grid3X3, List } from 'lucide-react'; import { Grid3X3, List } from 'lucide-react';
import { FilterState, SortState } from './Parks'; import { FilterState, SortState } from './Parks';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
const initialFilters: FilterState = { const initialFilters: FilterState = {
search: '', search: '',
@@ -45,6 +46,9 @@ export default function OwnerParks() {
const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid'); const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');
const [showFilters, setShowFilters] = useState(false); const [showFilters, setShowFilters] = useState(false);
// Update document title when owner changes
useDocumentTitle(owner ? `${owner.name} - Parks` : 'Owner Parks');
useEffect(() => { useEffect(() => {
if (ownerSlug) { if (ownerSlug) {
fetchData(); fetchData();

View File

@@ -29,6 +29,7 @@ import { Edit } from 'lucide-react';
import { VersionIndicator } from '@/components/versioning/VersionIndicator'; import { VersionIndicator } from '@/components/versioning/VersionIndicator';
import { EntityHistoryTabs } from '@/components/history/EntityHistoryTabs'; import { EntityHistoryTabs } from '@/components/history/EntityHistoryTabs';
import { useAuthModal } from '@/hooks/useAuthModal'; import { useAuthModal } from '@/hooks/useAuthModal';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function ParkDetail() { export default function ParkDetail() {
const { const {
@@ -47,6 +48,10 @@ export default function ParkDetail() {
const [photoCount, setPhotoCount] = useState<number>(0); const [photoCount, setPhotoCount] = useState<number>(0);
const [statsLoading, setStatsLoading] = useState(true); const [statsLoading, setStatsLoading] = useState(true);
const { isModerator } = useUserRole(); const { isModerator } = useUserRole();
// Update document title when park changes
useDocumentTitle(park?.name || 'Park Details');
const fetchPhotoCount = useCallback(async (parkId: string) => { const fetchPhotoCount = useCallback(async (parkId: string) => {
try { try {
const { count, error } = await supabase const { count, error } = await supabase

View File

@@ -18,8 +18,10 @@ 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'; import { getErrorMessage } from '@/lib/errorHandler';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
const ParkOwners = () => { const ParkOwners = () => {
useDocumentTitle('Property Owners');
const navigate = useNavigate(); const navigate = useNavigate();
const { user } = useAuth(); const { user } = useAuth();
const { isModerator } = useUserRole(); const { isModerator } = useUserRole();

View File

@@ -16,6 +16,7 @@ import { useAuth } from '@/hooks/useAuth';
import { toast } from '@/hooks/use-toast'; import { toast } from '@/hooks/use-toast';
import { getErrorMessage } from '@/lib/errorHandler'; import { getErrorMessage } from '@/lib/errorHandler';
import { useAuthModal } from '@/hooks/useAuthModal'; import { useAuthModal } from '@/hooks/useAuthModal';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function ParkRides() { export default function ParkRides() {
const { parkSlug } = useParams<{ parkSlug: string }>(); const { parkSlug } = useParams<{ parkSlug: string }>();
@@ -28,6 +29,9 @@ export default function ParkRides() {
const [searchQuery, setSearchQuery] = useState(''); const [searchQuery, setSearchQuery] = useState('');
const [sortBy, setSortBy] = useState('name'); const [sortBy, setSortBy] = useState('name');
const [filterCategory, setFilterCategory] = useState('all'); const [filterCategory, setFilterCategory] = useState('all');
// Update document title when park changes
useDocumentTitle(park ? `${park.name} - Rides` : 'Park Rides');
const [filterStatus, setFilterStatus] = useState('all'); const [filterStatus, setFilterStatus] = useState('all');
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);

View File

@@ -1,6 +1,8 @@
import { Header } from '@/components/layout/Header'; import { Header } from '@/components/layout/Header';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function Privacy() { export default function Privacy() {
useDocumentTitle('Privacy Policy');
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<Header /> <Header />

View File

@@ -30,6 +30,7 @@ import { LocationDisplay } from '@/components/profile/LocationDisplay';
import { UserBlockButton } from '@/components/profile/UserBlockButton'; import { UserBlockButton } from '@/components/profile/UserBlockButton';
import { PersonalLocationDisplay } from '@/components/profile/PersonalLocationDisplay'; import { PersonalLocationDisplay } from '@/components/profile/PersonalLocationDisplay';
import { useUserRole } from '@/hooks/useUserRole'; import { useUserRole } from '@/hooks/useUserRole';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
// Activity type definitions // Activity type definitions
interface SubmissionActivity { interface SubmissionActivity {
@@ -156,6 +157,9 @@ export default function Profile() {
// User role checking // User role checking
const { isModerator, loading: rolesLoading } = useUserRole(); const { isModerator, loading: rolesLoading } = useUserRole();
// Update document title when profile changes
useDocumentTitle(profile?.username ? `${profile.username}'s Profile` : 'Profile');
// Username validation // Username validation
const usernameValidation = useUsernameValidation(editForm.username, profile?.username); const usernameValidation = useUsernameValidation(editForm.username, profile?.username);
useEffect(() => { useEffect(() => {

View File

@@ -25,6 +25,7 @@ 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';
import { useAuthModal } from '@/hooks/useAuthModal'; import { useAuthModal } from '@/hooks/useAuthModal';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function PropertyOwnerDetail() { export default function PropertyOwnerDetail() {
const { slug } = useParams<{ slug: string }>(); const { slug } = useParams<{ slug: string }>();
@@ -42,6 +43,9 @@ export default function PropertyOwnerDetail() {
const { isModerator } = useUserRole(); const { isModerator } = useUserRole();
const { requireAuth } = useAuthModal(); const { requireAuth } = useAuthModal();
// Update document title when owner changes
useDocumentTitle(owner?.name || 'Property Owner Details');
useEffect(() => { useEffect(() => {
if (slug) { if (slug) {
fetchOwnerData(); fetchOwnerData();

View File

@@ -52,6 +52,7 @@ import { getErrorMessage } from '@/lib/errorHandler';
import { VersionIndicator } from '@/components/versioning/VersionIndicator'; import { VersionIndicator } from '@/components/versioning/VersionIndicator';
import { EntityHistoryTabs } from '@/components/history/EntityHistoryTabs'; import { EntityHistoryTabs } from '@/components/history/EntityHistoryTabs';
import { useAuthModal } from '@/hooks/useAuthModal'; import { useAuthModal } from '@/hooks/useAuthModal';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
// Extended Ride type with additional properties for easier access // Extended Ride type with additional properties for easier access
interface RideWithParkId extends Ride { interface RideWithParkId extends Ride {
@@ -71,6 +72,9 @@ export default function RideDetail() {
const [photoCount, setPhotoCount] = useState<number>(0); const [photoCount, setPhotoCount] = useState<number>(0);
const [statsLoading, setStatsLoading] = useState(true); const [statsLoading, setStatsLoading] = useState(true);
// Update document title when ride changes
useDocumentTitle(ride?.name || 'Ride Details');
useEffect(() => { useEffect(() => {
if (parkSlug && rideSlug) { if (parkSlug && rideSlug) {
fetchRideData(); fetchRideData();

View File

@@ -22,6 +22,7 @@ import { ManufacturerPhotoGallery } from '@/components/companies/ManufacturerPho
const RideModelForm = lazy(() => import('@/components/admin/RideModelForm').then(m => ({ default: m.RideModelForm }))); const RideModelForm = lazy(() => import('@/components/admin/RideModelForm').then(m => ({ default: m.RideModelForm })));
import { VersionIndicator } from '@/components/versioning/VersionIndicator'; import { VersionIndicator } from '@/components/versioning/VersionIndicator';
import { EntityVersionHistory } from '@/components/versioning/EntityVersionHistory'; import { EntityVersionHistory } from '@/components/versioning/EntityVersionHistory';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function RideModelDetail() { export default function RideModelDetail() {
const { manufacturerSlug, modelSlug } = useParams<{ manufacturerSlug: string; modelSlug: string }>(); const { manufacturerSlug, modelSlug } = useParams<{ manufacturerSlug: string; modelSlug: string }>();
@@ -33,6 +34,9 @@ export default function RideModelDetail() {
const [rides, setRides] = useState<Ride[]>([]); const [rides, setRides] = useState<Ride[]>([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [isEditModalOpen, setIsEditModalOpen] = useState(false); const [isEditModalOpen, setIsEditModalOpen] = useState(false);
// Update document title when model changes
useDocumentTitle(model?.name || 'Ride Model Details');
const [statistics, setStatistics] = useState({ rideCount: 0, photoCount: 0 }); const [statistics, setStatistics] = useState({ rideCount: 0, photoCount: 0 });
// Fetch technical specifications from relational table // Fetch technical specifications from relational table

View File

@@ -16,6 +16,7 @@ import { useAuthModal } from '@/hooks/useAuthModal';
import { toast } from '@/hooks/use-toast'; import { toast } from '@/hooks/use-toast';
import { getErrorMessage } from '@/lib/errorHandler'; import { getErrorMessage } from '@/lib/errorHandler';
import type { Ride, Company, RideModel } from "@/types/database"; import type { Ride, Company, RideModel } from "@/types/database";
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function RideModelRides() { export default function RideModelRides() {
const { manufacturerSlug, modelSlug } = useParams<{ manufacturerSlug: string; modelSlug: string }>(); const { manufacturerSlug, modelSlug } = useParams<{ manufacturerSlug: string; modelSlug: string }>();
@@ -28,6 +29,9 @@ export default function RideModelRides() {
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [searchQuery, setSearchQuery] = useState(''); const [searchQuery, setSearchQuery] = useState('');
const [sortBy, setSortBy] = useState('name'); const [sortBy, setSortBy] = useState('name');
// Update document title when model changes
useDocumentTitle(model ? `${model.name} - Rides` : 'Model Rides');
const [filterCategory, setFilterCategory] = useState('all'); const [filterCategory, setFilterCategory] = useState('all');
const [filterStatus, setFilterStatus] = useState('all'); const [filterStatus, setFilterStatus] = useState('all');
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);

View File

@@ -22,8 +22,10 @@ import { useUserRole } from '@/hooks/useUserRole';
import { toast } from '@/hooks/use-toast'; import { toast } from '@/hooks/use-toast';
import { getErrorMessage } from '@/lib/errorHandler'; import { getErrorMessage } from '@/lib/errorHandler';
import { useAuthModal } from '@/hooks/useAuthModal'; import { useAuthModal } from '@/hooks/useAuthModal';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function Rides() { export default function Rides() {
useDocumentTitle('Rides & Attractions');
const navigate = useNavigate(); const navigate = useNavigate();
const { user } = useAuth(); const { user } = useAuth();
const { isModerator } = useUserRole(); const { isModerator } = useUserRole();

View File

@@ -2,8 +2,10 @@ import { Header } from '@/components/layout/Header';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge'; import { Badge } from '@/components/ui/badge';
import { CheckCircle, AlertTriangle, Camera, Star, MapPin, Settings, Building2, Globe } from 'lucide-react'; import { CheckCircle, AlertTriangle, Camera, Star, MapPin, Settings, Building2, Globe } from 'lucide-react';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function SubmissionGuidelines() { export default function SubmissionGuidelines() {
useDocumentTitle('Submission Guidelines');
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<Header /> <Header />

View File

@@ -1,6 +1,8 @@
import { Header } from '@/components/layout/Header'; import { Header } from '@/components/layout/Header';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function Terms() { export default function Terms() {
useDocumentTitle('Terms of Service');
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
<Header /> <Header />

View File

@@ -131,6 +131,7 @@ interface EmailThread {
} }
export default function AdminContact() { export default function AdminContact() {
useDocumentTitle('Contact Submissions - Admin');
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const { theme } = useTheme(); const { theme } = useTheme();
const { isAdmin, loading: rolesLoading } = useUserRole(); const { isAdmin, loading: rolesLoading } = useUserRole();

View File

@@ -16,8 +16,10 @@ import { AdminLayout } from '@/components/layout/AdminLayout';
import { useUserRole } from '@/hooks/useUserRole'; import { useUserRole } from '@/hooks/useUserRole';
import { handleError, handleSuccess } from '@/lib/errorHandler'; import { handleError, handleSuccess } from '@/lib/errorHandler';
import { Alert, AlertDescription } from '@/components/ui/alert'; import { Alert, AlertDescription } from '@/components/ui/alert';
import { useDocumentTitle } from '@/hooks/useDocumentTitle';
export default function AdminEmailSettings() { export default function AdminEmailSettings() {
useDocumentTitle('Email Settings - Admin');
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const { isSuperuser, loading: rolesLoading } = useUserRole(); const { isSuperuser, loading: rolesLoading } = useUserRole();
const [signature, setSignature] = useState(''); const [signature, setSignature] = useState('');