Skip to content

Commit d4d1175

Browse files
authored
feat: spa elastic path payments (#423)
* feat: add spa-elastic-path-payments base files feat: rewrite readme feat: declutter App.tsx feat: update readme tree * feat: rename * feat: EP payments configured correctly * feat: finalize readme * feat: clear up debugging * feat: simplify hook * feat: add more setup instructions to the readme
1 parent ddff1d3 commit d4d1175

27 files changed

+3365
-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: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
# Elastic Path Payment Processing SPA Example
2+
3+
This example showcases how to implement **Elastic Path Payments** payment gateway with **Elastic Path Commerce Cloud** in a Single-Page Application (SPA) written in React. It builds on the `spa-manual-payments` example.
4+
5+
> **Heads-up:** This project focuses **exclusively** on Elastic Path Payments 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. **Elastic Path Payments Gateway** – processes payments using Elastic Path Payments gateway, powered by Stripe elements:
11+
3. **Order State Management** – converts incomplete orders to complete orders after Elastic Path payment processing.
12+
4. **Payment Status Tracking** – displays real-time order and payment status updates with proper UI indicators.
13+
5. **Stripe Payment Element** – Uses Stripe's recommended Payment Element for secure payment collection.
14+
15+
> The example purposefully uses simplified order creation and minimal product selection to keep the focus on Elastic Path payment mechanics.
16+
17+
---
18+
19+
## Prerequisites
20+
21+
Before running this example, you'll need:
22+
23+
1. **Elastic Path Commerce Cloud Store** with Elastic Path Payments enabled
24+
2. **Stripe Account** - Elastic Path Payments is powered by Stripe
25+
3. **Stripe Publishable Key** and **Account ID** - Get these from your Stripe Dashboard
26+
27+
---
28+
29+
## Store Setup Requirements
30+
31+
To use this example, your **Elastic Path Commerce Cloud store** must be properly configured:
32+
33+
### 🔌 **Payment Gateway Configuration**
34+
35+
1. **Enable Elastic Path Payments** in Commerce Manager:
36+
37+
- Go to **Settings****Payment Gateways**
38+
- Configure **Elastic Path Payments** gateway
39+
- Add your **Stripe Connect account**
40+
- Enable the gateway and test mode
41+
42+
### 📦 **Product Setup**
43+
44+
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):
45+
46+
1. **Product Requirements**:
47+
48+
- Add at least one **simple product** (not a base product requiring variations)
49+
- Products should have **prices** associated with them
50+
- Products must be **active** and included in the published catalog
51+
52+
2. **Inventory Configuration** (Optional):
53+
- If using inventory management, ensure products have **stock levels** configured
54+
55+
### 🔑 **API Access Setup**
56+
57+
1. **Client Credentials**:
58+
59+
- Go to **Settings****API Keys** and create a new application key
60+
- Note your **Client ID** and **Store URL** and use them in your .env
61+
62+
2. **Stripe Keys**:
63+
- From your **connected Stripe account**, obtain:
64+
- **Publishable Key** (`pk_test_...` for test mode or `pk_live_...` for live)
65+
- **Account ID** (`acct_...`) - This identifies your specific Stripe Connect account
66+
67+
### 🚨 **Common Setup Issues**
68+
69+
**"No such payment_intent" Error**:
70+
71+
- **Cause**: Frontend Stripe keys don't match the backend Stripe account
72+
- **Solution**: Ensure `VITE_STRIPE_PUBLISHABLE_KEY` and `VITE_STRIPE_ACCOUNT_ID` are from the same Stripe account connected to Elastic Path
73+
74+
**"No products available" Error**:
75+
76+
- **Cause**: No products in published catalog, catalog not published, or all products are base products
77+
- **Solution**: Create and publish a catalog with at least one simple product
78+
79+
**404 Inventory Errors**:
80+
81+
- **Cause**: Product inventory not configured
82+
- **Solution**: Either configure inventory or ignore (example handles gracefully)
83+
84+
---
85+
86+
## Project Structure
87+
88+
```
89+
spa-elastic-path-payments/
90+
├── index.html # Vite entry point
91+
├── src/
92+
│ ├── App.tsx # Main app orchestration & state management
93+
│ ├── components/
94+
│ │ ├── AppHeader.tsx # Authentication status & cart ID display
95+
│ │ ├── StepIndicator.tsx # Multi-step progress indicator
96+
│ │ ├── OrderCreator.tsx # Creates test orders for payment demo
97+
│ │ ├── ElasticPathPayment.tsx # Elastic Path payment processing with Stripe
98+
│ │ ├── OrderStatus.tsx # Order & payment status display
99+
│ │ └── OrderCompleteView.tsx # Success screen with reset functionality
100+
│ ├── hooks/
101+
│ │ ├── useAppInitialization.ts # App startup & authentication logic
102+
│ │ └── useOrderCreation.ts # Order creation workflow & state
103+
│ └── auth/
104+
│ ├── CartProvider.tsx # Basic cart initialization
105+
│ └── StorefrontProvider.tsx # Elastic Path client setup
106+
└── README.md # ← you are here
107+
```
108+
109+
## How It Works
110+
111+
### 1. Test Order Creation
112+
113+
`OrderCreator` automatically creates a test scenario:
114+
115+
```tsx
116+
// Creates cart → adds test product → checkout → incomplete order
117+
const createIncompleteOrder = async () => {
118+
const products = await getByContextAllProducts()
119+
const selectedProduct = products.data.find(/* stock logic */)
120+
// ... cart creation, checkout, order creation
121+
}
122+
```
123+
124+
This generates an incomplete order ready for payment processing.
125+
126+
### 2. Payment Processing
127+
128+
`ElasticPathPayment` captures payment details and processes them using Elastic Path Payments (powered by Stripe):
129+
130+
```tsx
131+
// 1. Initialize payment with Elastic Path
132+
const paymentResponse = await paymentSetup({
133+
path: { orderID: order.id },
134+
body: {
135+
data: {
136+
gateway: "elastic_path_payments_stripe",
137+
method: "purchase",
138+
payment: {
139+
currency: order.meta?.display_price?.with_tax?.currency,
140+
amount: order.meta?.display_price?.with_tax?.amount,
141+
},
142+
},
143+
},
144+
})
145+
146+
// 2. Confirm payment with Stripe
147+
const { error, paymentIntent } = await stripe.confirmPayment({
148+
elements,
149+
clientSecret,
150+
confirmParams: { return_url: window.location.origin },
151+
redirect: "if_required",
152+
})
153+
154+
// 3. Confirm with Elastic Path
155+
await confirmOrder({ path: { orderID: order.id } })
156+
```
157+
158+
### 3. Status Display
159+
160+
`OrderStatus` shows order and payment status.
161+
162+
---
163+
164+
## Running the Example Locally
165+
166+
1. **Install deps** (from the repo root):
167+
168+
```bash
169+
pnpm i # or npm install / yarn
170+
```
171+
172+
2. **Set environment variables** – create a `.env` file in `examples/spa-elastic-path-payments`:
173+
174+
```env
175+
# Elastic Path Commerce Cloud
176+
VITE_APP_EPCC_ENDPOINT_URL=https://YOUR_EP_DOMAIN.elasticpath.com
177+
VITE_APP_EPCC_CLIENT_ID=YOUR_CLIENT_ID
178+
179+
# Stripe Publishable Key
180+
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_YOUR_STRIPE_PUBLISHABLE_KEY
181+
182+
# Stripe Account ID
183+
VITE_STRIPE_ACCOUNT_ID=acct_YOUR_STRIPE_ACCOUNT_ID
184+
```
185+
186+
**Important**: Make sure you're using your Stripe **publishable key** (starts with `pk_test_` for test mode or `pk_live_` for live mode).
187+
188+
3. **Configure Elastic Path Payments** in your Elastic Path store:
189+
190+
- Enable Elastic Path Payments in your store settings
191+
- Connect your Stripe account
192+
- Ensure the payment gateway is configured properly (e.g. test mode, enabled)
193+
194+
4. **Start Vite dev server**:
195+
196+
```bash
197+
pnpm --filter spa-elastic-path-payments dev
198+
```
199+
200+
The app will be available at `http://localhost:5173`
201+
202+
---
203+
204+
## Learn More
205+
206+
- [Elastic Path Payments Documentation](https://elasticpath.dev/docs/developer-tools/fundamentals/checkout/payments/elastic-path-payments/implement-payments)
207+
- [Stripe Payment Element Guide](https://stripe.com/docs/payments/payment-element)
208+
- [Elastic Path Commerce Cloud Docs](https://elasticpath.dev/docs)
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 Elastic Path 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: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"name": "spa-elastic-path-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+
"@stripe/react-stripe-js": "^2.4.0",
15+
"@stripe/stripe-js": "^2.2.2",
16+
"react": "^18.3.1",
17+
"react-dom": "^18.3.1"
18+
},
19+
"devDependencies": {
20+
"@eslint/js": "^9.9.0",
21+
"@tailwindcss/vite": "^4.1.7",
22+
"@types/react": "^18.3.3",
23+
"@types/react-dom": "^18.3.0",
24+
"@vitejs/plugin-react": "^4.3.1",
25+
"eslint": "^9.9.0",
26+
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
27+
"eslint-plugin-react-refresh": "^0.4.9",
28+
"globals": "^15.9.0",
29+
"tailwindcss": "^4.1.7",
30+
"typescript": "^5.5.3",
31+
"vite": "^5.4.1"
32+
}
33+
}

0 commit comments

Comments
 (0)