diff --git a/docs/front-end-spec.md b/docs/front-end-spec.md new file mode 100644 index 0000000..d857c6a --- /dev/null +++ b/docs/front-end-spec.md @@ -0,0 +1,264 @@ +# Core Midtrans CIFO UI/UX Specification + +Purpose +- Improve legibility and contrast for older users by strengthening color, typography, and separators across Checkout flows (QRIS, GoPay, Convenience Store, Bank Transfer). +- Establish clear theme tokens so implementation stays consistent across components. + +Change Log +- 2025-11-10: Initial draft focused on contrast, typography, and card/divider clarity. + +Theme Foundations +- Color Roles (recommended hex values): + - Page background: `#F7FAFC` (very light slate) + - Surface/background (cards, panels): `#FFFFFF` + - Text primary: `#0B1020` (near-black for high contrast) + - Text secondary: `#374151` (medium slate; still readable) + - Border default: `#94A3B8` (slate 400) + - Border strong: `#64748B` (slate 500) + - Accent/primary: `#2563EB` (blue 600) + - Success: `#16A34A` (green 600) + - Danger: `#DC2626` (red 600) + - Warning: `#D97706` (amber 600) + - Info: `#0EA5E9` (sky 500) +- Focus and States: + - Focus ring color: `#2563EB` + - Focus ring width: `3px` + - Hover/active states should increase contrast by at least one shade (e.g., blue 600 → blue 700 on hover). +- Typography: + - Font stack (sans): `Inter, Segoe UI, system-ui, -apple-system, Roboto, Noto Sans, Arial, sans-serif` + - Base body size: `16px` minimum; labels `15px`; buttons `16px` + - Headings: `H4 20px`, `H3 24px`, `H2 28px` (line-height ~1.3) + - Body line-height: `1.5` for readability + - Avoid ultra-light weights; prefer `400–600` for body/labels +- Separators and Borders: + - Default divider: `1.5px` `#94A3B8` + - Strong divider: `2px` `#64748B` for section breaks and card boundaries + - Cards: visible 2px border, subtle shadow `0 1px 2px rgba(0,0,0,0.08)` +- Spacing Scale (base): + - `4px` units; common spacing: `8/12/16/24/32px` + - Minimum interior padding for cards: `16–24px` + +Accessibility Standards +- Contrast: + - Normal text contrast ≥ `4.5:1`; large text (≥18px) ≥ `3:1` + - Verify accent on white and on light surfaces meets ratios +- Touch Targets: + - Minimum hit area: `44x44px` for interactive elements + - Minimum tap spacing: `8px` around grouped actions +- Focus & Keyboard: + - Always-visible focus outline with `3px` ring in accent color + - Skip links available on long forms +- Motion & Feedback: + - Respect reduced motion; avoid aggressive animations + - Provide textual or icon feedback in addition to color changes + +Component Guidance +- Cards/Panels: + - Use strong border (`2px #64748B`) for outer frame when content density is high + - Title uses `H4/H3` with primary text color; subtitle uses secondary + - Interior dividers use default border (`1.5px #94A3B8`) +- Buttons: + - Primary: solid `#2563EB` with white text; hover `#1D4ED8` + - Secondary: outline with strong border and primary text + - Disabled: `#CBD5E1` background, `#64748B` text; maintain contrast + - Focus: `3px` accent ring outside button +- Inputs: + - Label size `15–16px` and primary text color; never rely on placeholder as label + - Field border default; on focus switch to strong border and accent ring + - Error state uses danger color and text hint; icon optional +- Lists/Selection (e.g., store selection): + - Row height ≥ `48px`; radio/checkbox minimum `24px` + - Selected state uses strong border and light accent background (`blue-50`) + +Implementation Notes +- CSS Variables (define once): + ```css + :root { + --color-bg-page: #F7FAFC; + --color-bg-surface: #FFFFFF; + --color-text-primary: #0B1020; + --color-text-secondary: #374151; + --color-border-default: #94A3B8; + --color-border-strong: #64748B; + --color-accent: #2563EB; + --color-success: #16A34A; + --color-danger: #DC2626; + --color-warning: #D97706; + --color-info: #0EA5E9; + --focus-ring-width: 3px; + --focus-ring-color: #2563EB; + --shadow-card: 0 1px 2px rgba(0,0,0,0.08); + --border-width-default: 1.5px; + --border-width-strong: 2px; + --font-family-sans: Inter, Segoe UI, system-ui, -apple-system, Roboto, Noto Sans, Arial, sans-serif; + --font-size-body: 16px; + --font-size-label: 15px; + --font-size-button: 16px; + --font-size-h4: 20px; + --font-size-h3: 24px; + --font-size-h2: 28px; + --line-height-body: 1.5; + } + ``` +- Tailwind Theme (high-level): + - Map CSS variables to custom colors via CSS-in-JS or add a custom palette in `tailwind.config.*` aligned to the hex values above + - Increase `ringWidth` default to `3`, add `ringColor` for focus, and define `borderWidth` scale with `1.5` and `2` +- Component Application: + - Replace `border-gray-200/300` with `border-[#94A3B8]` for dividers + - Use `border-[2px]` + `border-[#64748B]` for card frames when needed + - Set `text-[#0B1020]` as default text and avoid pure black for softer rendering + +Validation Checklist +- Body text ≥16px and headings per spec +- Divider visibility validated on standard laptop and low-contrast displays +- All critical actions meet contrast and focus outline requirements +- Component states (hover, active, disabled, error) meet color and contrast standards + +Instruksi Langkah Pembayaran +- Tujuan: Menyajikan cara bayar yang jelas tanpa Step Wizard. Fokus pada daftar langkah ringkas untuk tiap metode (QRIS, GoPay, Transfer Bank via Mobile/Internet Banking/ATM, Convenience Store). +- Prinsip Penyajian: + - Judul panel: "Cara Bayar" + nama metode/bank (mis. "Cara Bayar: BCA Mobile", "Cara Bayar: ATM BNI", "Cara Bayar: QRIS"). + - Gunakan daftar bernomor (1., 2., 3.) dengan jarak antar langkah `12–16px` dan body `16–18px`. + - Kalimat singkat, langsung, maksimal ±100 karakter per langkah. + - Gunakan teks primer `#0B1020`; hindari abu-abu pucat untuk keterbacaan. + - Divider opsional antar kelompok langkah memakai border default `#94A3B8`. + - Ikon langkah opsional; jangan menggantikan teks instruksi. + +Pola per Metode +- QRIS + - 1. Buka aplikasi e-wallet/mbanking yang mendukung QRIS. + - 2. Arahkan kamera ke QR di layar. + - 3. Periksa detail pembayaran dan konfirmasi. + - 4. Selesai. Simpan bukti transaksi. + - Catatan: tampilkan countdown kedaluwarsa dan state "QR kedaluwarsa" dengan aksi "Buat Ulang" jika diperlukan. + +- GoPay + - 1. Ketuk tombol "Buka GoPay" (atau buka aplikasi GoPay manual). + - 2. Periksa detail pembayaran. + - 3. Konfirmasi dan selesaikan pembayaran. + - 4. Simpan bukti transaksi. + +- Transfer Bank via Mobile Banking (contoh umum) + - 1. Buka aplikasi mobile banking dan login. + - 2. Pilih menu "Transfer" → "Virtual Account". + - 3. Masukkan nomor VA dan nominal. + - 4. Periksa detail, konfirmasi dengan PIN/OTP. + - 5. Simpan bukti transaksi. + +- Transfer Bank via Internet Banking (contoh umum) + - 1. Buka situs internet banking dan login. + - 2. Pilih menu "Transfer" → "Virtual Account". + - 3. Masukkan nomor VA dan nominal. + - 4. Periksa detail, konfirmasi dengan OTP. + - 5. Simpan bukti transaksi. + +- Transfer Bank via ATM (contoh umum) + - 1. Kunjungi ATM dan masukkan kartu, pilih bahasa. + - 2. Pilih menu "Transfer" → "Virtual Account". + - 3. Masukkan nomor VA dan nominal. + - 4. Periksa detail, konfirmasi. + - 5. Ambil dan simpan struk transaksi. + +- Convenience Store (Alfamart/Indomaret) + - 1. Kunjungi toko yang dipilih (Alfamart/Indomaret). + - 2. Tunjukkan "Kode Pembayaran" kepada kasir. + - 3. Lakukan pembayaran sebelum kedaluwarsa. + - 4. Simpan struk. Kunjungi halaman "Cek Status Pembayaran" jika diperlukan. + +Copywriting Baku +- Gunakan label konsisten: "Kode Pembayaran", "Salin Kode", "Cek Status Pembayaran", "Buka GoPay", "QRIS", "Kedaluwarsa dalam", "Buat Ulang". +- Bahasa Indonesia, kalimat aktif, hindari istilah teknis berlebihan. +- Pastikan penulisan brand dan bank sesuai pedoman resmi. + +Aksesibilitas & Lansia +- Body `16–18px`, line-height `1.5`; jarak antar langkah `12–16px`. +- Kontras AA untuk teks dan divider; fokus `ring 3px` selalu terlihat. +- Comfort Mode opsional: font `18px`, border kuat `3px`, spacing +20%. + +Mobile UX — Pembayaran +- Tata letak: + - Satu kolom pada lebar kecil; gunakan container `max-w-md`. + - Spasi internal panel `16–24px`; hindari konten menempel ke tepi. +- Target sentuh: + - Tinggi area tap minimal `44px`; jarak antar aksi `8–12px`. + - Baris pemilihan metode memakai `min-h-[44px]` dan `p-3`. +- Tipografi: + - Body `16px` (min); langkah instruksi `16–18px` dengan `line-height 1.5`. + - Hindari `text-xs` untuk konten utama di mobile. +- Aksi utama: + - Tombol utama `w-full`; boleh sticky di bawah layar. + - Pertimbangkan padding aman: `padding-bottom: env(safe-area-inset-bottom)`. +- Panel QR/Code: + - QR minimum `min(68vw, 280px)`; grid pusat; border jelas. + - Kode pembayaran memakai `font-mono`, `text-lg`, `letter-spacing ~0.06em`, `select-all`. + - Tombol “Salin Kode” `w-full` di mobile. +- Loading & status: + - Pakai teks pendamping pada spinner; tambahkan `aria-live="polite"`. + - Tampilkan countdown kedaluwarsa dan aksi “Buat Ulang” jika relevan. +- Performa: + - Lazy-load gambar brand/QR; batasi ukuran logo; cache aktif. + - Hormati `prefers-reduced-motion`. + +Implementasi Komponen (Opsional) +- InstructionList API: + ```ts + type InstructionListProps = { + title: string; // "Cara Bayar: QRIS", "Cara Bayar: BCA Mobile" + steps: string[]; // daftar langkah pendek + footnote?: string; // catatan opsional (mis. kedaluwarsa) + } + ``` +- Gaya default: + - Judul `H4/H3` dengan teks primer; langkah bernomor dengan spacing `12–16px`. + - Divider antar kelompok langkah memakai `#94A3B8`; tidak wajib. +- Ikon kecil opsional di kiri; jangan menggantikan teks. + +Bank Spesifik: BCA +- BCA Mobile (m-BCA) — Virtual Account + - 1. Buka aplikasi BCA mobile dan login. + - 2. Pilih menu "m-BCA" → "m-Transfer". + - 3. Pilih "BCA Virtual Account". + - 4. Masukkan "Nomor VA" yang tertera di halaman pembayaran. + - 5. Masukkan nominal jika tidak terisi otomatis. + - 6. Periksa detail pembayaran, lalu ketuk "Send". + - 7. Masukkan PIN m-BCA untuk konfirmasi. + - 8. Simpan bukti transaksi. + - Catatan: Nama menu dapat berbeda pada versi aplikasi tertentu; sesuaikan jika perlu. + +- ATM BCA — Virtual Account + - 1. Masukkan kartu BCA dan PIN. + - 2. Pilih "Transaksi Lainnya". + - 3. Pilih "Transfer". + - 4. Pilih "Ke BCA Virtual Account". + - 5. Masukkan "Nomor VA" yang tertera di halaman pembayaran. + - 6. Masukkan nominal jika diminta. + - 7. Periksa detail pembayaran, lalu konfirmasi. + - 8. Ambil dan simpan struk transaksi. + - Catatan: Urutan menu pada beberapa ATM bisa berbeda; gunakan opsi Virtual Account ketika tersedia. + +- Internet Banking (KlikBCA) — Virtual Account + - 1. Buka situs resmi KlikBCA dan login dengan user ID. + - 2. Pilih menu "Transfer Dana". + - 3. Pilih "Ke BCA Virtual Account". + - 4. Masukkan "Nomor VA" yang tertera di halaman pembayaran. + - 5. Masukkan nominal jika diperlukan. + - 6. Periksa detail pembayaran, lalu konfirmasi. + - 7. Masukkan OTP/KeyBCA (token) untuk menyetujui transaksi. + - 8. Simpan bukti transaksi. + - Catatan: Nama menu dapat berbeda antar versi; pastikan memilih opsi Virtual Account. + +Copywriting Baku — Tambahan +- Untuk metode Virtual Account, gunakan label "Nomor VA" secara konsisten pada UI dan instruksi. + +Roadmap Implementasi — Mobile Pembayaran (10 TODO) +- [x] Tambah panduan "Mobile UX — Pembayaran" di spesifikasi. +- [x] Perbesar area sentuh PaymentMethodList (min height ≥44px). +- [x] Tingkatkan keterbacaan PaymentInstructions (text-sm, spacing yang cukup). +- [x] Perbesar keterbacaan Kode Pembayaran di CStore (font-mono, text-lg, tracking, select-all). +- [x] Perbesar kontainer QR GoPay/QRIS dan buat tombol aksi full-width di mobile. +- [ ] PaymentSheet: optimalkan header mobile dan countdown jelas. + - Catatan: tombol utama sticky di bawah sudah diimplementasi. +- [x] BankTransferPanel: implementasi komponen InstructionList untuk BCA (Mobile/ATM/KlikBCA). +- [ ] Aksesibilitas: standarisasi aria-live untuk spinner/QR/kode, fokus ring 3px di semua panel. +- [ ] Comfort Mode: tambah toggle (font 18px, border 3px, spacing +20%) dan token gaya terkait. +- [ ] QA lintas perangkat: uji di layar kecil (iPhone SE/Android kecil), sesuaikan token bila perlu. \ No newline at end of file diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index e92b1af..0a8eb36 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -2,7 +2,7 @@ import { cva, type VariantProps } from 'class-variance-authority' import { cn } from '../../lib/cn' const buttonVariants = cva( - 'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:focus-ring disabled:opacity-50 disabled:pointer-events-none', + 'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-[#2563EB] focus-visible:ring-[3px] focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-black disabled:opacity-50 disabled:pointer-events-none', { variants: { variant: { diff --git a/src/features/payments/components/BankTransferPanel.tsx b/src/features/payments/components/BankTransferPanel.tsx index ab16556..457a5eb 100644 --- a/src/features/payments/components/BankTransferPanel.tsx +++ b/src/features/payments/components/BankTransferPanel.tsx @@ -2,6 +2,7 @@ import { Button } from '../../../components/ui/button' import { usePaymentNavigation } from '../lib/navigation' import React from 'react' import { PaymentInstructions } from './PaymentInstructions' +import { BcaInstructionList } from './BcaInstructionList' import { TrustStrip } from './TrustStrip' import { BankLogosRow, BankLogo, type BankKey } from './PaymentLogos' import { postCharge } from '../../../services/api' @@ -126,6 +127,13 @@ export function BankTransferPanel({ orderId, amount, locked, onChargeInitiated, // eslint-disable-next-line react-hooks/exhaustive-deps }, [selected]) + // Auto-show instructions when BCA is selected to reduce confusion + React.useEffect(() => { + if (selected === 'bca' && !showGuide) { + setShowGuide(true) + } + }, [selected]) + return (