163 lines
5.4 KiB
TypeScript
163 lines
5.4 KiB
TypeScript
import { createContext, useContext, type ReactNode } from 'react';
|
||
import type { AppSettings } from '~/lib/settings-management.server';
|
||
|
||
interface SettingsContextType {
|
||
settings: AppSettings;
|
||
formatNumber: (value: number) => string;
|
||
formatCurrency: (value: number) => string;
|
||
formatDate: (date: Date | string) => string;
|
||
formatDateTime: (date: Date | string) => string;
|
||
}
|
||
|
||
const SettingsContext = createContext<SettingsContextType | null>(null);
|
||
|
||
interface SettingsProviderProps {
|
||
children: ReactNode;
|
||
settings: AppSettings;
|
||
}
|
||
|
||
export function SettingsProvider({ children, settings }: SettingsProviderProps) {
|
||
// Helper function to convert Western numerals to Arabic numerals
|
||
const convertToArabicNumerals = (str: string): string => {
|
||
const arabicNumerals = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'];
|
||
return str.replace(/[0-9]/g, (digit) => arabicNumerals[parseInt(digit)]);
|
||
};
|
||
|
||
// Helper function to format date with custom pattern
|
||
const formatDateWithPattern = (date: Date, pattern: string): string => {
|
||
const day = date.getDate();
|
||
const month = date.getMonth() + 1;
|
||
const year = date.getFullYear();
|
||
|
||
// Format numbers according to locale
|
||
const formatNumber = (num: number, padLength: number = 2): string => {
|
||
const padded = num.toString().padStart(padLength, '0');
|
||
return settings.numberFormat === 'ar-SA'
|
||
? convertToArabicNumerals(padded)
|
||
: padded;
|
||
};
|
||
|
||
return pattern
|
||
.replace(/yyyy/g, formatNumber(year, 4))
|
||
.replace(/yy/g, formatNumber(year % 100, 2))
|
||
.replace(/MM/g, formatNumber(month, 2))
|
||
.replace(/M/g, formatNumber(month, 1))
|
||
.replace(/dd/g, formatNumber(day, 2))
|
||
.replace(/d/g, formatNumber(day, 1));
|
||
};
|
||
|
||
const formatNumber = (value: number): string => {
|
||
return value.toLocaleString(settings.numberFormat);
|
||
};
|
||
|
||
const formatCurrency = (value: number): string => {
|
||
const formatted = value.toLocaleString(settings.numberFormat, {
|
||
minimumFractionDigits: 2,
|
||
maximumFractionDigits: 2
|
||
});
|
||
return `${formatted} ${settings.currencySymbol}`;
|
||
};
|
||
|
||
const formatDate = (date: Date | string): string => {
|
||
const dateObj = typeof date === 'string' ? new Date(date) : date;
|
||
return formatDateWithPattern(dateObj, settings.dateDisplayFormat);
|
||
};
|
||
|
||
const formatDateTime = (date: Date | string): string => {
|
||
const dateObj = typeof date === 'string' ? new Date(date) : date;
|
||
const datePart = formatDateWithPattern(dateObj, settings.dateDisplayFormat);
|
||
const timePart = dateObj.toLocaleTimeString(settings.dateFormat, {
|
||
hour: '2-digit',
|
||
minute: '2-digit'
|
||
});
|
||
return `${datePart} ${timePart}`;
|
||
};
|
||
|
||
const contextValue: SettingsContextType = {
|
||
settings,
|
||
formatNumber,
|
||
formatCurrency,
|
||
formatDate,
|
||
formatDateTime
|
||
};
|
||
|
||
return (
|
||
<SettingsContext.Provider value={contextValue}>
|
||
{children}
|
||
</SettingsContext.Provider>
|
||
);
|
||
}
|
||
|
||
export function useSettings(): SettingsContextType {
|
||
const context = useContext(SettingsContext);
|
||
if (!context) {
|
||
throw new Error('useSettings must be used within a SettingsProvider');
|
||
}
|
||
return context;
|
||
}
|
||
|
||
// Hook for formatting utilities without requiring context
|
||
export function useFormatters(settings: AppSettings) {
|
||
// Helper function to convert Western numerals to Arabic numerals
|
||
const convertToArabicNumerals = (str: string): string => {
|
||
const arabicNumerals = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'];
|
||
return str.replace(/[0-9]/g, (digit) => arabicNumerals[parseInt(digit)]);
|
||
};
|
||
|
||
// Helper function to format date with custom pattern
|
||
const formatDateWithPattern = (date: Date, pattern: string): string => {
|
||
const day = date.getDate();
|
||
const month = date.getMonth() + 1;
|
||
const year = date.getFullYear();
|
||
|
||
// Format numbers according to locale
|
||
const formatNumber = (num: number, padLength: number = 2): string => {
|
||
const padded = num.toString().padStart(padLength, '0');
|
||
return settings.numberFormat === 'ar-SA'
|
||
? convertToArabicNumerals(padded)
|
||
: padded;
|
||
};
|
||
|
||
return pattern
|
||
.replace(/yyyy/g, formatNumber(year, 4))
|
||
.replace(/yy/g, formatNumber(year % 100, 2))
|
||
.replace(/MM/g, formatNumber(month, 2))
|
||
.replace(/M/g, formatNumber(month, 1))
|
||
.replace(/dd/g, formatNumber(day, 2))
|
||
.replace(/d/g, formatNumber(day, 1));
|
||
};
|
||
|
||
const formatNumber = (value: number): string => {
|
||
return value.toLocaleString(settings.numberFormat);
|
||
};
|
||
|
||
const formatCurrency = (value: number): string => {
|
||
const formatted = value.toLocaleString(settings.numberFormat, {
|
||
minimumFractionDigits: 2,
|
||
maximumFractionDigits: 2
|
||
});
|
||
return `${formatted} ${settings.currencySymbol}`;
|
||
};
|
||
|
||
const formatDate = (date: Date | string): string => {
|
||
const dateObj = typeof date === 'string' ? new Date(date) : date;
|
||
return formatDateWithPattern(dateObj, settings.dateDisplayFormat);
|
||
};
|
||
|
||
const formatDateTime = (date: Date | string): string => {
|
||
const dateObj = typeof date === 'string' ? new Date(date) : date;
|
||
const datePart = formatDateWithPattern(dateObj, settings.dateDisplayFormat);
|
||
const timePart = dateObj.toLocaleTimeString(settings.dateFormat, {
|
||
hour: '2-digit',
|
||
minute: '2-digit'
|
||
});
|
||
return `${datePart} ${timePart}`;
|
||
};
|
||
|
||
return {
|
||
formatNumber,
|
||
formatCurrency,
|
||
formatDate,
|
||
formatDateTime
|
||
};
|
||
} |