From 66cfce28a5fa78fed8d6527b5cf41533aac4d3a7 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 27 Jun 2026 10:33:21 +0000 Subject: [PATCH] feat: add push notification registration and preferences foundation - Implement notification store with Zustand and persistence - Add permission handling and device token registration with Expo Notifications - Add notification preferences management in Settings UI - Implement mock adapter for backend registration and preference syncing - Update documentation with setup instructions and updated roadmap Co-authored-by: gloskull <189399494+gloskull@users.noreply.github.com> --- README.md | 15 +- app.json | 3 +- app/_layout.tsx | 6 + app/settings.tsx | 53 +- package-lock.json | 18116 ---------------- package.json | 4 +- pnpm-lock.yaml | 110 +- src/components/Toggle.tsx | 24 + .../notifications/notifications.adapter.ts | 21 + .../notifications/notifications.store.ts | 82 + .../notifications/notifications.types.ts | 17 + .../notifications/useNotifications.ts | 92 + tests/notifications.test.ts | 102 + 13 files changed, 511 insertions(+), 18134 deletions(-) delete mode 100644 package-lock.json create mode 100644 src/components/Toggle.tsx create mode 100644 src/features/notifications/notifications.adapter.ts create mode 100644 src/features/notifications/notifications.store.ts create mode 100644 src/features/notifications/notifications.types.ts create mode 100644 src/features/notifications/useNotifications.ts create mode 100644 tests/notifications.test.ts diff --git a/README.md b/README.md index 35b7f8f..700acd2 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,19 @@ maestro studio See [`.maestro/README.md`](.maestro/README.md) for detailed E2E testing documentation, troubleshooting, and best practices. +## 🔔 Push Notifications + +GuildPass Mobile uses Expo Notifications for real-time updates. Foundation includes: + +- **Token Registration**: Device tokens are registered with the backend (mocked in MVP). +- **Preferences**: Users can opt-in/out of specific notification categories (Role Changes, Access Grants, Membership Status) in Settings. +- **Permissions**: Automatic permission handling and status reporting. + +To test push notifications in development: +1. Use a **physical device** (not a simulator). +2. Ensure you are logged into your Expo account (`npx expo login`). +3. The app will request permissions when first navigating to Settings or performing an action requiring notifications. + ## 🚀 Build & Release GuildPass Mobile uses **EAS Build** with three distinct profiles: @@ -237,7 +250,7 @@ Deep links work when the app is cold-started (not already running). The app will - [ ] **Native Wallet Integration**: Support for WalletConnect, MetaMask, and Coinbase Wallet. - [ ] **Smart Onboarding**: Social login and embedded wallets for non-crypto native users. -- [ ] **Push Notifications**: Real-time alerts for role updates and access grants. +- [x] **Push Notifications**: Foundation for push notifications with registration and preferences. - [x] **QR Access Verification**: Scan GuildPass QR codes to verify token-gated resource access from the mobile app. - [ ] **Offline Resilience**: Advanced caching layer for viewing memberships without connectivity. diff --git a/app.json b/app.json index 13d785e..b174215 100644 --- a/app.json +++ b/app.json @@ -82,7 +82,8 @@ { "cameraPermission": "Allow GuildPass to scan access check QR codes." } - ] + ], + "expo-notifications" ] } } diff --git a/app/_layout.tsx b/app/_layout.tsx index 113bbc7..5cd750e 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -8,8 +8,14 @@ import { isPersistableQuery, QUERY_GC_TIME_MS } from "../src/lib/offlineCache"; import "../src/lib/networkManager"; import { useWalletStore } from "../src/features/wallet/wallet.store"; import { useSessionStore } from "../src/features/session/session.store"; +import { configureNotifications } from "../src/features/notifications/useNotifications"; export default function RootLayout() { + // Configure notification handler and channels once + useEffect(() => { + configureNotifications(); + }, []); + // Restore session state from wallet store on cold start useEffect(() => { const { walletAddress } = useWalletStore.getState(); diff --git a/app/settings.tsx b/app/settings.tsx index 19adb6d..8e87f01 100644 --- a/app/settings.tsx +++ b/app/settings.tsx @@ -6,9 +6,13 @@ import { Button } from "../src/components/Button"; import { appConfig } from "../src/config/appConfig"; import { resetAppState } from "../src/lib/resetAppState"; import React, { useState } from "react"; +import { useNotifications } from "../src/features/notifications/useNotifications"; +import { Toggle } from "../src/components/Toggle"; export default function Settings() { - const { isConnected } = useWallet(); + const { isConnected, address } = useWallet(); + const { permissionStatus, preferences, requestPermissions, togglePreference, isRegistering } = + useNotifications(); const [isResetting, setIsResetting] = useState(false); const handleReset = async () => { @@ -27,6 +31,53 @@ export default function Settings() { + Notifications + + + + Push Notifications + + {permissionStatus.charAt(0).toUpperCase() + permissionStatus.slice(1)} + + + {permissionStatus !== "granted" && ( +