From fb2f5dd48d638b921863db52dd2446b45ac554ed Mon Sep 17 00:00:00 2001 From: MukhammadIbrokhimov Date: Wed, 18 Mar 2026 03:21:47 +0100 Subject: [PATCH 1/3] feat(notifications): add push notifications for completed and no-show bookings - booking_completed: prompts user to leave a review after visit - booking_no_show: friendly message when guest misses reservation - All messages in en/uz/ru --- backend/apps/notifications/messages.py | 28 ++++++++++++++++++++++++++ backend/apps/notifications/signals.py | 2 ++ 2 files changed, 30 insertions(+) diff --git a/backend/apps/notifications/messages.py b/backend/apps/notifications/messages.py index aadbe76..d8a35ce 100644 --- a/backend/apps/notifications/messages.py +++ b/backend/apps/notifications/messages.py @@ -66,6 +66,34 @@ class NotificationContent: body="Ваша бронь в {restaurant_name} на {date} была отменена.", ), }, + "booking_completed": { + "en": NotificationContent( + title="Thanks for visiting! 🍽️", + body="How was your experience at {restaurant_name}? We'd love to hear your feedback!", + ), + "uz": NotificationContent( + title="Tashrifingiz uchun rahmat! 🍽️", + body="{restaurant_name}da qanday bo'ldi? Fikringizni bilishni xohlaymiz!", + ), + "ru": NotificationContent( + title="Спасибо за визит! 🍽️", + body="Как вам в {restaurant_name}? Поделитесь впечатлениями!", + ), + }, + "booking_no_show": { + "en": NotificationContent( + title="We missed you!", + body="You missed your reservation at {restaurant_name}. Hope to see you next time!", + ), + "uz": NotificationContent( + title="Sizni sog'indik!", + body="{restaurant_name}dagi buyurtmangizga kelmadingiz. Keyingi safar kutamiz!", + ), + "ru": NotificationContent( + title="Мы вас не дождались!", + body="Вы пропустили бронь в {restaurant_name}. Ждём вас в следующий раз!", + ), + }, "reminder_24h": { "en": NotificationContent( title="Reminder: Tomorrow's Reservation", diff --git a/backend/apps/notifications/signals.py b/backend/apps/notifications/signals.py index e321b35..b64ec4c 100644 --- a/backend/apps/notifications/signals.py +++ b/backend/apps/notifications/signals.py @@ -13,6 +13,8 @@ Booking.Status.CONFIRMED: "booking_confirmed", Booking.Status.REJECTED: "booking_rejected", Booking.Status.CANCELLED: "booking_cancelled", + Booking.Status.COMPLETED: "booking_completed", + Booking.Status.NO_SHOW: "booking_no_show", } From 739a8b0583d86fbc23acac744584c835025fdacc Mon Sep 17 00:00:00 2001 From: MukhammadIbrokhimov Date: Wed, 18 Mar 2026 03:23:24 +0100 Subject: [PATCH 2/3] fix(fcm): specify notification icon and color in FCM message - Add icon='ic_notification' to AndroidNotification - Add color='#B52428' (brand red) for notification accent --- backend/apps/notifications/fcm.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/apps/notifications/fcm.py b/backend/apps/notifications/fcm.py index f7370ea..a47be17 100644 --- a/backend/apps/notifications/fcm.py +++ b/backend/apps/notifications/fcm.py @@ -91,6 +91,8 @@ def send(self, message: FCMMessage) -> FCMResult: android=messaging.AndroidConfig( priority="high", notification=messaging.AndroidNotification( + icon="ic_notification", + color="#B52428", click_action="OPEN_BOOKING", channel_id="bookings", ), From 6a6608d7fb852cfbdbcc4c8be33896aa10644266 Mon Sep 17 00:00:00 2001 From: MukhammadIbrokhimov Date: Wed, 18 Mar 2026 03:29:52 +0100 Subject: [PATCH 3/3] fix(android): register FCM token on OTP verification Users authenticating via OTP flow (first-time booking) weren't receiving push notifications because FCM token wasn't registered after OTP verification. Now registers token in verifyOtp() same as in login(). --- .../reservo/app/data/repository/AuthRepositoryImpl.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/android/app/src/main/java/com/reservo/app/data/repository/AuthRepositoryImpl.kt b/android/app/src/main/java/com/reservo/app/data/repository/AuthRepositoryImpl.kt index b8d3170..20488ed 100644 --- a/android/app/src/main/java/com/reservo/app/data/repository/AuthRepositoryImpl.kt +++ b/android/app/src/main/java/com/reservo/app/data/repository/AuthRepositoryImpl.kt @@ -197,6 +197,16 @@ class AuthRepositoryImpl @Inject constructor( // Map to domain user val user = mapToUser(userDto) + // Register FCM token if notifications are enabled + if (notificationPermissionManager.areNotificationsEnabled()) { + try { + val fcmToken = notificationRepository.getCurrentFcmToken() + fcmToken?.let { notificationRepository.registerDeviceToken(it) } + } catch (e: Exception) { + // Best effort - don't fail auth if FCM registration fails + } + } + // Update state _authState.value = AuthState.Authenticated( user = user,