Files
halobestie-clone/client_app/assets/payment_icons
Ramadhan Sjamsani 1f6d8e09ae Phase 5.x payment catalog + customer-app splash/register polish
Payment catalog (Phase 5.x — see requirement/phase5-payment-catalog-plan.md):
- New tables payment_method_groups + payment_methods with seed (3 groups,
  10 methods; GoPay seeded inactive pending Xendit channel confirmation).
- payment-catalog.service.js with two-layer cache (60s in-process + 1h
  Valkey) and config:invalidate pub/sub fanout. Mutator API + casing-
  tolerant findActiveMethodByCode for downstream validation.
- App-facing GET /api/client/payment-methods returns pre-grouped JSON,
  active-only, empty groups dropped server-side.
- POST /api/client/payment-requests now validates `method` against the
  catalog (INVALID_PAYMENT_METHOD 422) and stamps
  product_metadata.preferred_payment_code (upper-cased).
- Control-center /internal/payment-{groups,methods}{,/:id,/reorder}
  endpoints (full CRUD + idempotent reorder). New Payment Catalog page
  wired into the CC nav.
- Customer app renders the catalog as collapsible groups (first expanded)
  via paymentCatalogProvider; QRIS-only hardcoded fallback on 5xx so
  checkout never hard-fails. Replaces the hardcoded _PayMethod enum.
- 10 brand SVGs (~63KB) bundled in client_app/assets/payment_icons/ from
  github.com/hafidznoor/idn-finlogos. Xendit's per-channel media-asset
  pages were planned but found decommissioned during implementation —
  switched to idn-finlogos with the standard "channels-we-accept"
  trademark posture. See assets/payment_icons/README.md for the workflow
  to add new methods.
- 16 vitest cases covering the service + cache; full backend suite green
  (162/162).

Customer-app splash + register polish:
- Splash rewritten per figma S1: warm vertical gradient, two ImageFiltered
  radial orbs, 96×96 rounded-square logo tile, "HaloBestie" + "kamu gak
  harus ngerasain ini sendirian." Self-driving navigation via context.go
  after a 2.5s post-frame timer (native Android splash burns ~1-1.5s
  before Flutter paints — 1s timer yielded near-zero visible duration).
  Router early-returns null for isSplash so it never moves us off /splash
  on its own.
- 3-page onboarding carousel removed: user clarified the new splash
  REPLACES that carousel. Dropped /onboarding route, OnboardingScreen,
  onboardingDoneProvider + gating, dead splash_{1,2,3}.png + the
  splash_chat_hebat.png Flutter asset. Phase 4 /onboarding/* subroutes
  untouched; Android-native launch_background drawable left alone.
- Register screen (login-by-phone) polished: circular pink back button +
  72×72 logo badge (same brandLogoBg pink as splash, Transform.scale 1.4
  to fill the tile). Step-dots indicator removed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 23:06:46 +08:00
..

Payment method icons

Bundled SVGs referenced by the payment catalog (payment_methods.icon slug in the backend). The customer app's PaymentIcon widget resolves <slug>.svg from this directory and falls back to placeholder.svg when the file isn't bundled — see client_app/lib/features/payment/widgets/payment_icon.dart.

Naming convention

One SVG per slug, lower-case, hyphens not underscores. Currently bundled slugs (match the migrate.js seed):

Slug Method Source filename in idn-finlogos/icons/
qris QRIS qris.svg
ovo OVO ovo-new.svg
dana DANA dana.svg
shopeepay ShopeePay shopee-pay.svg
gopay GoPay (seeded inactive) gopay.svg
bca BCA Virtual Account bca.svg
mandiri Mandiri Virtual Account mandiri.svg
bni BNI Virtual Account bni.svg
bri BRI Virtual Account bri.svg
permata Permata Virtual Account permata.svg

Sourcing — idn-finlogos

We pull individual SVGs from github.com/hafidznoor/idn-finlogos rather than installing the Flutter package (idn_finlogos on pub.dev). The package bundles all 572 SVGs as Flutter assets — Flutter doesn't tree-shake assets, so adding the package ships ~4-6 MB of marks we never use. Manual copy keeps the APK lean: 10 marks ≈ 80 KB on-disk.

See NOTICE_IDN_FINLOGOS.txt for the upstream licensing terms (MIT for build tooling, CC BY-NC 4.0 for the SVG assets, plus the project's note that individual brand marks require permission from each brand holder for commercial use).

Adding a new method

  1. Catalog row (control center → Payment Catalog):
    • Add a method with payment_code set to the Xendit channel code (uppercase, e.g. LINKAJA) and icon set to the desired slug (lowercase, e.g. linkaja).
    • Method renders immediately with the generic placeholder icon.
  2. Branded SVG (one-time, requires an app release):
    cd client_app/assets/payment_icons
    curl -sS https://raw.githubusercontent.com/hafidznoor/idn-finlogos/main/icons/<source>.svg -o <slug>.svg
    
    (Browse the repo's icons/ directory if the source filename isn't an exact match — e.g. ovo-new.svg for the modern OVO mark.)
  3. Append the slug to _kBundledSlugs in client_app/lib/features/payment/widgets/payment_icon.dart so the widget stops falling back to the placeholder for that slug.
  4. Cut a release. Assets ship with the APK; new icons need a binary update.

Why the explicit _kBundledSlugs list?

Flutter's asset system throws if a referenced asset is missing — there's no "file exists?" check at runtime without round-tripping the AssetManifest. Keeping the bundled-slugs list in code makes "what we ship" explicit and keeps the icon widget cheap.

When to migrate to the pub package

The manual-copy approach beats idn_finlogos as long as we bundle fewer than ~50 icons (where the ~4-6 MB whole-library payload starts looking reasonable compared to per-file curl-and-commit overhead). If we cross that threshold, switch:

dependencies:
  idn_finlogos: ^2.3.0

…and delete this directory's per-icon SVGs (keep placeholder.svg + the slug allowlist).