- 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>
78 lines
2.6 KiB
TypeScript
78 lines
2.6 KiB
TypeScript
export const isValidPhone = (value: string) => /^[0-9]{10}$/.test(value.replace(/\D/g, ''));
|
|
|
|
export const isValidOtp = (value: string) => /^[0-9]{6}$/.test(value);
|
|
|
|
/**
|
|
* Single source of truth for how many digits an MPIN has. The backend accepts
|
|
* 4 or 6; this app standardises on 4, so the keypad, the validators and the
|
|
* stored-profile handling all read from here rather than each hard-coding it.
|
|
*/
|
|
export const MPIN_LENGTH = 4;
|
|
|
|
/**
|
|
* The backend refuses an all-same-digit MPIN. That rule is checked after
|
|
* decryption server-side, so it comes back as a `VALIDATION_ERROR` with a
|
|
* message rather than a field map — cheaper and clearer to catch it here
|
|
* before spending a round trip.
|
|
*/
|
|
export const isValidMpin = (value: string) =>
|
|
new RegExp(`^[0-9]{${MPIN_LENGTH}}$`).test(value) && !isRepeatedDigits(value);
|
|
|
|
export const isRepeatedDigits = (value: string) =>
|
|
value.length > 0 && /^(\d)\1*$/.test(value);
|
|
|
|
/**
|
|
* A straight run up or down — 1234, 6789, 4321. The backend refuses these
|
|
* when an MPIN is SET, in the same message-only way as repeated digits.
|
|
*/
|
|
export const isSequentialDigits = (value: string) => {
|
|
if (value.length < 2 || !/^[0-9]+$/.test(value)) {
|
|
return false;
|
|
}
|
|
|
|
const step = Number(value[1]) - Number(value[0]);
|
|
|
|
if (step !== 1 && step !== -1) {
|
|
return false;
|
|
}
|
|
|
|
for (let index = 1; index < value.length; index += 1) {
|
|
if (Number(value[index]) - Number(value[index - 1]) !== step) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* The stricter check for CHOOSING an MPIN — creation and reset.
|
|
*
|
|
* Deliberately separate from `isValidMpin`, which sign-in also uses: an MPIN
|
|
* like 1234 set before the backend began refusing runs still has to be
|
|
* enterable at sign-in, or its owner is locked out of their own profile.
|
|
*/
|
|
export const isAcceptableNewMpin = (value: string) =>
|
|
isValidMpin(value) && !isSequentialDigits(value);
|
|
|
|
/** Constraints as the API documents them, not as any one bank formats them. */
|
|
export const isValidAccountNumber = (value: string) => /^[0-9]{5,20}$/.test(value);
|
|
|
|
/**
|
|
* An IFSC is always 11 characters. Every IFSC input caps at this and the
|
|
* validator requires exactly this many, so the two cannot drift apart.
|
|
*/
|
|
export const IFSC_LENGTH = 11;
|
|
|
|
export const isValidIfsc = (value: string) =>
|
|
new RegExp(`^[A-Za-z0-9]{${IFSC_LENGTH}}$`).test(value);
|
|
|
|
export const isValidMmid = (value: string) => /^[0-9]{7}$/.test(value);
|
|
|
|
export const isValidNickname = (value: string) => value.length <= 60;
|
|
|
|
export const isValidAmount = (value: string) => {
|
|
const amount = Number(value);
|
|
return Number.isFinite(amount) && amount > 0;
|
|
};
|