- labelsUi.* (221+ keys): spot categories/features/types, access, shelter, event types, gear categories/conditions, price/listings, tours, crews, member-visibility, tag categories, spot status. New src/lib/labelKeys.ts holds the shared value->key maps (one source; the five duplicated EVENT_TYPE_KEYS copies now import it). spotStatus.statusTimeAgo() uses the locale date shim. - formatPrice() now takes an optional t so FREE/Trade/Make Offer translate. - Route helpers: skateTime/distanceReadout/maneuver descriptors/formatAge translated (routeUi.*), consumers updated. - Sasquatch: PRO_TIERS labels/badges + summarizeDraft titles/lines/ctas translated (sasquatchUi.*). - Lab *_LABELS/_DESCRIPTIONS maps remain English (documented out of scope).
91 lines
2.9 KiB
TypeScript
91 lines
2.9 KiB
TypeScript
import type { SpotStatusValue } from '@/lib/types';
|
|
import { formatDistanceToNow } from '@/lib/dateFnsI18n';
|
|
import { STATUS_KEYS, STATUS_DESC_KEYS } from '@/lib/labelKeys';
|
|
|
|
export interface SpotStatusMeta {
|
|
value: SpotStatusValue;
|
|
/** Short human label (English fallback — translate via `labelKey`). */
|
|
label: string;
|
|
/** `labelsUi.status.*` translation key for `label`. */
|
|
labelKey: string;
|
|
/** Emoji used in compact contexts. */
|
|
emoji: string;
|
|
/** One-line description for pickers (English fallback — translate via `descriptionKey`). */
|
|
description: string;
|
|
/** `labelsUi.status.*` translation key for `description`. */
|
|
descriptionKey: string;
|
|
/** Tailwind classes for badge text + background + border. */
|
|
badgeClass: string;
|
|
/** Hex dot color for map/legend use. */
|
|
dot: string;
|
|
}
|
|
|
|
export const SPOT_STATUS_META: Record<SpotStatusValue, SpotStatusMeta> = {
|
|
active: {
|
|
value: 'active',
|
|
label: 'Active',
|
|
labelKey: STATUS_KEYS.active,
|
|
emoji: '🟢',
|
|
description: 'Good to go — skate it.',
|
|
descriptionKey: STATUS_DESC_KEYS.active,
|
|
badgeClass: 'text-green-400 bg-green-500/10 border-green-500/30',
|
|
dot: '#22c55e',
|
|
},
|
|
bust: {
|
|
value: 'bust',
|
|
label: 'Bust',
|
|
labelKey: STATUS_KEYS.bust,
|
|
emoji: '🟡',
|
|
description: 'Heavy kick-out risk — security or cops.',
|
|
descriptionKey: STATUS_DESC_KEYS.bust,
|
|
badgeClass: 'text-yellow-400 bg-yellow-500/10 border-yellow-500/30',
|
|
dot: '#eab308',
|
|
},
|
|
skate_stopped: {
|
|
value: 'skate_stopped',
|
|
label: 'Skate-stopped',
|
|
labelKey: STATUS_KEYS.skate_stopped,
|
|
emoji: '🟠',
|
|
description: 'Knobbed / capped, but partially skateable.',
|
|
descriptionKey: STATUS_DESC_KEYS.skate_stopped,
|
|
badgeClass: 'text-orange-400 bg-orange-500/10 border-orange-500/30',
|
|
dot: '#f97316',
|
|
},
|
|
closed: {
|
|
value: 'closed',
|
|
label: 'Closed',
|
|
labelKey: STATUS_KEYS.closed,
|
|
emoji: '⚪',
|
|
description: 'Temporarily closed — construction or event.',
|
|
descriptionKey: STATUS_DESC_KEYS.closed,
|
|
badgeClass: 'text-gray-300 bg-gray-500/10 border-gray-500/30',
|
|
dot: '#9ca3af',
|
|
},
|
|
gone: {
|
|
value: 'gone',
|
|
label: 'Gone',
|
|
labelKey: STATUS_KEYS.gone,
|
|
emoji: '🔴',
|
|
description: 'Demolished, paved over, or fenced off for good.',
|
|
descriptionKey: STATUS_DESC_KEYS.gone,
|
|
badgeClass: 'text-red-400 bg-red-500/10 border-red-500/40',
|
|
dot: '#ef4444',
|
|
},
|
|
};
|
|
|
|
/** Ordered list for pickers/legends (best → worst). */
|
|
export const SPOT_STATUS_ORDER: SpotStatusValue[] = [
|
|
'active',
|
|
'bust',
|
|
'skate_stopped',
|
|
'closed',
|
|
'gone',
|
|
];
|
|
|
|
/**
|
|
* Human "time ago" for a unix-seconds timestamp, in the active app language
|
|
* (via the locale-aware `dateFnsI18n` shim — "3 days ago" / "hace 3 días").
|
|
*/
|
|
export function statusTimeAgo(unixSeconds: number): string {
|
|
return formatDistanceToNow(new Date(unixSeconds * 1000), { addSuffix: true });
|
|
}
|