mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
73 lines
2.9 KiB
TypeScript
73 lines
2.9 KiB
TypeScript
import type { AssignmentsMap } from '../types'
|
|
|
|
// Collapses verbose Nominatim display_name strings (e.g. "Place, 1, Road, Neighbourhood,
|
|
// City, County, State, Country, Postcode, Country") into "Place, Postcode, Country".
|
|
// Clean short names (≤3 parts) pass through untouched.
|
|
export function formatLocationName(raw: string | null | undefined): string {
|
|
if (!raw) return ''
|
|
const parts = raw.split(',').map(p => p.trim()).filter(Boolean)
|
|
if (parts.length <= 3) return raw.trim()
|
|
|
|
// Dedup preserving insertion order
|
|
const seen = new Set<string>()
|
|
const unique: string[] = []
|
|
for (const p of parts) {
|
|
if (!seen.has(p.toLowerCase())) { seen.add(p.toLowerCase()); unique.push(p) }
|
|
}
|
|
if (unique.length <= 3) return unique.join(', ')
|
|
|
|
const name = unique[0]
|
|
const last = unique[unique.length - 1]
|
|
const secondLast = unique.length >= 2 ? unique[unique.length - 2] : null
|
|
|
|
// Detect postcode at tail: short alphanumeric with at least one digit, ≤10 chars
|
|
const postalRe = /^[A-Z0-9][A-Z0-9\s\-]{1,8}$/i
|
|
const isLastPostal = postalRe.test(last) && /\d/.test(last) && last.length <= 10
|
|
const postcode = isLastPostal ? last : null
|
|
const country = isLastPostal ? secondLast : last
|
|
|
|
const result: string[] = [name]
|
|
if (postcode && postcode !== name) result.push(postcode)
|
|
if (country && country !== name && country !== postcode) result.push(country)
|
|
|
|
return result.join(', ')
|
|
}
|
|
|
|
const ZERO_DECIMAL_CURRENCIES = new Set(['JPY', 'KRW', 'VND', 'CLP', 'ISK', 'HUF'])
|
|
|
|
export function currencyDecimals(currency: string): number {
|
|
return ZERO_DECIMAL_CURRENCIES.has(currency.toUpperCase()) ? 0 : 2
|
|
}
|
|
|
|
export function formatDate(dateStr: string | null | undefined, locale: string, timeZone?: string): string | null {
|
|
if (!dateStr) return null
|
|
const opts: Intl.DateTimeFormatOptions = {
|
|
weekday: 'short', day: 'numeric', month: 'short',
|
|
timeZone: timeZone || 'UTC',
|
|
}
|
|
return new Date(dateStr + 'T00:00:00Z').toLocaleDateString(locale, opts)
|
|
}
|
|
|
|
export function formatTime(timeStr: string | null | undefined, locale: string, timeFormat: string): string {
|
|
if (!timeStr) return ''
|
|
try {
|
|
const parts = timeStr.split(':')
|
|
const h = Number(parts[0]) || 0
|
|
const m = Number(parts[1]) || 0
|
|
if (isNaN(h)) return timeStr
|
|
if (timeFormat === '12h') {
|
|
const period = h >= 12 ? 'PM' : 'AM'
|
|
const h12 = h === 0 ? 12 : h > 12 ? h - 12 : h
|
|
return `${h12}:${String(m).padStart(2, '0')} ${period}`
|
|
}
|
|
const str = `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`
|
|
return locale?.startsWith('de') ? `${str} Uhr` : str
|
|
} catch { return timeStr }
|
|
}
|
|
|
|
export function dayTotalCost(dayId: number, assignments: AssignmentsMap, currency: string): string | null {
|
|
const da = assignments[String(dayId)] || []
|
|
const total = da.reduce((s, a) => s + (parseFloat(a.place?.price || '') || 0), 0)
|
|
return total > 0 ? `${total.toFixed(0)} ${currency}` : null
|
|
}
|