Migrate date precision to exact

Batch update all date precision handling to use expanded DatePrecision, replace hardcoded day defaults, and adjust related validation, UI, and helpers. Includes wrapper migration across Phase 1-3 functions, updates to logs, displays, and formatting utilities to align frontend with new precision values ('exact', 'month', 'year', 'decade', 'century', 'approximate').
This commit is contained in:
gpt-engineer-app[bot]
2025-11-11 22:05:29 +00:00
parent 9ee84b31ff
commit d0c613031e
15 changed files with 189 additions and 43 deletions

View File

@@ -57,7 +57,7 @@ export function ManufacturerForm({ onSubmit, onCancel, initialData }: Manufactur
website_url: initialData?.website_url || '',
founded_year: initialData?.founded_year ? String(initialData.founded_year) : '',
founded_date: initialData?.founded_date || (initialData?.founded_year ? `${initialData.founded_year}-01-01` : undefined),
founded_date_precision: initialData?.founded_date_precision || (initialData?.founded_year ? ('year' as const) : ('day' as const)),
founded_date_precision: initialData?.founded_date_precision || (initialData?.founded_year ? ('year' as const) : ('exact' as const)),
headquarters_location: initialData?.headquarters_location || '',
source_url: initialData?.source_url || '',
submission_notes: initialData?.submission_notes || '',

View File

@@ -38,9 +38,9 @@ const parkSchema = z.object({
park_type: z.string().min(1, 'Park type is required'),
status: z.string().min(1, 'Status is required'),
opening_date: z.string().optional().transform(val => val || undefined),
opening_date_precision: z.enum(['day', 'month', 'year']).optional(),
opening_date_precision: z.enum(['exact', 'month', 'year', 'decade', 'century', 'approximate']).optional(),
closing_date: z.string().optional().transform(val => val || undefined),
closing_date_precision: z.enum(['day', 'month', 'year']).optional(),
closing_date_precision: z.enum(['exact', 'month', 'year', 'decade', 'century', 'approximate']).optional(),
location: z.object({
name: z.string(),
street_address: z.string().optional(),

View File

@@ -227,9 +227,9 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }:
ride_sub_type: initialData?.ride_sub_type || '',
status: initialData?.status || 'operating' as const, // Store DB value directly
opening_date: initialData?.opening_date || undefined,
opening_date_precision: initialData?.opening_date_precision || 'day',
opening_date_precision: initialData?.opening_date_precision || 'exact',
closing_date: initialData?.closing_date || undefined,
closing_date_precision: initialData?.closing_date_precision || 'day',
closing_date_precision: initialData?.closing_date_precision || 'exact',
// Convert metric values to user's preferred unit for display
height_requirement: initialData?.height_requirement
? convertValueFromMetric(initialData.height_requirement, getDisplayUnit('cm', measurementSystem), 'cm')

View File

@@ -102,11 +102,11 @@ export function TimeZoneIndependentDateRangePicker({
if (!fromDate && !toDate) return null;
if (fromDate && toDate) {
return `${formatDateDisplay(fromDate, 'day')} - ${formatDateDisplay(toDate, 'day')}`;
return `${formatDateDisplay(fromDate, 'exact')} - ${formatDateDisplay(toDate, 'exact')}`;
} else if (fromDate) {
return `From ${formatDateDisplay(fromDate, 'day')}`;
return `From ${formatDateDisplay(fromDate, 'exact')}`;
} else if (toDate) {
return `Until ${formatDateDisplay(toDate, 'day')}`;
return `Until ${formatDateDisplay(toDate, 'exact')}`;
}
return null;

View File

@@ -5,8 +5,10 @@ import { ArrowRight } from 'lucide-react';
import { ArrayFieldDiff } from './ArrayFieldDiff';
import { SpecialFieldDisplay } from './SpecialFieldDisplay';
import type { DatePrecision } from '@/components/ui/flexible-date-input';
// Helper to format compact values (truncate long strings)
function formatCompactValue(value: unknown, precision?: 'day' | 'month' | 'year', maxLength = 30): string {
function formatCompactValue(value: unknown, precision?: DatePrecision, maxLength = 30): string {
const formatted = formatFieldValue(value, precision);
if (formatted.length > maxLength) {
return formatted.substring(0, maxLength) + '...';

View File

@@ -211,7 +211,13 @@ function DateFieldDisplay({ change, compact }: { change: FieldChange; compact: b
{formatFieldName(change.field)}
{precision && (
<Badge variant="outline" className="text-xs ml-2">
{precision === 'year' ? 'Year Only' : precision === 'month' ? 'Month & Year' : 'Full Date'}
{precision === 'exact' ? 'Exact Day' :
precision === 'month' ? 'Month & Year' :
precision === 'year' ? 'Year Only' :
precision === 'decade' ? 'Decade' :
precision === 'century' ? 'Century' :
precision === 'approximate' ? 'Approximate' :
'Full Date'}
</Badge>
)}
</div>

View File

@@ -72,7 +72,7 @@ const timelineEventSchema = z.object({
event_date: z.date({
message: 'Event date is required',
}),
event_date_precision: z.enum(['day', 'month', 'year']).default('day'),
event_date_precision: z.enum(['exact', 'month', 'year', 'decade', 'century', 'approximate']).default('exact'),
title: z.string().min(1, 'Title is required').max(200, 'Title is too long'),
description: z.string().max(1000, 'Description is too long').optional(),
@@ -133,7 +133,7 @@ export function TimelineEventEditorDialog({
} : {
event_type: 'milestone',
event_date: new Date(),
event_date_precision: 'day',
event_date_precision: 'exact',
title: '',
description: '',
},
@@ -319,9 +319,12 @@ export function TimelineEventEditorDialog({
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="day">Exact Day</SelectItem>
<SelectItem value="exact">Exact Day</SelectItem>
<SelectItem value="month">Month Only</SelectItem>
<SelectItem value="year">Year Only</SelectItem>
<SelectItem value="decade">Decade</SelectItem>
<SelectItem value="century">Century</SelectItem>
<SelectItem value="approximate">Approximate</SelectItem>
</SelectContent>
</Select>
<FormMessage />

View File

@@ -11,7 +11,7 @@ interface FlexibleDateDisplayProps {
export function FlexibleDateDisplay({
date,
precision = 'day',
precision = 'exact',
fallback = 'Unknown',
className
}: FlexibleDateDisplayProps) {
@@ -36,7 +36,16 @@ export function FlexibleDateDisplay({
case 'month':
formatted = format(dateObj, 'MMMM yyyy');
break;
case 'day':
case 'decade':
formatted = `${Math.floor(dateObj.getFullYear() / 10) * 10}s`;
break;
case 'century':
formatted = `${Math.ceil(dateObj.getFullYear() / 100)}th century`;
break;
case 'approximate':
formatted = `circa ${format(dateObj, 'yyyy')}`;
break;
case 'exact':
default:
formatted = format(dateObj, 'PPP');
break;

View File

@@ -16,7 +16,7 @@ import {
} from "@/components/ui/select";
import { toDateOnly, toDateWithPrecision } from "@/lib/dateUtils";
export type DatePrecision = 'day' | 'month' | 'year';
export type DatePrecision = 'exact' | 'month' | 'year' | 'decade' | 'century' | 'approximate';
interface FlexibleDateInputProps {
value?: Date;
@@ -34,7 +34,7 @@ interface FlexibleDateInputProps {
export function FlexibleDateInput({
value,
precision = 'day',
precision = 'exact',
onChange,
placeholder = "Select date",
disabled = false,
@@ -71,13 +71,16 @@ export function FlexibleDateInput({
let newDate: Date;
switch (newPrecision) {
case 'year':
case 'decade':
case 'century':
case 'approximate':
newDate = new Date(year, 0, 1); // January 1st (local timezone)
setYearValue(year.toString());
break;
case 'month':
newDate = new Date(year, month, 1); // 1st of month (local timezone)
break;
case 'day':
case 'exact':
default:
newDate = value; // Keep existing date
break;
@@ -104,10 +107,13 @@ export function FlexibleDateInput({
const getPlaceholderText = () => {
switch (localPrecision) {
case 'year':
case 'decade':
case 'century':
case 'approximate':
return 'Enter year (e.g., 2005)';
case 'month':
return 'Select month and year';
case 'day':
case 'exact':
default:
return placeholder;
}
@@ -119,10 +125,10 @@ export function FlexibleDateInput({
<div className="flex gap-2">
<div className="flex-1">
{localPrecision === 'day' && (
{(localPrecision === 'exact') && (
<DatePicker
date={value}
onSelect={(date) => onChange(date, 'day')}
onSelect={(date) => onChange(date, 'exact')}
placeholder={getPlaceholderText()}
disabled={disabled}
disableFuture={disableFuture}
@@ -143,7 +149,7 @@ export function FlexibleDateInput({
/>
)}
{localPrecision === 'year' && (
{(localPrecision === 'year' || localPrecision === 'decade' || localPrecision === 'century' || localPrecision === 'approximate') && (
<Input
type="number"
value={yearValue}
@@ -166,9 +172,12 @@ export function FlexibleDateInput({
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="day">Use Full Date</SelectItem>
<SelectItem value="month">Use Month/Year</SelectItem>
<SelectItem value="year">Use Year Only</SelectItem>
<SelectItem value="exact">Exact Day</SelectItem>
<SelectItem value="month">Month & Year</SelectItem>
<SelectItem value="year">Year Only</SelectItem>
<SelectItem value="decade">Decade</SelectItem>
<SelectItem value="century">Century</SelectItem>
<SelectItem value="approximate">Approximate</SelectItem>
</SelectContent>
</Select>
</div>