FarmerHelp / frontend /src /utils /helpers.js
Gankit12's picture
All Code
b64de39
Raw
History Blame Contribute Delete
7.44 kB
/**
* 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);
}