Add global search, in-app + push notifications, and fix card/beneficiary/scroll issues
- Global feature search for the user app, wired to the home search icon - Notifications screen: swipe-to-delete, vanish animation, unread badge, and Notifee-backed foreground + background (scheduled) OS notifications - Fix Add Beneficiary save (single source of truth via beneficiaries slice) - Fix Cards tab scroll freeze and bottom blank space (use ScreenShell scroll) - User-friendly toast copy across the app - Android build tuning: parallel/caching/JVM G1 args, mobile-only ABIs Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
d7907e1d64
commit
58af541536
@@ -1,9 +1,130 @@
|
||||
import { PermissionsAndroid, Platform } from 'react-native';
|
||||
import notifee, {
|
||||
AndroidImportance,
|
||||
AuthorizationStatus,
|
||||
TriggerType,
|
||||
type TimestampTrigger,
|
||||
} from '@notifee/react-native';
|
||||
|
||||
export const registerForPushNotifications = async () => {
|
||||
if (Platform.OS === 'android' && Platform.Version >= 33) {
|
||||
return PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS);
|
||||
}
|
||||
import type { NotificationCategory } from '../../types/app';
|
||||
|
||||
return 'granted';
|
||||
const CHANNEL_ID = 'bankcbs-general';
|
||||
|
||||
export type DummyNotificationContent = {
|
||||
category: NotificationCategory;
|
||||
title: string;
|
||||
body: string;
|
||||
};
|
||||
|
||||
const DUMMY_POOL: DummyNotificationContent[] = [
|
||||
{
|
||||
category: 'transaction',
|
||||
title: 'Money received',
|
||||
body: '₹4,200 was credited to your Savings account from Rohan Mehta.',
|
||||
},
|
||||
{
|
||||
category: 'transaction',
|
||||
title: 'Payment successful',
|
||||
body: 'Your payment of ₹1,150 for a mobile recharge went through.',
|
||||
},
|
||||
{
|
||||
category: 'security',
|
||||
title: 'New sign-in detected',
|
||||
body: 'A new sign-in was detected on your account. Tap to review.',
|
||||
},
|
||||
{
|
||||
category: 'offer',
|
||||
title: 'Reward unlocked',
|
||||
body: 'You just earned 250 reward points on your last card spend.',
|
||||
},
|
||||
{
|
||||
category: 'reminder',
|
||||
title: 'Bill reminder',
|
||||
body: 'Your electricity bill of ₹2,340 is due in 3 days.',
|
||||
},
|
||||
];
|
||||
|
||||
const DEFAULT_CONTENT: DummyNotificationContent = DUMMY_POOL[0] ?? {
|
||||
category: 'system',
|
||||
title: 'New notification',
|
||||
body: 'You have a new update.',
|
||||
};
|
||||
|
||||
export const getDummyNotificationContent = (): DummyNotificationContent => {
|
||||
const index = Math.floor(Math.random() * DUMMY_POOL.length);
|
||||
return DUMMY_POOL[index] ?? DEFAULT_CONTENT;
|
||||
};
|
||||
|
||||
let channelReady = false;
|
||||
|
||||
const ensureChannel = async () => {
|
||||
if (!channelReady) {
|
||||
await notifee.createChannel({
|
||||
id: CHANNEL_ID,
|
||||
name: 'General alerts',
|
||||
importance: AndroidImportance.HIGH,
|
||||
});
|
||||
channelReady = true;
|
||||
}
|
||||
return CHANNEL_ID;
|
||||
};
|
||||
|
||||
/** Request OS notification permission and make sure the Android channel exists. */
|
||||
export const registerForPushNotifications = async () => {
|
||||
const settings = await notifee.requestPermission();
|
||||
await ensureChannel();
|
||||
|
||||
const granted =
|
||||
settings.authorizationStatus === AuthorizationStatus.AUTHORIZED ||
|
||||
settings.authorizationStatus === AuthorizationStatus.PROVISIONAL;
|
||||
|
||||
return granted ? 'granted' : 'denied';
|
||||
};
|
||||
|
||||
/**
|
||||
* Show a notification immediately. While the app is in the foreground this
|
||||
* appears as a heads-up popup (HIGH importance channel); it also lands in the
|
||||
* system tray.
|
||||
*/
|
||||
export const displayLocalNotification = async (content: DummyNotificationContent) => {
|
||||
const channelId = await ensureChannel();
|
||||
await notifee.displayNotification({
|
||||
title: content.title,
|
||||
body: content.body,
|
||||
android: {
|
||||
channelId,
|
||||
smallIcon: 'ic_launcher',
|
||||
importance: AndroidImportance.HIGH,
|
||||
pressAction: { id: 'default' },
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Schedule a notification to fire after `seconds`. This is how we demo a
|
||||
* background notification: trigger it, then minimise the app and it arrives in
|
||||
* the system tray even though the app is no longer in the foreground.
|
||||
*/
|
||||
export const scheduleLocalNotification = async (
|
||||
content: DummyNotificationContent,
|
||||
seconds = 5,
|
||||
) => {
|
||||
const channelId = await ensureChannel();
|
||||
const trigger: TimestampTrigger = {
|
||||
type: TriggerType.TIMESTAMP,
|
||||
timestamp: Date.now() + seconds * 1000,
|
||||
};
|
||||
|
||||
await notifee.createTriggerNotification(
|
||||
{
|
||||
title: content.title,
|
||||
body: content.body,
|
||||
android: {
|
||||
channelId,
|
||||
smallIcon: 'ic_launcher',
|
||||
importance: AndroidImportance.HIGH,
|
||||
pressAction: { id: 'default' },
|
||||
},
|
||||
},
|
||||
trigger,
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user