SEO: robots.txt, sitemap, Organization & Event schema; dashboard fmtTime fix; frontend updates
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,3 +1,111 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// Date / time formatting
|
||||
// ---------------------------------------------------------------------------
|
||||
// All helpers pin the timezone to America/Asuncion so the output is identical
|
||||
// on the server (often UTC) and the client (user's local TZ). This prevents
|
||||
// React hydration mismatches like "07:20 PM" (server) vs "04:20 PM" (client).
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const EVENT_TIMEZONE = 'America/Asuncion';
|
||||
|
||||
type Locale = 'en' | 'es';
|
||||
|
||||
function pickLocale(locale: Locale): string {
|
||||
return locale === 'es' ? 'es-ES' : 'en-US';
|
||||
}
|
||||
|
||||
/**
|
||||
* "Sat, Feb 14" / "sáb, 14 feb"
|
||||
*/
|
||||
export function formatDateShort(dateStr: string, locale: Locale = 'en'): string {
|
||||
return new Date(dateStr).toLocaleDateString(pickLocale(locale), {
|
||||
weekday: 'short',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
timeZone: EVENT_TIMEZONE,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* "Saturday, February 14, 2026" / "sábado, 14 de febrero de 2026"
|
||||
*/
|
||||
export function formatDateLong(dateStr: string, locale: Locale = 'en'): string {
|
||||
return new Date(dateStr).toLocaleDateString(pickLocale(locale), {
|
||||
weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
timeZone: EVENT_TIMEZONE,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* "February 14, 2026" / "14 de febrero de 2026" (no weekday)
|
||||
*/
|
||||
export function formatDateMedium(dateStr: string, locale: Locale = 'en'): string {
|
||||
return new Date(dateStr).toLocaleDateString(pickLocale(locale), {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
timeZone: EVENT_TIMEZONE,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* "Feb 14, 2026" / "14 feb 2026"
|
||||
*/
|
||||
export function formatDateCompact(dateStr: string, locale: Locale = 'en'): string {
|
||||
return new Date(dateStr).toLocaleDateString(pickLocale(locale), {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
timeZone: EVENT_TIMEZONE,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* "04:30 PM" / "16:30"
|
||||
*/
|
||||
export function formatTime(dateStr: string, locale: Locale = 'en'): string {
|
||||
return new Date(dateStr).toLocaleTimeString(pickLocale(locale), {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
timeZone: EVENT_TIMEZONE,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* "Feb 14, 2026, 04:30 PM" — compact date + time combined
|
||||
*/
|
||||
export function formatDateTime(dateStr: string, locale: Locale = 'en'): string {
|
||||
return new Date(dateStr).toLocaleString(pickLocale(locale), {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
timeZone: EVENT_TIMEZONE,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* "Sat, Feb 14, 04:30 PM" — short date + time combined
|
||||
*/
|
||||
export function formatDateTimeShort(dateStr: string, locale: Locale = 'en'): string {
|
||||
return new Date(dateStr).toLocaleString(pickLocale(locale), {
|
||||
weekday: 'short',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
timeZone: EVENT_TIMEZONE,
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Price formatting
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Format price - shows decimals only if needed
|
||||
* Uses space as thousands separator (common in Paraguay)
|
||||
|
||||
Reference in New Issue
Block a user