Update CBS Mobile App codebase

This commit is contained in:
Abin Toppo
2026-09-21 13:21:25 +05:30
parent 58af541536
commit 2dcb10775c
339 changed files with 26750 additions and 16767 deletions
+325
View File
@@ -0,0 +1,325 @@
/**
* Centralised feature keys for the whole application.
*
* Every gateable thing in the app — module, screen, tab, menu entry, button and
* action — has exactly one key here. UI code must never pass a raw string to the
* feature service; always reference a member of this enum so renames and typos
* are caught by the compiler.
*
* Keys use dot notation and the hierarchy is encoded in the key itself:
*
* loans → parent of
* loans.apply → parent of
* loans.apply.submit
*
* The feature service derives parent/child relationships from this path, so a
* disabled parent automatically disables everything beneath it. Adding a child
* key therefore only requires that its parent key also exists.
*/
export enum FeatureKey {
// ---------------------------------------------------------------- Auth ----
AUTH = 'auth',
AUTH_LOGIN = 'auth.login',
AUTH_LOGIN_USER_ROLE = 'auth.login.userRole',
AUTH_LOGIN_AGENT_ROLE = 'auth.login.agentRole',
AUTH_LOGIN_BIOMETRIC = 'auth.login.biometric',
AUTH_LOGIN_FORGOT_PASSWORD = 'auth.login.forgotPassword',
AUTH_REGISTER = 'auth.register',
AUTH_LOGIN_CREATE_ACCOUNT = 'auth.login.createAccount',
AUTH_LOGOUT = 'auth.logout',
// ---------------------------------------------------------------- Home ----
HOME = 'home',
HOME_ACCOUNTS = 'home.accounts',
HOME_ACCOUNTS_CAROUSEL = 'home.accounts.carousel',
HOME_ACCOUNTS_BALANCE_TOGGLE = 'home.accounts.balanceToggle',
HOME_ACCOUNTS_MINI_STATEMENT = 'home.accounts.miniStatement',
HOME_ACCOUNTS_DETAILS = 'home.accounts.details',
HOME_ACCOUNTS_EPASSBOOK = 'home.accounts.ePassbook',
HOME_ACCOUNTS_REKYC = 'home.accounts.reKyc',
HOME_ACCOUNTS_VIDEO_KYC = 'home.accounts.videoKyc',
HOME_ACCOUNTS_MMID = 'home.accounts.mmid',
HOME_QUICK_ACTIONS = 'home.quickActions',
HOME_QUICK_ACTIONS_TRANSFER = 'home.quickActions.transfer',
HOME_QUICK_ACTIONS_BILL_PAY = 'home.quickActions.billPay',
HOME_QUICK_ACTIONS_AIRTIME = 'home.quickActions.airtime',
HOME_QUICK_ACTIONS_LOANS = 'home.quickActions.loans',
HOME_QUICK_ACTIONS_CARDS = 'home.quickActions.cards',
HOME_QUICK_ACTIONS_STATS = 'home.quickActions.stats',
HOME_SERVICES = 'home.services',
HOME_SERVICES_TRANSFER = 'home.services.transfer',
HOME_SERVICES_SELF_TRANSFER = 'home.services.selfTransfer',
HOME_SERVICES_BILL_PAY = 'home.services.billPay',
HOME_SERVICES_COLLECT_REQUEST = 'home.services.collectRequest',
HOME_SERVICES_MANAGE_PAYEE = 'home.services.managePayee',
HOME_SERVICES_SUPPORT = 'home.services.support',
HOME_SERVICES_INSURANCE = 'home.services.insurance',
HOME_SERVICES_DEPOSITS = 'home.services.deposits',
HOME_SERVICES_GOLD_LOAN = 'home.services.goldLoan',
HOME_INSIGHTS = 'home.insights',
HOME_PROMO_BANNER = 'home.promoBanner',
// -------------------------------------------------------------- Search ----
SEARCH = 'search',
SEARCH_GLOBAL = 'search.global',
// ------------------------------------------------------- Notifications ----
NOTIFICATIONS = 'notifications',
NOTIFICATIONS_LIST = 'notifications.list',
NOTIFICATIONS_MARK_READ = 'notifications.markRead',
// ------------------------------------------------------------ Payments ----
PAYMENTS = 'payments',
PAYMENTS_HUB = 'payments.hub',
PAYMENTS_BENEFICIARIES = 'payments.beneficiaries',
PAYMENTS_BENEFICIARIES_LIST = 'payments.beneficiaries.list',
PAYMENTS_BENEFICIARIES_ADD = 'payments.beneficiaries.add',
PAYMENTS_BENEFICIARIES_DELETE = 'payments.beneficiaries.delete',
PAYMENTS_TRANSFER = 'payments.transfer',
PAYMENTS_TRANSFER_IMPS = 'payments.transfer.imps',
PAYMENTS_TRANSFER_NEFT = 'payments.transfer.neft',
PAYMENTS_TRANSFER_RTGS = 'payments.transfer.rtgs',
PAYMENTS_TRANSFER_INTERNAL = 'payments.transfer.internal',
PAYMENTS_TRANSFER_SUBMIT = 'payments.transfer.submit',
/**
* The three fund-transfer entry points on the payments hub. Each is a
* destination in its own right rather than a rail: `mobile` collects a
* mobile number and MMID, `account` an account number and IFSC, and `own`
* moves money
* between the customer's own accounts. The rail keys above still decide how
* the resulting transfer settles.
*/
PAYMENTS_TRANSFER_MOBILE = 'payments.transfer.mobile',
PAYMENTS_TRANSFER_ACCOUNT = 'payments.transfer.account',
PAYMENTS_TRANSFER_OWN = 'payments.transfer.own',
PAYMENTS_UPI = 'payments.upi',
PAYMENTS_UPI_SCAN = 'payments.upi.scan',
/** This customer's own MMIDs, for receiving money over IMPS. */
PAYMENTS_MMID = 'payments.mmid',
PAYMENTS_MMID_CANCEL = 'payments.mmid.cancel',
PAYMENTS_MMID_GENERATE = 'payments.mmid.generate',
// --------------------------------------------------------------- Cards ----
CARDS = 'cards',
CARDS_OVERVIEW = 'cards.overview',
CARDS_DETAILS = 'cards.details',
CARDS_TRANSACTIONS = 'cards.transactions',
CARDS_CONTROLS = 'cards.controls',
CARDS_CONTROLS_FREEZE = 'cards.controls.freeze',
CARDS_CONTROLS_ONLINE = 'cards.controls.online',
CARDS_CONTROLS_INTERNATIONAL = 'cards.controls.international',
CARDS_CONTROLS_CONTACTLESS = 'cards.controls.contactless',
CARDS_CONTROLS_ATM = 'cards.controls.atm',
CARDS_CONTROLS_LIMITS = 'cards.controls.limits',
CARDS_CONTROLS_BLOCK = 'cards.controls.block',
CARDS_APPLY_CREDIT = 'cards.applyCredit',
CARDS_REQUEST_PHYSICAL = 'cards.requestPhysical',
// ------------------------------------------------------------ Services ----
SERVICES = 'services',
SERVICES_HUB = 'services.hub',
SERVICES_DEPOSITS = 'services.deposits',
SERVICES_DEPOSITS_OVERVIEW = 'services.deposits.overview',
SERVICES_DEPOSITS_DETAILS = 'services.deposits.details',
SERVICES_DEPOSITS_OPEN_FD = 'services.deposits.openFd',
SERVICES_DEPOSITS_OPEN_RD = 'services.deposits.openRd',
SERVICES_DEPOSITS_CALCULATOR = 'services.deposits.calculator',
SERVICES_CHEQUE = 'services.cheque',
SERVICES_CHEQUE_HUB = 'services.cheque.hub',
SERVICES_CHEQUE_BOOK_REQUEST = 'services.cheque.bookRequest',
SERVICES_CHEQUE_STOP_PAYMENT = 'services.cheque.stopPayment',
SERVICES_CHEQUE_TRACKING = 'services.cheque.tracking',
SERVICES_CHEQUE_POSITIVE_PAY = 'services.cheque.positivePay',
SERVICES_CERTIFICATES = 'services.certificates',
SERVICES_CERTIFICATES_HUB = 'services.certificates.hub',
SERVICES_CERTIFICATES_LIST = 'services.certificates.list',
SERVICES_CERTIFICATES_BALANCE = 'services.certificates.balance',
SERVICES_CERTIFICATES_INTEREST = 'services.certificates.interest',
SERVICES_CERTIFICATES_SHARE = 'services.certificates.share',
SERVICES_CERTIFICATES_HYPOTHECATION = 'services.certificates.hypothecation',
SERVICES_CERTIFICATES_INSURANCE = 'services.certificates.insurance',
SERVICES_CERTIFICATES_TAX = 'services.certificates.tax',
SERVICES_CERTIFICATES_LOAN = 'services.certificates.loan',
SERVICES_REQUESTS = 'services.requests',
SERVICES_REQUESTS_HUB = 'services.requests.hub',
SERVICES_STANDING_INSTRUCTIONS = 'services.standingInstructions',
SERVICES_FORM_15G15H = 'services.form15g15h',
SERVICES_NOMINATION = 'services.nomination',
SERVICES_BRANCH_LOCATOR = 'services.branchLocator',
SERVICES_AWARENESS = 'services.awareness',
SERVICES_AWARENESS_LIST = 'services.awareness.list',
SERVICES_AWARENESS_DETAIL = 'services.awareness.detail',
SERVICES_PROTECTION = 'services.protection',
SERVICES_PROTECTION_HUB = 'services.protection.hub',
SERVICES_PROTECTION_SCHEME_DETAIL = 'services.protection.schemeDetail',
SERVICES_PROTECTION_ENROLLMENT = 'services.protection.enrollment',
SERVICES_PROTECTION_DEAF = 'services.protection.deaf',
SERVICES_PROTECTION_DEAF_CLAIM = 'services.protection.deafClaim',
SERVICES_PROTECTION_DICGC = 'services.protection.dicgc',
SERVICES_SUPPORT_CHAT = 'services.supportChat',
SERVICES_HELP_CENTER = 'services.helpCenter',
/**
* Enquiry desk: the entries that answer a question outright, or change a PIN,
* rather than opening a journey.
*
* `mpinChange` and `miniStatement` gate entry points rather than screens —
* those screens live in the profile and home stacks and keep their own keys.
* Having a key here lets the bank take the tile off the service desk without
* also removing the screen from where it already was.
*/
SERVICES_BALANCE_ENQUIRY = 'services.balanceEnquiry',
SERVICES_MINI_STATEMENT = 'services.miniStatement',
SERVICES_MPIN_CHANGE = 'services.mpinChange',
SERVICES_TPIN_CHANGE = 'services.tpinChange',
SERVICES_FATE_OF_CHEQUE = 'services.fateOfCheque',
// --------------------------------------------------------------- Loans ----
LOANS = 'loans',
LOANS_DASHBOARD = 'loans.dashboard',
LOANS_TYPES = 'loans.types',
LOANS_ELIGIBILITY = 'loans.eligibility',
LOANS_CALCULATOR = 'loans.calculator',
LOANS_APPLY = 'loans.apply',
LOANS_TRACKING = 'loans.tracking',
LOANS_ACTIVE_DETAILS = 'loans.activeDetails',
LOANS_EMI_PAYMENT = 'loans.emiPayment',
LOANS_FORECLOSURE = 'loans.foreclosure',
LOANS_HISTORY = 'loans.history',
LOANS_DOCUMENTS = 'loans.documents',
// ----------------------------------------------------------- Insurance ----
INSURANCE = 'insurance',
INSURANCE_DASHBOARD = 'insurance.dashboard',
INSURANCE_BUY = 'insurance.buy',
INSURANCE_POLICIES = 'insurance.policies',
INSURANCE_POLICY_DETAILS = 'insurance.policyDetails',
INSURANCE_RENEWALS = 'insurance.renewals',
INSURANCE_CLAIMS = 'insurance.claims',
INSURANCE_DOCUMENTS = 'insurance.documents',
INSURANCE_CALCULATOR = 'insurance.calculator',
INSURANCE_COMPARISON = 'insurance.comparison',
INSURANCE_NOTIFICATIONS = 'insurance.notifications',
// ------------------------------------------------------------- Profile ----
PROFILE = 'profile',
PROFILE_MAIN = 'profile.main',
PROFILE_EDIT = 'profile.edit',
PROFILE_ACCOUNTS = 'profile.accounts',
PROFILE_ACCOUNTS_ADD = 'profile.accounts.add',
PROFILE_BENEFICIARIES_SHORTCUT = 'profile.beneficiariesShortcut',
PROFILE_STATEMENTS_SHORTCUT = 'profile.statementsShortcut',
PROFILE_SETTINGS = 'profile.settings',
PROFILE_SETTINGS_LANGUAGE = 'profile.settings.language',
PROFILE_SETTINGS_NOTIFICATIONS = 'profile.settings.notifications',
PROFILE_SETTINGS_PRIVACY = 'profile.settings.privacy',
PROFILE_SECURITY = 'profile.security',
PROFILE_SECURITY_CHANGE_PIN = 'profile.security.changePin',
PROFILE_SECURITY_CHANGE_PASSWORD = 'profile.security.changePassword',
PROFILE_SECURITY_BIOMETRIC = 'profile.security.biometric',
PROFILE_SECURITY_TWO_FACTOR = 'profile.security.twoFactor',
PROFILE_SECURITY_DEVICES = 'profile.security.devices',
PROFILE_SECURITY_LOGOUT_ALL = 'profile.security.logoutAll',
PROFILE_SECURITY_HIDE_BALANCE = 'profile.security.hideBalance',
PROFILE_SUPPORT = 'profile.support',
PROFILE_LEGAL = 'profile.legal',
PROFILE_ABOUT = 'profile.about',
/**
* In-app switchboard for the curated operational features.
*
* Ships disabled and is meant to be turned on through remote config for the
* tenants whose staff need it — so the bank decides which installs expose it,
* rather than it being present for every customer.
*/
PROFILE_FEATURE_FLAGS = 'profile.featureFlags',
// --------------------------------------------------------------- Agent ----
AGENT = 'agent',
AGENT_DASHBOARD = 'agent.dashboard',
AGENT_DASHBOARD_MAIN = 'agent.dashboard.main',
AGENT_DASHBOARD_ROUTE = 'agent.dashboard.route',
AGENT_CUSTOMERS = 'agent.customers',
AGENT_CUSTOMERS_LIST = 'agent.customers.list',
AGENT_CUSTOMERS_DETAIL = 'agent.customers.detail',
AGENT_CUSTOMERS_CREATE = 'agent.customers.create',
AGENT_CUSTOMERS_EDIT = 'agent.customers.edit',
AGENT_CUSTOMERS_DELETE = 'agent.customers.delete',
AGENT_CUSTOMERS_INSTALLMENT_HISTORY = 'agent.customers.installmentHistory',
AGENT_COLLECTIONS = 'agent.collections',
AGENT_COLLECTIONS_DAILY = 'agent.collections.daily',
AGENT_COLLECTIONS_HISTORY = 'agent.collections.history',
AGENT_COLLECTIONS_RECEIPT = 'agent.collections.receipt',
AGENT_LOANS = 'agent.loans',
AGENT_LOANS_LIST = 'agent.loans.list',
AGENT_LOANS_CREATE_REQUEST = 'agent.loans.createRequest',
AGENT_LOANS_ACCOUNT_OPENING = 'agent.loans.accountOpening',
AGENT_LOANS_COMMISSION = 'agent.loans.commission',
AGENT_PROFILE = 'agent.profile',
AGENT_PROFILE_MAIN = 'agent.profile.main',
AGENT_PROFILE_SMS_HISTORY = 'agent.profile.smsHistory',
AGENT_PROFILE_CHANGE_PASSWORD = 'agent.profile.changePassword',
}
/** Every declared feature key, in declaration order. */
export const ALL_FEATURE_KEYS = Object.values(FeatureKey) as FeatureKey[];
/** Set form, for O(1) membership checks when validating untrusted strings. */
const FEATURE_KEY_SET: ReadonlySet<string> = new Set<string>(ALL_FEATURE_KEYS);
/**
* Narrows an arbitrary string (remote config, JSON-driven UI, deep link) to a
* known FeatureKey. Returns `undefined` when the string is not a declared key,
* which callers must treat as "not enabled".
*/
export const toFeatureKey = (value: string | null | undefined): FeatureKey | undefined =>
typeof value === 'string' && FEATURE_KEY_SET.has(value) ? (value as FeatureKey) : undefined;
/**
* Parent key of a feature, derived from its dot path.
* `loans.apply.submit` → `loans.apply`; a root key → `undefined`.
*/
export const getParentFeatureKey = (key: FeatureKey): FeatureKey | undefined => {
const lastDot = key.lastIndexOf('.');
if (lastDot === -1) {
return undefined;
}
return toFeatureKey(key.slice(0, lastDot));
};
/**
* All ancestors of a key, nearest parent first.
* `loans.apply.submit` → [`loans.apply`, `loans`].
*/
export const getFeatureAncestors = (key: FeatureKey): FeatureKey[] => {
const ancestors: FeatureKey[] = [];
let current = getParentFeatureKey(key);
while (current) {
ancestors.push(current);
current = getParentFeatureKey(current);
}
return ancestors;
};
+88
View File
@@ -0,0 +1,88 @@
/**
* The bank's identity and its legal copy, in one place.
*
* Both the pre-auth sign-in footer and the in-app Legal & Information screen
* read from here. They used to carry their own wording, which is how an app
* ends up telling a customer two different things about the same policy — and
* the pre-auth copy is the version a regulator looks at first, because it is
* the one shown before anybody agrees to anything.
*
* Legal wording is not developer copy. Anything in `terms` or `privacy` should
* come from whoever signs off on it at the bank; the placeholder text below is
* scaffolding and is marked as such.
*/
export const company = {
/** Full registered name. Used wherever the entity has to be named exactly. */
legalName: 'CBS Bank Limited',
/** Conversational name, for running text. */
shortName: 'CBS Bank',
/** Shown under the sign-in form; a bank is expected to name its regulator. */
regulator: 'Regulated by the Reserve Bank of India',
/** Appears as "© <year> <legalName>". */
copyrightFrom: 2026,
} as const;
/**
* The current year, so the sign-in footer does not quietly go stale every
* January. Computed per call rather than at module load: the process can
* outlive midnight on a handset that is never fully closed.
*/
export const copyrightLine = () => {
const now = new Date().getFullYear();
const from = company.copyrightFrom;
// A range only once there is a range to show.
return `© ${now > from ? `${from}–${now}` : from} ${company.legalName}`;
};
export type LegalSection = {
heading: string;
body: string[];
};
/** PLACEHOLDER — replace with the bank's approved terms before release. */
export const terms: LegalSection[] = [
{
heading: 'Using this app',
body: [
`By signing in to the ${company.shortName} mobile app you agree to these terms and to the privacy policy.`,
'You are responsible for keeping your MPIN, passwords and registered device secure. Do not share your MPIN with anyone, including anybody claiming to be from the bank — we will never ask for it.',
],
},
{
heading: 'Transfers and payments',
body: [
'Real-time transfers such as IMPS and UPI are irreversible once processed. Check the beneficiary details before you confirm a payment.',
'Transaction limits are set by the bank and by the relevant payment network, and may change without notice.',
],
},
{
heading: 'Availability',
body: [
'Services may be unavailable during maintenance or for reasons outside the bank’s control. The bank is not liable for losses arising from an interruption it could not reasonably prevent.',
],
},
];
/** PLACEHOLDER — replace with the bank's approved privacy policy before release. */
export const privacy: LegalSection[] = [
{
heading: 'What we collect',
body: [
'Identity and contact details, account and transaction records, and technical information about the device you sign in from — including its SIM-registered mobile number, which is what links this app to your account.',
],
},
{
heading: 'Why we collect it',
body: [
'To operate your accounts, process payments, detect fraud, and meet the KYC and record-keeping obligations placed on the bank by law.',
'Biometric data never leaves your device. Fingerprint and face unlock are verified by the handset itself; the bank receives only the result.',
],
},
{
heading: 'Your choices',
body: [
'You can ask for a copy of the personal data the bank holds about you, or ask for it to be corrected, by contacting your branch.',
],
},
];
+18
View File
@@ -32,6 +32,7 @@ export const demoUser: UserProfile = {
phone: '+91 98765 43210',
customerId: '0090421877',
kycStatus: 'verified',
lastKycDate: '2025-04-18',
ckycNumber: '10041285694218',
language: 'en',
biometricEnabled: true,
@@ -99,6 +100,8 @@ export const demoAccounts: AccountSummary[] = [
type: 'Savings',
accountHolder: 'Aarav Sharma',
branch: 'Bengaluru Koramangala',
ifscCode: 'CBSB0001001',
status: 'Active',
maskedNumber: 'XXXX 9312',
availableBalance: 248560.78,
currentBalance: 251040.78,
@@ -110,6 +113,8 @@ export const demoAccounts: AccountSummary[] = [
type: 'Salary',
accountHolder: 'Aarav Sharma',
branch: 'Bengaluru Tech Park',
ifscCode: 'CBSB0001002',
status: 'Active',
maskedNumber: 'XXXX 7081',
availableBalance: 82450,
currentBalance: 82450,
@@ -625,6 +630,19 @@ export const demoLoanProducts: LoanProduct[] = [
description: 'Fund your higher education dreams in India or abroad.',
features: ['Zero processing fee', 'Moratorium period', 'Tax benefits u/s 80E', 'Covers tuition & living'],
},
{
id: 'loan_dds',
name: 'Loan Against DDS Deposit',
category: 'Loan Against DDS Deposit',
interestRate: 9,
maxAmount: 2000000,
minAmount: 10000,
tenureMonths: 36,
minTenureMonths: 6,
processingFeePercent: 0.5,
description: 'Borrow against your Daily Deposit Scheme balance while your deposit keeps earning interest.',
features: ['Up to 90% of deposit value', 'No income proof needed', 'Deposit keeps earning', 'Quick disbursal'],
},
];
export const demoActiveLoans: ActiveLoan[] = [
+1
View File
@@ -8,6 +8,7 @@ export const QUERY_TAGS = [
'Payments',
'Deposits',
'Services',
'ChequeBooks',
'Loans',
'LoanActive',
'LoanApplications',