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:
Abin Toppo
2026-10-14 18:18:40 +05:30
co-authored by Claude Opus 5.5
parent 5fbd13ba12
commit f960a119e8
510 changed files with 20268 additions and 6483 deletions
+16 -12
View File
@@ -220,18 +220,22 @@ const checkRamp = (ramp, rampName) => {
add(sep >= TINT_SEPARATION, `category.${hue} tint distinct from surface`, sep, TINT_SEPARATION);
}
// The on-brand tiers, against the LIGHTEST stop of the wash — the worst case.
const wash = ramp.brandGradient[0];
for (const tier of ['onBrandPrimary', 'onBrandSecondary', 'onBrandMuted']) {
const r = ratio(ramp[tier], wash);
add(r >= AA, `${tier} on the brand wash`, r, AA);
}
// And solid white on each translucent fill — the tiers do not stack, so a
// fill always carries the solid tone.
for (const fill of ['onBrandSurface', 'onBrandSurfaceStrong']) {
const composited = composite(ramp[fill], wash);
const r = ratio(ramp.onBrandPrimary, composited);
add(r >= AA, `onBrandPrimary on ${fill}`, r, AA);
// The on-brand tiers, against the LIGHTEST stop of each wash — the worst
// case. `heroGradient` carries the same tiers (the account card, a promo
// banner), so it is held to the same bar.
for (const gradient of ['brandGradient', 'heroGradient']) {
const wash = ramp[gradient][0];
for (const tier of ['onBrandPrimary', 'onBrandSecondary', 'onBrandMuted']) {
const r = ratio(ramp[tier], wash);
add(r >= AA, `${tier} on ${gradient}`, r, AA);
}
// And solid white on each translucent fill — the tiers do not stack, so a
// fill always carries the solid tone.
for (const fill of ['onBrandSurface', 'onBrandSurfaceStrong']) {
const composited = composite(ramp[fill], wash);
const r = ratio(ramp.onBrandPrimary, composited);
add(r >= AA, `onBrandPrimary on ${fill} over ${gradient}`, r, AA);
}
}
return results;
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env node
/**
* `react-native run-android`, minus one inherited setting that stops it from
* opening Metro on Windows.
*
* Why this exists: run-android opens Metro by running `cmd.exe /C
* launchPackager.bat` in a new window, and the first thing that script does is
* `call .packager.bat` — a bare name, resolved from the current directory.
* Tools started from inside VS Code (Claude Code among them) carry
* `NoDefaultCurrentDirectoryInExePath=1`, which tells cmd not to look in the
* current directory. The call then fails, the project paths it would have set
* stay empty, Metro dies with `Cannot find module 'D:\cli.js'`, and because the
* window gets no stdin its closing `pause` returns at once. The Metro window
* flashes and is gone, and the app has no bundle to load.
*
* The setting is dropped for this command only. Everything else passes
* through, so this takes the same flags as the CLI:
*
* npm run android
* npm run android -- --mode release
*/
const { spawnSync } = require('child_process');
const env = {};
for (const [key, value] of Object.entries(process.env)) {
// Windows variable names are case-insensitive.
if (key.toLowerCase() !== 'nodefaultcurrentdirectoryinexepath') {
env[key] = value;
}
}
const cli = require.resolve('react-native/cli.js');
const result = spawnSync(
process.execPath,
[cli, 'run-android', ...process.argv.slice(2)],
{ stdio: 'inherit', env },
);
if (result.error) {
console.error(result.error);
}
process.exit(result.status ?? 1);