Merge pull request #3 from PEDZEO/PEDZ

Add ticket notification system with user and admin notification setti…
This commit is contained in:
PEDZEO
2026-01-19 00:26:03 +03:00
committed by GitHub
6 changed files with 102 additions and 7 deletions

View File

@@ -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 {

View File

@@ -338,7 +338,7 @@ export default function Layout({ children }: LayoutProps) {
)} )}
<PromoDiscountBadge /> <PromoDiscountBadge />
<TicketNotificationBell isAdmin={isAdminActive()} /> <TicketNotificationBell isAdmin={isAdmin} />
<LanguageSwitcher /> <LanguageSwitcher />
{/* Profile - Desktop */} {/* Profile - Desktop */}

View File

@@ -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",

View File

@@ -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": "Управление тарифами",

View File

@@ -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>

View File

@@ -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
}