Files
CRM_Montzar/apps/web/src/lib/gamification.ts
T

104 lines
3.2 KiB
TypeScript
Raw Normal View History

import type { GamificationEvent, GamificationTxDto } from '@mento/shared';
import { GAMIFICATION_EVENTS } from '@mento/shared';
import { toFaDigits } from '@/lib/jalali';
export { apiError } from '@/lib/routines';
type IconName =
| 'trophy'
| 'user-plus'
| 'funnel'
| 'briefcase'
| 'phone'
| 'calendar'
| 'document'
| 'check'
| 'refresh'
| 'dollar'
| 'chat'
| 'star'
| 'medal'
| 'gift'
| 'sliders'
| 'building'
| 'trend';
const EVENT_ICONS: Record<GamificationEvent, IconName> = {
LEAD_CREATED: 'funnel',
LEAD_STAGE_CHANGED: 'trend',
LEAD_CONVERTED: 'user-plus',
CUSTOMER_CREATED: 'user-plus',
COMPANY_CREATED: 'building',
DEAL_CREATED: 'briefcase',
DEAL_STAGE_CHANGED: 'trend',
DEAL_WON: 'trophy',
DEAL_LOST: 'briefcase',
CALL_LOGGED: 'phone',
MEETING_CREATED: 'calendar',
FOLLOW_UP_CREATED: 'calendar',
NOTE_CREATED: 'document',
ACTIVITY_CREATED: 'check',
TASK_COMPLETED: 'check',
ROUTINE_COMPLETED: 'refresh',
QUOTE_CREATED: 'document',
INVOICE_ISSUED: 'dollar',
PAYMENT_REGISTERED: 'dollar',
TICKET_CREATED: 'chat',
TICKET_RESOLVED: 'chat',
};
export function txIcon(tx: Pick<GamificationTxDto, 'kind' | 'event'>): IconName {
if (tx.kind === 'bonus') return 'star';
if (tx.kind === 'achievement') return 'medal';
if (tx.kind === 'redeem' || tx.kind === 'refund') return 'gift';
if (tx.kind === 'adjust') return 'sliders';
return tx.event ? EVENT_ICONS[tx.event] : 'star';
}
export function eventLabel(event: GamificationEvent | null | undefined): string {
return event ? GAMIFICATION_EVENTS[event]?.label ?? event : '';
}
/** عدد فارسی با جداکننده هزارگان */
export function faNum(value: number | null | undefined): string {
if (value == null || !Number.isFinite(value)) return '—';
return toFaDigits(Math.round(value).toLocaleString('en-US'));
}
export function signedFa(value: number): string {
if (!value) return toFaDigits(0);
return `${value > 0 ? '+' : '−'}${faNum(Math.abs(value))}`;
}
/** «۵ دقیقه پیش»، «دیروز ۱۴:۲۰» … */
export function timeAgo(iso: string): string {
const d = new Date(iso);
const diff = Date.now() - d.getTime();
const min = Math.floor(diff / 60_000);
if (min < 1) return 'همین الان';
if (min < 60) return `${toFaDigits(min)} دقیقه پیش`;
const hours = Math.floor(min / 60);
if (hours < 24) return `${toFaDigits(hours)} ساعت پیش`;
const days = Math.floor(hours / 24);
if (days < 7) return `${toFaDigits(days)} روز پیش`;
return new Intl.DateTimeFormat('fa-IR', { dateStyle: 'medium' }).format(d);
}
export function formatDateTime(iso: string): string {
try {
return new Intl.DateTimeFormat('fa-IR', { dateStyle: 'medium', timeStyle: 'short' }).format(new Date(iso));
} catch {
return iso;
}
}
export const REWARD_ICONS = ['gift', 'star', 'trophy', 'medal', 'crown', 'calendar-sun', 'bag', 'target', 'fire'] as const;
export const BADGE_ICONS = ['medal', 'trophy', 'crown', 'star', 'fire', 'phone', 'users', 'funnel', 'target', 'check'] as const;
export const ROLE_LABELS: Record<string, string> = {
owner: 'مالک',
admin: 'مدیر',
sales: 'فروش',
support: 'پشتیبانی',
};