Add in-app + real-time notifications (SignalR/mock, Iran-friendly)
- AppNotification + OnlineService.onNotification (hub event + mock periodic) — no FCM/APNs (blocked in Iran); uses the existing realtime channel - notification-store + pushNotification(); 🔔 bell with unread badge in TopBar, notifications screen, global toaster (plays notify sfx) - Wired events: daily reward, post-match achievements, friend requests - Closed-app push (Pushe/Najva/Chabok) noted as a later step (needs provider keys) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -11,12 +11,16 @@ import { MatchmakingScreen } from "@/components/screens/MatchmakingScreen";
|
||||
import { LeaderboardScreen } from "@/components/screens/LeaderboardScreen";
|
||||
import { ShopScreen } from "@/components/screens/ShopScreen";
|
||||
import { ChatScreen } from "@/components/screens/ChatScreen";
|
||||
import { NotificationsScreen } from "@/components/screens/NotificationsScreen";
|
||||
import { AuthScreen } from "@/components/screens/AuthScreen";
|
||||
import { DailyRewardModal } from "@/components/online/DailyRewardModal";
|
||||
import { NotificationToaster } from "@/components/online/NotificationToaster";
|
||||
import { CapacitorBack } from "@/components/CapacitorBack";
|
||||
import { useSessionStore } from "@/lib/session-store";
|
||||
import { useGameStore } from "@/lib/game-store";
|
||||
import { useOnlineStore } from "@/lib/online-store";
|
||||
import { useNotifStore, pushNotification } from "@/lib/notification-store";
|
||||
import { getService } from "@/lib/online/service";
|
||||
import { screenFromHash, useUIStore, type Screen } from "@/lib/ui-store";
|
||||
|
||||
/** Transient screens can't be restored without their state — fall back to home. */
|
||||
@@ -43,6 +47,20 @@ export default function Page() {
|
||||
useEffect(() => {
|
||||
init();
|
||||
useUIStore.getState().initHistory();
|
||||
useNotifStore.getState().init();
|
||||
// surface a daily-reward notification if it's available
|
||||
getService()
|
||||
.getDailyState()
|
||||
.then((d) => {
|
||||
if (d.available)
|
||||
pushNotification({
|
||||
kind: "daily",
|
||||
titleFa: "پاداش روزانه آماده است",
|
||||
titleEn: "Daily reward is ready",
|
||||
icon: "🎁",
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
|
||||
const onPop = (e: PopStateEvent) => {
|
||||
const raw = ((e.state?.screen as Screen) ?? screenFromHash());
|
||||
@@ -56,6 +74,7 @@ export default function Page() {
|
||||
<>
|
||||
{renderScreen(screen)}
|
||||
<DailyRewardModal />
|
||||
<NotificationToaster />
|
||||
<CapacitorBack />
|
||||
{loading && null}
|
||||
</>
|
||||
@@ -84,6 +103,8 @@ function renderScreen(screen: string) {
|
||||
return <ShopScreen />;
|
||||
case "chat":
|
||||
return <ChatScreen />;
|
||||
case "notifications":
|
||||
return <NotificationsScreen />;
|
||||
default:
|
||||
return <HomeScreen />;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user