From adcdce1704ead68b6a60d8f5bfcfc13de9d31686 Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Wed, 18 Feb 2026 03:57:33 +0100 Subject: [PATCH] fixed notifications --- .../0016_notification_ticket_and_more.py | 24 ++++ backend/api/models.py | 5 +- backend/api/views.py | 6 +- frontend/src/App.tsx | 104 ++++++++++-------- frontend/src/i18n.ts | 12 +- frontend/src/main.tsx | 5 +- frontend/src/pages/Support.tsx | 71 ++++++++++-- 7 files changed, 165 insertions(+), 62 deletions(-) create mode 100644 backend/api/migrations/0016_notification_ticket_and_more.py diff --git a/backend/api/migrations/0016_notification_ticket_and_more.py b/backend/api/migrations/0016_notification_ticket_and_more.py new file mode 100644 index 0000000..b41f3c3 --- /dev/null +++ b/backend/api/migrations/0016_notification_ticket_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 6.0.2 on 2026-02-18 02:55 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0015_ticket_ticketmessage_userip'), + ] + + operations = [ + migrations.AddField( + model_name='notification', + name='ticket', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='api.ticket'), + ), + migrations.AlterField( + model_name='notification', + name='notification_type', + field=models.CharField(choices=[('reply', 'Reply'), ('mention', 'Mention'), ('ticket_new', 'New Ticket'), ('ticket_reply', 'Ticket Reply')], max_length=20), + ), + ] diff --git a/backend/api/models.py b/backend/api/models.py index e05f5df..4118fbe 100644 --- a/backend/api/models.py +++ b/backend/api/models.py @@ -124,11 +124,12 @@ class Notification(models.Model): TYPE_CHOICES = [ ('reply', 'Reply'), ('mention', 'Mention'), - ('ticket', 'Ticket Update'), + ('ticket_new', 'New Ticket'), + ('ticket_reply', 'Ticket Reply'), ] recipient = models.ForeignKey(User, related_name='notifications', on_delete=models.CASCADE) actor = models.ForeignKey(User, related_name='actions', on_delete=models.CASCADE) - notification_type = models.CharField(max_length=10, choices=TYPE_CHOICES) + notification_type = models.CharField(max_length=20, choices=TYPE_CHOICES) rating = models.ForeignKey(Rating, on_delete=models.CASCADE, null=True, blank=True) reply = models.ForeignKey(Reply, on_delete=models.CASCADE, null=True, blank=True) ticket = models.ForeignKey('Ticket', on_delete=models.CASCADE, null=True, blank=True) diff --git a/backend/api/views.py b/backend/api/views.py index 9c2106e..819f3e0 100644 --- a/backend/api/views.py +++ b/backend/api/views.py @@ -583,7 +583,7 @@ class TicketViewSet(viewsets.ModelViewSet): Notification.objects.create( recipient=admin, actor=self.request.user, - notification_type='ticket', + notification_type='ticket_new', ticket=ticket ) @@ -603,7 +603,7 @@ class TicketViewSet(viewsets.ModelViewSet): Notification.objects.create( recipient=ticket.user, actor=request.user, - notification_type='ticket', + notification_type='ticket_reply', ticket=ticket ) else: @@ -613,7 +613,7 @@ class TicketViewSet(viewsets.ModelViewSet): Notification.objects.create( recipient=admin, actor=request.user, - notification_type='ticket', + notification_type='ticket_reply', ticket=ticket ) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index a58cf83..a5198cf 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect, useMemo, Suspense, lazy } from 'react'; -import { BrowserRouter as Router, Routes, Route, Link, useNavigate, useLocation } from 'react-router-dom'; +import { Routes, Route, Link, useNavigate, useLocation } from 'react-router-dom'; import { ThemeProvider, CssBaseline, @@ -206,6 +206,7 @@ const GlobalSearch = () => { const App: React.FC = () => { const { i18n, t } = useTranslation(); + const navigate = useNavigate(); const [themeName, setThemeName] = useState((localStorage.getItem('theme') as CatppuccinTheme) || 'holy_light'); const [anchorEl, setAnchorEl] = useState(null); const [notifAnchorEl, setNotifAnchorEl] = useState(null); @@ -492,35 +493,52 @@ const App: React.FC = () => { No notifications yet ) : ( - notifications.map(n => ( - handleNotificationClick(n)} - sx={{ - py: 1.5, - px: 2, - borderBottom: '1px solid', - borderColor: 'divider', - bgcolor: n.is_read ? 'transparent' : alpha(theme.palette.primary.main, 0.05), - whiteSpace: 'normal', - display: 'flex', - gap: 2, - alignItems: 'flex-start' - }} - > - - {n.actor_username.charAt(0).toUpperCase()} - - - - {n.actor_username} {n.notification_type === 'reply' ? 'replied' : 'mentioned you'} on {n.flavor_name} - - - {formatDate(n.created_at)} - - - - )) + notifications.map(n => { + let message = ""; + if (n.notification_type === 'reply') message = `replied to your review on ${n.flavor_name}`; + else if (n.notification_type === 'mention') message = `mentioned you on ${n.flavor_name}`; + else if (n.notification_type === 'ticket_new') message = t('community.notifTicketNew'); + else if (n.notification_type === 'ticket_reply') message = user?.is_superuser ? t('community.notifTicketReplyAdmin') : t('community.notifTicketReply'); + + const handleClick = () => { + if (n.notification_type.startsWith('ticket')) { + handleNotificationClick(n); + navigate('/support'); + } else { + handleNotificationClick(n); + } + }; + + return ( + + + {n.actor_username.charAt(0).toUpperCase()} + + + + {n.actor_username} {message} + + + {formatDate(n.created_at)} + + + + ); + }) )} @@ -529,19 +547,18 @@ const App: React.FC = () => { return ( - - - alpha(theme.palette.background.paper, 0.8), - backdropFilter: 'blur(12px)', - color: 'text.primary' - }} - > + + alpha(theme.palette.background.paper, 0.8), + backdropFilter: 'blur(12px)', + color: 'text.primary' + }} + > @@ -678,7 +695,6 @@ const App: React.FC = () => {