mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
Merge pull request #3 from PEDZEO/PEDZ
Add ticket notification system with user and admin notification setti…
This commit is contained in:
@@ -59,6 +59,8 @@ export interface TicketSettings {
|
|||||||
sla_check_interval_seconds: number
|
sla_check_interval_seconds: number
|
||||||
sla_reminder_cooldown_minutes: number
|
sla_reminder_cooldown_minutes: number
|
||||||
support_system_mode: string // tickets, contact, both
|
support_system_mode: string // tickets, contact, both
|
||||||
|
cabinet_user_notifications_enabled: boolean
|
||||||
|
cabinet_admin_notifications_enabled: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TicketSettingsUpdate {
|
export interface TicketSettingsUpdate {
|
||||||
@@ -67,6 +69,8 @@ export interface TicketSettingsUpdate {
|
|||||||
sla_check_interval_seconds?: number
|
sla_check_interval_seconds?: number
|
||||||
sla_reminder_cooldown_minutes?: number
|
sla_reminder_cooldown_minutes?: number
|
||||||
support_system_mode?: string
|
support_system_mode?: string
|
||||||
|
cabinet_user_notifications_enabled?: boolean
|
||||||
|
cabinet_admin_notifications_enabled?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AdminTicketListResponse {
|
export interface AdminTicketListResponse {
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ export default function Layout({ children }: LayoutProps) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<PromoDiscountBadge />
|
<PromoDiscountBadge />
|
||||||
<TicketNotificationBell isAdmin={isAdminActive()} />
|
<TicketNotificationBell isAdmin={isAdmin} />
|
||||||
<LanguageSwitcher />
|
<LanguageSwitcher />
|
||||||
|
|
||||||
{/* Profile - Desktop */}
|
{/* Profile - Desktop */}
|
||||||
|
|||||||
@@ -35,6 +35,20 @@
|
|||||||
"info": "Info",
|
"info": "Info",
|
||||||
"wheel": "Fortune Wheel"
|
"wheel": "Fortune Wheel"
|
||||||
},
|
},
|
||||||
|
"notifications": {
|
||||||
|
"ticketNotifications": "Ticket Notifications",
|
||||||
|
"markAllRead": "Mark all read",
|
||||||
|
"noNotifications": "No notifications",
|
||||||
|
"justNow": "Just now",
|
||||||
|
"minutesAgo": "{{count}} min ago",
|
||||||
|
"hoursAgo": "{{count}} h ago",
|
||||||
|
"daysAgo": "{{count}} d ago",
|
||||||
|
"viewAll": "View all tickets",
|
||||||
|
"newNotification": "New notification",
|
||||||
|
"clickToView": "Click to view",
|
||||||
|
"newTicket": "New ticket: {{title}}",
|
||||||
|
"newReply": "New reply in ticket"
|
||||||
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"register": "Register",
|
"register": "Register",
|
||||||
@@ -732,7 +746,12 @@
|
|||||||
"reminderCooldown": "Reminder interval (minutes)",
|
"reminderCooldown": "Reminder interval (minutes)",
|
||||||
"reminderCooldownDesc": "Minimum time between reminders (1-120 minutes)",
|
"reminderCooldownDesc": "Minimum time between reminders (1-120 minutes)",
|
||||||
"settingsUpdateError": "Error saving settings",
|
"settingsUpdateError": "Error saving settings",
|
||||||
"copyTelegramId": "Click to copy Telegram ID"
|
"copyTelegramId": "Click to copy Telegram ID",
|
||||||
|
"cabinetNotifications": "Cabinet Notifications",
|
||||||
|
"userNotificationsEnabled": "User Notifications",
|
||||||
|
"userNotificationsEnabledDesc": "Send notifications to users about admin replies",
|
||||||
|
"adminNotificationsEnabled": "Admin Notifications",
|
||||||
|
"adminNotificationsEnabledDesc": "Send notifications to admins about new tickets and replies"
|
||||||
},
|
},
|
||||||
"tariffs": {
|
"tariffs": {
|
||||||
"title": "Tariff Management",
|
"title": "Tariff Management",
|
||||||
|
|||||||
@@ -35,6 +35,20 @@
|
|||||||
"info": "Информация",
|
"info": "Информация",
|
||||||
"wheel": "Колесо удачи"
|
"wheel": "Колесо удачи"
|
||||||
},
|
},
|
||||||
|
"notifications": {
|
||||||
|
"ticketNotifications": "Уведомления о тикетах",
|
||||||
|
"markAllRead": "Прочитать все",
|
||||||
|
"noNotifications": "Нет уведомлений",
|
||||||
|
"justNow": "Только что",
|
||||||
|
"minutesAgo": "{{count}} мин. назад",
|
||||||
|
"hoursAgo": "{{count}} ч. назад",
|
||||||
|
"daysAgo": "{{count}} д. назад",
|
||||||
|
"viewAll": "Все тикеты",
|
||||||
|
"newNotification": "Новое уведомление",
|
||||||
|
"clickToView": "Нажмите для просмотра",
|
||||||
|
"newTicket": "Новый тикет: {{title}}",
|
||||||
|
"newReply": "Новый ответ в тикете"
|
||||||
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"login": "Вход",
|
"login": "Вход",
|
||||||
"register": "Регистрация",
|
"register": "Регистрация",
|
||||||
@@ -732,7 +746,12 @@
|
|||||||
"reminderCooldown": "Интервал напоминаний (минуты)",
|
"reminderCooldown": "Интервал напоминаний (минуты)",
|
||||||
"reminderCooldownDesc": "Минимальное время между напоминаниями (1-120 минут)",
|
"reminderCooldownDesc": "Минимальное время между напоминаниями (1-120 минут)",
|
||||||
"settingsUpdateError": "Ошибка сохранения настроек",
|
"settingsUpdateError": "Ошибка сохранения настроек",
|
||||||
"copyTelegramId": "Нажмите чтобы скопировать Telegram ID"
|
"copyTelegramId": "Нажмите чтобы скопировать Telegram ID",
|
||||||
|
"cabinetNotifications": "Уведомления в кабинете",
|
||||||
|
"userNotificationsEnabled": "Уведомления для пользователей",
|
||||||
|
"userNotificationsEnabledDesc": "Отправлять уведомления пользователям об ответах админа",
|
||||||
|
"adminNotificationsEnabled": "Уведомления для админов",
|
||||||
|
"adminNotificationsEnabledDesc": "Отправлять уведомления админам о новых тикетах и ответах"
|
||||||
},
|
},
|
||||||
"tariffs": {
|
"tariffs": {
|
||||||
"title": "Управление тарифами",
|
"title": "Управление тарифами",
|
||||||
|
|||||||
@@ -460,6 +460,8 @@ function TicketSettingsModal({ onClose }: { onClose: () => void }) {
|
|||||||
sla_check_interval_seconds: settings?.sla_check_interval_seconds ?? 60,
|
sla_check_interval_seconds: settings?.sla_check_interval_seconds ?? 60,
|
||||||
sla_reminder_cooldown_minutes: settings?.sla_reminder_cooldown_minutes ?? 15,
|
sla_reminder_cooldown_minutes: settings?.sla_reminder_cooldown_minutes ?? 15,
|
||||||
support_system_mode: settings?.support_system_mode ?? 'both',
|
support_system_mode: settings?.support_system_mode ?? 'both',
|
||||||
|
cabinet_user_notifications_enabled: settings?.cabinet_user_notifications_enabled ?? true,
|
||||||
|
cabinet_admin_notifications_enabled: settings?.cabinet_admin_notifications_enabled ?? true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Update form when settings load
|
// Update form when settings load
|
||||||
@@ -471,6 +473,8 @@ function TicketSettingsModal({ onClose }: { onClose: () => void }) {
|
|||||||
sla_check_interval_seconds: settings.sla_check_interval_seconds,
|
sla_check_interval_seconds: settings.sla_check_interval_seconds,
|
||||||
sla_reminder_cooldown_minutes: settings.sla_reminder_cooldown_minutes,
|
sla_reminder_cooldown_minutes: settings.sla_reminder_cooldown_minutes,
|
||||||
support_system_mode: settings.support_system_mode,
|
support_system_mode: settings.support_system_mode,
|
||||||
|
cabinet_user_notifications_enabled: settings.cabinet_user_notifications_enabled ?? true,
|
||||||
|
cabinet_admin_notifications_enabled: settings.cabinet_admin_notifications_enabled ?? true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, [settings])
|
}, [settings])
|
||||||
@@ -526,6 +530,43 @@ function TicketSettingsModal({ onClose }: { onClose: () => void }) {
|
|||||||
<p className="text-xs text-dark-500 mt-1">{t('admin.tickets.supportModeDesc')}</p>
|
<p className="text-xs text-dark-500 mt-1">{t('admin.tickets.supportModeDesc')}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Cabinet Notifications */}
|
||||||
|
<div className="border-t border-dark-800/50 pt-6">
|
||||||
|
<h3 className="text-lg font-semibold text-dark-100 mb-4">{t('admin.tickets.cabinetNotifications')}</h3>
|
||||||
|
|
||||||
|
{/* User Notifications */}
|
||||||
|
<div className="mb-4">
|
||||||
|
<label className="flex items-center gap-3 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={formData.cabinet_user_notifications_enabled}
|
||||||
|
onChange={(e) => setFormData({ ...formData, cabinet_user_notifications_enabled: e.target.checked })}
|
||||||
|
className="w-5 h-5 rounded border-dark-700 bg-dark-800 text-accent-500 focus:ring-2 focus:ring-accent-500 focus:ring-offset-0"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<div className="text-dark-100 font-medium">{t('admin.tickets.userNotificationsEnabled')}</div>
|
||||||
|
<div className="text-sm text-dark-500">{t('admin.tickets.userNotificationsEnabledDesc')}</div>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Admin Notifications */}
|
||||||
|
<div>
|
||||||
|
<label className="flex items-center gap-3 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={formData.cabinet_admin_notifications_enabled}
|
||||||
|
onChange={(e) => setFormData({ ...formData, cabinet_admin_notifications_enabled: e.target.checked })}
|
||||||
|
className="w-5 h-5 rounded border-dark-700 bg-dark-800 text-accent-500 focus:ring-2 focus:ring-accent-500 focus:ring-offset-0"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<div className="text-dark-100 font-medium">{t('admin.tickets.adminNotificationsEnabled')}</div>
|
||||||
|
<div className="text-sm text-dark-500">{t('admin.tickets.adminNotificationsEnabledDesc')}</div>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="border-t border-dark-800/50 pt-6">
|
<div className="border-t border-dark-800/50 pt-6">
|
||||||
<h3 className="text-lg font-semibold text-dark-100 mb-4">{t('admin.tickets.slaSettings')}</h3>
|
<h3 className="text-lg font-semibold text-dark-100 mb-4">{t('admin.tickets.slaSettings')}</h3>
|
||||||
|
|
||||||
|
|||||||
@@ -517,21 +517,33 @@ export interface ManualCheckResponse {
|
|||||||
new_status: string | null
|
new_status: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ticket notification types
|
// Ticket notifications types
|
||||||
export interface TicketNotification {
|
export interface TicketNotification {
|
||||||
id: number
|
id: number
|
||||||
ticket_id: number
|
ticket_id: number
|
||||||
notification_type: string
|
notification_type: 'new_ticket' | 'admin_reply' | 'user_reply'
|
||||||
message: string
|
message: string | null
|
||||||
is_read: boolean
|
is_read: boolean
|
||||||
created_at: string
|
created_at: string
|
||||||
|
read_at: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TicketNotificationList {
|
export interface TicketNotificationList {
|
||||||
items: TicketNotification[]
|
items: TicketNotification[]
|
||||||
total: number
|
unread_count: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UnreadCountResponse {
|
export interface UnreadCountResponse {
|
||||||
unread_count: number
|
unread_count: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extended TicketSettings with cabinet notifications
|
||||||
|
export interface TicketSettings {
|
||||||
|
sla_enabled: boolean
|
||||||
|
sla_minutes: number
|
||||||
|
sla_check_interval_seconds: number
|
||||||
|
sla_reminder_cooldown_minutes: number
|
||||||
|
support_system_mode: string
|
||||||
|
cabinet_user_notifications_enabled: boolean
|
||||||
|
cabinet_admin_notifications_enabled: boolean
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user