docs: Add Phase 1 Payment UX Improvements planning (problem-solution, tech-spec, epic, stories)

This commit is contained in:
CIFO Dev 2025-11-25 13:51:14 +07:00
parent 96c4cd3aba
commit 90923de3bd
6 changed files with 3401 additions and 0 deletions

View File

@ -0,0 +1,148 @@
# Brainstorming Session Results
**Session Date:** {{date}}
**Facilitator:** {{agent_role}} {{agent_name}}
**Participant:** {{user_name}}
## Session Start
Pendekatan: AI-Recommended Techniques
Rencana Teknik:
- First Principles Thinking
- Assumption Reversal
- Mind Mapping
- Question Storming
- SCAMPER Method
## Executive Summary
**Topic:** Callback pembayaran dipindahkan ke backend (Midtrans)
**Session Goals:**
- Backend mengeksekusi callback berdasarkan status Midtrans (webhook/status API)
- Tidak bergantung pada keberadaan tab/browser di sisi pengguna
- Verifikasi sukses via signature dan idempoten agar tidak duplikat
**Techniques Used:** {{techniques_list}}
First Principles Thinking; Assumption Reversal; Mind Mapping; Question Storming; SCAMPER Method
**Total Ideas Generated:** {{total_ideas}}
### Key Themes Identified:
{{key_themes}}
## Technique Sessions
First Principles Thinking — Pengantar & Prompt Awal
- Apa fakta yang kita ketahui pasti tentang notifikasi Midtrans dan status transaksi?
- Apa elemen paling mendasar dari alur callback backend yang wajib ada?
- Jika kita mulai dari nol, bagaimana alur minimal yang bebas dari ketergantungan frontend?
Assumption Reversal — Kerangka Tantangan
- Asumsi yang dibalik: “Frontend harus aktif untuk callback” → “Backend sendiri cukup melalui webhook + status”.
- Apa perubahan arsitektur/operasional yang langsung mengikuti dari pembalikan ini?
Mind Mapping — Pemetaan State/Trigger
- Node: `Midtrans → webhook → backend → ERP notify → UI status`.
- Alternatif: `activeOrders → polling status → backend → ERP notify`.
Question Storming — Unknowns Kritis
- Metode bayar apa yang Anda gunakan utama (VA, kartu 3DS, GoPay/QR)?
- Apakah Notification URL sudah terpasang di dashboard Midtrans produksi?
- Apakah perlu multi-ERP endpoint atau hanya satu?
SCAMPER — Modifikasi Sistematik
- Substitute: frontend-callback → backend-callback.
- Combine: webhook + status check + polling.
- Adapt: idempoten dan signature untuk ERP.
━━━━━━━━━━━━━━━━━━━━━━━
Masukkan jawaban untuk pertanyaan First Principles pertama: “Apa fakta yang kita ketahui pasti tentang notifikasi Midtrans dan status transaksi?”
Pilihan: [a] Advanced Elicitation, [c] Continue, [p] Party-Mode, [y] YOLO
## Idea Categorization
### Immediate Opportunities
_Ideas ready to implement now_
{{immediate_opportunities}}
### Future Innovations
_Ideas requiring development/research_
{{future_innovations}}
### Moonshots
_Ambitious, transformative concepts_
{{moonshots}}
### Insights and Learnings
_Key realizations from the session_
{{insights_learnings}}
## Action Planning
### Top 3 Priority Ideas
#### #1 Priority: {{priority_1_name}}
- Rationale: {{priority_1_rationale}}
- Next steps: {{priority_1_steps}}
- Resources needed: {{priority_1_resources}}
- Timeline: {{priority_1_timeline}}
#### #2 Priority: {{priority_2_name}}
- Rationale: {{priority_2_rationale}}
- Next steps: {{priority_2_steps}}
- Resources needed: {{priority_2_resources}}
- Timeline: {{priority_2_timeline}}
#### #3 Priority: {{priority_3_name}}
- Rationale: {{priority_3_rationale}}
- Next steps: {{priority_3_steps}}
- Resources needed: {{priority_3_resources}}
- Timeline: {{priority_3_timeline}}
## Reflection and Follow-up
### What Worked Well
{{what_worked}}
### Areas for Further Exploration
{{areas_exploration}}
### Recommended Follow-up Techniques
{{recommended_techniques}}
### Questions That Emerged
{{questions_emerged}}
### Next Session Planning
- **Suggested topics:** {{followup_topics}}
- **Recommended timeframe:** {{timeframe}}
- **Preparation needed:** {{preparation}}
---
_Session facilitated using the BMAD CIS brainstorming framework_

284
docs/epics.md Normal file
View File

