inogen/app/lib/utils.ts
2025-10-10 19:11:38 +03:30

137 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { clsx, type ClassValue } from "clsx";
import EventEmitter from "events";
import moment from "moment-jalaali";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
export const formatNumber = (value: string | number) => {
// if (!value) return "0";
const numericValue = typeof value === "string" ? parseFloat(value) : value;
if (isNaN(numericValue)) return "0";
return new Intl.NumberFormat("fa-IR").format(numericValue);
};
export const formatCurrency = (amount: string | number) => {
if (!amount) return "0 ریال";
// Remove commas and convert to number
const numericAmount =
typeof amount === "string" ? parseFloat(amount.replace(/,/g, "")) : amount;
if (isNaN(numericAmount)) return "0 ریال";
return new Intl.NumberFormat("fa-IR").format(numericAmount) + " ریال";
};
/**
* محاسبه دامنه nice numbers برای محور Y نمودارها
* @param values آرایه از مقادیر داده‌ها
* @param minValue حداقل مقدار (پیش‌فرض: 0 برای داده‌های درصدی)
* @param marginPercent درصد حاشیه اضافی (پیش‌فرض: 5%)
* @returns شیء شامل حداکثر nice، فاصله tick ها، و آرایه tick ها
*/
export function calculateNiceRange(
values: number[],
minValue: number = 0,
marginPercent: number = 5
): {
niceMax: number;
tickInterval: number;
ticks: number[];
} {
if (values.length === 0) {
return { niceMax: 100, tickInterval: 20, ticks: [0, 20, 40, 60, 80, 100] };
}
// پیدا کردن حداکثر مقدار در داده‌ها
const dataMax = Math.max(...values);
// اگر همه مقادیر صفر یا منفی هستند
if (dataMax <= 0) {
return { niceMax: 100, tickInterval: 20, ticks: [0, 20, 40, 60, 80, 100] };
}
// اضافه کردن حاشیه
const maxWithMargin = dataMax * (1 + marginPercent / 100);
// محاسبه nice upper limit
const niceMax = calculateNiceNumber(maxWithMargin, true);
// محاسبه فاصله مناسب tick ها بر اساس niceMax
const range = niceMax - minValue;
const targetTicks = 5; // هدف: 5 tick
const roughTickInterval = range / (targetTicks - 1);
const niceTickInterval = calculateNiceNumber(roughTickInterval, false);
// ایجاد آرایه tick ها
const ticks: number[] = [];
for (let i = minValue; i <= niceMax; i += niceTickInterval) {
ticks.push(Math.round(i));
}
// اطمینان از اینکه niceMax در آرایه tick ها باشد
if (ticks[ticks.length - 1] !== niceMax) {
ticks.push(niceMax);
}
return {
niceMax,
tickInterval: niceTickInterval,
ticks,
};
}
/**
* محاسبه عدد nice (گرد و خوانا) بر اساس الگوریتم nice numbers
* @param value مقدار ورودی
* @param round آیا به سمت بالا گرد شود یا نه
* @returns عدد nice
*/
function calculateNiceNumber(value: number, round: boolean): number {
if (value <= 0) return 0;
// پیدا کردن قدرت 10
const exponent = Math.floor(Math.log10(value));
const fraction = value / Math.pow(10, exponent);
let niceFraction: number;
if (round) {
// برای حداکثر: به سمت بالا گرد می‌کنیم با دقت بیشتر
if (fraction <= 1.0) niceFraction = 1;
else if (fraction <= 2.0) niceFraction = 2;
else if (fraction <= 2.5) niceFraction = 2.5;
else if (fraction <= 5.0) niceFraction = 5;
else if (fraction <= 7.5) niceFraction = 7.5;
else niceFraction = 10;
} else {
// برای فاصله tick ها: اعداد ساده‌تر
if (fraction <= 1.0) niceFraction = 1;
else if (fraction <= 2.0) niceFraction = 2;
else if (fraction <= 5.0) niceFraction = 5;
else niceFraction = 10;
}
return niceFraction * Math.pow(10, exponent);
}
export const handleDataValue = (val: any): any => {
moment.loadPersian({ usePersianDigits: true });
if (val == null) return val;
if (
typeof val === "string" &&
/^\d{4}[-/]\d{2}[-/]\d{2}( \d{2}:\d{2}(:\d{2})?)?$/.test(val)
) {
return moment(val, "YYYY-MM-DD HH:mm:ss").format("YYYY/MM/DD");
}
if (
typeof val === "number" ||
(typeof val === "string" && /^-?\d+$/.test(val))
) {
return val.toString().replace(/\d/g, (d) => "۰۱۲۳۴۵۶۷۸۹"[+d]);
}
return val;
};
export const EventBus = new EventEmitter();