Add Positive Pay, statement guide v1.0, onboarding, and switch every feature on
- 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>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5fbd13ba12
commit
f960a119e8
@@ -7,7 +7,7 @@ import {
|
||||
View,
|
||||
} from 'react-native';
|
||||
import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||
import Ionicons from '@react-native-vector-icons/ionicons';
|
||||
import { Icon } from '../../../components/Icon';
|
||||
import LinearGradient from 'react-native-linear-gradient';
|
||||
|
||||
import { BottomSheet, Button, Card, Input, ScreenShell } from '../../../components';
|
||||
@@ -16,7 +16,7 @@ import type { HomeStackParamList } from '../../../navigation/types';
|
||||
import { useTheme, fontFamily } from '../../../theme';
|
||||
|
||||
type Props = NativeStackScreenProps<HomeStackParamList, 'ReKyc'>;
|
||||
type IconName = React.ComponentProps<typeof Ionicons>['name'];
|
||||
type IconName = React.ComponentProps<typeof Icon>['name'];
|
||||
type ChangeField = 'name' | 'mobile' | 'email' | 'address';
|
||||
|
||||
type ChangeOption = {
|
||||
@@ -102,10 +102,10 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
<View
|
||||
style={[
|
||||
styles.emptyIcon,
|
||||
{ backgroundColor: `${theme.colors.danger}12` },
|
||||
{ backgroundColor: theme.tint(theme.colors.danger, 0.07) },
|
||||
]}
|
||||
>
|
||||
<Ionicons name="alert-circle-outline" size={28} color={theme.colors.danger} />
|
||||
<Icon name="alert-circle-outline" size={28} color={theme.colors.danger} />
|
||||
</View>
|
||||
<Text style={[styles.emptyTitle, { color: theme.colors.textPrimary }]}>
|
||||
Account not found
|
||||
@@ -212,7 +212,7 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
contentContainerStyle={styles.contentContainer}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={['#F4F9FF', '#E8F2FE', '#F8FBFF']}
|
||||
colors={[theme.colors.surface, theme.colors.primarySurface, theme.colors.surface]}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
style={[styles.heroCard, { borderColor: theme.colors.cardBorder }]}
|
||||
@@ -221,10 +221,10 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
<View
|
||||
style={[
|
||||
styles.heroIcon,
|
||||
{ backgroundColor: `${theme.colors.primary}12` },
|
||||
{ backgroundColor: theme.tint(theme.colors.primary, 0.07) },
|
||||
]}
|
||||
>
|
||||
<Ionicons name="shield-checkmark-outline" size={20} color={theme.colors.primary} />
|
||||
<Icon name="shield-checkmark-outline" size={20} color={theme.colors.primary} />
|
||||
</View>
|
||||
<View style={styles.heroCopy}>
|
||||
<Text style={[styles.heroTitle, { color: theme.colors.textPrimary }]}>
|
||||
@@ -242,7 +242,7 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
<View
|
||||
style={[
|
||||
styles.stepIndex,
|
||||
{ backgroundColor: `${theme.colors.primary}12` },
|
||||
{ backgroundColor: theme.tint(theme.colors.primary, 0.07) },
|
||||
]}
|
||||
>
|
||||
<Text style={[styles.stepIndexText, { color: theme.colors.primary }]}>
|
||||
@@ -260,10 +260,10 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
<View
|
||||
style={[
|
||||
styles.sectionIcon,
|
||||
{ backgroundColor: `${theme.colors.info}12` },
|
||||
{ backgroundColor: theme.tint(theme.colors.info, 0.07) },
|
||||
]}
|
||||
>
|
||||
<Ionicons name="card-outline" size={18} color={theme.colors.info} />
|
||||
<Icon name="card-outline" size={18} color={theme.colors.info} />
|
||||
</View>
|
||||
<View style={styles.sectionCopy}>
|
||||
<Text style={[styles.sectionTitle, { color: theme.colors.textPrimary }]}>
|
||||
@@ -282,7 +282,7 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
keyboardType="number-pad"
|
||||
maxLength={14}
|
||||
placeholder="1234 5678 9012"
|
||||
leftAccessory={<Ionicons name="finger-print-outline" size={18} color={theme.colors.textMuted} />}
|
||||
leftAccessory={<Icon name="finger-print-outline" size={18} color={theme.colors.textMuted} />}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
@@ -291,10 +291,10 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
<View
|
||||
style={[
|
||||
styles.sectionIcon,
|
||||
{ backgroundColor: `${theme.colors.warning}12` },
|
||||
{ backgroundColor: theme.tint(theme.colors.warning, 0.07) },
|
||||
]}
|
||||
>
|
||||
<Ionicons name="create-outline" size={18} color={theme.colors.warning} />
|
||||
<Icon name="create-outline" size={18} color={theme.colors.warning} />
|
||||
</View>
|
||||
<View style={styles.sectionCopy}>
|
||||
<Text style={[styles.sectionTitle, { color: theme.colors.textPrimary }]}>
|
||||
@@ -317,12 +317,12 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
style={[
|
||||
styles.changeChip,
|
||||
{
|
||||
backgroundColor: isSelected ? `${theme.colors.primary}12` : theme.colors.surfaceMuted,
|
||||
borderColor: isSelected ? `${theme.colors.primary}45` : theme.colors.cardBorder,
|
||||
backgroundColor: isSelected ? theme.tint(theme.colors.primary, 0.07) : theme.colors.surfaceMuted,
|
||||
borderColor: isSelected ? theme.tint(theme.colors.primary, 0.27) : theme.colors.cardBorder,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Ionicons
|
||||
<Icon
|
||||
name={option.icon as any}
|
||||
size={16}
|
||||
color={isSelected ? theme.colors.primary : theme.colors.textSecondary}
|
||||
@@ -348,7 +348,7 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
{ backgroundColor: theme.colors.surfaceMuted, borderColor: theme.colors.cardBorder },
|
||||
]}
|
||||
>
|
||||
<Ionicons
|
||||
<Icon
|
||||
name={consentGiven ? 'checkmark-circle' : 'ellipse-outline'}
|
||||
size={22}
|
||||
color={consentGiven ? theme.colors.success : theme.colors.textMuted}
|
||||
@@ -404,8 +404,8 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
{/* Document upload */}
|
||||
<Card style={styles.sectionCard}>
|
||||
<View style={styles.sectionHeader}>
|
||||
<View style={[styles.sectionIcon, { backgroundColor: `${theme.colors.success}12` }]}>
|
||||
<Ionicons name="cloud-upload-outline" size={18} color={theme.colors.success} />
|
||||
<View style={[styles.sectionIcon, { backgroundColor: theme.tint(theme.colors.success, 0.07) }]}>
|
||||
<Icon name="cloud-upload-outline" size={18} color={theme.colors.success} />
|
||||
</View>
|
||||
<View style={styles.sectionCopy}>
|
||||
<Text style={[styles.sectionTitle, { color: theme.colors.textPrimary }]}>Upload documents</Text>
|
||||
@@ -424,13 +424,13 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
style={[
|
||||
styles.uploadRow,
|
||||
{
|
||||
backgroundColor: isUploaded ? `${theme.colors.success}10` : theme.colors.surfaceMuted,
|
||||
borderColor: isUploaded ? `${theme.colors.success}45` : theme.colors.cardBorder,
|
||||
backgroundColor: isUploaded ? theme.tint(theme.colors.success, 0.06) : theme.colors.surfaceMuted,
|
||||
borderColor: isUploaded ? theme.tint(theme.colors.success, 0.27) : theme.colors.cardBorder,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<View style={[styles.uploadIcon, { backgroundColor: theme.colors.surface }]}>
|
||||
<Ionicons name={doc.icon} size={18} color={theme.colors.primary} />
|
||||
<Icon name={doc.icon} size={18} color={theme.colors.primary} />
|
||||
</View>
|
||||
<View style={styles.uploadCopy}>
|
||||
<Text style={[styles.uploadLabel, { color: theme.colors.textPrimary }]}>{doc.label}</Text>
|
||||
@@ -438,7 +438,7 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
{isUploaded ? 'Uploaded · tap to remove' : doc.hint}
|
||||
</Text>
|
||||
</View>
|
||||
<Ionicons
|
||||
<Icon
|
||||
name={isUploaded ? 'checkmark-circle' : 'add-circle-outline'}
|
||||
size={22}
|
||||
color={isUploaded ? theme.colors.success : theme.colors.primary}
|
||||
@@ -451,8 +451,8 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
{/* Latest photograph */}
|
||||
<Card style={styles.sectionCard}>
|
||||
<View style={styles.sectionHeader}>
|
||||
<View style={[styles.sectionIcon, { backgroundColor: `${theme.colors.info}12` }]}>
|
||||
<Ionicons name="camera-outline" size={18} color={theme.colors.info} />
|
||||
<View style={[styles.sectionIcon, { backgroundColor: theme.tint(theme.colors.info, 0.07) }]}>
|
||||
<Icon name="camera-outline" size={18} color={theme.colors.info} />
|
||||
</View>
|
||||
<View style={styles.sectionCopy}>
|
||||
<Text style={[styles.sectionTitle, { color: theme.colors.textPrimary }]}>Latest photograph</Text>
|
||||
@@ -467,12 +467,12 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
style={[
|
||||
styles.photoTile,
|
||||
{
|
||||
backgroundColor: photoUploaded ? `${theme.colors.success}10` : theme.colors.surfaceMuted,
|
||||
borderColor: photoUploaded ? `${theme.colors.success}45` : theme.colors.cardBorder,
|
||||
backgroundColor: photoUploaded ? theme.tint(theme.colors.success, 0.06) : theme.colors.surfaceMuted,
|
||||
borderColor: photoUploaded ? theme.tint(theme.colors.success, 0.27) : theme.colors.cardBorder,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Ionicons
|
||||
<Icon
|
||||
name={photoUploaded ? 'checkmark-circle' : 'person-circle-outline'}
|
||||
size={48}
|
||||
color={photoUploaded ? theme.colors.success : theme.colors.textMuted}
|
||||
@@ -486,8 +486,8 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
{/* Self declaration */}
|
||||
<Card style={styles.sectionCard}>
|
||||
<View style={styles.sectionHeader}>
|
||||
<View style={[styles.sectionIcon, { backgroundColor: `${theme.colors.warning}12` }]}>
|
||||
<Ionicons name="document-text-outline" size={18} color={theme.colors.warning} />
|
||||
<View style={[styles.sectionIcon, { backgroundColor: theme.tint(theme.colors.warning, 0.07) }]}>
|
||||
<Icon name="document-text-outline" size={18} color={theme.colors.warning} />
|
||||
</View>
|
||||
<View style={styles.sectionCopy}>
|
||||
<Text style={[styles.sectionTitle, { color: theme.colors.textPrimary }]}>Self declaration</Text>
|
||||
@@ -508,7 +508,7 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
{ backgroundColor: theme.colors.surfaceMuted, borderColor: theme.colors.cardBorder },
|
||||
]}
|
||||
>
|
||||
<Ionicons
|
||||
<Icon
|
||||
name={accepted ? 'checkmark-circle' : 'ellipse-outline'}
|
||||
size={22}
|
||||
color={accepted ? theme.colors.success : theme.colors.textMuted}
|
||||
@@ -522,8 +522,8 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
{/* Video KYC option */}
|
||||
<Card style={styles.sectionCard}>
|
||||
<View style={styles.sectionHeader}>
|
||||
<View style={[styles.sectionIcon, { backgroundColor: `${theme.colors.primary}12` }]}>
|
||||
<Ionicons name="videocam-outline" size={18} color={theme.colors.primary} />
|
||||
<View style={[styles.sectionIcon, { backgroundColor: theme.tint(theme.colors.primary, 0.07) }]}>
|
||||
<Icon name="videocam-outline" size={18} color={theme.colors.primary} />
|
||||
</View>
|
||||
<View style={styles.sectionCopy}>
|
||||
<Text style={[styles.sectionTitle, { color: theme.colors.textPrimary }]}>Prefer a video call?</Text>
|
||||
@@ -536,13 +536,13 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
title="Start Video KYC"
|
||||
variant="secondary"
|
||||
onPress={() => account && navigation.navigate('VideoKyc', { accountNumber: account.accountNumber })}
|
||||
leftAccessory={<Ionicons name="videocam-outline" size={18} color={theme.colors.textPrimary} />}
|
||||
leftAccessory={<Icon name="videocam-outline" size={18} color={theme.colors.textPrimary} />}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<Card style={styles.footerCard}>
|
||||
<View style={styles.footerHeader}>
|
||||
<Ionicons name="time-outline" size={18} color={theme.colors.primary} />
|
||||
<Icon name="time-outline" size={18} color={theme.colors.primary} />
|
||||
<Text style={[styles.footerTitle, { color: theme.colors.textPrimary }]}>
|
||||
Processing note
|
||||
</Text>
|
||||
@@ -553,7 +553,7 @@ export default function ReKycScreen({ route, navigation }: Props) {
|
||||
<Button
|
||||
title="Submit re-KYC request"
|
||||
onPress={handleSubmit}
|
||||
leftAccessory={<Ionicons name="paper-plane-outline" size={18} color={theme.colors.white} />}
|
||||
leftAccessory={<Icon name="paper-plane-outline" size={18} color={theme.colors.white} />}
|
||||
/>
|
||||
</Card>
|
||||
<View style={{ height: 60 }} />
|
||||
|
||||
Reference in New Issue
Block a user