# core-midtrans-cifo - Technical Specification **Author:** BMad **Date:** 2025-11-25 **Project Level:** Quick-Flow (2 Stories) **Change Type:** UX Enhancement + Bug Fix **Development Context:** Brownfield - Payment Flow Improvements --- ## Context ### Available Documents **Loaded Documents:** - ✅ **Problem-Solution Analysis** (`problem-solution-2025-11-25.md`) - Comprehensive problem analysis by Dr. Quinn identifying 3 interconnected payment flow issues with systematic root cause analysis and 15 evaluated solutions - ✅ **Project Codebase** - Existing React + TypeScript + Midtrans integration **Project Type:** Brownfield - Existing functional payment application **Key Context:** - Target users: Non-tech-savvy customers (ibu-ibu awam) - Platform: Mobile-first web application - Payment Gateway: Midtrans (1 VA per transaction constraint) - Current Issues: Duplicate VA generation, poor post-payment UX, inadequate error handling ### Project Stack **Frontend Stack:** - **React** 19.1.1 - Latest React with modern hooks and concurrent features - **TypeScript** 5.9.3 - Type-safe development - **Vite** 7.1.7 - Fast build tool and dev server - **React Router DOM** 7.9.5 - Client-side routing - **TailwindCSS** 4.1.17 - Utility-first CSS framework - **Framer Motion** 12.23.24 - Animation library - **React Hook Form** 7.66.0 - Form state management - **TanStack React Query** 5.90.7 - Server state management and data fetching - **Axios** 1.13.2 - HTTP client **Backend Stack:** - **Express** 5.1.0 - Node.js web framework - **Midtrans Client** 1.4.3 - Official Midtrans SDK for payment processing - **CORS** 2.8.5 - Cross-origin resource sharing - **dotenv** 17.2.3 - Environment variable management **Development Tools:** - **ESLint** 9.36.0 - Code linting - **Prettier** 3.6.2 - Code formatting - **TypeScript ESLint** 8.45.0 - TypeScript-specific linting rules **Project Type:** Vite + React + TypeScript SPA with Express backend ### Existing Codebase Structure **Directory Organization:** ``` src/ ├── features/ (16 feature modules) - Feature-based architecture ├── pages/ (6 pages) - Route-level components ├── components/ (3 shared components) - Reusable UI components ├── services/ (API services) - Backend communication layer ├── lib/ (utilities) - Helper functions and utilities └── app/ (app config) - Application configuration ``` **Architecture Pattern:** Feature-based modular architecture - Each feature is self-contained with its own components, hooks, and logic - Shared components in `/components` for cross-feature reusability - Centralized API services in `/services` - Utility functions in `/lib` **Styling Approach:** TailwindCSS utility classes - Responsive mobile-first design - Custom design system via `tailwind.config.ts` **State Management:** - React Query for server state - React Hook Form for form state - React hooks (useState, useEffect) for local component state --- ## The Change ### Problem Statement **Core Problem:** Mobile-first payment application untuk non-tech-savvy users (ibu-ibu awam) mengalami critical UX failures dan poor state management yang menyebabkan: 1. **Duplicate VA Generation** - Users click generate VA button multiple times during 3-5 second delay, triggering HTTP 409 errors with technical error messages 2. **Post-Payment Confusion** - After successful payment, users are redirected to status page with no clear next steps, causing them to press back button which triggers invalid transaction states 3. **Poor Error Handling** - HTTP errors (409, 404) displayed as technical messages; invalid states show "Rp 0" instead of helpful recovery options **Business Impact:** - Abandoned transactions → lost revenue - High support ticket volume - User frustration and distrust - Poor mobile UX for primary user demographic **Root Causes Identified:** 1. Lack of defensive UX design patterns (no loading states, no button disable) 2. Poor React lifecycle management (useEffect re-triggering on navigation) 3. Missing error handling framework (no user-friendly messages, no recovery paths) ### Proposed Solution **Phase 1: Quick Wins Bundle** - Implement 5 high-impact, low-risk solutions organized into 2 user stories: **Story 1: Prevent Duplicate VA Generation & Improve Feedback** - Solution #1: Button State Management - Disable button during processing - Solution #2: Request Debouncing - 500ms debounce on VA generation - Solution #3: User-Friendly Error Messages - Map HTTP codes to bahasa Indonesia - Solution #4: Loading Overlay - Full-screen overlay with clear messaging **Story 2: Improve Post-Payment UX** - Solution #5: Auto-Redirect After Success - 5-second countdown with clear CTA **Expected Impact:** Solves 70-80% of payment flow issues with minimal risk ### Scope **In Scope:** ✅ **Story 1: Prevent Duplicate VA Generation & Improve Feedback** 1. Implement button disable/enable logic on VA generation button 2. Add loading spinner to button during processing 3. Implement 500ms debounce on VA generation function 4. Create full-screen loading overlay component 5. Map HTTP 409 → "Kode pembayaran Anda sudah dibuat! Klik di sini untuk melihat" 6. Map HTTP 404 → "Terjadi kesalahan. Silakan coba lagi" 7. Add "Coba Lagi" recovery button on error states 8. Add "Lihat Kode Pembayaran" button on 409 errors ✅ **Story 2: Improve Post-Payment UX** 1. Implement 5-second countdown timer on payment success page 2. Add "Anda akan diarahkan ke dashboard dalam X detik..." message 3. Add "Kembali Sekarang" button for impatient users 4. Implement auto-redirect logic to dashboard/home after countdown ✅ **Cross-Story Requirements** 1. Mobile-first responsive design (primary focus) 2. Bahasa Indonesia for all user-facing text 3. Consistent with existing TailwindCSS design system 4. Accessible (keyboard navigation, screen reader friendly) **Out of Scope:** ❌ **Phase 2 Solutions** (future work): - 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 --- ## Implementation Details ### Source Tree Changes **Files to CREATE:** 1. **`src/components/LoadingOverlay.tsx`** - NEW - Full-screen loading overlay component - Props: `isLoading: boolean`, `message: string` - Semi-transparent backdrop with centered spinner and message 2. **`src/components/CountdownRedirect.tsx`** - NEW - Countdown timer component for auto-redirect - Props: `seconds: number`, `onComplete: () => void`, `destination: string` - Display countdown with "Kembali Sekarang" button 3. **`src/lib/errorMessages.ts`** - NEW - Error message mapping utility - Function: `mapErrorToUserMessage(error: AxiosError): string` - Maps HTTP status codes to user-friendly Indonesian messages 4. **`src/lib/debounce.ts`** - NEW - Debounce utility function - Function: `debounce(func: T, delay: number): T` - Generic debounce implementation for click handlers **Files to MODIFY:** 1. **`src/features/payment/components/PaymentMethodSelector.tsx`** (or equivalent) - ADD: Button disable logic (disabled state during VA generation) - ADD: Loading spinner on button - ADD: Debounce wrapper on generateVA handler - ADD: LoadingOverlay integration - MODIFY: Error handling to use mapErrorToUserMessage 2. **`src/features/payment/pages/PaymentSuccessPage.tsx`** (or equivalent) - ADD: CountdownRedirect component - ADD: Auto-redirect logic after 5 seconds - MODIFY: Layout to include countdown timer and CTA button 3. **`src/features/payment/hooks/useGenerateVA.ts`** (or create if doesn't exist) - ADD: Loading state management - ADD: Error state with user-friendly messages - ADD: Button disable logic - MODIFY: Error handling to use mapErrorToUserMessage **Files to ADD TESTS:** 1. **`src/components/__tests__/LoadingOverlay.test.tsx`** - CREATE 2. **`src/components/__tests__/CountdownRedirect.test.tsx`** - CREATE 3. **`src/lib/__tests__/errorMessages.test.ts`** - CREATE 4. **`src/lib/__tests__/debounce.test.ts`** - CREATE ### Technical Approach **1. Button State Management (Solution #1)** **Approach:** Use React state to track loading status and disable button during API call ```typescript const [isGenerating, setIsGenerating] = useState(false); const handleGenerateVA = async () => { setIsGenerating(true); try { await generateVAAPI(); } finally { setIsGenerating(false); } }; ``` **Why:** Simple, effective, uses existing React patterns --- **2. Request Debouncing (Solution #2)** **Approach:** Wrap VA generation handler with debounce utility (500ms delay) ```typescript import { debounce } from '@/lib/debounce'; const debouncedGenerateVA = useMemo( () => debounce(handleGenerateVA, 500), [] ); ``` **Why:** Prevents rapid successive clicks, complements button disable --- **3. User-Friendly Error Messages (Solution #3)** **Approach:** Create error mapping utility that translates HTTP codes to Indonesian ```typescript // src/lib/errorMessages.ts export const mapErrorToUserMessage = (error: AxiosError): string => { if (error.response?.status === 409) { return "Kode pembayaran Anda sudah dibuat! Klik di sini untuk melihat"; } if (error.response?.status === 404) { return "Terjadi kesalahan. Silakan coba lagi"; } return "Terjadi kesalahan. Silakan coba lagi"; }; ``` **Why:** Centralized error handling, easy to maintain and extend --- **4. Loading Overlay (Solution #4)** **Approach:** Create reusable LoadingOverlay component with Framer Motion animations ```typescript // src/components/LoadingOverlay.tsx export const LoadingOverlay = ({ isLoading, message }) => { if (!isLoading) return null; return (

