import { type ClassValue, clsx } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } export function formatDate(dateString: string): string { if (!dateString) return 'N/A'; const date = new Date(dateString); return date.toLocaleDateString('en-ZA', { day: '2-digit', month: 'short', year: 'numeric', }); } export function formatDateTime(dateString: string): string { if (!dateString) return 'N/A'; const date = new Date(dateString); return date.toLocaleString('en-ZA', { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', }); } export function formatCurrency(amount: number): string { return new Intl.NumberFormat('en-ZA', { style: 'currency', currency: 'ZAR', }).format(amount); } export function getRelativeTime(dateString: string): string { const date = new Date(dateString); const now = new Date(); const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000); if (diffInSeconds < 60) return 'Just now'; if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`; if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`; if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)}d ago`; return formatDate(dateString); } export function debounce unknown>( func: T, wait: number ): (...args: Parameters) => void { let timeout: ReturnType; return (...args: Parameters) => { clearTimeout(timeout); timeout = setTimeout(() => func(...args), wait); }; } export function groupBy(array: T[], key: keyof T): Record { return array.reduce((result, item) => { const groupKey = String(item[key]); if (!result[groupKey]) { result[groupKey] = []; } result[groupKey].push(item); return result; }, {} as Record); } export function calculateDistance( lat1: number, lon1: number, lat2: number, lon2: number ): number { const R = 6371; // Earth's radius in km const dLat = (lat2 - lat1) * Math.PI / 180; const dLon = (lon2 - lon1) * Math.PI / 180; const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); return R * c; } /** * Parse coordinates from a text field. * Supports formats like: * "-33.9249, 18.4241" * "-33.9249 18.4241" * "lat: -33.9249, lng: 18.4241" * Returns null if parsing fails. */ export function parseCoordinates(coordString: string | undefined): { latitude: number; longitude: number } | null { if (!coordString) return null; // Try to extract two numbers that look like lat/lng const matches = coordString.match(/-?\d+\.?\d*/g); if (matches && matches.length >= 2) { const lat = parseFloat(matches[0]); const lng = parseFloat(matches[1]); if (!isNaN(lat) && !isNaN(lng)) { return { latitude: lat, longitude: lng }; } } return null; }