notification

This commit is contained in:
2026-07-09 20:58:19 +03:30
parent 0732964753
commit c485ee326c
21 changed files with 1402 additions and 1 deletions
@@ -0,0 +1,291 @@
import { NotificationScenarioKey } from '../enums/notification-scenario-key.enum';
export interface NotificationScenarioVariable {
key: string;
label: string;
description: string;
sampleValue: string;
}
export interface NotificationScenarioDefinition {
key: NotificationScenarioKey;
label: string;
description: string;
defaultTitle: string;
defaultBody: string;
variables: NotificationScenarioVariable[];
}
export const NOTIFICATION_SCENARIOS: NotificationScenarioDefinition[] = [
{
key: NotificationScenarioKey.RESERVE_CREATED,
label: 'ثبت رزرو جدید',
description: 'اعلان برای سالن هنگام ثبت رزرو جدید',
defaultTitle: 'رزرو جدید ثبت شد',
defaultBody:
'رزرو {customerName} برای {appointmentDate} ساعت {startTime} با {stylistName} ثبت شد.',
variables: [
{
key: 'customerName',
label: 'نام مشتری',
description: 'نام و نام خانوادگی مشتری',
sampleValue: 'مریم احمدی',
},
{
key: 'salonName',
label: 'نام سالن',
description: 'نام سالن زیبایی',
sampleValue: 'سالن زیبایی رز',
},
{
key: 'stylistName',
label: 'نام متخصص',
description: 'نام متخصص انجام‌دهنده خدمت',
sampleValue: 'سارا محمدی',
},
{
key: 'appointmentDate',
label: 'تاریخ نوبت',
description: 'تاریخ رزرو',
sampleValue: '۱۴۰۴/۰۴/۲۰',
},
{
key: 'startTime',
label: 'ساعت شروع',
description: 'ساعت شروع نوبت',
sampleValue: '۱۰:۰۰',
},
{
key: 'endTime',
label: 'ساعت پایان',
description: 'ساعت پایان نوبت',
sampleValue: '۱۱:۳۰',
},
{
key: 'totalAmount',
label: 'مبلغ کل',
description: 'مبلغ کل رزرو به تومان',
sampleValue: '۱,۵۰۰,۰۰۰',
},
],
},
{
key: NotificationScenarioKey.RESERVE_CONFIRMED,
label: 'تأیید رزرو',
description: 'اعلان برای سالن پس از پرداخت بیعانه و تأیید رزرو',
defaultTitle: 'رزرو تأیید شد',
defaultBody:
'رزرو {customerName} برای {appointmentDate} ساعت {startTime} تأیید شد. بیعانه: {depositAmount} تومان',
variables: [
{
key: 'customerName',
label: 'نام مشتری',
description: 'نام و نام خانوادگی مشتری',
sampleValue: 'مریم احمدی',
},
{
key: 'salonName',
label: 'نام سالن',
description: 'نام سالن زیبایی',
sampleValue: 'سالن زیبایی رز',
},
{
key: 'appointmentDate',
label: 'تاریخ نوبت',
description: 'تاریخ رزرو',
sampleValue: '۱۴۰۴/۰۴/۲۰',
},
{
key: 'startTime',
label: 'ساعت شروع',
description: 'ساعت شروع نوبت',
sampleValue: '۱۰:۰۰',
},
{
key: 'depositAmount',
label: 'مبلغ بیعانه',
description: 'مبلغ بیعانه به تومان',
sampleValue: '۵۰۰,۰۰۰',
},
{
key: 'totalAmount',
label: 'مبلغ کل',
description: 'مبلغ کل رزرو به تومان',
sampleValue: '۱,۵۰۰,۰۰۰',
},
],
},
{
key: NotificationScenarioKey.RESERVE_CANCELLED,
label: 'لغو رزرو',
description: 'اعلان برای سالن هنگام لغو رزرو',
defaultTitle: 'رزرو لغو شد',
defaultBody:
'رزرو {customerName} برای {appointmentDate} ساعت {startTime} لغو شد.',
variables: [
{
key: 'customerName',
label: 'نام مشتری',
description: 'نام و نام خانوادگی مشتری',
sampleValue: 'مریم احمدی',
},
{
key: 'salonName',
label: 'نام سالن',
description: 'نام سالن زیبایی',
sampleValue: 'سالن زیبایی رز',
},
{
key: 'appointmentDate',
label: 'تاریخ نوبت',
description: 'تاریخ رزرو',
sampleValue: '۱۴۰۴/۰۴/۲۰',
},
{
key: 'startTime',
label: 'ساعت شروع',
description: 'ساعت شروع نوبت',
sampleValue: '۱۰:۰۰',
},
{
key: 'cancellationReason',
label: 'دلیل لغو',
description: 'دلیل لغو رزرو (در صورت ثبت)',
sampleValue: 'درخواست مشتری',
},
],
},
{
key: NotificationScenarioKey.RESERVE_REMINDER_SENT,
label: 'ارسال یادآوری رزرو',
description:
'اعلان خلاصه برای سالن پس از ارسال پیامک‌های یادآوری نوبت‌های امروز',
defaultTitle: 'یادآوری نوبت‌ها ارسال شد',
defaultBody:
'{sentCount} پیامک یادآوری برای نوبت‌های امروز ({appointmentDate}) ارسال شد.',
variables: [
{
key: 'sentCount',
label: 'تعداد ارسال‌شده',
description: 'تعداد پیامک‌های یادآوری ارسال‌شده',
sampleValue: '۵',
},
{
key: 'appointmentDate',
label: 'تاریخ نوبت',
description: 'تاریخ روز یادآوری',
sampleValue: '۱۴۰۴/۰۴/۲۰',
},
{
key: 'salonName',
label: 'نام سالن',
description: 'نام سالن زیبایی',
sampleValue: 'سالن زیبایی رز',
},
],
},
{
key: NotificationScenarioKey.CAMPAIGN_SENT,
label: 'ارسال کمپین',
description: 'اعلان برای سالن پس از اجرای موفق یا جزئی کمپین پیامکی',
defaultTitle: 'کمپین «{campaignLabel}» ارسال شد',
defaultBody:
'{sentCount} از {targetCount} پیامک ارسال شد. درآمد تخمینی: {estimatedRevenue} تومان',
variables: [
{
key: 'campaignLabel',
label: 'عنوان کمپین',
description: 'نام نوع کمپین',
sampleValue: 'کمپین تولد مشتری',
},
{
key: 'campaignType',
label: 'نوع کمپین',
description: 'کد نوع کمپین',
sampleValue: 'birthday',
},
{
key: 'sentCount',
label: 'تعداد ارسال‌شده',
description: 'تعداد پیامک‌های موفق',
sampleValue: '۱۲',
},
{
key: 'failedCount',
label: 'تعداد ناموفق',
description: 'تعداد پیامک‌های ناموفق',
sampleValue: '۱',
},
{
key: 'targetCount',
label: 'تعداد هدف',
description: 'تعداد کل مخاطبان کمپین',
sampleValue: '۱۳',
},
{
key: 'estimatedRevenue',
label: 'درآمد تخمینی',
description: 'درآمد تخمینی به تومان',
sampleValue: '۸,۰۰۰,۰۰۰',
},
{
key: 'salonName',
label: 'نام سالن',
description: 'نام سالن زیبایی',
sampleValue: 'سالن زیبایی رز',
},
],
},
{
key: NotificationScenarioKey.CAMPAIGN_FAILED,
label: 'شکست کمپین',
description:
'اعلان برای سالن وقتی کمپین به‌دلیل کمبود اعتبار یا خطای ارسال اجرا نشود',
defaultTitle: 'کمپین «{campaignLabel}» ارسال نشد',
defaultBody:
'کمپین برای {targetCount} مشتری اجرا نشد. موجودی پیامک یا تنظیمات را بررسی کنید.',
variables: [
{
key: 'campaignLabel',
label: 'عنوان کمپین',
description: 'نام نوع کمپین',
sampleValue: 'کمپین بازگشت مشتریان',
},
{
key: 'campaignType',
label: 'نوع کمپین',
description: 'کد نوع کمپین',
sampleValue: 'returning_customers',
},
{
key: 'targetCount',
label: 'تعداد هدف',
description: 'تعداد کل مخاطبان کمپین',
sampleValue: '۸',
},
{
key: 'salonName',
label: 'نام سالن',
description: 'نام سالن زیبایی',
sampleValue: 'سالن زیبایی رز',
},
],
},
];
export const NOTIFICATION_SCENARIO_MAP = new Map(
NOTIFICATION_SCENARIOS.map((scenario) => [scenario.key, scenario]),
);
export function getNotificationSampleVariables(
key: NotificationScenarioKey,
): Record<string, string> {
const scenario = NOTIFICATION_SCENARIO_MAP.get(key);
if (!scenario) {
return {};
}
return Object.fromEntries(
scenario.variables.map((variable) => [variable.key, variable.sampleValue]),
);
}