@akinon/projectzero 1.96.0-snapshot-ZERO-35861-20250908151109 → 1.96.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -1
- package/app-template/.github/instructions/checkout.instructions.md +678 -0
- package/app-template/.github/instructions/settings.instructions.md +338 -0
- package/app-template/AGENTS.md +7 -0
- package/app-template/CHANGELOG.md +28 -0
- package/app-template/package.json +18 -18
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: 'src/app/**/checkout/**|src/views/checkout/**|src/components/**/checkout/**'
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Project Zero Checkout - Developer Instructions
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
The checkout functionality in Project Zero Next.js is a multi-step e-commerce flow that handles user authentication, shipping, payment, and order completion. It's built with Redux state management, RTK Query for API calls, and supports various payment plugins.
|
|
10
|
+
|
|
11
|
+
## Checkout Architecture
|
|
12
|
+
|
|
13
|
+
### Route Structure
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
/[commerce]/[locale]/[currency]/orders/checkout/
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
- **Main Page**: `src/app/[commerce]/[locale]/[currency]/orders/checkout/page.tsx`
|
|
20
|
+
- **Route Constants**: Defined in `src/routes/index.ts` as `ROUTES.CHECKOUT`
|
|
21
|
+
|
|
22
|
+
### Core Components
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
src/views/checkout/
|
|
26
|
+
├── auth.tsx # Authentication/Guest checkout
|
|
27
|
+
├── step-list.tsx # Progress indicator
|
|
28
|
+
├── index.tsx # Summary component
|
|
29
|
+
└── steps/
|
|
30
|
+
├── shipping/ # Shipping step components
|
|
31
|
+
└── payment/ # Payment step components
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### State Management
|
|
35
|
+
|
|
36
|
+
**Redux Store**: `checkout` slice handles multi-step flow state
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import { useAppSelector, useAppDispatch } from '@akinon/next/redux/hooks';
|
|
40
|
+
import { setCurrentStep, resetCheckoutState } from '@akinon/next/redux/reducers/checkout';
|
|
41
|
+
|
|
42
|
+
// Access checkout state
|
|
43
|
+
const { steps, preOrder } = useAppSelector((state: RootState) => state.checkout);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Checkout Flow Steps
|
|
47
|
+
|
|
48
|
+
### 1. Authentication Step
|
|
49
|
+
|
|
50
|
+
**Template Detection**: `checkoutData?.template_name === 'orders/index.html'`
|
|
51
|
+
|
|
52
|
+
**Components Used**:
|
|
53
|
+
- `CheckoutAuth` - Main authentication wrapper
|
|
54
|
+
- `Login` - Existing user login
|
|
55
|
+
- `GuestLogin` - Guest checkout option
|
|
56
|
+
|
|
57
|
+
**Key Features**:
|
|
58
|
+
- NextAuth.js integration with `useSession()`
|
|
59
|
+
- Callback URL handling for post-login redirect
|
|
60
|
+
- Guest checkout with email/phone validation
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
// Authentication check pattern
|
|
64
|
+
const { status } = useSession();
|
|
65
|
+
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (status === 'authenticated') {
|
|
68
|
+
dispatch(api.util.invalidateTags(['Checkout']));
|
|
69
|
+
} else if (status === 'unauthenticated') {
|
|
70
|
+
router.replace(ROUTES.CHECKOUT + `?callbackUrl=${ROUTES.CHECKOUT}`);
|
|
71
|
+
}
|
|
72
|
+
}, [status]);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 2. Shipping Step
|
|
76
|
+
|
|
77
|
+
**When Active**: `steps.current === CheckoutStep.Shipping`
|
|
78
|
+
|
|
79
|
+
**Key APIs**:
|
|
80
|
+
- `setDeliveryOption` - Select delivery method
|
|
81
|
+
- `setAddresses` - Set billing/shipping addresses
|
|
82
|
+
- `setShippingOption` - Choose shipping method
|
|
83
|
+
|
|
84
|
+
**Auto-progression**: Automatically moves to payment when shipping is completed
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
if (steps.shipping.completed && !initialStepChanged.current) {
|
|
89
|
+
dispatch(setCurrentStep(CheckoutStep.Payment));
|
|
90
|
+
initialStepChanged.current = true;
|
|
91
|
+
}
|
|
92
|
+
}, [steps.shipping.completed]);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 3. Payment Step
|
|
96
|
+
|
|
97
|
+
**When Active**: `steps.current === CheckoutStep.Payment`
|
|
98
|
+
|
|
99
|
+
**Key APIs**:
|
|
100
|
+
- `setPaymentOption` - Select payment method
|
|
101
|
+
- `setInstallmentOption` - Choose installments
|
|
102
|
+
- `completeCreditCardPayment` - Process card payments
|
|
103
|
+
- Various plugin-specific payment completions
|
|
104
|
+
|
|
105
|
+
**Plugin Integration**: Extensive payment plugin support via `PluginModule`
|
|
106
|
+
|
|
107
|
+
## API Integration
|
|
108
|
+
|
|
109
|
+
### Core Hooks
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
// Primary checkout data fetching
|
|
113
|
+
const { data: checkoutData, isFetching, isError, refetch } = useFetchCheckoutQuery(null);
|
|
114
|
+
|
|
115
|
+
// State reset on page load
|
|
116
|
+
const { data: indexData, isLoading } = useResetCheckoutStateQuery(null);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Mutation Patterns
|
|
120
|
+
|
|
121
|
+
**All checkout mutations follow this pattern**:
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
const [mutationFn] = useMutationHook();
|
|
125
|
+
|
|
126
|
+
// With loading state management
|
|
127
|
+
async onQueryStarted(arg, { dispatch, queryFulfilled }) {
|
|
128
|
+
dispatch(setShippingStepBusy(true)); // or setPaymentStepBusy
|
|
129
|
+
await queryFulfilled;
|
|
130
|
+
dispatch(setShippingStepBusy(false));
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Error Handling
|
|
135
|
+
|
|
136
|
+
**Standard error UI pattern**:
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
if (isResetStateLoading || isFetching || isError) {
|
|
140
|
+
return (
|
|
141
|
+
<div className="flex flex-col items-center justify-center h-80">
|
|
142
|
+
{isResetStateLoading || isFetching ? (
|
|
143
|
+
<LoaderSpinner />
|
|
144
|
+
) : (
|
|
145
|
+
<>
|
|
146
|
+
<div>{t('checkout.error.title')}</div>
|
|
147
|
+
<div className="mt-5">
|
|
148
|
+
<Button onClick={refetchCheckout}>
|
|
149
|
+
{t('checkout.error.button')}
|
|
150
|
+
</Button>
|
|
151
|
+
</div>
|
|
152
|
+
</>
|
|
153
|
+
)}
|
|
154
|
+
</div>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Plugin System
|
|
160
|
+
|
|
161
|
+
### Core Plugin Architecture
|
|
162
|
+
|
|
163
|
+
**Plugin Wrapper**: All checkout features use `PluginModule` for extensibility
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
import PluginModule, { Component } from '@akinon/next/components/plugin-module';
|
|
167
|
+
|
|
168
|
+
// Conditional plugin rendering
|
|
169
|
+
<PluginModule component={Component.PluginName} props={...} />
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Available Checkout Plugins
|
|
173
|
+
|
|
174
|
+
**Payment Plugins**:
|
|
175
|
+
- `pz-masterpass` - Masterpass integration
|
|
176
|
+
- `pz-apple-pay` - Apple Pay support (with custom UI override capabilities)
|
|
177
|
+
- `pz-gpay` - Google Pay integration
|
|
178
|
+
- `pz-bkm` - BKM Express payments
|
|
179
|
+
- `pz-saved-card` - Saved card management
|
|
180
|
+
- `pz-credit-payment` - Credit/installment payments
|
|
181
|
+
- `pz-flow-payment` - Flow payment gateway
|
|
182
|
+
- `pz-tabby-extension` - Tabby BNPL (MENA)
|
|
183
|
+
- `pz-tamara-extension` - Tamara BNPL (MENA)
|
|
184
|
+
|
|
185
|
+
**Checkout Enhancement Plugins**:
|
|
186
|
+
- `pz-one-click-checkout` - Simplified one-click payments
|
|
187
|
+
- `pz-checkout-gift-pack` - Gift wrapping options
|
|
188
|
+
- `pz-click-collect` - Store pickup options
|
|
189
|
+
- `pz-otp` - OTP verification
|
|
190
|
+
- `pz-pay-on-delivery` - Cash on delivery
|
|
191
|
+
|
|
192
|
+
### Plugin Integration Example
|
|
193
|
+
|
|
194
|
+
```tsx
|
|
195
|
+
// Masterpass integration in checkout
|
|
196
|
+
<PluginModule component={Component.MasterpassProvider}>
|
|
197
|
+
<PluginModule component={Component.MasterpassDeleteConfirmationModal} />
|
|
198
|
+
<PluginModule component={Component.MasterpassOtpModal} />
|
|
199
|
+
<PluginModule component={Component.MasterpassLinkModal} />
|
|
200
|
+
|
|
201
|
+
{/* Your checkout content */}
|
|
202
|
+
</PluginModule>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Apple Pay Implementation**:
|
|
206
|
+
|
|
207
|
+
There are two ways to implement Apple Pay:
|
|
208
|
+
|
|
209
|
+
### Option 1: Full Plugin (Recommended)
|
|
210
|
+
Use the `pz-apple-pay` package for complete Apple Pay functionality:
|
|
211
|
+
|
|
212
|
+
**Quick Setup** (Recommended):
|
|
213
|
+
```bash
|
|
214
|
+
npx @akinon/projectzero@latest --plugins
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Manual Setup**:
|
|
218
|
+
|
|
219
|
+
### Option 2: UI Customization Only
|
|
220
|
+
If you only need to customize the Apple Pay UI, create a custom component:
|
|
221
|
+
|
|
222
|
+
1. **Create the Apple Pay component**: Create `src/views/checkout/steps/payment/options/apple-pay.tsx`
|
|
223
|
+
2. **Import in payment.tsx**: Add `import ApplePay from './options/apple-pay';`
|
|
224
|
+
3. **Add to PaymentOptionViews**: Add the component to the PaymentOptionViews array
|
|
225
|
+
|
|
226
|
+
**Implementation Pattern**:
|
|
227
|
+
```tsx
|
|
228
|
+
// In payment.tsx
|
|
229
|
+
import ApplePay from './options/apple-pay';
|
|
230
|
+
|
|
231
|
+
export const PaymentOptionViews: Array<CheckoutPaymentOption> = [
|
|
232
|
+
{
|
|
233
|
+
slug: 'apple-pay-wallet',
|
|
234
|
+
view: ApplePay
|
|
235
|
+
}
|
|
236
|
+
];
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Payment UI Customization Patterns
|
|
240
|
+
|
|
241
|
+
**Apple Pay Component Structure**:
|
|
242
|
+
|
|
243
|
+
Here's the basic structure for the Apple Pay component that should be placed in `src/views/checkout/steps/payment/options/apple-pay.tsx`:
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
'use client';
|
|
247
|
+
|
|
248
|
+
import { checkoutApi } from '@akinon/next/data/client/checkout';
|
|
249
|
+
import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
|
|
250
|
+
import { Button, Modal } from '@theme/components';
|
|
251
|
+
import { RootState } from '@theme/redux/store';
|
|
252
|
+
import { useState } from 'react';
|
|
253
|
+
import { SubmitHandler, useForm } from 'react-hook-form';
|
|
254
|
+
import { useLocalization } from '@akinon/next/hooks';
|
|
255
|
+
|
|
256
|
+
export default function ApplePay() {
|
|
257
|
+
const { handleSubmit } = useForm();
|
|
258
|
+
const { t } = useLocalization();
|
|
259
|
+
const { walletPaymentData, preOrder } = useAppSelector(
|
|
260
|
+
(state: RootState) => state.checkout
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
const dispatch = useAppDispatch();
|
|
264
|
+
const [errors, setErrors] = useState(null);
|
|
265
|
+
const [showConfirmationModal, setShowConfirmationModal] = useState(false);
|
|
266
|
+
|
|
267
|
+
const onSubmit: SubmitHandler<null> = async () => {
|
|
268
|
+
try {
|
|
269
|
+
// 1. Prepare payment request
|
|
270
|
+
const request = new PaymentRequest(paymentMethodData, paymentDetails);
|
|
271
|
+
|
|
272
|
+
// 2. Show confirmation modal instead of directly calling request.show()
|
|
273
|
+
setShowConfirmationModal(true);
|
|
274
|
+
|
|
275
|
+
// 3. Store request for later use
|
|
276
|
+
window.applePayRequest = request;
|
|
277
|
+
} catch (error) {
|
|
278
|
+
setErrors(error);
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const handleApplePayConfirm = async () => {
|
|
283
|
+
setShowConfirmationModal(false);
|
|
284
|
+
|
|
285
|
+
try {
|
|
286
|
+
const request = window.applePayRequest;
|
|
287
|
+
|
|
288
|
+
// 4. Now trigger the actual Apple Pay flow
|
|
289
|
+
request.show().then(async (paymentRequestResponse) => {
|
|
290
|
+
// 5. Handle payment response and API calls
|
|
291
|
+
// - Call setWalletPaymentPage
|
|
292
|
+
// - Call setWalletCompletePage
|
|
293
|
+
// - Handle success/failure
|
|
294
|
+
// - Redirect to thank you page
|
|
295
|
+
});
|
|
296
|
+
} catch (error) {
|
|
297
|
+
setErrors(error);
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
if (!walletPaymentData) {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return (
|
|
306
|
+
<>
|
|
307
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
308
|
+
<Button className="!hidden" type="submit"></Button>
|
|
309
|
+
</form>
|
|
310
|
+
|
|
311
|
+
{/* Custom confirmation modal */}
|
|
312
|
+
{showConfirmationModal && (
|
|
313
|
+
<Modal
|
|
314
|
+
open={showConfirmationModal}
|
|
315
|
+
setOpen={setShowConfirmationModal}
|
|
316
|
+
>
|
|
317
|
+
<div className="p-6">
|
|
318
|
+
<p>{t('checkout.payment.apple_pay.confirmation_message')}</p>
|
|
319
|
+
<Button onClick={handleApplePayConfirm}>
|
|
320
|
+
{t('common.confirm')}
|
|
321
|
+
</Button>
|
|
322
|
+
</div>
|
|
323
|
+
</Modal>
|
|
324
|
+
)}
|
|
325
|
+
</>
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**Key Implementation Steps**:
|
|
331
|
+
|
|
332
|
+
1. **Payment Request Setup**: Create PaymentRequest with proper method data and details
|
|
333
|
+
2. **Confirmation Modal**: Show custom UI before triggering native Apple Pay
|
|
334
|
+
3. **Request Storage**: Store payment request for later use via `window.applePayRequest`
|
|
335
|
+
4. **Payment Flow**: Handle the complete Apple Pay flow with API integrations
|
|
336
|
+
5. **Error Handling**: Implement comprehensive error handling throughout the process
|
|
337
|
+
6. **State Management**: Use Redux for checkout state and payment session management
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
## Form Handling
|
|
341
|
+
|
|
342
|
+
### Standard Form Pattern
|
|
343
|
+
|
|
344
|
+
**Use React Hook Form + Yup validation**:
|
|
345
|
+
|
|
346
|
+
```tsx
|
|
347
|
+
import { useForm } from 'react-hook-form';
|
|
348
|
+
import { yupResolver } from '@hookform/resolvers/yup';
|
|
349
|
+
import * as yup from 'yup';
|
|
350
|
+
|
|
351
|
+
const schema = (t) => yup.object().shape({
|
|
352
|
+
email: yup.string().email().required(t('error.required')),
|
|
353
|
+
phone: yup.string().required(t('error.required'))
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
const { register, handleSubmit, formState: { errors } } = useForm({
|
|
357
|
+
resolver: yupResolver(schema(t))
|
|
358
|
+
});
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Guest Login Form Example
|
|
362
|
+
|
|
363
|
+
```tsx
|
|
364
|
+
const onSubmit = async (data) => {
|
|
365
|
+
try {
|
|
366
|
+
await guestLogin(data);
|
|
367
|
+
// Handle success - usually redirects automatically
|
|
368
|
+
} catch (error) {
|
|
369
|
+
// Handle validation errors
|
|
370
|
+
if (error?.data?.form_errors) {
|
|
371
|
+
// Set form errors from backend
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## Internationalization
|
|
378
|
+
|
|
379
|
+
### Translation Keys
|
|
380
|
+
|
|
381
|
+
**Checkout-specific translations**: `checkout.json`
|
|
382
|
+
|
|
383
|
+
```tsx
|
|
384
|
+
import { useLocalization } from '@akinon/next/hooks';
|
|
385
|
+
|
|
386
|
+
const { t } = useLocalization();
|
|
387
|
+
|
|
388
|
+
// Common translation patterns
|
|
389
|
+
t('checkout.auth.title') // "Don't have an account?"
|
|
390
|
+
t('checkout.auth.signup') // "Sign up"
|
|
391
|
+
t('checkout.auth.guest_checkout') // "Guest Checkout"
|
|
392
|
+
t('checkout.error.title') // "Error occurred"
|
|
393
|
+
t('checkout.error.button') // "Try Again"
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### Multi-language Support
|
|
397
|
+
|
|
398
|
+
**Route structure includes locale**: `/[commerce]/[locale]/[currency]/orders/checkout/`
|
|
399
|
+
|
|
400
|
+
## Analytics Integration
|
|
401
|
+
|
|
402
|
+
### GTM/E-commerce Tracking
|
|
403
|
+
|
|
404
|
+
**Automatic event tracking**:
|
|
405
|
+
|
|
406
|
+
```tsx
|
|
407
|
+
import { pushAddShippingInfo, pushAddPaymentInfo } from '@theme/utils/gtm';
|
|
408
|
+
|
|
409
|
+
// Auto-triggered on step completion
|
|
410
|
+
useEffect(() => {
|
|
411
|
+
if (isSuccess) {
|
|
412
|
+
const products = checkoutData?.pre_order?.basket?.basketitem_set.map(
|
|
413
|
+
(basketItem) => ({ ...basketItem.product })
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
if (steps.current === 'shipping') {
|
|
417
|
+
pushAddShippingInfo(products);
|
|
418
|
+
}
|
|
419
|
+
if (steps.current === 'payment') {
|
|
420
|
+
pushAddPaymentInfo(products, String(preOrder?.payment_option?.name));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}, [isSuccess, steps, checkoutData, preOrder?.payment_option?.name]);
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
## Development Guidelines
|
|
427
|
+
|
|
428
|
+
### Component Structure
|
|
429
|
+
|
|
430
|
+
**Follow this hierarchy**:
|
|
431
|
+
|
|
432
|
+
```tsx
|
|
433
|
+
// Page-level component (src/app/.../checkout/page.tsx)
|
|
434
|
+
const Checkout = () => {
|
|
435
|
+
// 1. Hooks and state
|
|
436
|
+
const { t } = useLocalization();
|
|
437
|
+
const { steps, preOrder } = useAppSelector((state) => state.checkout);
|
|
438
|
+
|
|
439
|
+
// 2. API calls
|
|
440
|
+
const { data: checkoutData } = useFetchCheckoutQuery(null);
|
|
441
|
+
|
|
442
|
+
// 3. Effects for flow control
|
|
443
|
+
useEffect(() => {
|
|
444
|
+
// Step progression logic
|
|
445
|
+
}, [dependencies]);
|
|
446
|
+
|
|
447
|
+
// 4. Early returns for different states
|
|
448
|
+
if (isAuthRequired) return <CheckoutAuth />;
|
|
449
|
+
if (isLoading) return <LoaderSpinner />;
|
|
450
|
+
if (isError) return <ErrorState />;
|
|
451
|
+
|
|
452
|
+
// 5. Main render with plugin wrappers
|
|
453
|
+
return (
|
|
454
|
+
<PluginModule component={Component.PaymentProvider}>
|
|
455
|
+
<CheckoutStepList />
|
|
456
|
+
<div className="checkout-content">
|
|
457
|
+
{steps.current === CheckoutStep.Shipping && <ShippingStep />}
|
|
458
|
+
{steps.current === CheckoutStep.Payment && <PaymentStep />}
|
|
459
|
+
</div>
|
|
460
|
+
<Summary />
|
|
461
|
+
</PluginModule>
|
|
462
|
+
);
|
|
463
|
+
};
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Dynamic Imports
|
|
467
|
+
|
|
468
|
+
**Use dynamic imports for step components**:
|
|
469
|
+
|
|
470
|
+
```tsx
|
|
471
|
+
const CheckoutAuth = useMemo(
|
|
472
|
+
() => dynamic(() => import('@theme/views/checkout/auth')),
|
|
473
|
+
[]
|
|
474
|
+
);
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### State Management Best Practices
|
|
478
|
+
|
|
479
|
+
**1. Always reset checkout state on unmount**:
|
|
480
|
+
|
|
481
|
+
```tsx
|
|
482
|
+
useEffect(() => {
|
|
483
|
+
return () => {
|
|
484
|
+
dispatch(resetCheckoutState());
|
|
485
|
+
};
|
|
486
|
+
}, []);
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
**2. Use step-specific busy states**:
|
|
490
|
+
|
|
491
|
+
```tsx
|
|
492
|
+
// In mutations
|
|
493
|
+
dispatch(setShippingStepBusy(true));
|
|
494
|
+
// or
|
|
495
|
+
dispatch(setPaymentStepBusy(true));
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
**3. Handle step progression carefully**:
|
|
499
|
+
|
|
500
|
+
```tsx
|
|
501
|
+
const initialStepChanged = useRef<boolean>(false);
|
|
502
|
+
|
|
503
|
+
useEffect(() => {
|
|
504
|
+
if (shouldProgressToNextStep && !initialStepChanged.current) {
|
|
505
|
+
dispatch(setCurrentStep(NextStep));
|
|
506
|
+
initialStepChanged.current = true;
|
|
507
|
+
}
|
|
508
|
+
}, [shouldProgressToNextStep]);
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
### Styling Guidelines
|
|
512
|
+
|
|
513
|
+
**Use TailwindCSS with responsive design**:
|
|
514
|
+
|
|
515
|
+
```tsx
|
|
516
|
+
<div className="container flex flex-col flex-wrap w-full px-4 md:px-0">
|
|
517
|
+
<div className="w-full h-fit-content lg:w-2/3">
|
|
518
|
+
{/* Main content */}
|
|
519
|
+
</div>
|
|
520
|
+
<div className="w-full h-fit-content mt-6 lg:w-1/3 lg:pl-8 lg:mt-0">
|
|
521
|
+
{/* Sidebar */}
|
|
522
|
+
</div>
|
|
523
|
+
</div>
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
## Security Considerations
|
|
527
|
+
|
|
528
|
+
### Authentication
|
|
529
|
+
|
|
530
|
+
- Always check authentication status before allowing checkout
|
|
531
|
+
- Handle callback URLs properly for post-login redirects
|
|
532
|
+
- Support both authenticated and guest checkout flows
|
|
533
|
+
|
|
534
|
+
### Data Validation
|
|
535
|
+
|
|
536
|
+
- Validate all form inputs on both client and server
|
|
537
|
+
- Use proper form validation with Yup schemas
|
|
538
|
+
- Handle backend validation errors gracefully
|
|
539
|
+
|
|
540
|
+
### Payment Security
|
|
541
|
+
|
|
542
|
+
- Never store sensitive payment data in frontend state
|
|
543
|
+
- Use secure payment provider integrations
|
|
544
|
+
- Implement proper 3D Secure flows when required
|
|
545
|
+
|
|
546
|
+
## Testing Guidelines
|
|
547
|
+
|
|
548
|
+
### Component Testing
|
|
549
|
+
|
|
550
|
+
**Test checkout flow components**:
|
|
551
|
+
|
|
552
|
+
```typescript
|
|
553
|
+
// Test authentication flow
|
|
554
|
+
describe('CheckoutAuth', () => {
|
|
555
|
+
it('redirects authenticated users', () => {
|
|
556
|
+
// Mock authenticated session
|
|
557
|
+
// Verify redirect behavior
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
it('shows guest login for unauthenticated users', () => {
|
|
561
|
+
// Mock unauthenticated session
|
|
562
|
+
// Verify guest login form is shown
|
|
563
|
+
});
|
|
564
|
+
});
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
### Integration Testing
|
|
568
|
+
|
|
569
|
+
**Test complete checkout flows**:
|
|
570
|
+
|
|
571
|
+
```typescript
|
|
572
|
+
describe('Checkout Flow', () => {
|
|
573
|
+
it('completes guest checkout successfully', async () => {
|
|
574
|
+
// 1. Add items to basket
|
|
575
|
+
// 2. Navigate to checkout
|
|
576
|
+
// 3. Complete guest login
|
|
577
|
+
// 4. Fill shipping information
|
|
578
|
+
// 5. Select payment method
|
|
579
|
+
// 6. Complete order
|
|
580
|
+
});
|
|
581
|
+
});
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
## Common Patterns
|
|
585
|
+
|
|
586
|
+
### Redirect Handling
|
|
587
|
+
|
|
588
|
+
```tsx
|
|
589
|
+
// Handle API redirects
|
|
590
|
+
if (checkoutData?.redirect_url?.includes('basket')) {
|
|
591
|
+
router.push(ROUTES.BASKET);
|
|
592
|
+
return null;
|
|
593
|
+
}
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
### Plugin Component Patterns
|
|
597
|
+
|
|
598
|
+
```tsx
|
|
599
|
+
// Conditional plugin usage
|
|
600
|
+
<PluginModule component={Component.PluginName} props={{ data }}>
|
|
601
|
+
{/* Children components */}
|
|
602
|
+
</PluginModule>
|
|
603
|
+
|
|
604
|
+
// Multiple plugin modals
|
|
605
|
+
<PluginModule component={Component.MasterpassProvider}>
|
|
606
|
+
<PluginModule component={Component.MasterpassDeleteConfirmationModal} />
|
|
607
|
+
<PluginModule component={Component.MasterpassOtpModal} />
|
|
608
|
+
{/* Main content */}
|
|
609
|
+
</PluginModule>
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
### Loading State Management
|
|
613
|
+
|
|
614
|
+
```tsx
|
|
615
|
+
// Standard loading pattern
|
|
616
|
+
if (isResetStateLoading || isFetching || isError) {
|
|
617
|
+
return (
|
|
618
|
+
<div className="flex flex-col items-center justify-center h-80">
|
|
619
|
+
{isResetStateLoading || isFetching ? (
|
|
620
|
+
<LoaderSpinner />
|
|
621
|
+
) : (
|
|
622
|
+
<ErrorWithRetry onRetry={refetchCheckout} />
|
|
623
|
+
)}
|
|
624
|
+
</div>
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
## Troubleshooting
|
|
630
|
+
|
|
631
|
+
### Common Issues
|
|
632
|
+
|
|
633
|
+
**1. Checkout state not resetting**:
|
|
634
|
+
- Ensure `resetCheckoutState()` is called on component unmount
|
|
635
|
+
- Check if `useResetCheckoutStateQuery` is properly called
|
|
636
|
+
|
|
637
|
+
**2. Step progression not working**:
|
|
638
|
+
- Verify `initialStepChanged` ref is being used correctly
|
|
639
|
+
- Check step completion conditions in Redux state
|
|
640
|
+
|
|
641
|
+
**3. Plugin not loading**:
|
|
642
|
+
- Ensure plugin is listed in `src/plugins.js`
|
|
643
|
+
- Verify plugin component is available in `Component` enum
|
|
644
|
+
- Check plugin dependencies in `package.json`
|
|
645
|
+
|
|
646
|
+
**4. Authentication flow issues**:
|
|
647
|
+
- Check NextAuth configuration
|
|
648
|
+
- Verify callback URLs are properly set
|
|
649
|
+
- Ensure session status is being handled correctly
|
|
650
|
+
|
|
651
|
+
### Debugging Tips
|
|
652
|
+
|
|
653
|
+
**1. Redux DevTools**: Monitor checkout state changes
|
|
654
|
+
**2. Network Tab**: Check API calls and responses
|
|
655
|
+
**3. Console Logs**: Add logging for step transitions
|
|
656
|
+
**4. Plugin Logging**: Enable plugin-specific debug logs
|
|
657
|
+
|
|
658
|
+
## Performance Considerations
|
|
659
|
+
|
|
660
|
+
### Code Splitting
|
|
661
|
+
|
|
662
|
+
- Use dynamic imports for step components
|
|
663
|
+
- Lazy load payment provider components
|
|
664
|
+
- Split plugin bundles appropriately
|
|
665
|
+
|
|
666
|
+
### API Optimization
|
|
667
|
+
|
|
668
|
+
- Use RTK Query caching effectively
|
|
669
|
+
- Invalidate tags only when necessary
|
|
670
|
+
- Implement proper loading states
|
|
671
|
+
|
|
672
|
+
### Bundle Size
|
|
673
|
+
|
|
674
|
+
- Tree-shake unused plugins
|
|
675
|
+
- Optimize payment provider scripts
|
|
676
|
+
- Monitor bundle size with webpack-bundle-analyzer
|
|
677
|
+
|
|
678
|
+
When working on checkout functionality, always consider the complete user journey, handle edge cases gracefully, and ensure compatibility with the extensive plugin ecosystem.
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
# Settings.js Configuration Instructions
|
|
2
|
+
|
|
3
|
+
This file is the main configuration file for the ProjectZero Next.js application. All customizable settings are defined here.
|
|
4
|
+
|
|
5
|
+
## 📋 Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Basic Structure](#basic-structure)
|
|
8
|
+
- [Available Settings](#available-settings)
|
|
9
|
+
- [Detailed Explanations](#detailed-explanations)
|
|
10
|
+
- [Example Configuration](#example-configuration)
|
|
11
|
+
- [Plugin Configuration](#plugin-configuration)
|
|
12
|
+
- [Important Notes](#important-notes)
|
|
13
|
+
|
|
14
|
+
## Basic Structure
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
/** @type {import('@akinon/next/types').Settings} */
|
|
18
|
+
module.exports = {
|
|
19
|
+
// Settings are defined here
|
|
20
|
+
};
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Available Settings
|
|
24
|
+
|
|
25
|
+
### 1. 🌐 Web Vitals
|
|
26
|
+
```javascript
|
|
27
|
+
webVitals: {
|
|
28
|
+
enabled: true // Enables/disables web performance metrics
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 2. 🔗 Commerce URL
|
|
33
|
+
```javascript
|
|
34
|
+
commerceUrl: string // Backend API URL (taken from SERVICE_BACKEND_URL environment variable)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 3. 🏷️ Product Attributes
|
|
38
|
+
```javascript
|
|
39
|
+
commonProductAttributes: [
|
|
40
|
+
{
|
|
41
|
+
translationKey: 'color', // Translation key
|
|
42
|
+
key: 'color' // Attribute key from API
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
translationKey: 'size',
|
|
46
|
+
key: 'size'
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 4. 🌍 Localization Settings
|
|
52
|
+
```javascript
|
|
53
|
+
localization: {
|
|
54
|
+
// Supported languages
|
|
55
|
+
locales: [
|
|
56
|
+
{
|
|
57
|
+
label: 'EN', // Display label
|
|
58
|
+
value: 'en', // Language code in ISO 639-1 format
|
|
59
|
+
localePath: 'en', // URL path
|
|
60
|
+
apiValue: 'en-us', // Value used for API
|
|
61
|
+
rtl: false // Right-to-left writing (true for Arabic, Hebrew)
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
|
|
65
|
+
// Supported currencies
|
|
66
|
+
currencies: [
|
|
67
|
+
{
|
|
68
|
+
label: 'USD', // Display label
|
|
69
|
+
code: 'usd', // Currency code in ISO 4217 format
|
|
70
|
+
decimalScale: 2 // Number of decimal places (optional)
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
|
|
74
|
+
defaultLocaleValue: 'en', // Default language
|
|
75
|
+
localeUrlStrategy: LocaleUrlStrategy.HideDefaultLocale, // URL strategy
|
|
76
|
+
redirectToDefaultLocale: true, // Redirect to default locale
|
|
77
|
+
defaultCurrencyCode: 'usd', // Default currency
|
|
78
|
+
|
|
79
|
+
// Dynamic currency determination (optional)
|
|
80
|
+
getActiveCurrencyCode: ({ req, locale, defaultCurrencyCode }) => {
|
|
81
|
+
// Custom currency determination logic
|
|
82
|
+
return defaultCurrencyCode;
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
// Locale included pretty URL pattern (optional)
|
|
86
|
+
localeIncludedPrettyUrlPattern: new RegExp('.+/pages/.+$')
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### Locale URL Strategies:
|
|
91
|
+
- `LocaleUrlStrategy.HideDefaultLocale`: Default language is hidden in URL
|
|
92
|
+
- `LocaleUrlStrategy.ShowAllLocales`: All languages are shown in URL
|
|
93
|
+
- `LocaleUrlStrategy.HideAllLocales`: No language is shown in URL
|
|
94
|
+
|
|
95
|
+
### 5. 🔄 URL Rewrites
|
|
96
|
+
```javascript
|
|
97
|
+
rewrites: [
|
|
98
|
+
{
|
|
99
|
+
source: '/auth', // Source URL
|
|
100
|
+
destination: '/auth' // Destination URL
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 6. ⚡ Redis Cache Settings
|
|
106
|
+
```javascript
|
|
107
|
+
redis: {
|
|
108
|
+
defaultExpirationTime: 900 // Default cache duration (seconds)
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 7. 💳 Checkout Settings
|
|
113
|
+
```javascript
|
|
114
|
+
checkout: {
|
|
115
|
+
// Payment options to exclude from iframe (deprecated)
|
|
116
|
+
iframeExcludedPaymentOptions: ['payment-option-slug'],
|
|
117
|
+
|
|
118
|
+
// Payment options to include in iframe
|
|
119
|
+
iframeIncludedPaymentOptions: ['payment-option-slug'],
|
|
120
|
+
|
|
121
|
+
// Additional payment types
|
|
122
|
+
extraPaymentTypes: ['custom-payment-type'],
|
|
123
|
+
|
|
124
|
+
// Masterpass JS URL
|
|
125
|
+
masterpassJsUrl: 'https://example.com/masterpass.js'
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 8. ⚙️ Other Settings
|
|
130
|
+
```javascript
|
|
131
|
+
// Enable custom 404 page
|
|
132
|
+
customNotFoundEnabled: false,
|
|
133
|
+
|
|
134
|
+
// Use optimized translations
|
|
135
|
+
useOptimizedTranslations: true,
|
|
136
|
+
|
|
137
|
+
// Use pretty URL route
|
|
138
|
+
usePrettyUrlRoute: true,
|
|
139
|
+
|
|
140
|
+
// Plugin settings
|
|
141
|
+
plugins: {
|
|
142
|
+
'plugin-name': {
|
|
143
|
+
setting1: 'value1',
|
|
144
|
+
setting2: 'value2'
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
// Proxy headers - determines which headers should be passed to Commerce API
|
|
149
|
+
includedProxyHeaders: ['x-custom-header', 'x-forwarded-for', 'user-agent'],
|
|
150
|
+
|
|
151
|
+
// Commerce redirection ignore list
|
|
152
|
+
commerceRedirectionIgnoreList: ['/api/', '/_next/'],
|
|
153
|
+
|
|
154
|
+
// Reset basket when currency changes
|
|
155
|
+
resetBasketOnCurrencyChange: true,
|
|
156
|
+
|
|
157
|
+
// Frontend IDs used to pass x-frontend-id header to commerce
|
|
158
|
+
frontendIds: {
|
|
159
|
+
'frontend-name': 123
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Detailed Explanations
|
|
164
|
+
|
|
165
|
+
### 🔒 includedProxyHeaders
|
|
166
|
+
|
|
167
|
+
This setting determines which HTTP headers should be passed in proxy requests from the Next.js application to the Commerce API.
|
|
168
|
+
|
|
169
|
+
#### How It Works?
|
|
170
|
+
|
|
171
|
+
1. **Default Behavior**: The system does not pass certain headers to the Commerce API by default
|
|
172
|
+
2. **Override Mechanism**: Headers specified in the `includedProxyHeaders` array are passed to the Commerce API even if they are in the excluded list
|
|
173
|
+
|
|
174
|
+
#### Why Is It Used?
|
|
175
|
+
|
|
176
|
+
- **🔐 Security**: Prevents headers containing sensitive information from being passed to the Commerce API
|
|
177
|
+
- **⚡ Performance**: Prevents unnecessary headers from being passed
|
|
178
|
+
- **🔧 Flexibility**: Allows specific headers to be passed for special cases
|
|
179
|
+
|
|
180
|
+
#### Usage Example
|
|
181
|
+
|
|
182
|
+
```javascript
|
|
183
|
+
includedProxyHeaders: [
|
|
184
|
+
'x-forwarded-for',
|
|
185
|
+
'user-agent',
|
|
186
|
+
'x-custom-header',
|
|
187
|
+
'x-device-type'
|
|
188
|
+
]
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 🚫 commerceRedirectionIgnoreList
|
|
192
|
+
|
|
193
|
+
This setting determines which URL patterns should disable redirections (redirects) coming from the Commerce API.
|
|
194
|
+
|
|
195
|
+
#### How It Works?
|
|
196
|
+
|
|
197
|
+
1. **Middleware Process**: The `url-redirection.ts` middleware runs on every URL request
|
|
198
|
+
2. **Commerce Check**: The middleware sends the current URL to the Commerce API
|
|
199
|
+
3. **Redirect Check**: If a redirect response comes from the Commerce API, `commerceRedirectionIgnoreList` is checked
|
|
200
|
+
4. **Pattern Matching**: If the redirect URL matches one of the patterns in the ignore list, the redirect is not performed
|
|
201
|
+
|
|
202
|
+
#### Why Is It Used?
|
|
203
|
+
|
|
204
|
+
- Ensures that certain pages are not affected by Commerce redirects
|
|
205
|
+
|
|
206
|
+
#### Usage Example
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
commerceRedirectionIgnoreList: ['/users/reset']
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Example Configuration
|
|
213
|
+
|
|
214
|
+
```javascript
|
|
215
|
+
const { LocaleUrlStrategy } = require('@akinon/next/localization');
|
|
216
|
+
const { ROUTES } = require('@theme/routes');
|
|
217
|
+
|
|
218
|
+
const commerceUrl = encodeURI(process.env.SERVICE_BACKEND_URL ?? 'default');
|
|
219
|
+
|
|
220
|
+
/** @type {import('@akinon/next/types').Settings} */
|
|
221
|
+
module.exports = {
|
|
222
|
+
webVitals: {
|
|
223
|
+
enabled: true
|
|
224
|
+
},
|
|
225
|
+
commerceUrl,
|
|
226
|
+
commonProductAttributes: [
|
|
227
|
+
{ translationKey: 'color', key: 'color' },
|
|
228
|
+
{ translationKey: 'size', key: 'size' }
|
|
229
|
+
],
|
|
230
|
+
localization: {
|
|
231
|
+
locales: [
|
|
232
|
+
{
|
|
233
|
+
label: 'EN',
|
|
234
|
+
value: 'en',
|
|
235
|
+
localePath: 'en',
|
|
236
|
+
apiValue: 'en-us',
|
|
237
|
+
rtl: false
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
label: 'TR',
|
|
241
|
+
value: 'tr',
|
|
242
|
+
localePath: 'tr',
|
|
243
|
+
apiValue: 'tr-tr',
|
|
244
|
+
rtl: false
|
|
245
|
+
}
|
|
246
|
+
],
|
|
247
|
+
currencies: [
|
|
248
|
+
{
|
|
249
|
+
label: 'USD',
|
|
250
|
+
code: 'usd',
|
|
251
|
+
decimalScale: 2
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
label: 'TRY',
|
|
255
|
+
code: 'try',
|
|
256
|
+
decimalScale: 2
|
|
257
|
+
}
|
|
258
|
+
],
|
|
259
|
+
defaultLocaleValue: 'en',
|
|
260
|
+
localeUrlStrategy: LocaleUrlStrategy.HideDefaultLocale,
|
|
261
|
+
redirectToDefaultLocale: true,
|
|
262
|
+
defaultCurrencyCode: 'usd'
|
|
263
|
+
},
|
|
264
|
+
rewrites: [
|
|
265
|
+
{
|
|
266
|
+
source: ROUTES.AUTH,
|
|
267
|
+
destination: '/auth'
|
|
268
|
+
}
|
|
269
|
+
],
|
|
270
|
+
redis: {
|
|
271
|
+
defaultExpirationTime: 900
|
|
272
|
+
},
|
|
273
|
+
customNotFoundEnabled: false
|
|
274
|
+
};
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Plugin Configuration
|
|
278
|
+
|
|
279
|
+
The `plugins` setting allows you to customize the behavior of plugins in the ProjectZero ecosystem.
|
|
280
|
+
|
|
281
|
+
### 🎛️ How It Works?
|
|
282
|
+
|
|
283
|
+
1. **Plugin System**: Plugins are loaded through the `PluginModule` component
|
|
284
|
+
2. **Settings Integration**: Each plugin gets its own settings through `settings.plugins[pluginName]`
|
|
285
|
+
3. **Dynamic Loading**: Plugins are loaded only when needed (lazy loading)
|
|
286
|
+
4. **Customization**: Each plugin has its own specific settings
|
|
287
|
+
|
|
288
|
+
### 🚀 Example: pz-akifast Plugin Configuration
|
|
289
|
+
|
|
290
|
+
```javascript
|
|
291
|
+
plugins: {
|
|
292
|
+
'pz-akifast': {
|
|
293
|
+
quickLogin: false, // Hide quick login button
|
|
294
|
+
pdp: false, // Hide checkout button on product detail page
|
|
295
|
+
basket: true // Show checkout button on basket page
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
### 💡 Plugin Usage Examples
|
|
302
|
+
|
|
303
|
+
#### Akifast Quick Login Button
|
|
304
|
+
```javascript
|
|
305
|
+
// settings.js
|
|
306
|
+
plugins: {
|
|
307
|
+
'pz-akifast': {
|
|
308
|
+
quickLogin: true // Show button
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
#### Akifast Checkout Button
|
|
314
|
+
```javascript
|
|
315
|
+
// settings.js
|
|
316
|
+
plugins: {
|
|
317
|
+
'pz-akifast': {
|
|
318
|
+
pdp: true, // Show on product detail page
|
|
319
|
+
basket: false // Hide on basket page
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### ⚠️ Things to Consider
|
|
325
|
+
|
|
326
|
+
1. **Plugin Names**: Plugin names must match exactly (e.g., `pz-akifast`)
|
|
327
|
+
5. **Performance**: Plugins are loaded only when needed
|
|
328
|
+
|
|
329
|
+
## Important Notes
|
|
330
|
+
|
|
331
|
+
1. **📝 TypeScript Support**: The file provides TypeScript support with `@type` comment
|
|
332
|
+
2. **🌐 Environment Variables**: Commerce URL is taken from `SERVICE_BACKEND_URL` environment variable
|
|
333
|
+
3. **📦 Imports**: Required modules must be imported at the beginning of the file
|
|
334
|
+
4. **✅ Validation**: All settings must comply with the Settings interface
|
|
335
|
+
5. **⚡ Performance**: Redis cache settings affect performance
|
|
336
|
+
6. **🌍 Localization**: Language and currency settings directly affect the e-commerce experience
|
|
337
|
+
7. **🔒 Proxy Headers**: The `includedProxyHeaders` setting is critical for security and performance
|
|
338
|
+
8. **🚫 Redirect Control**: The `commerceRedirectionIgnoreList` setting is important for protecting APIs and static files
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Project Zero Next.js - Developer Instructions
|
|
2
|
+
|
|
3
|
+
## 📚 Available Instruction Files
|
|
4
|
+
|
|
5
|
+
This project contains comprehensive instruction files to guide developers through different aspects of the Project Zero Next.js e-commerce platform.
|
|
6
|
+
|
|
7
|
+
**[.github/instructions/](.github/instructions/)**
|
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# projectzeronext
|
|
2
2
|
|
|
3
|
+
## 1.96.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 994dafe: ZERO-3616: Add settings instruction file
|
|
8
|
+
- 48bf7bd: ZERO-3612: Add checkout instruction
|
|
9
|
+
|
|
10
|
+
### Patch Changes
|
|
11
|
+
|
|
12
|
+
- Updated dependencies [af5c93a]
|
|
13
|
+
- Updated dependencies [a420947]
|
|
14
|
+
- @akinon/next@1.96.0
|
|
15
|
+
- @akinon/pz-akifast@1.96.0
|
|
16
|
+
- @akinon/pz-b2b@1.96.0
|
|
17
|
+
- @akinon/pz-basket-gift-pack@1.96.0
|
|
18
|
+
- @akinon/pz-bkm@1.96.0
|
|
19
|
+
- @akinon/pz-checkout-gift-pack@1.96.0
|
|
20
|
+
- @akinon/pz-click-collect@1.96.0
|
|
21
|
+
- @akinon/pz-credit-payment@1.96.0
|
|
22
|
+
- @akinon/pz-gpay@1.96.0
|
|
23
|
+
- @akinon/pz-masterpass@1.96.0
|
|
24
|
+
- @akinon/pz-one-click-checkout@1.96.0
|
|
25
|
+
- @akinon/pz-otp@1.96.0
|
|
26
|
+
- @akinon/pz-pay-on-delivery@1.96.0
|
|
27
|
+
- @akinon/pz-saved-card@1.96.0
|
|
28
|
+
- @akinon/pz-tabby-extension@1.96.0
|
|
29
|
+
- @akinon/pz-tamara-extension@1.96.0
|
|
30
|
+
|
|
3
31
|
## 1.95.0
|
|
4
32
|
|
|
5
33
|
### Patch Changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "projectzeronext",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.96.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"scripts": {
|
|
@@ -24,22 +24,22 @@
|
|
|
24
24
|
"test:middleware": "jest middleware-matcher.test.ts --bail"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@akinon/next": "1.
|
|
28
|
-
"@akinon/pz-akifast": "1.
|
|
29
|
-
"@akinon/pz-b2b": "1.
|
|
30
|
-
"@akinon/pz-basket-gift-pack": "1.
|
|
31
|
-
"@akinon/pz-bkm": "1.
|
|
32
|
-
"@akinon/pz-checkout-gift-pack": "1.
|
|
33
|
-
"@akinon/pz-click-collect": "1.
|
|
34
|
-
"@akinon/pz-credit-payment": "1.
|
|
35
|
-
"@akinon/pz-gpay": "1.
|
|
36
|
-
"@akinon/pz-masterpass": "1.
|
|
37
|
-
"@akinon/pz-one-click-checkout": "1.
|
|
38
|
-
"@akinon/pz-otp": "1.
|
|
39
|
-
"@akinon/pz-pay-on-delivery": "1.
|
|
40
|
-
"@akinon/pz-saved-card": "1.
|
|
41
|
-
"@akinon/pz-tabby-extension": "1.
|
|
42
|
-
"@akinon/pz-tamara-extension": "1.
|
|
27
|
+
"@akinon/next": "1.96.0",
|
|
28
|
+
"@akinon/pz-akifast": "1.96.0",
|
|
29
|
+
"@akinon/pz-b2b": "1.96.0",
|
|
30
|
+
"@akinon/pz-basket-gift-pack": "1.96.0",
|
|
31
|
+
"@akinon/pz-bkm": "1.96.0",
|
|
32
|
+
"@akinon/pz-checkout-gift-pack": "1.96.0",
|
|
33
|
+
"@akinon/pz-click-collect": "1.96.0",
|
|
34
|
+
"@akinon/pz-credit-payment": "1.96.0",
|
|
35
|
+
"@akinon/pz-gpay": "1.96.0",
|
|
36
|
+
"@akinon/pz-masterpass": "1.96.0",
|
|
37
|
+
"@akinon/pz-one-click-checkout": "1.96.0",
|
|
38
|
+
"@akinon/pz-otp": "1.96.0",
|
|
39
|
+
"@akinon/pz-pay-on-delivery": "1.96.0",
|
|
40
|
+
"@akinon/pz-saved-card": "1.96.0",
|
|
41
|
+
"@akinon/pz-tabby-extension": "1.96.0",
|
|
42
|
+
"@akinon/pz-tamara-extension": "1.96.0",
|
|
43
43
|
"@hookform/resolvers": "2.9.0",
|
|
44
44
|
"@next/third-parties": "14.1.0",
|
|
45
45
|
"@react-google-maps/api": "2.17.1",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"yup": "0.32.11"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
|
-
"@akinon/eslint-plugin-projectzero": "1.
|
|
65
|
+
"@akinon/eslint-plugin-projectzero": "1.96.0",
|
|
66
66
|
"@semantic-release/changelog": "6.0.2",
|
|
67
67
|
"@semantic-release/exec": "6.0.3",
|
|
68
68
|
"@semantic-release/git": "10.0.1",
|