mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-23 07:31:12 -05:00
Refactor code structure and remove redundant changes
This commit is contained in:
85
src-old/components/history/EntityHistoryTabs.tsx
Normal file
85
src-old/components/history/EntityHistoryTabs.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { EntityTimelineManager } from '@/components/timeline/EntityTimelineManager';
|
||||
import { EntityVersionHistory } from '@/components/versioning/EntityVersionHistory';
|
||||
import { FormerNamesSection } from './FormerNamesSection';
|
||||
import { RideNameHistory } from '@/types/database';
|
||||
import type { EntityType } from '@/types/timeline';
|
||||
|
||||
interface EntityHistoryTabsProps {
|
||||
entityType: EntityType;
|
||||
entityId: string;
|
||||
entityName: string;
|
||||
formerNames?: RideNameHistory[];
|
||||
currentName?: string;
|
||||
}
|
||||
|
||||
const getHistoryLabel = (entityType: string) => {
|
||||
switch (entityType) {
|
||||
case 'park':
|
||||
return 'Park History';
|
||||
case 'ride':
|
||||
return 'Ride History';
|
||||
case 'company':
|
||||
return 'Company History';
|
||||
default:
|
||||
return 'History';
|
||||
}
|
||||
};
|
||||
|
||||
const getHistoryValue = (entityType: string) => {
|
||||
switch (entityType) {
|
||||
case 'park':
|
||||
return 'park-history';
|
||||
case 'ride':
|
||||
return 'ride-history';
|
||||
case 'company':
|
||||
return 'company-history';
|
||||
default:
|
||||
return 'entity-history';
|
||||
}
|
||||
};
|
||||
|
||||
export function EntityHistoryTabs({
|
||||
entityType,
|
||||
entityId,
|
||||
entityName,
|
||||
formerNames,
|
||||
currentName,
|
||||
}: EntityHistoryTabsProps) {
|
||||
const historyValue = getHistoryValue(entityType);
|
||||
const historyLabel = getHistoryLabel(entityType);
|
||||
|
||||
return (
|
||||
<Tabs defaultValue={historyValue} className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-2">
|
||||
<TabsTrigger value={historyValue}>{historyLabel}</TabsTrigger>
|
||||
<TabsTrigger value="version-history">Version History</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value={historyValue} className="mt-6 space-y-6">
|
||||
{formerNames && formerNames.length > 0 && currentName && (
|
||||
<FormerNamesSection
|
||||
currentName={currentName}
|
||||
formerNames={formerNames}
|
||||
entityType={entityType}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Dynamic Timeline Manager with Edit/Delete */}
|
||||
<EntityTimelineManager
|
||||
entityType={entityType}
|
||||
entityId={entityId}
|
||||
entityName={entityName}
|
||||
/>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="version-history" className="mt-6">
|
||||
<EntityVersionHistory
|
||||
entityType={entityType}
|
||||
entityId={entityId}
|
||||
entityName={entityName}
|
||||
/>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
137
src-old/components/history/EntityHistoryTimeline.tsx
Normal file
137
src-old/components/history/EntityHistoryTimeline.tsx
Normal file
@@ -0,0 +1,137 @@
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Calendar, MapPin, Building2, Tag, Milestone, ArrowRight } from "lucide-react";
|
||||
import { format } from "date-fns";
|
||||
|
||||
export type HistoryEventType = 'name_change' | 'status_change' | 'ownership_change' | 'relocation' | 'milestone';
|
||||
|
||||
export interface HistoryEvent {
|
||||
date: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
type: HistoryEventType;
|
||||
from?: string;
|
||||
to?: string;
|
||||
}
|
||||
|
||||
interface EntityHistoryTimelineProps {
|
||||
events: HistoryEvent[];
|
||||
entityName: string;
|
||||
}
|
||||
|
||||
const eventTypeConfig: Record<HistoryEventType, { icon: typeof Tag; color: string; label: string }> = {
|
||||
name_change: { icon: Tag, color: 'text-blue-500', label: 'Name Change' },
|
||||
status_change: { icon: Calendar, color: 'text-amber-500', label: 'Status Change' },
|
||||
ownership_change: { icon: Building2, color: 'text-purple-500', label: 'Ownership Change' },
|
||||
relocation: { icon: MapPin, color: 'text-green-500', label: 'Relocation' },
|
||||
milestone: { icon: Milestone, color: 'text-pink-500', label: 'Milestone' },
|
||||
};
|
||||
|
||||
// Fallback config for unknown event types
|
||||
const defaultEventConfig = { icon: Tag, color: 'text-gray-500', label: 'Event' };
|
||||
|
||||
export function EntityHistoryTimeline({ events, entityName }: EntityHistoryTimelineProps) {
|
||||
if (events.length === 0) {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>No Historical Events</CardTitle>
|
||||
<CardDescription>
|
||||
No historical events recorded for {entityName}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
// Sort events by date (most recent first)
|
||||
const sortedEvents = [...events].sort((a, b) => {
|
||||
const dateA = new Date(a.date);
|
||||
const dateB = new Date(b.date);
|
||||
return dateB.getTime() - dateA.getTime();
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="relative space-y-4">
|
||||
{/* Timeline line */}
|
||||
<div className="absolute left-6 top-0 bottom-0 w-0.5 bg-border" />
|
||||
|
||||
{sortedEvents.map((event, index) => {
|
||||
// Safety check: verify event.type exists in eventTypeConfig, use fallback if not
|
||||
const config = event.type && eventTypeConfig[event.type]
|
||||
? eventTypeConfig[event.type]
|
||||
: defaultEventConfig;
|
||||
const Icon = config.icon;
|
||||
|
||||
return (
|
||||
<div key={index} className="relative flex gap-4">
|
||||
{/* Timeline dot */}
|
||||
<div className="relative flex-shrink-0">
|
||||
<div className={`flex h-12 w-12 items-center justify-center rounded-full border-2 border-background bg-card ${config.color}`}>
|
||||
<Icon className="h-5 w-5" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Event content */}
|
||||
<Card className="flex-1">
|
||||
<CardHeader className="pb-3">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="space-y-1">
|
||||
<CardTitle className="text-lg">{event.title}</CardTitle>
|
||||
<CardDescription className="flex items-center gap-2">
|
||||
<Calendar className="h-3 w-3" />
|
||||
{formatEventDate(event.date)}
|
||||
<span className="text-xs">•</span>
|
||||
<span className={config.color}>{config.label}</span>
|
||||
</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
{(event.description || (event.from && event.to)) && (
|
||||
<CardContent className="pt-0">
|
||||
{event.from && event.to && (
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground mb-2">
|
||||
<span className="font-medium">{event.from}</span>
|
||||
<ArrowRight className="h-4 w-4" />
|
||||
<span className="font-medium">{event.to}</span>
|
||||
</div>
|
||||
)}
|
||||
{event.description && (
|
||||
<p className="text-sm text-muted-foreground">{event.description}</p>
|
||||
)}
|
||||
</CardContent>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function formatEventDate(dateString: string): string {
|
||||
// Safety check: validate dateString exists and is a string
|
||||
if (!dateString || typeof dateString !== 'string') {
|
||||
return 'Unknown date';
|
||||
}
|
||||
|
||||
try {
|
||||
// Handle year-only dates
|
||||
if (/^\d{4}$/.test(dateString)) {
|
||||
return dateString;
|
||||
}
|
||||
|
||||
// Validate date string before creating Date object
|
||||
const date = new Date(dateString);
|
||||
|
||||
// Check if date is valid
|
||||
if (isNaN(date.getTime())) {
|
||||
return dateString;
|
||||
}
|
||||
|
||||
return format(date, 'MMMM d, yyyy');
|
||||
} catch {
|
||||
return dateString;
|
||||
}
|
||||
}
|
||||
100
src-old/components/history/FormerNamesSection.tsx
Normal file
100
src-old/components/history/FormerNamesSection.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Tag, Calendar } from "lucide-react";
|
||||
|
||||
interface FormerName {
|
||||
former_name?: string;
|
||||
name?: string;
|
||||
from_year?: number;
|
||||
to_year?: number;
|
||||
reason?: string;
|
||||
date_changed?: string;
|
||||
}
|
||||
|
||||
interface FormerNamesSectionProps {
|
||||
currentName: string;
|
||||
formerNames: FormerName[];
|
||||
entityType: 'ride' | 'park' | 'company' | 'ride_model';
|
||||
}
|
||||
|
||||
export function FormerNamesSection({ currentName, formerNames, entityType }: FormerNamesSectionProps) {
|
||||
if (!formerNames || formerNames.length === 0) {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Tag className="h-5 w-5" />
|
||||
Former Names
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
This {entityType} has not had any previous names
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
// Sort by date (most recent first)
|
||||
const sortedNames = [...formerNames].sort((a, b) => {
|
||||
const yearA = a.to_year || (a.date_changed ? new Date(a.date_changed).getFullYear() : 0);
|
||||
const yearB = b.to_year || (b.date_changed ? new Date(b.date_changed).getFullYear() : 0);
|
||||
return yearB - yearA;
|
||||
});
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Tag className="h-5 w-5" />
|
||||
Former Names
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Historical names for this {entityType}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
{/* Current name */}
|
||||
<div className="flex items-start gap-3 p-3 rounded-lg bg-primary/5 border border-primary/20">
|
||||
<div className="flex-shrink-0 mt-1">
|
||||
<div className="h-3 w-3 rounded-full bg-primary" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h4 className="font-semibold text-foreground">{currentName}</h4>
|
||||
<p className="text-sm text-muted-foreground">Current Name</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Former names */}
|
||||
{sortedNames.map((name, index) => {
|
||||
const displayName = name.former_name || name.name;
|
||||
const yearRange = name.from_year && name.to_year
|
||||
? `${name.from_year} - ${name.to_year}`
|
||||
: name.date_changed
|
||||
? `Until ${new Date(name.date_changed).getFullYear()}`
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div key={index} className="flex items-start gap-3 p-3 rounded-lg border">
|
||||
<div className="flex-shrink-0 mt-1">
|
||||
<div className="h-3 w-3 rounded-full bg-muted-foreground/30" />
|
||||
</div>
|
||||
<div className="flex-1 space-y-1">
|
||||
<h4 className="font-medium text-foreground">{displayName}</h4>
|
||||
{yearRange && (
|
||||
<p className="text-sm text-muted-foreground flex items-center gap-1">
|
||||
<Calendar className="h-3 w-3" />
|
||||
{yearRange}
|
||||
</p>
|
||||
)}
|
||||
{name.reason && (
|
||||
<p className="text-sm text-muted-foreground italic">{name.reason}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user