A mock Payment Gateway built with Next.js App Router and TypeScript that simulates real-world payment processing flows including retries, timeouts, transaction persistence, and idempotency handling.
- Cardholder name input
- Card number formatting (
4242 4242 4242 4242) - Expiry date validation (
MM/YY) - CVV validation
- Amount input with currency selector (
INR,USD) - Real-time validation with field-level errors
- Submit button disabled until form is valid
- Detects:
- Visa
- Mastercard
- American Express
- Dynamic card badge rendering
- CVV length changes based on card type
- Updates in real time while typing
- Displays:
- Cardholder name
- Formatted card number
- Expiry date
Supports complete payment states:
- Idle
- Processing
- Success
- Failed
- Timeout
Server-side randomized responses:
| Outcome | Probability |
|---|---|
| Success | ~60% |
| Failed | ~25% |
| Timeout | ~15% |
Timeout responses simulate delayed network conditions using an 8-second response delay.
Frontend request cancellation using:
AbortController- 6-second client timeout
- Maximum 3 attempts per transaction
- Retry counter shown to user
- Retry disabled after max attempts
- Same transaction ID reused across retries
- Persistent transaction history using
localStorage - Displays:
- Transaction ID
- Amount
- Status
- Timestamp
- Clickable transaction detail view
Transactions use:
crypto.randomUUID()The same transaction ID is reused for retries to avoid duplicate transaction entries.
- Next.js 15 (App Router)
- TypeScript
- Zustand
- Tailwind CSS
- React Hooks
- AbortController API
src/
├── app/
│ ├── api/
│ │ └── pay/
│ └── page.tsx
│
├── components/
│ ├── CardInput.tsx
│ ├── CardPreview.tsx
│ ├── PaymentForm.tsx
│ ├── StatusScreen.tsx
│ └── TransactionHistory.tsx
│
├── hooks/
│ └── usePayment.ts
│
├── store/
│ └── paymentStore.ts
│
├── utils/
│ ├── formatters.ts
│ ├── validators.ts
│ └── cardUtils.ts
│
├── types/
│ └── payment.tsThis project uses Zustand for global state management.
Global state includes:
- Payment status
- Transaction history
- Shared payment lifecycle state
Local component state is used for:
- Form values
- Input focus state
- Field-level validation UI
git clone <your-repository-url>cd SoluLabs-Payments-Gatewaynpm installnpm run devhttp://localhost:3000- Auto-formatted with spaces
- Validates supported card types
- Must follow
MM/YY - Rejects expired dates
- 3 digits for Visa/Mastercard
- 4 digits for American Express
- Must be greater than 0
Implemented accessibility considerations:
- Visible labels for all inputs
aria-describedbyfor validation errors- Keyboard-friendly navigation
- Responsive layouts
- Proper focus handling after payment transitions
The application distinguishes between:
- API failures
- Network failures
- Client-side timeouts
Friendly messages are shown instead of raw errors.
- Transactions are stored only on the frontend using
localStorage - No real payment processing occurs
- Mock gateway behavior is randomized intentionally
- Retry attempts are scoped per transaction ID
- Preventing double submissions
- Request timeout handling
- Idempotent retries
- Persistent transaction tracking
- Clear processing feedback
- Retry attempt limitation
npm run devnpm run buildnpm run startnpm run lintGulam Mohammad Ali
MIT