{message}

); }; ``` **Why:** Prevents interaction during processing, clear visual feedback --- **5. Auto-Redirect After Success (Solution #5)** **Approach:** Use countdown timer with useEffect and setTimeout ```typescript // src/components/CountdownRedirect.tsx export const CountdownRedirect = ({ seconds, onComplete, destination }) => { const [countdown, setCountdown] = useState(seconds); useEffect(() => { if (countdown === 0) { onComplete(); return; } const timer = setTimeout(() => { setCountdown(c => c - 1); }, 1000); return () => clearTimeout(timer); }, [countdown, onComplete]); return (

Anda akan diarahkan ke {destination} dalam {countdown} detik...

); }; ``` **Why:** Clear user guidance, option for impatient users, prevents back button confusion ### Existing Patterns to Follow **React Patterns:** - Functional components with hooks (no class components) - Custom hooks for reusable logic (e.g., `useGenerateVA`) - TypeScript for type safety - Props interfaces defined with `interface` keyword **Styling Patterns:** - TailwindCSS utility classes - Responsive design with mobile-first breakpoints (`sm:`, `md:`, `lg:`) - Custom colors and spacing from `tailwind.config.ts` - Framer Motion for animations (already in use) **State Management Patterns:** - React Query for API calls and server state - React Hook Form for form state - Local useState for component-specific state **Error Handling Patterns:** - Try-catch blocks for async operations - Error states in components - User-friendly error messages (to be improved by this change) **File Naming Conventions:** - PascalCase for components: `LoadingOverlay.tsx` - camelCase for utilities: `errorMessages.ts` - Test files: `ComponentName.test.tsx` ### Integration Points **1. Midtrans API Integration** - **Location:** `src/services/midtrans.ts` (or similar) - **Integration:** VA generation API call - **Changes:** Wrap with loading state, error handling, debounce **2. React Query Integration** - **Usage:** Manage VA generation API state - **Pattern:** Use `useMutation` for VA generation - **Changes:** Add onMutate (loading), onError (error messages), onSuccess (redirect) **3. React Router Integration** - **Usage:** Navigate to success page, auto-redirect after payment - **Pattern:** Use `useNavigate` hook - **Changes:** Implement programmatic navigation in CountdownRedirect **4. TailwindCSS Design System** - **Integration:** All new components use Tailwind classes - **Consistency:** Match existing color scheme, spacing, typography - **Responsive:** Mobile-first breakpoints **5. Framer Motion Animations** - **Usage:** LoadingOverlay fade-in animation - **Pattern:** `motion.div` with initial/animate props - **Consistency:** Match existing animation timing and easing --- ## Development Context ### Relevant Existing Code **Payment Feature Module:** - **Location:** `src/features/payment/` (assumed based on feature-based architecture) - **Components:** PaymentMethodSelector, PaymentSuccessPage (names may vary) - **Hooks:** Likely has custom hooks for payment logic - **Services:** API calls to Midtrans via backend **Reference Patterns:** - Check existing components in `src/components/` for styling patterns - Review existing API calls in `src/services/` for error handling patterns - Look at existing hooks for state management patterns **Key Files to Review Before Implementation:** 1. Payment method selection component (where VA generation button lives) 2. Payment success/status page component 3. Existing API service layer for Midtrans calls 4. Existing error handling utilities (if any) ### Dependencies **Framework/Libraries:** **Production Dependencies (Already Installed):** - `react@19.1.1` - Core React library - `react-dom@19.1.1` - React DOM rendering - `react-router-dom@7.9.5` - Routing - `@tanstack/react-query@5.90.7` - Server state management - `axios@1.13.2` - HTTP client - `framer-motion@12.23.24` - Animations - `tailwindcss@4.1.17` - Styling - `clsx@2.1.1` - Conditional class names - `tailwind-merge@3.3.1` - Merge Tailwind classes **Development Dependencies (Already Installed):** - `typescript@5.9.3` - TypeScript compiler - `vite@7.1.7` - Build tool - `eslint@9.36.0` - Linting - `prettier@3.6.2` - Code formatting **No New Dependencies Required** - All solutions use existing stack ### Internal Modules **Modules to Create:** - `@/components/LoadingOverlay` - Loading overlay component - `@/components/CountdownRedirect` - Countdown redirect component - `@/lib/errorMessages` - Error message mapping utility - `@/lib/debounce` - Debounce utility function **Modules to Import:** - `@/services/midtrans` (or equivalent) - Midtrans API service - `react-router-dom` - useNavigate hook - `@tanstack/react-query` - useMutation hook - `framer-motion` - motion components - `clsx` or `tailwind-merge` - Conditional styling ### Configuration Changes **No Configuration Changes Required** All solutions work within existing configuration: - ✅ No new environment variables - ✅ No Vite config changes - ✅ No TailwindCSS config changes - ✅ No ESLint/Prettier config changes - ✅ No package.json changes (no new dependencies) ### Existing Conventions (Brownfield) **Code Style:** - **TypeScript:** Strict mode enabled - **Quotes:** Single quotes (based on Prettier config) - **Semicolons:** Yes (TypeScript default) - **Indentation:** 2 spaces - **Line Length:** 80-100 characters (Prettier default) **Component Patterns:** - Functional components with TypeScript interfaces for props - Named exports preferred - Props interface named `ComponentNameProps` **Import Organization:** - React imports first - Third-party libraries second - Internal imports last - Absolute imports using `@/` alias **Error Handling:** - Try-catch for async operations - Error boundaries for component errors (if implemented) - User-friendly error messages (to be improved) **Testing:** - Test files co-located with components in `__tests__/` folder - File naming: `ComponentName.test.tsx` - Framework: Likely Vitest (Vite's test framework) or Jest ### Test Framework & Standards **Test Framework:** Vitest (recommended for Vite projects) or Jest **Test File Patterns:** - Location: `src/components/__tests__/` or `src/lib/__tests__/` - Naming: `ComponentName.test.tsx` or `utilityName.test.ts` - Structure: Describe blocks for component/function, it blocks for test cases **Testing Strategy:** - Unit tests for utilities (`debounce`, `errorMessages`) - Component tests for UI components (`LoadingOverlay`, `CountdownRedirect`) - Integration tests for payment flow (optional, recommended) **Coverage Requirements:** - Aim for 80%+ coverage on new code - All utility functions must have tests - All new components must have basic render tests --- ## Implementation Stack **Runtime Environment:** - Node.js 20.x (recommended for Express 5.x) - Browser: Modern browsers with ES2020+ support **Frontend Stack:** - React 19.1.1 - TypeScript 5.9.3 - Vite 7.1.7 - TailwindCSS 4.1.17 - Framer Motion 12.23.24 - React Router DOM 7.9.5 - TanStack React Query 5.90.7 - Axios 1.13.2 **Backend Stack:** - Express 5.1.0 - Midtrans Client 1.4.3 **Development Tools:** - ESLint 9.36.0 - Prettier 3.6.2 - TypeScript ESLint 8.45.0 **Testing:** - Vitest (recommended) or Jest - React Testing Library (for component tests) --- ## Technical Details ### Story 1: Prevent Duplicate VA Generation & Improve Feedback **Technical Implementation Details:** **1. Button Disable Logic** - State variable: `isGenerating: boolean` - Set to `true` on button click, `false` on API response (success or error) - Button `disabled` attribute bound to `isGenerating` - Visual feedback: Show spinner when `isGenerating === true` **2. Debounce Implementation** - Debounce delay: 500ms - Implementation: Custom debounce utility using setTimeout - Applied to: VA generation click handler - Edge case: Clear timeout on component unmount **3. Error Message Mapping** - HTTP 409 → "Kode pembayaran Anda sudah dibuat! Klik di sini untuk melihat" - HTTP 404 → "Terjadi kesalahan. Silakan coba lagi" - HTTP 500 → "Terjadi kesalahan server. Silakan coba lagi nanti" - Network error → "Tidak dapat terhubung ke server. Periksa koneksi internet Anda" - Default → "Terjadi kesalahan. Silakan coba lagi" **4. Loading Overlay** - Z-index: 50 (above all content) - Backdrop: Semi-transparent black (`bg-black/50`) - Content: White card with spinner and message - Animation: Fade in (200ms) using Framer Motion - Message: "Sedang membuat kode pembayaran..." - Accessibility: Focus trap, ESC key to cancel (optional) **5. Recovery Buttons** - "Coba Lagi" button on all errors → Retry VA generation - "Lihat Kode Pembayaran" button on 409 error → Navigate to existing VA view - "Kembali" button on errors → Navigate back to payment method selection ### Story 2: Improve Post-Payment UX **Technical Implementation Details:** **1. Countdown Timer** - Initial value: 5 seconds - Update interval: 1 second (1000ms) - Implementation: useEffect with setTimeout - Cleanup: Clear timeout on unmount - Display format: "Anda akan diarahkan ke dashboard dalam {X} detik..." **2. Auto-Redirect** - Trigger: When countdown reaches 0 - Destination: Dashboard or home page (configurable) - Method: `useNavigate()` from react-router-dom - Fallback: Manual "Kembali Sekarang" button **3. Manual Redirect Button** - Label: "Kembali Sekarang" - Action: Immediately navigate to destination (skip countdown) - Styling: Primary button style (prominent, easy to find) - Position: Below countdown message **Performance Considerations:** - Debounce prevents excessive API calls - Loading overlay prevents UI interaction during processing - Countdown timer uses single setTimeout (not setInterval) for better performance **Security Considerations:** - No sensitive data in error messages - Error messages don't reveal system internals - Rate limiting handled by backend (out of scope) **Accessibility Considerations:** - Loading overlay has proper ARIA labels - Countdown timer announced by screen readers - Buttons have clear labels and keyboard navigation - Focus management during loading states --- ## Development Setup **Prerequisites:** - Node.js 20.x installed - npm or yarn package manager - Git for version control **Initial Setup (if not already done):** ```bash # 1. Clone repository (if not already cloned) git clone cd core-midtrans-cifo # 2. Install dependencies npm install # 3. Set up environment variables cp .env.example .env # Edit .env with your Midtrans credentials # 4. Start development server npm run dev # 5. Start backend server (in separate terminal) npm run server ``` **Development Workflow:** ```bash # Start Vite dev server (frontend) npm run dev # Access at http://localhost:5173 # Start Express server (backend) npm run server # Access at http://localhost:3000 (or configured port) # Run linter npm run lint # Run tests (when implemented) npm test # Build for production npm run build # Preview production build npm run preview ``` **Environment Variables Required:** - `VITE_MIDTRANS_CLIENT_KEY` - Midtrans client key - `MIDTRANS_SERVER_KEY` - Midtrans server key (backend) - `MIDTRANS_IS_PRODUCTION` - true/false for sandbox vs production --- ## Implementation Guide ### Setup Steps **Pre-Implementation Checklist:** 1. ✅ Create feature branch ```bash git checkout -b feature/payment-ux-improvements ``` 2. ✅ Verify development environment running - Frontend dev server: `npm run dev` - Backend server: `npm run server` - Both running without errors 3. ✅ Review existing payment flow code - Locate payment method selection component - Locate payment success page component - Locate Midtrans API service layer - Understand current error handling 4. ✅ Set up test environment (if not already) - Install Vitest or Jest - Configure test runner - Create test file structure ### Implementation Steps **Story 1: Prevent Duplicate VA Generation & Improve Feedback** **Phase 1: Create Utility Functions (30 minutes)** 1. Create `src/lib/debounce.ts` - Implement generic debounce function - Add TypeScript types - Write unit tests 2. Create `src/lib/errorMessages.ts` - Implement error mapping function - Map all HTTP status codes - Add recovery action suggestions - Write unit tests **Phase 2: Create UI Components (1 hour)** 3. Create `src/components/LoadingOverlay.tsx` - Implement overlay with backdrop - Add Framer Motion animations - Add spinner and message - Make responsive for mobile - Write component tests **Phase 3: Modify Payment Method Component (1.5 hours)** 4. Locate and modify payment method selection component - Add `isGenerating` state - Wrap VA generation handler with debounce - Add button disable logic - Add loading spinner to button - Integrate LoadingOverlay - Update error handling to use `mapErrorToUserMessage` - Add recovery buttons based on error type **Phase 4: Testing & Refinement (1 hour)** 5. Manual testing - Test duplicate click prevention - Test loading overlay display - Test error messages for different error types - Test recovery buttons - Test on mobile devices 6. Fix any issues found during testing **Story 2: Improve Post-Payment UX** **Phase 1: Create Countdown Component (45 minutes)** 1. Create `src/components/CountdownRedirect.tsx` - Implement countdown timer with useEffect - Add auto-redirect logic - Add manual redirect button - Make responsive for mobile - Write component tests **Phase 2: Modify Payment Success Page (45 minutes)** 2. Locate and modify payment success page component - Integrate CountdownRedirect component - Configure redirect destination - Update layout for mobile-first - Add clear success messaging **Phase 3: Testing & Refinement (30 minutes)** 3. Manual testing - Test countdown timer accuracy - Test auto-redirect functionality - Test manual redirect button - Test on mobile devices - Verify no back button issues 4. Fix any issues found during testing ### Testing Strategy **Unit Tests:** 1. **`debounce.test.ts`** - Test debounce delays function execution - Test multiple rapid calls only execute once - Test cleanup on unmount 2. **`errorMessages.test.ts`** - Test HTTP 409 maps to correct message - Test HTTP 404 maps to correct message - Test default error message - Test network error message **Component Tests:** 3. **`LoadingOverlay.test.tsx`** - Test renders when isLoading=true - Test doesn't render when isLoading=false - Test displays correct message - Test animation 4. **`CountdownRedirect.test.tsx`** - Test countdown decrements every second - Test onComplete called when countdown reaches 0 - Test manual redirect button works - Test cleanup on unmount **Integration Tests (Recommended):** 5. **Payment Flow Integration Test** - Test full VA generation flow with loading states - Test error handling and recovery - Test success flow with auto-redirect **Manual Testing Checklist:** - [ ] Click VA generation button multiple times rapidly → Only one request sent - [ ] Loading overlay appears during VA generation - [ ] Error 409 shows user-friendly message with "Lihat Kode" button - [ ] Error 404 shows user-friendly message with "Coba Lagi" button - [ ] Payment success page shows countdown timer - [ ] Auto-redirect works after 5 seconds - [ ] Manual "Kembali Sekarang" button works immediately - [ ] All flows work on mobile devices (Chrome, Safari) - [ ] All text is in Bahasa Indonesia - [ ] Keyboard navigation works - [ ] Screen reader announces loading states and countdown ### Acceptance Criteria **Story 1: Prevent Duplicate VA Generation & Improve Feedback** **AC1: 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..." **AC2: 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 **AC3: 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 **AC4: 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 **AC5: 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 **Story 2: Improve Post-Payment UX** **AC6: 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 **AC7: 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 **AC8: 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 **AC9: Mobile-First Responsive Design** - GIVEN user accesses payment flow on mobile device - WHEN any new UI element is displayed - THEN all elements are properly sized and positioned for mobile - AND all text is readable without zooming - AND all buttons are easily tappable (minimum 44x44px) **AC10: Bahasa Indonesia Throughout** - GIVEN user interacts with any new UI element - WHEN text is displayed - THEN all text is in Bahasa Indonesia - AND language is appropriate for non-tech-savvy users (ibu-ibu awam) - AND no technical jargon is used --- ## Developer Resources ### File Paths Reference **New Files to Create:** - `src/components/LoadingOverlay.tsx` - `src/components/CountdownRedirect.tsx` - `src/lib/errorMessages.ts` - `src/lib/debounce.ts` - `src/components/__tests__/LoadingOverlay.test.tsx` - `src/components/__tests__/CountdownRedirect.test.tsx` - `src/lib/__tests__/errorMessages.test.ts` - `src/lib/__tests__/debounce.test.ts` **Existing Files to Modify:** - `src/features/payment/components/PaymentMethodSelector.tsx` (or equivalent) - `src/features/payment/pages/PaymentSuccessPage.tsx` (or equivalent) - `src/features/payment/hooks/useGenerateVA.ts` (or create if doesn't exist) **Configuration Files (No Changes):** - `package.json` - No new dependencies - `vite.config.ts` - No changes - `tailwind.config.ts` - No changes - `tsconfig.json` - No changes ### Key Code Locations **Payment Feature Module:** - **Location:** `src/features/payment/` (assumed) - **Key Components:** - Payment method selection component (contains VA generation button) - Payment success/status page component - **Key Hooks:** - VA generation hook (may need to create) - **Key Services:** - Midtrans API service (`src/services/midtrans.ts` or similar) **Shared Components:** - **Location:** `src/components/` - **New Components:** - LoadingOverlay - CountdownRedirect **Utilities:** - **Location:** `src/lib/` - **New Utilities:** - errorMessages - debounce **Important Functions to Locate:** 1. VA generation API call function 2. Payment success navigation logic 3. Error handling in payment flow 4. Existing loading state management (if any) ### Testing Locations **Unit Tests:** - `src/lib/__tests__/` - Utility function tests - `debounce.test.ts` - `errorMessages.test.ts` **Component Tests:** - `src/components/__tests__/` - Component tests - `LoadingOverlay.test.tsx` - `CountdownRedirect.test.tsx` **Integration Tests (Recommended):** - `src/features/payment/__tests__/` - Payment flow integration tests - `PaymentFlow.integration.test.tsx` **Test Configuration:** - `vitest.config.ts` or `jest.config.js` (if exists) - Test setup file (if exists) ### Documentation to Update **Code Documentation:** - [ ] Add JSDoc comments to all new functions and components - [ ] Add inline comments for complex logic (debounce, countdown timer) - [ ] Add TypeScript interfaces with descriptions **Project Documentation:** - [ ] Update `README.md` with new features (optional) - [ ] Update API documentation if error responses changed (unlikely) - [ ] Add this tech-spec to `docs/` folder for future reference **User Documentation (Optional):** - [ ] Update user guide with new payment flow behavior - [ ] Update FAQ with error message explanations - [ ] Create internal documentation for support team --- ## UX/UI Considerations **UI Components Affected:** **Story 1:** 1. **VA Generation Button** - MODIFY: Add disabled state styling - MODIFY: Add loading spinner - ENSURE: Button remains accessible (keyboard, screen reader) 2. **Loading Overlay** (NEW) - CREATE: Full-screen overlay component - DESIGN: Semi-transparent backdrop, centered content - ANIMATION: Fade in/out with Framer Motion - MOBILE: Full viewport coverage, readable text 3. **Error Display** (MODIFY) - MODIFY: Replace technical errors with user-friendly messages - ADD: Recovery action buttons - DESIGN: Clear, non-threatening, helpful tone **Story 2:** 1. **Payment Success Page** - ADD: Countdown timer component - ADD: Manual redirect button - MODIFY: Layout to accommodate new elements - MOBILE: Ensure all elements visible without scrolling **UX Flow Changes:** **Current Flow:** 1. User selects payment method 2. User clicks "Generate VA" 3. (3-5 second delay with no feedback) 4. VA displayed OR error shown 5. After payment: Success page with no clear next step 6. User presses back → Invalid state **New Flow:** 1. User selects payment method 2. User clicks "Generate VA" 3. **Button disables, loading overlay appears** 4. **"Sedang membuat kode pembayaran..." message shown** 5. VA displayed OR **user-friendly error with recovery options** 6. After payment: Success page with **countdown timer** 7. **Auto-redirect after 5 seconds** OR **user clicks "Kembali Sekarang"** 8. User lands on dashboard (no back button confusion) **Visual/Interaction Patterns:** **Loading States:** - Spinner: Use existing spinner component or create simple CSS spinner - Color: Match primary brand color - Size: Appropriate for mobile (not too small) - Animation: Smooth, not distracting **Error States:** - Color: Warning yellow or soft red (not harsh) - Icon: Information icon (not scary error icon) - Tone: Helpful, not blaming user - Actions: Clear buttons with action verbs **Success States:** - Color: Success green - Icon: Checkmark - Tone: Positive, reassuring - Actions: Clear next step **Responsive Design:** - Mobile-first: Design for 320px width minimum - Breakpoints: Use TailwindCSS defaults (sm: 640px, md: 768px, lg: 1024px) - Touch targets: Minimum 44x44px for buttons - Text size: Minimum 16px for body text (prevents zoom on iOS) **Accessibility:** **Keyboard Navigation:** - All interactive elements focusable - Logical tab order - Visible focus indicators - ESC key to dismiss overlay (optional) **Screen Reader:** - ARIA labels for loading states - ARIA live regions for countdown timer - Descriptive button labels - Alt text for icons **Color Contrast:** - WCAG AA compliance minimum - Text on overlay readable - Error messages high contrast **User Feedback:** **Loading Feedback:** - Visual: Spinner + overlay - Text: Clear message in Bahasa Indonesia - Duration: Show immediately, hide on response **Error Feedback:** - Visual: Error message + icon - Text: User-friendly explanation + recovery action - Persistence: Stay until user takes action **Success Feedback:** - Visual: Success message + checkmark - Text: Countdown timer with destination - Action: Auto-redirect + manual option --- ## Testing Approach **Test Framework:** Vitest (recommended for Vite) or Jest **Testing Pyramid:** - 70% Unit Tests (utilities, hooks) - 20% Component Tests (UI components) - 10% Integration Tests (full flows) **Unit Tests:** 1. **`debounce.test.ts`** ```typescript describe('debounce', () => { it('delays function execution', () => { // Test implementation }); it('only executes once for multiple rapid calls', () => { // Test implementation }); it('clears timeout on cleanup', () => { // Test implementation }); }); ``` 2. **`errorMessages.test.ts`** ```typescript describe('mapErrorToUserMessage', () => { it('maps HTTP 409 to user-friendly message', () => { // Test implementation }); it('maps HTTP 404 to user-friendly message', () => { // Test implementation }); it('returns default message for unknown errors', () => { // Test implementation }); }); ``` **Component Tests:** 3. **`LoadingOverlay.test.tsx`** ```typescript describe('LoadingOverlay', () => { it('renders when isLoading is true', () => { // Test implementation }); it('does not render when isLoading is false', () => { // Test implementation }); it('displays the provided message', () => { // Test implementation }); }); ``` 4. **`CountdownRedirect.test.tsx`** ```typescript describe('CountdownRedirect', () => { it('decrements countdown every second', () => { // Test implementation with fake timers }); it('calls onComplete when countdown reaches 0', () => { // Test implementation }); it('redirects immediately when button clicked', () => { // Test implementation }); }); ``` **Integration Tests (Recommended):** 5. **Payment Flow Integration Test** ```typescript describe('Payment Flow', () => { it('prevents duplicate VA generation', () => { // Test full flow with multiple clicks }); it('shows user-friendly error on 409', () => { // Test error handling }); it('auto-redirects after payment success', () => { // Test success flow }); }); ``` **Coverage Goals:** - Overall: 80%+ - New utilities: 100% - New components: 90%+ - Modified components: 80%+ **Manual Testing Checklist:** - [ ] Desktop Chrome - [ ] Desktop Firefox - [ ] Desktop Safari - [ ] Mobile Chrome (Android) - [ ] Mobile Safari (iOS) - [ ] Tablet (iPad) - [ ] Slow 3G network simulation - [ ] Offline scenario - [ ] Keyboard-only navigation - [ ] Screen reader (NVDA/JAWS/VoiceOver) --- ## Deployment Strategy ### Deployment Steps **Pre-Deployment:** 1. **Code Review** - Create pull request from feature branch - Request review from team lead - Address all review comments - Ensure all tests pass 2. **QA Testing** - Deploy to staging environment - QA team tests all acceptance criteria - Fix any bugs found - Re-test until all criteria pass 3. **Merge to Main** ```bash git checkout main git merge feature/payment-ux-improvements git push origin main ``` **Deployment to Production:** 4. **Build Production Bundle** ```bash npm run build ``` 5. **Deploy Frontend** - Upload `dist/` folder to hosting (Vercel, Netlify, or custom server) - Verify environment variables are set - Test production build locally with `npm run preview` 6. **Deploy Backend (if changes)** - No backend changes in Phase 1 - Backend deployment not required 7. **Verify Deployment** - Test VA generation on production - Test error scenarios - Test payment success flow - Monitor for errors **Post-Deployment:** 8. **Monitor** - Watch error logs for 24 hours - Monitor user behavior analytics - Check support ticket volume - Gather user feedback 9. **Iterate** - Address any issues found - Plan Phase 2 improvements based on data ### Rollback Plan **If Critical Issues Found:** 1. **Immediate Rollback** ```bash # Revert to previous commit git revert HEAD git push origin main # Rebuild and redeploy npm run build # Deploy dist/ folder ``` 2. **Verify Rollback** - Test that old behavior is restored - Confirm no errors in logs - Notify users if necessary 3. **Post-Mortem** - Identify what went wrong - Fix issues in feature branch - Re-test thoroughly - Re-deploy when ready **Rollback Triggers:** - Critical bug preventing payments - Widespread errors (>5% of transactions) - Security vulnerability discovered - Performance degradation (>2s load time increase) ### Monitoring **Metrics to Monitor:** **User Behavior:** - VA generation success rate (target: >95%) - Error rate (target: <5%) - Payment completion rate (target: increase by 10%+) - Time on payment success page (target: decrease by 50%) - Back button usage after payment (target: decrease by 80%) **Technical Metrics:** - API response time (target: <3 seconds) - Frontend load time (target: <2 seconds) - Error logs (target: <1% error rate) - 409 error frequency (target: near zero) **Business Metrics:** - Abandoned transaction rate (target: decrease by 20%+) - Support ticket volume (target: decrease by 30%+) - User satisfaction score (target: increase) **Monitoring Tools:** - Google Analytics for user behavior - Sentry or similar for error tracking - Server logs for API monitoring - User feedback surveys **Alert Thresholds:** - Error rate >10% → Immediate alert - API response time >5s → Warning alert - Payment success rate <90% → Critical alert --- **End of Technical Specification** This tech-spec provides a comprehensive guide for implementing Phase 1 Quick Wins Bundle (2 stories, 5 solutions) to improve payment flow UX for non-tech-savvy users in a brownfield Midtrans payment application.