Files
service-finder/frontend_admin/composables/useFormatter.ts

163 lines
4.7 KiB
TypeScript

import { useRegionStore } from '~/stores/region'
/**
* 🌍 useFormatter Composable
*
* Provides locale-aware formatting utilities for numbers, currencies, dates,
* and percentages. Uses the active region configuration from the RegionStore
* to determine the appropriate locale, currency, and timezone.
*
* Falls back to 'en-EU' locale and 'EUR' currency if no region is configured.
*/
export function useFormatter() {
const regionStore = useRegionStore()
/**
* Format a number according to the active locale.
* Example: 1234567.89 → "1,234,567.89" (en) or "1 234 567,89" (hu)
*/
function formatNumber(value: number, options?: Intl.NumberFormatOptions): string {
const locale = regionStore.activeLocale || 'en-EU'
try {
return new Intl.NumberFormat(locale, options).format(value)
} catch {
return new Intl.NumberFormat('en-EU', options).format(value)
}
}
/**
* Format a currency value according to the active region's currency and locale.
* Example: 1234.50 → "€1,234.50" (EUR/en) or "3 456 Ft" (HUF/hu)
*/
function formatCurrency(
value: number,
currency?: string,
options?: Intl.NumberFormatOptions,
): string {
const locale = regionStore.activeLocale || 'en-EU'
const curr = currency || regionStore.activeCurrency || 'EUR'
try {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency: curr,
minimumFractionDigits: 2,
maximumFractionDigits: 2,
...options,
}).format(value)
} catch {
return `${value.toFixed(2)} ${curr}`
}
}
/**
* Format a date according to the active locale and timezone.
* Example: 2026-06-24 → "24/06/2026" (en-GB) or "2026. 06. 24." (hu-HU)
*/
function formatDate(
date: Date | string | number,
options?: Intl.DateTimeFormatOptions,
): string {
const locale = regionStore.activeLocale || 'en-EU'
const timezone = regionStore.activeTimezone || 'Europe/Brussels'
const d = typeof date === 'string' || typeof date === 'number' ? new Date(date) : date
try {
return new Intl.DateTimeFormat(locale, {
timezone,
year: 'numeric',
month: '2-digit',
day: '2-digit',
...options,
}).format(d)
} catch {
return d.toLocaleDateString('en-GB')
}
}
/**
* Format a datetime with time according to the active locale and timezone.
* Example: "2026-06-24T14:30:00Z" → "24/06/2026, 16:30" (hu-HU/Budapest)
*/
function formatDateTime(
date: Date | string | number,
options?: Intl.DateTimeFormatOptions,
): string {
const locale = regionStore.activeLocale || 'en-EU'
const timezone = regionStore.activeTimezone || 'Europe/Brussels'
const d = typeof date === 'string' || typeof date === 'number' ? new Date(date) : date
try {
return new Intl.DateTimeFormat(locale, {
timezone,
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
...options,
}).format(d)
} catch {
return d.toLocaleString('en-GB')
}
}
/**
* Format a percentage value.
* Example: 27 → "27%" or 27.5 → "27,5%" (hu)
*/
function formatPercent(
value: number,
options?: Intl.NumberFormatOptions,
): string {
const locale = regionStore.activeLocale || 'en-EU'
try {
return new Intl.NumberFormat(locale, {
style: 'percent',
minimumFractionDigits: 0,
maximumFractionDigits: 1,
...options,
}).format(value / 100)
} catch {
return `${value}%`
}
}
/**
* Calculate price including VAT for the active region.
* VAT rate comes from the active region's default_vat_rate.
*/
function calculatePriceWithVat(
netPrice: number,
vatRate?: number,
): { net: number; vat: number; gross: number; vatRate: number } {
const rate = vatRate ?? regionStore.activeVatRate ?? 0
const vat = netPrice * (rate / 100)
const gross = netPrice + vat
return { net: netPrice, vat, gross, vatRate: rate }
}
/**
* Format a price range with VAT breakdown.
* Example: (100, 27) → "Net: €100.00 | VAT: €27.00 (27%) | Gross: €127.00"
*/
function formatPriceWithVat(
netPrice: number,
vatRate?: number,
currency?: string,
): string {
const { net, vat, gross, vatRate: rate } = calculatePriceWithVat(netPrice, vatRate)
const curr = currency || regionStore.activeCurrency || 'EUR'
return `Net: ${formatCurrency(net, curr)} | VAT: ${formatCurrency(vat, curr)} (${rate}%) | Gross: ${formatCurrency(gross, curr)}`
}
return {
formatNumber,
formatCurrency,
formatDate,
formatDateTime,
formatPercent,
calculatePriceWithVat,
formatPriceWithVat,
}
}