- Positive Pay on the 12 Oct /pps contract (account number, not account ID): OTP enrollment, cheque submit, saved cheques, detail and stop payment. Full flow passed on the phone against mobile-banking-backend.lincpay. - Statement & Mini Statement guide v1.0 (14 Oct): mini statement JSON on Home and the Statement screen; dated PDF export with the password rule. - Onboarding slides and splash screen, Inter font, shared Icon and TypewriterText components, nearby branches via OpenStreetMap. - Every feature switched on; the 14 Oct switch set is kept in featureConfig.stage-2026-10-14.ts. Loans run on demo data until the backend has /loans routes. - npm run android wraps run-android for shells spawned from VS Code. - OpenProject work packages updated to 14-10-2026 status, with screenshots of Positive Pay, statement, loans and cards. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
129 lines
4.0 KiB
TypeScript
129 lines
4.0 KiB
TypeScript
import React, { memo } from 'react';
|
|
import {
|
|
Pressable,
|
|
StyleSheet,
|
|
Text,
|
|
View,
|
|
} from 'react-native';
|
|
|
|
import { Icon } from '../../../components/Icon';
|
|
import { useTheme, fontFamily, type CategoryHue } from '../../../theme';
|
|
import { Card } from '../../../components';
|
|
import { FeatureKey } from '../../../constants/featureKeys';
|
|
import { useEnabledItems } from '../../../features';
|
|
|
|
/**
|
|
* The tiles.
|
|
*
|
|
* Each names a categorical HUE rather than a hex. The hue is decorative — it
|
|
* exists so that neighbouring tiles are easy to tell apart, and it carries no
|
|
* state — so it resolves through `theme.colors.category`, which supplies a
|
|
* legible tone plus a matching tint chip for whichever theme is live.
|
|
*
|
|
* The previous `${hex}15` suffix built that chip by compositing the raw hue at
|
|
* 8% alpha over the card. That reads on white and disappears completely on a
|
|
* dark card, which is the specific bug the paired ramp exists to fix.
|
|
*/
|
|
const CBS_ACTIONS: ReadonlyArray<{
|
|
id: string;
|
|
feature: FeatureKey;
|
|
title: string;
|
|
subtitle: string;
|
|
icon: string;
|
|
hue: CategoryHue;
|
|
route: string;
|
|
}> = [
|
|
{ id: 'transfer', feature: FeatureKey.HOME_QUICK_ACTIONS_TRANSFER, title: 'Transfer', subtitle: 'Send Funds', icon: 'send', hue: 'blue', route: 'Payments' },
|
|
{ id: 'payments', feature: FeatureKey.HOME_QUICK_ACTIONS_BILL_PAY, title: 'Pay Bills', subtitle: 'Utilities', icon: 'receipt', hue: 'green', route: 'Payments' },
|
|
{ id: 'airtime', feature: FeatureKey.HOME_QUICK_ACTIONS_AIRTIME, title: 'Airtime', subtitle: 'Recharge', icon: 'phone-portrait', hue: 'violet', route: 'Payments' },
|
|
{ id: 'loans', feature: FeatureKey.HOME_QUICK_ACTIONS_LOANS, title: 'Loans', subtitle: 'Manage', icon: 'cash', hue: 'amber', route: 'LoanFlow' },
|
|
{ id: 'cards', feature: FeatureKey.HOME_QUICK_ACTIONS_CARDS, title: 'Cards', subtitle: 'Security', icon: 'card', hue: 'pink', route: 'Cards' },
|
|
{ id: 'services', feature: FeatureKey.HOME_QUICK_ACTIONS_STATS, title: 'Stats', subtitle: 'Summary', icon: 'stats-chart', hue: 'sky', route: 'Home' },
|
|
];
|
|
|
|
interface QuickActionsProps {
|
|
onPressRoute: (route: string) => void;
|
|
}
|
|
|
|
const QuickActionsComponent = ({ onPressRoute }: QuickActionsProps) => {
|
|
const theme = useTheme();
|
|
const actions = useEnabledItems(CBS_ACTIONS);
|
|
|
|
return (
|
|
<View style={styles.grid}>
|
|
{actions.map((action) => (
|
|
<Card
|
|
key={action.id}
|
|
style={styles.card}
|
|
>
|
|
<Pressable
|
|
onPress={() => onPressRoute(action.route)}
|
|
style={styles.pressable}
|
|
>
|
|
<View
|
|
style={[
|
|
styles.iconContainer,
|
|
{ backgroundColor: theme.colors.category[action.hue].surface },
|
|
]}
|
|
>
|
|
<Icon
|
|
name={action.icon as any}
|
|
size={22}
|
|
color={theme.colors.category[action.hue].tone}
|
|
/>
|
|
</View>
|
|
<View>
|
|
<Text style={[styles.title, { color: theme.colors.textPrimary }]}>{action.title}</Text>
|
|
<Text style={[styles.subtitle, { color: theme.colors.textSecondary }]}>
|
|
{action.subtitle}
|
|
</Text>
|
|
</View>
|
|
</Pressable>
|
|
</Card>
|
|
))}
|
|
</View>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
grid: {
|
|
flexDirection: 'row',
|
|
flexWrap: 'wrap',
|
|
gap: 12,
|
|
},
|
|
card: {
|
|
width: '31%', // Three columns for a more dense, premium feel
|
|
padding: 0,
|
|
borderRadius: 20,
|
|
overflow: 'hidden',
|
|
},
|
|
pressable: {
|
|
padding: 16,
|
|
gap: 10,
|
|
alignItems: 'center',
|
|
},
|
|
iconContainer: {
|
|
width: 48,
|
|
height: 48,
|
|
borderRadius: 14,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
},
|
|
title: {
|
|
fontSize: 13,
|
|
fontFamily: fontFamily.bold,
|
|
textAlign: 'center',
|
|
letterSpacing: -0.2,
|
|
},
|
|
subtitle: {
|
|
fontSize: 11,
|
|
marginTop: 2,
|
|
fontFamily: fontFamily.semibold,
|
|
textAlign: 'center',
|
|
opacity: 0.6,
|
|
},
|
|
});
|
|
|
|
export const QuickActions = memo(QuickActionsComponent);
|
|
|