Spaces:
Sleeping
Sleeping
| /** | |
| * General-purpose utility/helper functions. | |
| * | |
| * Pure, side-effect-free functions for common formatting, | |
| * date operations, and data transformations used across the UI. | |
| */ | |
| // --------------------------------------------------------------------------- | |
| // Date Formatting | |
| // --------------------------------------------------------------------------- | |
| /** | |
| * Format an ISO date string to a human-readable short date. | |
| * Example: "2026-02-07T10:30:00Z" -> "07 Feb 2026" | |
| * | |
| * @param {string|Date} dateInput - ISO string or Date object. | |
| * @param {string} locale - BCP 47 locale tag. | |
| * @returns {string} Formatted date string. | |
| */ | |
| export function formatDate(dateInput, locale = "en-IN") { | |
| if (!dateInput) { | |
| return "N/A"; | |
| } | |
| const date = dateInput instanceof Date ? dateInput : new Date(dateInput); | |
| if (Number.isNaN(date.getTime())) { | |
| return "Invalid date"; | |
| } | |
| return date.toLocaleDateString(locale, { | |
| day: "2-digit", | |
| month: "short", | |
| year: "numeric", | |
| }); | |
| } | |
| /** | |
| * Format an ISO date string to a short date + time. | |
| * Example: "2026-02-07T10:30:00Z" -> "07 Feb 2026, 04:00 PM" | |
| * | |
| * @param {string|Date} dateInput - ISO string or Date object. | |
| * @param {string} locale - BCP 47 locale tag. | |
| * @returns {string} Formatted date-time string. | |
| */ | |
| export function formatDateTime(dateInput, locale = "en-IN") { | |
| if (!dateInput) { | |
| return "N/A"; | |
| } | |
| const date = dateInput instanceof Date ? dateInput : new Date(dateInput); | |
| if (Number.isNaN(date.getTime())) { | |
| return "Invalid date"; | |
| } | |
| return date.toLocaleString(locale, { | |
| day: "2-digit", | |
| month: "short", | |
| year: "numeric", | |
| hour: "2-digit", | |
| minute: "2-digit", | |
| }); | |
| } | |
| /** | |
| * Return a relative time description (e.g. "2 hours ago"). | |
| * | |
| * @param {string|Date} dateInput - ISO string or Date object. | |
| * @returns {string} Relative time string. | |
| */ | |
| export function timeAgo(dateInput) { | |
| if (!dateInput) { | |
| return "N/A"; | |
| } | |
| const date = dateInput instanceof Date ? dateInput : new Date(dateInput); | |
| if (Number.isNaN(date.getTime())) { | |
| return "Invalid date"; | |
| } | |
| const seconds = Math.floor((Date.now() - date.getTime()) / 1000); | |
| const intervals = [ | |
| { label: "year", seconds: 31536000 }, | |
| { label: "month", seconds: 2592000 }, | |
| { label: "week", seconds: 604800 }, | |
| { label: "day", seconds: 86400 }, | |
| { label: "hour", seconds: 3600 }, | |
| { label: "minute", seconds: 60 }, | |
| ]; | |
| for (const interval of intervals) { | |
| const count = Math.floor(seconds / interval.seconds); | |
| if (count >= 1) { | |
| return `${count} ${interval.label}${count > 1 ? "s" : ""} ago`; | |
| } | |
| } | |
| return "Just now"; | |
| } | |
| // --------------------------------------------------------------------------- | |
| // Price / Currency Formatting | |
| // --------------------------------------------------------------------------- | |
| /** | |
| * Format a number as Indian Rupee currency. | |
| * Example: 2250.5 -> "Rs 2,250.50" | |
| * | |
| * @param {number} amount - Numeric value. | |
| * @param {number} fractionDigits - Decimal places (default 2). | |
| * @returns {string} Formatted currency string. | |
| */ | |
| export function formatPrice(amount, fractionDigits = 2) { | |
| if (amount === null || amount === undefined || Number.isNaN(Number(amount))) { | |
| return "N/A"; | |
| } | |
| return `Rs ${Number(amount).toLocaleString("en-IN", { | |
| minimumFractionDigits: fractionDigits, | |
| maximumFractionDigits: fractionDigits, | |
| })}`; | |
| } | |
| /** | |
| * Format a price per quintal with unit label. | |
| * | |
| * @param {number} price - Price per quintal. | |
| * @returns {string} Formatted string e.g. "Rs 2,250/qtl" | |
| */ | |
| export function formatPricePerQuintal(price) { | |
| if (price === null || price === undefined) { | |
| return "N/A"; | |
| } | |
| return `${formatPrice(price, 0)}/qtl`; | |
| } | |
| // --------------------------------------------------------------------------- | |
| // Temperature Formatting | |
| // --------------------------------------------------------------------------- | |
| /** | |
| * Format a temperature value with the degree symbol. | |
| * | |
| * @param {number} temp - Temperature in Celsius. | |
| * @param {number} decimals - Decimal places. | |
| * @returns {string} e.g. "28.5 C" | |
| */ | |
| export function formatTemperature(temp, decimals = 1) { | |
| if (temp === null || temp === undefined) { | |
| return "N/A"; | |
| } | |
| return `${Number(temp).toFixed(decimals)} C`; | |
| } | |
| // --------------------------------------------------------------------------- | |
| // Number Formatting | |
| // --------------------------------------------------------------------------- | |
| /** | |
| * Format a percentage value. | |
| * | |
| * @param {number} value - Decimal (0-1) or percentage (0-100). | |
| * @param {boolean} isDecimal - If true, multiply by 100 first. | |
| * @returns {string} e.g. "85.2%" | |
| */ | |
| export function formatPercentage(value, isDecimal = false) { | |
| if (value === null || value === undefined) { | |
| return "N/A"; | |
| } | |
| const pct = isDecimal ? value * 100 : value; | |
| return `${pct.toFixed(1)}%`; | |
| } | |
| // --------------------------------------------------------------------------- | |
| // String Utilities | |
| // --------------------------------------------------------------------------- | |
| /** | |
| * Capitalize the first letter of a string. | |
| * | |
| * @param {string} str - Input string. | |
| * @returns {string} Capitalized string. | |
| */ | |
| export function capitalize(str) { | |
| if (!str) { | |
| return ""; | |
| } | |
| return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); | |
| } | |
| /** | |
| * Convert a string to title case. | |
| * | |
| * @param {string} str - Input string. | |
| * @returns {string} Title-cased string. | |
| */ | |
| export function titleCase(str) { | |
| if (!str) { | |
| return ""; | |
| } | |
| return str | |
| .split(" ") | |
| .map((word) => capitalize(word)) | |
| .join(" "); | |
| } | |
| /** | |
| * Truncate a string to a maximum length with an ellipsis. | |
| * | |
| * @param {string} str - Input string. | |
| * @param {number} maxLength - Maximum character count. | |
| * @returns {string} Truncated string. | |
| */ | |
| export function truncate(str, maxLength = 100) { | |
| if (!str) { | |
| return ""; | |
| } | |
| if (str.length <= maxLength) { | |
| return str; | |
| } | |
| return `${str.slice(0, maxLength).trimEnd()}...`; | |
| } | |
| // --------------------------------------------------------------------------- | |
| // Miscellaneous | |
| // --------------------------------------------------------------------------- | |
| /** | |
| * Generate a simple unique ID (for UI keys, not cryptographic). | |
| * | |
| * @param {string} prefix - Optional prefix. | |
| * @returns {string} Unique identifier. | |
| */ | |
| export function generateId(prefix = "id") { | |
| return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`; | |
| } | |
| /** | |
| * Debounce a function call. | |
| * | |
| * @param {Function} fn - Function to debounce. | |
| * @param {number} delay - Delay in milliseconds. | |
| * @returns {Function} Debounced function. | |
| */ | |
| export function debounce(fn, delay = 300) { | |
| let timerId; | |
| return function debounced(...args) { | |
| clearTimeout(timerId); | |
| timerId = setTimeout(() => fn.apply(this, args), delay); | |
| }; | |
| } | |
| /** | |
| * Clamp a number within min and max bounds. | |
| * | |
| * @param {number} value - Input value. | |
| * @param {number} min - Lower bound. | |
| * @param {number} max - Upper bound. | |
| * @returns {number} Clamped value. | |
| */ | |
| export function clamp(value, min, max) { | |
| return Math.min(Math.max(value, min), max); | |
| } | |
| /** | |
| * Deep-clone a plain object or array via structured cloning. | |
| * | |
| * @param {*} obj - Object to clone. | |
| * @returns {*} Deep copy. | |
| */ | |
| export function deepClone(obj) { | |
| if (obj === null || typeof obj !== "object") { | |
| return obj; | |
| } | |
| return structuredClone(obj); | |
| } | |