Files
2026-03-05 10:34:59 +07:00

264 lines
7.3 KiB
TypeScript

/**
* Format number with thousand separators
* @param value - Number to format
* @param decimals - Number of decimal places (default: 0)
* @param decimalSeparator - Decimal separator (default: ',')
* @param thousandSeparator - Thousand separator (default: '.')
* @returns Formatted number string
*
* @example
* numberFormat(1234567.89) // "1.234.567"
* numberFormat(1234567.89, 2) // "1.234.567,89"
* numberFormat(1234.5, 2, '.', ',') // "1,234.50"
*/
export function numberFormat(
value: number | string | null | undefined,
decimals: number = 0,
decimalSeparator: string = ',',
thousandSeparator: string = '.'
): string {
if (value === null || value === undefined || value === '') {
return '0';
}
const num = typeof value === 'string' ? parseFloat(value) : value;
if (isNaN(num)) {
return '0';
}
const fixedNum = num.toFixed(decimals);
const parts = fixedNum.split('.');
// Format integer part with thousand separator
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, thousandSeparator);
// Join with decimal separator if decimals exist
if (decimals > 0 && parts[1]) {
return parts.join(decimalSeparator);
}
return parts[0];
}
/**
* Format number as currency (Indonesian Rupiah)
* @param value - Number to format
* @param decimals - Number of decimal places (default: 0)
* @param prefix - Currency prefix (default: 'Rp ')
* @returns Formatted currency string
*
* @example
* currencyFormat(1234567) // "Rp 1.234.567"
* currencyFormat(1234567.89, 2) // "Rp 1.234.567,89"
*/
export function currencyFormat(
value: number | string | null | undefined,
decimals: number = 0,
prefix: string = 'Rp '
): string {
return prefix + numberFormat(value, decimals);
}
/**
* Format number as percentage
* @param value - Number to format (0-100 or 0-1)
* @param decimals - Number of decimal places (default: 2)
* @param isDecimal - Whether value is in decimal form (0-1) or percentage form (0-100)
* @returns Formatted percentage string
*
* @example
* percentageFormat(45.5) // "45,50%"
* percentageFormat(0.455, 2, true) // "45,50%"
*/
export function percentageFormat(
value: number | string | null | undefined,
decimals: number = 2,
isDecimal: boolean = false
): string {
if (value === null || value === undefined || value === '') {
return '0%';
}
const num = typeof value === 'string' ? parseFloat(value) : value;
if (isNaN(num)) {
return '0%';
}
const percentage = isDecimal ? num * 100 : num;
return numberFormat(percentage, decimals) + '%';
}
/**
* Format file size
* @param bytes - File size in bytes
* @param decimals - Number of decimal places (default: 2)
* @returns Formatted file size string
*
* @example
* fileSizeFormat(1024) // "1,00 KB"
* fileSizeFormat(1048576) // "1,00 MB"
*/
export function fileSizeFormat(
bytes: number | string | null | undefined,
decimals: number = 2
): string {
if (bytes === null || bytes === undefined || bytes === '') {
return '0 Bytes';
}
const num = typeof bytes === 'string' ? parseFloat(bytes) : bytes;
if (num === 0) return '0 Bytes';
if (isNaN(num)) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
const i = Math.floor(Math.log(Math.abs(num)) / Math.log(k));
return numberFormat(num / Math.pow(k, i), decimals) + ' ' + sizes[i];
}
/**
* Abbreviate large numbers
* @param value - Number to abbreviate
* @param decimals - Number of decimal places (default: 1)
* @returns Abbreviated number string
*
* @example
* abbreviateNumber(1234) // "1,2 K"
* abbreviateNumber(1234567) // "1,2 M"
* abbreviateNumber(1234567890) // "1,2 B"
*/
export function abbreviateNumber(
value: number | string | null | undefined,
decimals: number = 1
): string {
if (value === null || value === undefined || value === '') {
return '0';
}
const num = typeof value === 'string' ? parseFloat(value) : value;
if (isNaN(num)) {
return '0';
}
if (Math.abs(num) < 1000) {
return numberFormat(num, 0);
}
const units = ['K', 'M', 'B', 'T'];
const unit = Math.floor((Math.abs(num).toString().length - 1) / 3);
const unitValue = Math.pow(1000, unit);
const shortValue = num / unitValue;
return numberFormat(shortValue, decimals) + ' ' + units[unit - 1];
}
/**
* Parse formatted number string back to number
* @param value - Formatted number string
* @param decimalSeparator - Decimal separator used in the string
* @param thousandSeparator - Thousand separator used in the string
* @returns Parsed number
*
* @example
* parseNumber("1.234.567,89") // 1234567.89
* parseNumber("1,234.50", '.', ',') // 1234.50
*/
export function parseNumber(
value: string | null | undefined,
decimalSeparator: string = ',',
thousandSeparator: string = '.'
): number {
if (!value) return 0;
// Remove thousand separators and replace decimal separator with dot
const cleanValue = value
.replace(new RegExp('\\' + thousandSeparator, 'g'), '')
.replace(decimalSeparator, '.');
const num = parseFloat(cleanValue);
return isNaN(num) ? 0 : num;
}
/**
* Format phone number to Indonesian format
* @param value - Phone number to format
* @returns Formatted phone number
*
* @example
* phoneFormat("081234567890") // "0812-3456-7890"
* phoneFormat("628123456789") // "62-812-3456-7890"
*/
export function phoneFormat(value: string | null | undefined): string {
if (!value) return '';
const cleaned = value.replace(/\D/g, '');
if (cleaned.startsWith('62')) {
// International format
const match = cleaned.match(/^(\d{2})(\d{3})(\d{4})(\d+)$/);
if (match) {
return `${match[1]}-${match[2]}-${match[3]}-${match[4]}`;
}
} else if (cleaned.startsWith('0')) {
// Local format
const match = cleaned.match(/^(\d{4})(\d{4})(\d+)$/);
if (match) {
return `${match[1]}-${match[2]}-${match[3]}`;
}
}
return cleaned;
}
/**
* Capitalize first letter of each word
* @param value - String to capitalize
* @returns Capitalized string
*
* @example
* capitalize("hello world") // "Hello World"
*/
export function capitalize(value: string | null | undefined): string {
if (!value) return '';
return value
.toLowerCase()
.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
}
/**
* Truncate string with ellipsis
* @param value - String to truncate
* @param length - Maximum length
* @param suffix - Suffix to add (default: '...')
* @returns Truncated string
*
* @example
* truncate("Hello World", 8) // "Hello..."
*/
export function truncate(
value: string | null | undefined,
length: number,
suffix: string = '...'
): string {
if (!value) return '';
if (value.length <= length) return value;
return value.substring(0, length) + suffix;
}
export function formatDate(date: string | Date | null | undefined, options?: Intl.DateTimeFormatOptions): string {
if (!date) return '-';
return new Date(date).toLocaleDateString('id-ID', {
year: 'numeric',
month: 'short',
day: 'numeric'
});
};