@ -0,0 +1,284 @@
# core-midtrans-cifo - Epic Breakdown
**Date:** 2025-11-25
**Project Level:** Quick-Flow (2 Stories)
---
## Epic 1: Payment Flow UX Improvements
**Slug:** payment-ux-improvements
### Goal
Improve payment flow user experience for non-tech-savvy users (ibu-ibu awam) by eliminating duplicate VA generation errors, providing clear loading feedback, implementing user-friendly error messages, and guiding users after successful payment completion.
**Business Value:**
- Reduce abandoned transactions by 20%+
- Decrease support tickets by 30%+
- Increase payment completion rate by 10%+
- Improve user trust and satisfaction
**User Value:**
- Clear feedback during payment processing
- No more confusing technical error messages
- Obvious next steps after payment success
- Smooth, anxiety-free payment experience
### Scope
**In Scope:**
✅ **Prevent Duplicate VA Generation**
- Button disable logic during VA generation
- Request debouncing (500ms)
- Loading overlay with clear messaging
- User-friendly error messages in Bahasa Indonesia
✅ **Improve Error Handling**
- Map HTTP 409 → "Kode pembayaran Anda sudah dibuat! Klik di sini untuk melihat"
- Map HTTP 404 → "Terjadi kesalahan. Silakan coba lagi"
- Recovery buttons ("Coba Lagi", "Lihat Kode Pembayaran", "Kembali")
✅ **Post-Payment UX**
- 5-second countdown timer on success page
- Auto-redirect to dashboard after countdown
- Manual "Kembali Sekarang" button for impatient users
✅ **Mobile-First Design**
- All components optimized for mobile devices
- Responsive design with TailwindCSS
- Touch-friendly buttons (minimum 44x44px)
**Out of Scope:**
**Phase 2 Solutions** (future epics):
- Navigation guards (useEffect cleanup)
- Modal-based success page
- Progressive loading states
- Transaction state machine
- Idempotency key implementation
❌ **Backend Changes:**
- Midtrans API modifications
- Database schema changes
- Backend validation logic
❌ **Complete Redesign:**
- Single-page payment flow
- Optimistic UI patterns
- Guided tour/onboarding
### Success Criteria
**User Experience Success:**
1. ✅ Users cannot generate VA multiple times (button disabled during processing)
2. ✅ Users see clear loading feedback ("Sedang membuat kode pembayaran...")
3. ✅ Error messages are in Bahasa Indonesia and user-friendly
4. ✅ Users have clear recovery options on errors
5. ✅ Users know exactly what to do after payment success (countdown + CTA)
**Technical Success:**
1. ✅ Zero HTTP 409 errors from duplicate VA generation
2. ✅ All error messages mapped to user-friendly Indonesian text
3. ✅ Loading overlay prevents interaction during processing
4. ✅ Auto-redirect works correctly after 5-second countdown
5. ✅ All components work on mobile devices (Chrome, Safari)
**Business Success:**
1. ✅ Reduced abandoned transaction rate (measure before/after)
2. ✅ Reduced support tickets related to payment confusion
3. ✅ Increased payment completion rate
4. ✅ Positive user feedback on payment experience
**Acceptance Criteria Coverage:**
- 10 detailed acceptance criteria defined in tech-spec
- All criteria testable and measurable
- Coverage across both user stories
### Dependencies
**External Dependencies:**
- ✅ Midtrans API (existing integration, no changes required)
- ✅ React 19.1.1 (already installed)
- ✅ Framer Motion 12.23.24 (already installed)
- ✅ TailwindCSS 4.1.17 (already installed)
**Internal Dependencies:**
- ✅ Existing payment feature module (`src/features/payment/`)
- ✅ Existing Midtrans service layer (`src/services/`)
- ✅ Existing TailwindCSS design system
**No New Dependencies Required** - All solutions use existing tech stack
**Prerequisites:**
- None - This is Phase 1, no prior work required
- Brownfield codebase analysis completed (problem-solution doc)
- Tech-spec completed and approved
---
## Story Map - Epic 1
```
Epic 1: Payment Flow UX Improvements (7 points)
├── Story 1.1: Prevent Duplicate VA/QR/Code Generation & Improve Feedback (5 points)
│ │
│ ├── Create utility functions (debounce, errorMessages)
│ ├── Create LoadingOverlay component
│ ├── Modify payment method component
│ │ ├── Add button disable logic
│ ├── Add auto-redirect logic
│ └── Add manual redirect button
└── Write tests and verify
Dependencies: None (independent of Story 1.1)
Deliverable: Users have clear guidance after payment success,
auto-redirect prevents back button confusion
```
**Implementation Sequence:**
1. **Story 1.1** - Can be implemented first (no dependencies)
2. **Story 1.2** - Can be implemented in parallel or after Story 1.1
**Note:** Stories are independent and can be implemented in any order or in parallel.
---
## Stories - Epic 1
### Story 1.1: Prevent Duplicate VA Generation & Improve Feedback
As a **non-tech-savvy user (ibu-ibu)**,
I want **clear feedback during VA generation and user-friendly error messages**,
So that **I don't accidentally create duplicate payment codes and I understand what to do when errors occur**.
**Acceptance Criteria:**
**AC #1: Button Disable During Processing**
- **Given** user clicks "Generate VA" button
- **When** API request is in progress
- **Then** button is disabled and shows loading spinner
- **And** user cannot click button again
- **And** loading overlay appears with message "Sedang membuat kode pembayaran..."
**AC #2: Debounce Prevents Rapid Clicks**
- **Given** user clicks "Generate VA" button multiple times within 500ms
- **When** debounce is active
- **Then** only one API request is sent
- **And** subsequent clicks within 500ms are ignored
**AC #3: User-Friendly Error Messages**
- **Given** VA generation fails with HTTP 409
- **When** error is displayed to user
- **Then** message shows "Kode pembayaran Anda sudah dibuat! Klik di sini untuk melihat"
- **And** "Lihat Kode Pembayaran" button is displayed
- **And** clicking button navigates to existing VA view
**AC #4: Error Recovery Options**
- **Given** VA generation fails with any error
- **When** error is displayed to user
- **Then** "Coba Lagi" button is displayed
- **And** clicking button retries VA generation
- **And** "Kembali" button is displayed
- **And** clicking button returns to payment method selection
**AC #5: Loading Overlay Prevents Interaction**
- **Given** VA generation is in progress
- **When** loading overlay is displayed
- **Then** user cannot interact with page content
- **And** overlay shows clear message in Bahasa Indonesia
- **And** overlay is responsive on mobile devices
**Prerequisites:** None
**Technical Notes:**
- Use existing React hooks (useState, useEffect)
- Leverage Framer Motion for overlay animations
- Follow existing TailwindCSS design patterns
- No new dependencies required
**Estimated Effort:** 5 points (~2-3 days) - Covers all 3 payment methods (Bank Transfer, GoPay/QRIS, Convenience Store)
---
### Story 1.2: Improve Post-Payment UX
As a **non-tech-savvy user (ibu-ibu)**,
I want **clear guidance on what to do after successful payment**,
So that **I don't get confused and press the back button which causes errors**.
**Acceptance Criteria:**
**AC #6: Countdown Timer Display**
- **Given** user completes payment successfully
- **When** payment success page loads
- **Then** countdown timer shows "Anda akan diarahkan ke dashboard dalam 5 detik..."
- **And** countdown decrements every second (5, 4, 3, 2, 1)
- **And** timer is visible and readable on mobile devices
**AC #7: Auto-Redirect After Countdown**
- **Given** countdown timer reaches 0
- **When** timer completes
- **Then** user is automatically redirected to dashboard/home page
- **And** redirect happens smoothly without errors
**AC #8: Manual Redirect Button**
- **Given** countdown timer is active
- **When** user clicks "Kembali Sekarang" button
- **Then** user is immediately redirected to dashboard/home page
- **And** countdown is cancelled
**AC #9: Mobile-First Responsive Design**
- **Given** user accesses payment flow on mobile device
- **When** countdown and button are displayed
- **Then** all elements are properly sized and positioned for mobile
- **And** all text is readable without zooming
- **And** button is easily tappable (minimum 44x44px)
**AC #10: Bahasa Indonesia Throughout**
- **Given** user views success page
- **When** text is displayed
- **Then** all text is in Bahasa Indonesia
- **And** language is appropriate for non-tech-savvy users
- **And** no technical jargon is used
**Prerequisites:** None
**Technical Notes:**
- Use useEffect with setTimeout for countdown
- Use useNavigate from react-router-dom for redirect
- Follow existing TailwindCSS responsive patterns
- Ensure proper cleanup on component unmount
**Estimated Effort:** 2 points (~1 day)
---
## Implementation Timeline - Epic 1
**Total Story Points:** 7 points
**Estimated Timeline:** 3-4 days (assuming 1.5-2 points per day)
**Recommended Sequence:**
1. Story 1.1 (3 points) - Implement first or in parallel
2. Story 1.2 (2 points) - Implement second or in parallel
**Notes:**
- Stories are independent and can be worked on in parallel by different developers
- Both stories should be completed before deployment to production
- Comprehensive testing required after both stories complete
- Deployment can happen after both stories pass QA
---
**Epic Status:** Draft - Ready for Implementation
**Next Steps:**
1. Review and approve epic and stories
2. Assign stories to developers
3. Begin implementation following tech-spec guidance
4. Track progress in sprint board
5. Deploy to production after QA approval

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,330 @@
# Story 1.1: Prevent Duplicate VA Generation & Improve Feedback
**Status:** Draft
---
## User Story
As a **non-tech-savvy user (ibu-ibu)**,
I want **clear feedback during automatic payment code generation (VA/QR/C-Store) and user-friendly error messages**,
So that **I don't see confusing technical errors and I understand what to do when problems occur across all payment methods (Bank Transfer, GoPay/QRIS, Convenience Store)**.
---
## Acceptance Criteria
### AC #1: Auto-Generation Loading State
**Given** user enters BankTransferPanel with selected bank
**When** VA generation automatically starts (via useEffect on component mount)
**Then** loading spinner is displayed with "Membuat VA…" message
**And** user sees clear feedback that generation is in progress
**And** loading overlay appears with message "Sedang membuat kode pembayaran..."
**And** user cannot interact with page during generation
### AC #2: Prevent Duplicate Generation on Reload/Remount
**Given** VA generation is already in progress or completed for an order+bank combination
**When** user reloads page or component remounts (React StrictMode, navigation back/forward)
**Then** system detects existing in-flight or completed charge via `attemptedChargeKeys` Set
**And** does not create duplicate VA generation request to Midtrans
**And** reuses existing VA code if already generated
**And** shows existing loading state if generation still in progress
### AC #3: User-Friendly Error Messages
**Given** VA generation fails with HTTP 409 (duplicate VA)
**When** error is displayed to user
**Then** message shows "Kode pembayaran Anda sudah dibuat! Klik di sini untuk melihat" (instead of technical "Request Failed 409")
**And** "Lihat Kode Pembayaran" button is displayed
**And** clicking button navigates to payment status page with existing VA
### AC #4: Error Recovery Options
**Given** VA generation fails with any error (404, 500, network error)
**When** error is displayed to user
**Then** "Buat VA" retry button is displayed (currently exists in code line 201-288)
**And** clicking button retries VA generation
**And** error message is in Bahasa Indonesia (not technical English)
**And** user has clear path to recover from error
### AC #5: Loading Overlay Prevents Interaction
**Given** VA generation is in progress
**When** loading overlay is displayed
**Then** user cannot interact with page content (no clicks, no navigation)
**And** overlay shows clear message in Bahasa Indonesia
**And** overlay is responsive on mobile devices
**And** overlay has proper z-index (50+) to stay above all content
---
## Implementation Details
### Tasks / Subtasks
**Phase 1: Understand Existing Implementation** (~30 minutes)
- [ ] Review `BankTransferPanel.tsx` (AC: #1, #2)
- [ ] Understand auto-generation logic in useEffect (lines 35-129)
- [ ] Understand duplicate prevention with `attemptedChargeKeys` Set (line 13)
- [ ] Understand shared promise pattern with `chargeTasks` Map (line 15)
- [ ] Understand retry button logic (lines 201-288)
- [ ] Identify what needs to be improved (AC: #3, #4, #5)
- [ ] Current error handling (lines 110-116, 268-271)
- [ ] Current loading feedback (lines 162-165, 281-286)
- [ ] Missing: Full-screen loading overlay
- [ ] Missing: User-friendly error message mapping
**Phase 2: Create Utility Functions** (~30 minutes)
- [ ] Create `src/lib/errorMessages.ts` (AC: #3, #4)
- [ ] Implement `mapErrorToUserMessage(error: AxiosError): string`
- [ ] Map HTTP 409 → "Kode pembayaran Anda sudah dibuat! Klik di sini untuk melihat"
- [ ] Map HTTP 404 → "Terjadi kesalahan. Silakan coba lagi"
- [ ] Map HTTP 500 → "Terjadi kesalahan server. Silakan coba lagi nanti"
- [ ] Map network error → "Tidak dapat terhubung ke server. Periksa koneksi internet Anda"
- [ ] Map "Gagal membuat VA." → More specific message based on error type
- [ ] Add default fallback message
- [ ] Write unit tests for error mapping
- [ ] Test HTTP 409 mapping
- [ ] Test HTTP 404 mapping
- [ ] Test HTTP 500 mapping
- [ ] Test network error mapping
- [ ] Test default fallback
**Phase 3: Create LoadingOverlay Component** (~1 hour)
- [ ] Create `src/components/LoadingOverlay.tsx` (AC: #1, #5)
- [ ] Implement full-screen overlay with semi-transparent backdrop
- [ ] Add Framer Motion fade-in animation (200ms)
- [ ] Add spinner (reuse existing spinner from line 163 or create new)
- [ ] Add message prop: "Sedang membuat kode pembayaran..."
- [ ] Make responsive for mobile (TailwindCSS)
- [ ] Add z-index: 50 to stay above all content
- [ ] Add accessibility (ARIA labels, role="status", aria-live="polite")
- [ ] Props interface: `{ isLoading: boolean; message: string }`
- [ ] Write component tests for LoadingOverlay
- [ ] Test renders when isLoading=true
- [ ] Test doesn't render when isLoading=false
- [ ] Test displays correct message
- [ ] Test fade-in animation works
- [ ] Test accessibility attributes
**Phase 4: Modify All Payment Panels** (~2 hours)
- [ ] Update error handling in `BankTransferPanel.tsx` (AC: #3, #4)
- [ ] Import `mapErrorToUserMessage` utility
- [ ] Replace line 66: `const msg = ax?.response?.data?.message || ax?.message || 'Gagal membuat VA.'`
- [ ] With: `const msg = mapErrorToUserMessage(ax)`
- [ ] Replace line 112: Same error handling
- [ ] Replace line 234: Same error handling
- [ ] Replace line 270: Same error handling
- [ ] Ensure all 4 error catch blocks use new mapping
- [ ] Add LoadingOverlay integration (AC: #1, #5)
- [ ] Import LoadingOverlay component
- [ ] Add LoadingOverlay to JSX (line 139, before main content)
- [ ] Pass `isLoading={busy}` prop
- [ ] Pass `message="Sedang membuat kode pembayaran..."` prop
- [ ] Enhance error display (AC: #3, #4)
- [ ] Update Alert component usage (line 148-150)
- [ ] Add conditional "Lihat Kode Pembayaran" button for HTTP 409
- [ ] Ensure "Buat VA" retry button (line 201-288) is visible on errors
- [ ] Update error handling in `GoPayPanel.tsx` (AC: #3, #4)
- [ ] Import `mapErrorToUserMessage` utility
- [ ] Replace line 178: `toast.error(\`Gagal membuat QR: ${(e as Error).message}\`)`
- [ ] With: `toast.error(mapErrorToUserMessage(e))`
- [ ] Replace line 207: Same error handling
- [ ] Add LoadingOverlay integration (AC: #1, #5)
- [ ] Import LoadingOverlay component
- [ ] Add LoadingOverlay to JSX (line 55, before main content)
- [ ] Pass `isLoading={busy}` prop
- [ ] Pass `message="Sedang membuat kode QR..."` prop
- [ ] Update error handling in `CStorePanel.tsx` (AC: #3, #4)
- [ ] Import `mapErrorToUserMessage` utility
- [ ] Replace line 39: `toast.error(\`Gagal membuat kode pembayaran: ${(e as Error).message}\`)`
- [ ] With: `toast.error(mapErrorToUserMessage(e))`
- [ ] Replace line 63: Same error handling
- [ ] Add LoadingOverlay integration (AC: #1, #5)
- [ ] Import LoadingOverlay component
- [ ] Add LoadingOverlay to JSX (line 81, before main content)
- [ ] Pass `isLoading={busy}` prop
- [ ] Pass `message="Sedang membuat kode pembayaran..."` prop
- [ ] Verify duplicate prevention still works in all panels (AC: #2)
- [ ] Ensure `attemptedChargeKeys` / `attemptedCStoreKeys` Set logic unchanged
- [ ] Ensure `chargeTasks` / `cstoreTasks` Map logic unchanged
- [ ] Ensure ref-based guards unchanged
**Phase 5: Testing & Refinement** (~1.5 hours)
- [ ] Manual testing on desktop - Bank Transfer (AC: #1, #2, #3, #4, #5)
- [ ] Test auto-generation on panel mount → loading overlay appears
- [ ] Test page reload during generation → no duplicate request
- [ ] Test React StrictMode double-mount → no duplicate request
- [ ] Test HTTP 409 error → user-friendly message + "Lihat Kode" button
- [ ] Test HTTP 404 error → user-friendly message + "Buat VA" retry
- [ ] Test network error → user-friendly message
- [ ] Test loading overlay prevents interaction
- [ ] Test retry button works after error
- [ ] Manual testing on desktop - GoPay/QRIS (AC: #1, #2, #3, #4, #5)
- [ ] Test auto-generation when mode=QRIS → loading overlay appears
- [ ] Test page reload during QR generation → no duplicate request
- [ ] Test mode switch (GoPay ↔ QRIS) → proper generation
- [ ] Test error scenarios → user-friendly messages via toast
- [ ] Test loading overlay prevents interaction
- [ ] Manual testing on desktop - Convenience Store (AC: #1, #2, #3, #4, #5)
- [ ] Test auto-generation on panel mount → loading overlay appears
- [ ] Test page reload during code generation → no duplicate request
- [ ] Test error scenarios → user-friendly messages via toast
- [ ] Test loading overlay prevents interaction
- [ ] Manual testing on mobile devices (all payment methods)
- [ ] Test on Chrome Android (Bank, QRIS, C-Store)
- [ ] Test on Safari iOS (Bank, QRIS, C-Store)
- [ ] Verify loading overlay is full-screen and readable
- [ ] Verify error messages are readable
- [ ] Verify buttons are tappable (44x44px minimum)
- [ ] Test page reload on mobile → no duplicate for all methods
- [ ] Fix any issues found
- [ ] Code review and cleanup
### Technical Summary
**Current Implementation (BankTransferPanel.tsx):**
- **Auto-generation:** VA generation happens automatically via useEffect when `selected` bank changes (line 35-129)
- **Duplicate prevention:** Uses `attemptedChargeKeys` Set to track attempted charges (line 13)
- **Shared promises:** Uses `chargeTasks` Map to share in-flight requests across remounts (line 15)
- **Loading state:** `busy` state variable controls loading spinner (line 21)
- **Error handling:** Catches errors and sets `errorMessage` state (lines 110-116, 268-271)
- **Retry button:** "Buat VA" button appears when `!vaCode || errorMessage` (line 201)
**What Needs to Be Added:**
- **LoadingOverlay component:** Full-screen overlay during VA generation (currently only inline spinner)
- **Error message mapping:** User-friendly Bahasa Indonesia messages (currently technical English)
- **Enhanced error recovery:** Conditional buttons based on error type (409 vs others)
**Key Technical Decisions:**
- **Don't change duplicate prevention logic:** Existing `attemptedChargeKeys` and `chargeTasks` pattern works well
- **Don't change auto-generation trigger:** Keep useEffect pattern (line 35-129)
- **Add overlay on top:** LoadingOverlay wraps existing UI, doesn't replace inline spinner
- **Map errors at catch sites:** Replace error message at all 4 catch blocks
**Files/Modules Involved:**
- **Modified:** `src/features/payments/components/BankTransferPanel.tsx` (main changes)
- **New utility:** `src/lib/errorMessages.ts`
- **New component:** `src/components/LoadingOverlay.tsx`
- **Test files:** Tests for new utility and component
### Project Structure Notes
- **Files to modify:**
- `src/features/payments/components/BankTransferPanel.tsx` (confirmed - Bank VA generation)
- `src/features/payments/components/GoPayPanel.tsx` (confirmed - QRIS/GoPay QR generation)
- `src/features/payments/components/CStorePanel.tsx` (confirmed - Convenience Store code generation)
- **Files to create:**
- `src/lib/errorMessages.ts`
- `src/components/LoadingOverlay.tsx`
- `src/lib/__tests__/errorMessages.test.ts`
- `src/components/__tests__/LoadingOverlay.test.tsx`
- **Expected test locations:**
- `src/lib/__tests__/` - Utility function tests
- `src/components/__tests__/` - Component tests
- `src/features/payments/__tests__/` - Integration tests (optional)
- **Estimated effort:** 5 story points (~2-3 days) - Covers all 3 payment methods
- **Prerequisites:** None - This is the first story, no dependencies
### Key Code References
**Actual Existing Code:**
**BankTransferPanel.tsx (Bank VA):**
- **Auto-generation useEffect:** Lines 35-129
- **Duplicate prevention:** Lines 13 (Set), 15 (Map), 39-77 (check logic), 78-124 (main logic)
- **Error handling:** Lines 64-67 (catch #1), 110-116 (catch #2), 232-236 (catch #3), 268-272 (catch #4)
- **Loading state:** Line 21 (`busy` state), 162-165 (inline spinner), 281-286 (button spinner)
- **Retry button:** Lines 201-288 (manual "Buat VA" button)
- **Error display:** Lines 148-150 (Alert component)
**GoPayPanel.tsx (QRIS/GoPay):**
- **Auto-generation useEffect:** Lines 157-220 (in `GoPayPanel_AutoEffect` component)
- **Duplicate prevention:** Lines 11 (Set), 12 (Map), 163-186 (check logic), 188-215 (main logic)
- **Error handling:** Lines 177-178 (catch #1), 206-208 (catch #2)
- **Loading state:** Line 33 (`busy` state), 94-98 (inline spinner), 140-144 (button spinner)
- **Error display:** Lines 178, 207 (toast.error)
**CStorePanel.tsx (Convenience Store):**
- **Auto-generation useEffect:** Lines 23-72
- **Duplicate prevention:** Lines 12 (Set), 13 (Map), 30-44 (check logic), 46-68 (main logic)
- **Error handling:** Lines 38-39 (catch #1), 62-64 (catch #2)
- **Loading state:** Line 19 (`busy` state), 104-108 (inline spinner)
- **Error display:** Lines 39, 63 (toast.error)
**API Service:**
- `postCharge` function imported from `src/services/api` (line 7)
- Called at lines 90, 250 with payload containing `payment_type`, `transaction_details`, `bank_transfer`
**Important Functions:**
1. `postCharge(payload)` - API call to create VA (lines 90, 250)
2. `run()` async function - Main auto-generation logic (lines 37-125)
3. Button onClick handler - Manual retry logic (lines 205-277)
**Code Patterns to Follow:**
- Functional components with TypeScript
- TailwindCSS utility classes
- Existing spinner pattern (line 163): `<span className="h-3 w-3 animate-spin rounded-full border-2 border-black/40 border-t-transparent" />`
- Existing Alert component (line 148): `<Alert title="...">{message}</Alert>`
- Existing Button component (line 202): `<Button disabled={...} onClick={...}>`
---
## Context References
**Tech-Spec:** [tech-spec.md](../tech-spec.md) - Primary context document containing:
- Brownfield codebase analysis (React 19, TypeScript, Vite, TailwindCSS stack)
- Framework and library details with exact versions
- Existing patterns to follow (functional components, TailwindCSS, Framer Motion)
- Integration points (Midtrans API via `postCharge`, React Router)
- Complete implementation guidance with code examples
- Testing strategy and acceptance criteria
- Deployment and rollback plan
**Problem-Solution Analysis:** [problem-solution-2025-11-25.md](../problem-solution-2025-11-25.md) - Root cause analysis identifying:
- Problem #1: Repeated VA Generation (3-5 second delay, duplicate clicks)
- Root cause: Lack of defensive UX design + no user behavior anticipation
- Solution: Loading overlay + user-friendly errors + duplicate prevention
**Actual Code:** [BankTransferPanel.tsx](../src/features/payments/components/BankTransferPanel.tsx) - Current implementation with:
- Auto-generation via useEffect
- Duplicate prevention with `attemptedChargeKeys` Set
- Shared promises with `chargeTasks` Map
- Inline loading spinner
- Technical error messages (needs improvement)
**Architecture:** Feature-based modular architecture with 16 feature modules
<!-- Additional context XML paths will be added here if story-context workflow is run -->
---
## Dev Agent Record
### Agent Model Used
<!-- Will be populated during dev-story execution -->
### Debug Log References
<!-- Will be populated during dev-story execution -->
### Completion Notes
<!-- Will be populated during dev-story execution -->
### Files Modified
<!-- Will be populated during dev-story execution -->
### Test Results
<!-- Will be populated during dev-story execution -->
---
## Review Notes
<!-- Will be populated during code review -->

View File

@ -0,0 +1,234 @@
# Story 1.2: Improve Post-Payment UX
**Status:** Draft
---
## User Story
As a **non-tech-savvy user (ibu-ibu)**,
I want **clear guidance on what to do after successful payment**,
So that **I don't get confused and press the back button which causes errors**.
---
## Acceptance Criteria
### AC #6: Countdown Timer Display
**Given** user completes payment successfully
**When** payment success page loads
**Then** countdown timer shows "Anda akan diarahkan ke dashboard dalam 5 detik..."
**And** countdown decrements every second (5, 4, 3, 2, 1)
**And** timer is visible and readable on mobile devices
### AC #7: Auto-Redirect After Countdown
**Given** countdown timer reaches 0
**When** timer completes
**Then** user is automatically redirected to dashboard/home page
**And** redirect happens smoothly without errors
### AC #8: Manual Redirect Button
**Given** countdown timer is active
**When** user clicks "Kembali Sekarang" button
**Then** user is immediately redirected to dashboard/home page
**And** countdown is cancelled
### AC #9: Mobile-First Responsive Design
**Given** user accesses payment flow on mobile device
**When** countdown and button are displayed
**Then** all elements are properly sized and positioned for mobile
**And** all text is readable without zooming
**And** button is easily tappable (minimum 44x44px)
### AC #10: Bahasa Indonesia Throughout
**Given** user views success page
**When** text is displayed
**Then** all text is in Bahasa Indonesia
**And** language is appropriate for non-tech-savvy users
**And** no technical jargon is used
---
## Implementation Details
### Tasks / Subtasks
**Phase 1: Create Countdown Component** (~45 minutes)
- [ ] Create `src/components/CountdownRedirect.tsx` (AC: #6, #7, #8)
- [ ] Define component props interface:
- [ ] `seconds: number` - Initial countdown value (default: 5)
- [ ] `onComplete: () => void` - Callback when countdown reaches 0
- [ ] `destination: string` - Display name of redirect destination
- [ ] Implement countdown timer with useEffect
- [ ] Initialize countdown state with `seconds` prop
- [ ] Use setTimeout to decrement every 1000ms
- [ ] Call `onComplete` when countdown reaches 0
- [ ] Clean up timeout on component unmount
- [ ] Implement manual redirect button
- [ ] "Kembali Sekarang" button
- [ ] onClick calls `onComplete` immediately
- [ ] Cancel countdown timer
- [ ] Style with TailwindCSS
- [ ] Mobile-first responsive design
- [ ] Readable text (minimum 16px)
- [ ] Tappable button (minimum 44x44px)
- [ ] Center-aligned layout
- [ ] Add Bahasa Indonesia text
- [ ] "Anda akan diarahkan ke {destination} dalam {countdown} detik..."
- [ ] "Kembali Sekarang" button label
- [ ] Write component tests for CountdownRedirect
- [ ] Test countdown decrements every second (use fake timers)
- [ ] Test onComplete called when countdown reaches 0
- [ ] Test manual redirect button calls onComplete immediately
- [ ] Test cleanup on unmount (no memory leaks)
**Phase 2: Modify Payment Success Page** (~45 minutes)
- [ ] Locate payment success page component (AC: #6, #7, #8, #9, #10)
- [ ] Find payment success/status page file
- [ ] Identify current layout and structure
- [ ] Integrate CountdownRedirect component (AC: #6, #7, #8)
- [ ] Import CountdownRedirect
- [ ] Add to success page layout
- [ ] Configure props:
- [ ] `seconds={5}` - 5-second countdown
- [ ] `onComplete={handleRedirect}` - Navigate to dashboard
- [ ] `destination="dashboard"` - Display name
- [ ] Implement `handleRedirect` function
- [ ] Use `useNavigate()` from react-router-dom
- [ ] Navigate to dashboard/home route
- [ ] Update page layout (AC: #9, #10)
- [ ] Ensure mobile-first responsive design
- [ ] Add success icon/checkmark
- [ ] Add success message in Bahasa Indonesia
- [ ] Position countdown timer prominently
- [ ] Ensure all text is readable on mobile
- [ ] Verify Bahasa Indonesia throughout (AC: #10)
- [ ] Success message: "Pembayaran Berhasil!"
- [ ] Countdown message from component
- [ ] Button label from component
- [ ] No technical jargon anywhere
**Phase 3: Testing & Refinement** (~30 minutes)
- [ ] Manual testing on desktop
- [ ] Test countdown timer accuracy (5, 4, 3, 2, 1, redirect)
- [ ] Test auto-redirect works correctly
- [ ] Test manual "Kembali Sekarang" button works
- [ ] Test countdown cancels when manual button clicked
- [ ] Verify redirect destination is correct
- [ ] Manual testing on mobile devices
- [ ] Test on Chrome Android
- [ ] Test on Safari iOS
- [ ] Verify countdown timer is readable
- [ ] Verify button is easily tappable
- [ ] Verify layout is responsive
- [ ] Verify all text is in Bahasa Indonesia
- [ ] Fix any issues found
- [ ] Code review and cleanup
### Technical Summary
**Approach:**
- Create reusable CountdownRedirect component with countdown timer logic
- Use useEffect with setTimeout for countdown implementation
- Use useNavigate from react-router-dom for programmatic navigation
- Follow existing TailwindCSS design patterns for mobile-first responsive design
- Ensure all text is in Bahasa Indonesia appropriate for non-tech-savvy users
**Key Technical Decisions:**
- **Countdown Duration:** 5 seconds chosen to give users time to read success message while not feeling too long
- **Manual Override:** "Kembali Sekarang" button for impatient users who don't want to wait
- **Cleanup:** Proper useEffect cleanup to prevent memory leaks and errors
- **Destination:** Configurable destination prop for flexibility (dashboard, home, or other)
**Files/Modules Involved:**
- New component: `CountdownRedirect.tsx`
- Modified component: Payment success page (exact path TBD based on codebase exploration)
- Test files for new component
### Project Structure Notes
- **Files to modify:**
- `src/features/payment/pages/PaymentSuccessPage.tsx` (or equivalent - to be confirmed)
- **Files to create:**
- `src/components/CountdownRedirect.tsx`
- `src/components/__tests__/CountdownRedirect.test.tsx`
- **Expected test locations:**
- `src/components/__tests__/` - Component tests
- `src/features/payment/__tests__/` - Integration tests (optional)
- **Estimated effort:** 2 story points (~1 day)
- **Prerequisites:** None - This story is independent of Story 1.1 and can be implemented in parallel
### Key Code References
**From Tech-Spec - Relevant Existing Code:**
- Payment feature module: `src/features/payment/` (assumed based on feature-based architecture)
- Payment success page: `src/features/payment/pages/` or `src/pages/` (to be located)
- React Router integration: Check existing navigation patterns in codebase
- Existing components: `src/components/` (for styling reference)
**Important Functions to Locate:**
1. Payment success page component
2. Current success page layout and messaging
3. Existing navigation patterns (useNavigate usage)
4. Existing TailwindCSS responsive patterns
**Code Patterns to Follow:**
- Functional components with TypeScript interfaces for props
- TailwindCSS utility classes for styling
- Mobile-first responsive design (sm:, md:, lg: breakpoints)
- useNavigate for programmatic navigation
- Proper useEffect cleanup
---
## Context References
**Tech-Spec:** [tech-spec.md](../tech-spec.md) - Primary context document containing:
- Brownfield codebase analysis (React 19, TypeScript, Vite, TailwindCSS stack)
- Framework and library details with exact versions
- Existing patterns to follow (functional components, TailwindCSS, React Router)
- Integration points (React Router navigation)
- Complete implementation guidance with code examples
- Testing strategy and acceptance criteria
- Deployment and rollback plan
**Problem-Solution Analysis:** [problem-solution-2025-11-25.md](../problem-solution-2025-11-25.md) - Root cause analysis identifying post-payment confusion as a key issue
**Architecture:** Feature-based modular architecture with 16 feature modules
<!-- Additional context XML paths will be added here if story-context workflow is run -->
---
## Dev Agent Record
### Agent Model Used
<!-- Will be populated during dev-story execution -->
### Debug Log References
<!-- Will be populated during dev-story execution -->
### Completion Notes
<!-- Will be populated during dev-story execution -->
### Files Modified
<!-- Will be populated during dev-story execution -->
### Test Results
<!-- Will be populated during dev-story execution -->
---
## Review Notes
<!-- Will be populated during code review -->

1378
docs/tech-spec.md Normal file

File diff suppressed because it is too large Load Diff