Skip to content

Commit ddff1d3

Browse files
authored
feat: spa-manual-payment example (#422)
* feat: add a very simple manual payment workflow * feat: rewrite readme * feat: declutter App.tsx * feat: update readme tree * feat: add more setup instructions to the readme
1 parent 8231a6b commit ddff1d3

27 files changed

+3153
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
pnpm-debug.log*
8+
lerna-debug.log*
9+
10+
node_modules
11+
dist
12+
dist-ssr
13+
*.local
14+
15+
# Editor directories and files
16+
.vscode/*
17+
!.vscode/extensions.json
18+
.idea
19+
.DS_Store
20+
*.suo
21+
*.ntvs*
22+
*.njsproj
23+
*.sln
24+
*.sw?
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# Manual Payment Processing SPA Example
2+
3+
This example showcases how to implement **manual payment gateway processing** with **Elastic Path Commerce Cloud** in a Single-Page Application (SPA) written in React. It builds on the `spa-guest-checkout` example, although omits a number of its features.
4+
5+
> **Heads-up:** This project focuses **exclusively** on manual payment processing workflows. It creates minimal test orders solely to demonstrate payment handling—cart management, product catalogs, customer accounts, etc. are kept deliberately simple and are not the focus.
6+
7+
Key capabilities demonstrated:
8+
9+
1. **Test Order Creation** – automatically creates incomplete orders with test products for payment processing demonstration.
10+
2. **Manual Payment Gateway** – processes payments using Elastic Path's manual payment gateway for scenarios like:
11+
• Bank transfers
12+
• Cash payments
13+
• Check payments
14+
• Custom payment workflows
15+
3. **Order State Management** – converts incomplete orders to complete orders after manual payment recording.
16+
4. **Payment Status Tracking** – displays real-time order and payment status updates with proper UI indicators.
17+
18+
> The example purposefully uses simplified order creation and minimal product selection to keep the focus on manual payment mechanics.
19+
20+
---
21+
22+
## Project Structure
23+
24+
```
25+
spa-manual-payments/
26+
├── index.html # Vite entry point
27+
├── src/
28+
│ ├── App.tsx # Main app orchestration & state management
29+
│ ├── components/
30+
│ │ ├── AppHeader.tsx # Authentication status & cart ID display
31+
│ │ ├── StepIndicator.tsx # Multi-step progress indicator
32+
│ │ ├── OrderCreator.tsx # Creates test orders for payment demo
33+
│ │ ├── ManualPayment.tsx # Manual payment processing form
34+
│ │ ├── OrderStatus.tsx # Order & payment status display
35+
│ │ └── OrderCompleteView.tsx # Success screen with reset functionality
36+
│ ├── hooks/
37+
│ │ ├── useAppInitialization.ts # App startup & authentication logic
38+
│ │ └── useOrderCreation.ts # Order creation workflow & state
39+
│ └── auth/
40+
│ ├── CartProvider.tsx # Basic cart initialization
41+
│ └── StorefrontProvider.tsx # Elastic Path client setup
42+
└── README.md # ← you are here
43+
```
44+
45+
---
46+
47+
## Store Setup Requirements
48+
49+
To use this example, your **Elastic Path Commerce Cloud store** must be properly configured:
50+
51+
### 🔌 **Payment Gateway Configuration**
52+
53+
1. **Enable Manual Gateway** in Commerce Manager:
54+
55+
- Go to **Settings****Payments**
56+
- Configure **Manual** gateway
57+
- Enable the gateway
58+
59+
### 📦 **Product Setup**
60+
61+
Your store needs products in a published catalog for the payment demo to work. Learn more about how to publish a catalog [in the docs](https://elasticpath.dev/docs/commerce-manager/product-experience-manager/catalogs/catalog-configuration):
62+
63+
1. **Product Requirements**:
64+
65+
- Add at least one **simple product** (not a base product requiring variations)
66+
- Products should have **prices** associated with them
67+
- Products must be **active** and included in the published catalog
68+
69+
2. **Inventory Configuration** (Optional):
70+
- If using inventory management, ensure products have **stock levels** configured
71+
72+
### 🔑 **API Access Setup**
73+
74+
1. **Client Credentials**:
75+
76+
- Go to **Settings****API Keys** and create a new application key
77+
- Note your **Client ID** and **Store URL** and use them in your .env
78+
79+
### 🚨 **Common Setup Issues**
80+
81+
**"No products available" Error**:
82+
83+
- **Cause**: No products in published catalog, catalog not published, or all products are base products
84+
- **Solution**: Create and publish a catalog with at least one simple product
85+
86+
**404 Inventory Errors**:
87+
88+
- **Cause**: Product inventory not configured
89+
- **Solution**: Either configure inventory or ignore (example handles gracefully)
90+
91+
---
92+
93+
## How It Works
94+
95+
### 1. Test Order Creation
96+
97+
`OrderCreator` automatically creates a test scenario:
98+
99+
```tsx
100+
// Creates cart → adds test product → checkout → incomplete order
101+
const createIncompleteOrder = async () => {
102+
const products = await getByContextAllProducts()
103+
const selectedProduct = products.data.find(/* stock logic */)
104+
// ... cart creation, checkout, order creation
105+
}
106+
```
107+
108+
This generates an incomplete order ready for manual payment processing.
109+
110+
### 2. Manual Payment Processing
111+
112+
`ManualPayment` captures payment details and processes them:
113+
114+
```tsx
115+
const paymentData = {
116+
gateway: "manual",
117+
method: "purchase",
118+
// if the user supplies a reference
119+
paymentmethod_meta: {
120+
custom_reference: paymentReference,
121+
name: "Manual Payment",
122+
},
123+
}
124+
125+
await paymentSetup({
126+
path: { orderID: order.id },
127+
body: { data: paymentData },
128+
})
129+
```
130+
131+
### 3. Status Display
132+
133+
`OrderStatus` shows order and payment status.
134+
135+
---
136+
137+
## Running the Example Locally
138+
139+
1. **Install deps** (from the repo root):
140+
141+
```bash
142+
pnpm i # or npm install / yarn
143+
```
144+
145+
2. **Set environment variables** – create a `.env` file in `examples/spa-manual-payments` (or export in your shell):
146+
147+
```
148+
VITE_APP_EPCC_ENDPOINT_URL=https://YOUR_EP_DOMAIN.elasticpath.com
149+
VITE_APP_EPCC_CLIENT_ID=YOUR_CLIENT_ID
150+
```
151+
152+
3. **Start Vite dev server**:
153+
154+
```bash
155+
pnpm --filter spa-manual-payments dev
156+
```
157+
158+
## Learn More
159+
160+
- [Manual Payment Gateway Documentation](https://elasticpath.dev/docs/api/carts/cart-management)
161+
- [Order Management with Elastic Path](https://elasticpath.dev/docs/api/carts/cart-management)
162+
- [Payment Processing APIs](https://elasticpath.dev/docs/api/carts/cart-management)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import js from '@eslint/js'
2+
import globals from 'globals'
3+
import reactHooks from 'eslint-plugin-react-hooks'
4+
import reactRefresh from 'eslint-plugin-react-refresh'
5+
import tseslint from 'typescript-eslint'
6+
7+
export default tseslint.config(
8+
{ ignores: ['dist'] },
9+
{
10+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
11+
files: ['**/*.{ts,tsx}'],
12+
languageOptions: {
13+
ecmaVersion: 2020,
14+
globals: globals.browser,
15+
},
16+
plugins: {
17+
'react-hooks': reactHooks,
18+
'react-refresh': reactRefresh,
19+
},
20+
rules: {
21+
...reactHooks.configs.recommended.rules,
22+
'react-refresh/only-export-components': [
23+
'warn',
24+
{ allowConstantExport: true },
25+
],
26+
},
27+
},
28+
)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en" class="h-full">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>SPA Manual Payments Example - Elastic Path</title>
8+
</head>
9+
<body class="h-full bg-gray-50">
10+
<div id="root" class="h-full"></div>
11+
<script type="module" src="/src/main.tsx"></script>
12+
</body>
13+
</html>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "spa-manual-payments",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "vite build",
9+
"lint": "eslint .",
10+
"preview": "vite preview"
11+
},
12+
"dependencies": {
13+
"@epcc-sdk/sdks-shopper": "workspace:*",
14+
"react": "^18.3.1",
15+
"react-dom": "^18.3.1"
16+
},
17+
"devDependencies": {
18+
"@eslint/js": "^9.9.0",
19+
"@tailwindcss/vite": "^4.1.7",
20+
"@types/react": "^18.3.3",
21+
"@types/react-dom": "^18.3.0",
22+
"@vitejs/plugin-react": "^4.3.1",
23+
"eslint": "^9.9.0",
24+
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
25+
"eslint-plugin-react-refresh": "^0.4.9",
26+
"globals": "^15.9.0",
27+
"tailwindcss": "^4.1.7",
28+
"typescript": "^5.5.3",
29+
"vite": "^5.4.1"
30+
}
31+
}

0 commit comments

Comments
 (0)