@akinon/projectzero 1.126.19 → 1.126.20
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 +2 -0
- package/app-template/.env.example +6 -0
- package/app-template/CHANGELOG.md +40 -0
- package/app-template/package.json +29 -28
- package/app-template/public/locales/en/checkout.json +50 -0
- package/app-template/public/locales/tr/checkout.json +50 -0
- package/app-template/src/app/[pz]/account/(dashboard)/layout.tsx +20 -0
- package/app-template/src/app/[pz]/account/account-page-slot.tsx +35 -0
- package/app-template/src/app/[pz]/account/address/layout.tsx +18 -0
- package/app-template/src/app/[pz]/account/change-email/layout.tsx +18 -0
- package/app-template/src/app/[pz]/account/change-password/layout.tsx +18 -0
- package/app-template/src/app/[pz]/account/contact/layout.tsx +18 -0
- package/app-template/src/app/[pz]/account/coupons/layout.tsx +18 -0
- package/app-template/src/app/[pz]/account/faq/layout.tsx +14 -0
- package/app-template/src/app/[pz]/account/favourite-products/layout.tsx +21 -0
- package/app-template/src/app/[pz]/account/layout.tsx +36 -3
- package/app-template/src/app/[pz]/account/orders/(list)/layout.tsx +20 -0
- package/app-template/src/app/[pz]/account/orders/[id]/(detail)/layout.tsx +40 -0
- package/app-template/src/app/[pz]/account/profile/layout.tsx +18 -0
- package/app-template/src/app/[pz]/auth/(login)/layout.tsx +37 -0
- package/app-template/src/app/[pz]/basket/layout.tsx +25 -0
- package/app-template/src/app/[pz]/client-root.tsx +2 -0
- package/app-template/src/app/[pz]/configure-page-context.ts +17 -0
- package/app-template/src/app/[pz]/layout.tsx +22 -3
- package/app-template/src/app/[pz]/orders/checkout/layout.tsx +47 -0
- package/app-template/src/app/[pz]/orders/checkout/page.tsx +75 -97
- package/app-template/src/app/[pz]/orders/completed/[token]/layout.tsx +24 -2
- package/app-template/src/app/[pz]/users/password/reset/layout.tsx +21 -0
- package/app-template/src/app/[pz]/users/reset/[[...id]]/layout.tsx +30 -0
- package/app-template/src/components/checkbox.tsx +22 -3
- package/app-template/src/components/route-handler.tsx +48 -0
- package/app-template/src/routes/index.ts +6 -6
- package/app-template/src/views/checkout/__tests__/part-style-reachability.test.ts +119 -0
- package/app-template/src/views/checkout/step-button.tsx +13 -2
- package/app-template/src/views/checkout/step-list.tsx +5 -1
- package/app-template/src/views/checkout/steps/payment/agreements.tsx +9 -1
- package/app-template/src/views/checkout/steps/payment/index.tsx +10 -2
- package/app-template/src/views/checkout/steps/payment/options/credit-card/index.tsx +2 -0
- package/app-template/src/views/checkout/steps/payment/options/funds-transfer.tsx +2 -0
- package/app-template/src/views/checkout/steps/payment/payment-header.tsx +5 -1
- package/app-template/src/views/checkout/steps/payment/payment-option-buttons.tsx +16 -4
- package/app-template/src/views/checkout/steps/shipping/addresses.tsx +2 -1
- package/app-template/src/views/checkout/steps/shipping/index.tsx +2 -0
- package/app-template/src/views/checkout/steps/shipping/shipping-options.tsx +2 -0
- package/app-template/src/views/checkout/summary.tsx +56 -18
- package/app-template/src/views/checkout/variants/__tests__/registry.test.tsx +82 -0
- package/app-template/src/views/checkout/variants/__tests__/use-resolved-config.test.tsx +208 -0
- package/app-template/src/views/checkout/variants/basket-and-checkout/basket-section.tsx +150 -0
- package/app-template/src/views/checkout/variants/basket-and-checkout/index.tsx +135 -0
- package/app-template/src/views/checkout/variants/multi-step/index.tsx +78 -0
- package/app-template/src/views/checkout/variants/one-page/accordion-section.tsx +165 -0
- package/app-template/src/views/checkout/variants/one-page/hooks/use-checkout-funnel-gtm.ts +60 -0
- package/app-template/src/views/checkout/variants/one-page/hooks/use-section-state.ts +103 -0
- package/app-template/src/views/checkout/variants/one-page/index.tsx +125 -0
- package/app-template/src/views/checkout/variants/one-page/mobile-summary-sheet.tsx +109 -0
- package/app-template/src/views/checkout/variants/one-page/one-page-summary.tsx +301 -0
- package/app-template/src/views/checkout/variants/one-page/payment-options-grid.tsx +220 -0
- package/app-template/src/views/checkout/variants/one-page/sections/address-section.tsx +320 -0
- package/app-template/src/views/checkout/variants/one-page/sections/contact-section.tsx +62 -0
- package/app-template/src/views/checkout/variants/one-page/sections/payment-section.tsx +73 -0
- package/app-template/src/views/checkout/variants/one-page/sections/shipping-section.tsx +328 -0
- package/app-template/src/views/checkout/variants/one-page/skeletons/address-skeleton.tsx +25 -0
- package/app-template/src/views/checkout/variants/one-page/skeletons/checkout-skeleton.tsx +27 -0
- package/app-template/src/views/checkout/variants/one-page/skeletons/index.ts +6 -0
- package/app-template/src/views/checkout/variants/one-page/skeletons/payment-skeleton.tsx +23 -0
- package/app-template/src/views/checkout/variants/one-page/skeletons/section-skeleton.tsx +47 -0
- package/app-template/src/views/checkout/variants/one-page/skeletons/shipping-skeleton.tsx +20 -0
- package/app-template/src/views/checkout/variants/one-page/skeletons/summary-skeleton.tsx +38 -0
- package/app-template/src/views/checkout/variants/one-page/trust-badges.tsx +35 -0
- package/app-template/src/views/checkout/variants/registry.ts +43 -0
- package/app-template/src/views/checkout/variants/types.ts +30 -0
- package/app-template/src/views/checkout/variants/use-resolved-config.ts +168 -0
- package/app-template/tailwind.config.js +3 -1
- package/dist/commands/plugins.js +23 -2
- package/package.json +1 -1
- package/app-template/src/app/[pz]/account/orders/[id]/layout.tsx +0 -5
- /package/app-template/src/app/[pz]/account/{page.tsx → (dashboard)/page.tsx} +0 -0
- /package/app-template/src/app/[pz]/account/orders/{page.tsx → (list)/page.tsx} +0 -0
- /package/app-template/src/app/[pz]/account/orders/[id]/{page.tsx → (detail)/page.tsx} +0 -0
- /package/app-template/src/app/[pz]/auth/{page.tsx → (login)/page.tsx} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ NEXTAUTH_URL=http://localhost:3000
|
|
|
4
4
|
NEXT_PUBLIC_MAP_API_KEY=YOUR_MAP_API_KEY
|
|
5
5
|
NEXT_PUBLIC_GTM_KEY=GTM_KEY
|
|
6
6
|
NEXT_PUBLIC_URL=http://localhost:3000
|
|
7
|
+
# Theme editor origins the storefront accepts postMessage from, comma-separated.
|
|
8
|
+
# Local: the editor dev server. Production: the theme editor extension's own
|
|
9
|
+
# origin (the document that embeds the storefront), not the Omnitron shell.
|
|
10
|
+
# Setting it also switches session cookies to SameSite=None, so a sign-in
|
|
11
|
+
# survives the editor's cross-site preview iframe.
|
|
12
|
+
NEXT_PUBLIC_THEME_EDITOR_ORIGINS=http://localhost:5174
|
|
7
13
|
SERVICE_BACKEND_URL=https://02fde10fee4440269e695aa10707dfaf.lb.akinoncloud.com
|
|
8
14
|
SITEMAP_S3_BUCKET_NAME=0fb534
|
|
9
15
|
NEXT_PUBLIC_VIRTUAL_TRY_ON_API_URL=https://d2a26507c7094f359aba349b96a96881.lb.akinoncloud.com
|
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# projectzeronext
|
|
2
2
|
|
|
3
|
+
## 1.126.20
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 55b89cb: ZERO-5206: Port the theme editor's app skeleton (chrome and page slots) to the v1 line
|
|
8
|
+
|
|
9
|
+
The `[pz]` layout now wraps the brand header and footer in `ChromeSlot` (the brand markup stays as the fallback) and mounts `ThemeModals`, so a designer can compose the header, the footer and modals from the theme editor. Basket, checkout (top/body/bottom outlets and the variants registry), auth, forgot and reset password, order success and the account area (menu, page body and the ten subpages) get the same slot layouts as 2.x, so the editor takes these pages over without any mounting in the brand. Account routes moved into route groups (`(dashboard)`, `orders/(list)`, `orders/[id]/(detail)`, `auth/(login)`); URLs are unchanged.
|
|
10
|
+
|
|
11
|
+
Inside the editor's cross-site preview iframe the storefront's cookies are now usable: when embedding is enabled (`NEXT_PUBLIC_THEME_EDITOR_ORIGINS` holds a valid origin, or outside production) the next-auth session, CSRF and callback cookies, the Django `csrftoken`, the commerce session cookies set at sign-in and the Set-Cookie headers relayed by the BFF and middlewares are sent as `SameSite=None; Secure`, and the BFF checks the request origin on every state-changing call. A storefront without the editor keeps the Lax defaults. The CSP `frame-ancestors` also lists the editor origins (`*.akinon.net`, `localhost:5174`).
|
|
12
|
+
|
|
13
|
+
The app depends on `@akinon/pz-theme` 2.0.143; `@akinon/pz-theme` and `@akinon/theme-contract` are transpiled and protected from plugin installs, and the Tailwind content globs include pz-theme's sources.
|
|
14
|
+
|
|
15
|
+
- Updated dependencies [55b89cb]
|
|
16
|
+
- @akinon/next@1.126.20
|
|
17
|
+
- @akinon/pz-virtual-try-on@1.126.20
|
|
18
|
+
- @akinon/pz-akifast@1.126.20
|
|
19
|
+
- @akinon/pz-apple-pay@1.126.20
|
|
20
|
+
- @akinon/pz-b2b@1.126.20
|
|
21
|
+
- @akinon/pz-basket-gift-pack@1.126.20
|
|
22
|
+
- @akinon/pz-bkm@1.126.20
|
|
23
|
+
- @akinon/pz-checkout-gift-pack@1.126.20
|
|
24
|
+
- @akinon/pz-click-collect@1.126.20
|
|
25
|
+
- @akinon/pz-credit-payment@1.126.20
|
|
26
|
+
- @akinon/pz-cybersource-uc@1.126.20
|
|
27
|
+
- @akinon/pz-flow-payment@1.126.20
|
|
28
|
+
- @akinon/pz-google-pay@1.126.20
|
|
29
|
+
- @akinon/pz-gpay@1.126.20
|
|
30
|
+
- @akinon/pz-haso@1.126.20
|
|
31
|
+
- @akinon/pz-hepsipay@1.126.20
|
|
32
|
+
- @akinon/pz-masterpass@1.126.20
|
|
33
|
+
- @akinon/pz-masterpass-rest@1.126.20
|
|
34
|
+
- @akinon/pz-multi-basket@1.126.20
|
|
35
|
+
- @akinon/pz-one-click-checkout@1.126.20
|
|
36
|
+
- @akinon/pz-otp@1.126.20
|
|
37
|
+
- @akinon/pz-pay-on-delivery@1.126.20
|
|
38
|
+
- @akinon/pz-saved-card@1.126.20
|
|
39
|
+
- @akinon/pz-similar-products@1.126.20
|
|
40
|
+
- @akinon/pz-tabby-extension@1.126.20
|
|
41
|
+
- @akinon/pz-tamara-extension@1.126.20
|
|
42
|
+
|
|
3
43
|
## 1.126.19
|
|
4
44
|
|
|
5
45
|
### Patch Changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "projectzeronext",
|
|
3
|
-
"version": "1.126.
|
|
3
|
+
"version": "1.126.20",
|
|
4
4
|
"private": true,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"scripts": {
|
|
@@ -24,32 +24,33 @@
|
|
|
24
24
|
"test:middleware": "jest middleware-matcher.test.ts --bail"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@akinon/next": "1.126.
|
|
28
|
-
"@akinon/pz-akifast": "1.126.
|
|
29
|
-
"@akinon/pz-apple-pay": "1.126.
|
|
30
|
-
"@akinon/pz-b2b": "1.126.
|
|
31
|
-
"@akinon/pz-basket-gift-pack": "1.126.
|
|
32
|
-
"@akinon/pz-bkm": "1.126.
|
|
33
|
-
"@akinon/pz-checkout-gift-pack": "1.126.
|
|
34
|
-
"@akinon/pz-click-collect": "1.126.
|
|
35
|
-
"@akinon/pz-credit-payment": "1.126.
|
|
36
|
-
"@akinon/pz-cybersource-uc": "1.126.
|
|
37
|
-
"@akinon/pz-flow-payment": "1.126.
|
|
38
|
-
"@akinon/pz-google-pay": "1.126.
|
|
39
|
-
"@akinon/pz-gpay": "1.126.
|
|
40
|
-
"@akinon/pz-haso": "1.126.
|
|
41
|
-
"@akinon/pz-hepsipay": "1.126.
|
|
42
|
-
"@akinon/pz-masterpass": "1.126.
|
|
43
|
-
"@akinon/pz-masterpass-rest": "1.126.
|
|
44
|
-
"@akinon/pz-multi-basket": "1.126.
|
|
45
|
-
"@akinon/pz-one-click-checkout": "1.126.
|
|
46
|
-
"@akinon/pz-otp": "1.126.
|
|
47
|
-
"@akinon/pz-pay-on-delivery": "1.126.
|
|
48
|
-
"@akinon/pz-saved-card": "1.126.
|
|
49
|
-
"@akinon/pz-similar-products": "1.126.
|
|
50
|
-
"@akinon/pz-tabby-extension": "1.126.
|
|
51
|
-
"@akinon/pz-tamara-extension": "1.126.
|
|
52
|
-
"@akinon/pz-
|
|
27
|
+
"@akinon/next": "1.126.20",
|
|
28
|
+
"@akinon/pz-akifast": "1.126.20",
|
|
29
|
+
"@akinon/pz-apple-pay": "1.126.20",
|
|
30
|
+
"@akinon/pz-b2b": "1.126.20",
|
|
31
|
+
"@akinon/pz-basket-gift-pack": "1.126.20",
|
|
32
|
+
"@akinon/pz-bkm": "1.126.20",
|
|
33
|
+
"@akinon/pz-checkout-gift-pack": "1.126.20",
|
|
34
|
+
"@akinon/pz-click-collect": "1.126.20",
|
|
35
|
+
"@akinon/pz-credit-payment": "1.126.20",
|
|
36
|
+
"@akinon/pz-cybersource-uc": "1.126.20",
|
|
37
|
+
"@akinon/pz-flow-payment": "1.126.20",
|
|
38
|
+
"@akinon/pz-google-pay": "1.126.20",
|
|
39
|
+
"@akinon/pz-gpay": "1.126.20",
|
|
40
|
+
"@akinon/pz-haso": "1.126.20",
|
|
41
|
+
"@akinon/pz-hepsipay": "1.126.20",
|
|
42
|
+
"@akinon/pz-masterpass": "1.126.20",
|
|
43
|
+
"@akinon/pz-masterpass-rest": "1.126.20",
|
|
44
|
+
"@akinon/pz-multi-basket": "1.126.20",
|
|
45
|
+
"@akinon/pz-one-click-checkout": "1.126.20",
|
|
46
|
+
"@akinon/pz-otp": "1.126.20",
|
|
47
|
+
"@akinon/pz-pay-on-delivery": "1.126.20",
|
|
48
|
+
"@akinon/pz-saved-card": "1.126.20",
|
|
49
|
+
"@akinon/pz-similar-products": "1.126.20",
|
|
50
|
+
"@akinon/pz-tabby-extension": "1.126.20",
|
|
51
|
+
"@akinon/pz-tamara-extension": "1.126.20",
|
|
52
|
+
"@akinon/pz-theme": "2.0.143",
|
|
53
|
+
"@akinon/pz-virtual-try-on": "1.126.20",
|
|
53
54
|
"@hookform/resolvers": "2.9.0",
|
|
54
55
|
"@next/third-parties": "14.1.0",
|
|
55
56
|
"@react-google-maps/api": "2.17.1",
|
|
@@ -72,7 +73,7 @@
|
|
|
72
73
|
"yup": "0.32.11"
|
|
73
74
|
},
|
|
74
75
|
"devDependencies": {
|
|
75
|
-
"@akinon/eslint-plugin-projectzero": "1.126.
|
|
76
|
+
"@akinon/eslint-plugin-projectzero": "1.126.20",
|
|
76
77
|
"@semantic-release/changelog": "6.0.2",
|
|
77
78
|
"@semantic-release/exec": "6.0.3",
|
|
78
79
|
"@semantic-release/git": "10.0.1",
|
|
@@ -160,5 +160,55 @@
|
|
|
160
160
|
"processing": "Processing...",
|
|
161
161
|
"pay_button": "Pay with Apple Pay",
|
|
162
162
|
"payment_failed": "Payment failed"
|
|
163
|
+
},
|
|
164
|
+
"one_page": {
|
|
165
|
+
"edit": "Edit",
|
|
166
|
+
"continue_to_shipping": "Continue to shipping",
|
|
167
|
+
"continue_to_payment": "Continue to payment",
|
|
168
|
+
"contact": {
|
|
169
|
+
"title": "Contact information",
|
|
170
|
+
"guest_user": "Guest user",
|
|
171
|
+
"guest_badge": "Guest",
|
|
172
|
+
"guest_note": "You are continuing checkout as a guest."
|
|
173
|
+
},
|
|
174
|
+
"address": {
|
|
175
|
+
"title": "Delivery & billing address",
|
|
176
|
+
"shipping_label": "Delivery address",
|
|
177
|
+
"billing_label": "Billing address",
|
|
178
|
+
"use_for_billing": "Use the same address for billing",
|
|
179
|
+
"same_as_shipping": "Same as shipping",
|
|
180
|
+
"pick_different_billing": "Pick a different address if you'd like a separate billing destination."
|
|
181
|
+
},
|
|
182
|
+
"shipping": {
|
|
183
|
+
"title": "Shipping method"
|
|
184
|
+
},
|
|
185
|
+
"payment": {
|
|
186
|
+
"title": "Payment",
|
|
187
|
+
"select_method": "Please select a payment method to continue.",
|
|
188
|
+
"no_options": "No payment options are available at the moment."
|
|
189
|
+
},
|
|
190
|
+
"summary": {
|
|
191
|
+
"show_summary": "Show order summary",
|
|
192
|
+
"hide_summary": "Hide order summary",
|
|
193
|
+
"review_title": "Order details",
|
|
194
|
+
"deliver_to": "Deliver to",
|
|
195
|
+
"shipping_method": "Shipping method",
|
|
196
|
+
"payment_method": "Payment method"
|
|
197
|
+
},
|
|
198
|
+
"trust": {
|
|
199
|
+
"secure_title": "Secure checkout",
|
|
200
|
+
"secure_note": "Your payment is encrypted and processed securely. We never store your card details."
|
|
201
|
+
},
|
|
202
|
+
"basket": {
|
|
203
|
+
"title": "Your cart",
|
|
204
|
+
"empty": "Your cart is empty.",
|
|
205
|
+
"show": "Show items",
|
|
206
|
+
"hide": "Hide items",
|
|
207
|
+
"quantity": "Quantity",
|
|
208
|
+
"increase": "Increase quantity",
|
|
209
|
+
"decrease": "Decrease quantity",
|
|
210
|
+
"remove": "Remove from cart",
|
|
211
|
+
"update_error": "Could not update the cart. Please try again."
|
|
212
|
+
}
|
|
163
213
|
}
|
|
164
214
|
}
|
|
@@ -159,5 +159,55 @@
|
|
|
159
159
|
"processing": "İşleniyor...",
|
|
160
160
|
"pay_button": "Apple Pay ile Öde",
|
|
161
161
|
"payment_failed": "Ödeme başarısız oldu"
|
|
162
|
+
},
|
|
163
|
+
"one_page": {
|
|
164
|
+
"edit": "Düzenle",
|
|
165
|
+
"continue_to_shipping": "Kargo seçimine geç",
|
|
166
|
+
"continue_to_payment": "Ödemeye geç",
|
|
167
|
+
"contact": {
|
|
168
|
+
"title": "İletişim bilgileri",
|
|
169
|
+
"guest_user": "Misafir kullanıcı",
|
|
170
|
+
"guest_badge": "Misafir",
|
|
171
|
+
"guest_note": "Alışverişe misafir olarak devam ediyorsunuz."
|
|
172
|
+
},
|
|
173
|
+
"address": {
|
|
174
|
+
"title": "Teslimat ve fatura adresi",
|
|
175
|
+
"shipping_label": "Teslimat adresi",
|
|
176
|
+
"billing_label": "Fatura adresi",
|
|
177
|
+
"use_for_billing": "Fatura adresi olarak da kullan",
|
|
178
|
+
"same_as_shipping": "Teslimat adresiyle aynı",
|
|
179
|
+
"pick_different_billing": "Faturayı farklı bir adrese istiyorsanız aşağıdan seçin."
|
|
180
|
+
},
|
|
181
|
+
"shipping": {
|
|
182
|
+
"title": "Kargo seçimi"
|
|
183
|
+
},
|
|
184
|
+
"payment": {
|
|
185
|
+
"title": "Ödeme",
|
|
186
|
+
"select_method": "Devam etmek için bir ödeme yöntemi seçin.",
|
|
187
|
+
"no_options": "Şu anda kullanılabilir bir ödeme yöntemi bulunmuyor."
|
|
188
|
+
},
|
|
189
|
+
"summary": {
|
|
190
|
+
"show_summary": "Sipariş özetini göster",
|
|
191
|
+
"hide_summary": "Sipariş özetini gizle",
|
|
192
|
+
"review_title": "Sipariş detayları",
|
|
193
|
+
"deliver_to": "Teslim adresi",
|
|
194
|
+
"shipping_method": "Kargo yöntemi",
|
|
195
|
+
"payment_method": "Ödeme yöntemi"
|
|
196
|
+
},
|
|
197
|
+
"trust": {
|
|
198
|
+
"secure_title": "Güvenli ödeme",
|
|
199
|
+
"secure_note": "Ödemeniz şifrelenir ve güvenli olarak işlenir. Kart bilgileriniz saklanmaz."
|
|
200
|
+
},
|
|
201
|
+
"basket": {
|
|
202
|
+
"title": "Sepetiniz",
|
|
203
|
+
"empty": "Sepetiniz boş.",
|
|
204
|
+
"show": "Ürünleri göster",
|
|
205
|
+
"hide": "Ürünleri gizle",
|
|
206
|
+
"quantity": "Adet",
|
|
207
|
+
"increase": "Adedi artır",
|
|
208
|
+
"decrease": "Adedi azalt",
|
|
209
|
+
"remove": "Sepetten çıkar",
|
|
210
|
+
"update_error": "Sepet güncellenemedi. Lütfen tekrar deneyin."
|
|
211
|
+
}
|
|
162
212
|
}
|
|
163
213
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { PLACEHOLDER_SLUGS } from '@akinon/pz-theme/src/chrome/placeholder-slugs';
|
|
2
|
+
import { ROUTES } from 'routes';
|
|
3
|
+
import AccountPageSlot from '../account-page-slot';
|
|
4
|
+
|
|
5
|
+
// The account root screen lives in its own route group so its takeover slug
|
|
6
|
+
// covers exactly this screen, not the whole account subtree.
|
|
7
|
+
export default function DashboardLayout({
|
|
8
|
+
children
|
|
9
|
+
}: {
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
}) {
|
|
12
|
+
return (
|
|
13
|
+
<AccountPageSlot
|
|
14
|
+
slug={PLACEHOLDER_SLUGS.accountDashboard}
|
|
15
|
+
path={ROUTES.ACCOUNT}
|
|
16
|
+
>
|
|
17
|
+
{children}
|
|
18
|
+
</AccountPageSlot>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import ChromeSlot from '@akinon/pz-theme/src/chrome/chrome-slot';
|
|
2
|
+
import { buildAccountPageContext } from '@akinon/pz-theme/src/chrome/page-context';
|
|
3
|
+
import { getServerSession } from 'next-auth/next';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Shared takeover slot for the account subpages. Each subpage keeps its own
|
|
7
|
+
* layout so a composition replaces exactly one screen — a single slot higher
|
|
8
|
+
* up would leak one composition across every account route.
|
|
9
|
+
*/
|
|
10
|
+
export default async function AccountPageSlot({
|
|
11
|
+
slug,
|
|
12
|
+
path,
|
|
13
|
+
children
|
|
14
|
+
}: {
|
|
15
|
+
slug: string;
|
|
16
|
+
path: string;
|
|
17
|
+
children: React.ReactNode;
|
|
18
|
+
}) {
|
|
19
|
+
// The account layout above already gates auth; this read only feeds the
|
|
20
|
+
// context's user fields. Null-safe on purpose: nested layouts render in
|
|
21
|
+
// parallel with the parent's redirect for signed-out visitors.
|
|
22
|
+
const session = await getServerSession();
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<ChromeSlot
|
|
26
|
+
slug={slug}
|
|
27
|
+
fallback={children}
|
|
28
|
+
pageContext={buildAccountPageContext({
|
|
29
|
+
path,
|
|
30
|
+
sessionUser:
|
|
31
|
+
(session?.user as unknown as Record<string, unknown>) ?? null
|
|
32
|
+
})}
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PLACEHOLDER_SLUGS } from '@akinon/pz-theme/src/chrome/placeholder-slugs';
|
|
2
|
+
import { ROUTES } from 'routes';
|
|
3
|
+
import AccountPageSlot from '../account-page-slot';
|
|
4
|
+
|
|
5
|
+
export default function AddressLayout({
|
|
6
|
+
children
|
|
7
|
+
}: {
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
}) {
|
|
10
|
+
return (
|
|
11
|
+
<AccountPageSlot
|
|
12
|
+
slug={PLACEHOLDER_SLUGS.accountAddresses}
|
|
13
|
+
path={ROUTES.ACCOUNT_ADDRESS}
|
|
14
|
+
>
|
|
15
|
+
{children}
|
|
16
|
+
</AccountPageSlot>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PLACEHOLDER_SLUGS } from '@akinon/pz-theme/src/chrome/placeholder-slugs';
|
|
2
|
+
import { ROUTES } from 'routes';
|
|
3
|
+
import AccountPageSlot from '../account-page-slot';
|
|
4
|
+
|
|
5
|
+
export default function ChangeEmailLayout({
|
|
6
|
+
children
|
|
7
|
+
}: {
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
}) {
|
|
10
|
+
return (
|
|
11
|
+
<AccountPageSlot
|
|
12
|
+
slug={PLACEHOLDER_SLUGS.accountChangeEmail}
|
|
13
|
+
path={ROUTES.ACCOUNT_CHANGE_EMAIL}
|
|
14
|
+
>
|
|
15
|
+
{children}
|
|
16
|
+
</AccountPageSlot>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PLACEHOLDER_SLUGS } from '@akinon/pz-theme/src/chrome/placeholder-slugs';
|
|
2
|
+
import { ROUTES } from 'routes';
|
|
3
|
+
import AccountPageSlot from '../account-page-slot';
|
|
4
|
+
|
|
5
|
+
export default function ChangePasswordLayout({
|
|
6
|
+
children
|
|
7
|
+
}: {
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
}) {
|
|
10
|
+
return (
|
|
11
|
+
<AccountPageSlot
|
|
12
|
+
slug={PLACEHOLDER_SLUGS.accountChangePassword}
|
|
13
|
+
path={ROUTES.ACCOUNT_CHANGE_PASSWORD}
|
|
14
|
+
>
|
|
15
|
+
{children}
|
|
16
|
+
</AccountPageSlot>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PLACEHOLDER_SLUGS } from '@akinon/pz-theme/src/chrome/placeholder-slugs';
|
|
2
|
+
import { ROUTES } from 'routes';
|
|
3
|
+
import AccountPageSlot from '../account-page-slot';
|
|
4
|
+
|
|
5
|
+
export default function ContactLayout({
|
|
6
|
+
children
|
|
7
|
+
}: {
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
}) {
|
|
10
|
+
return (
|
|
11
|
+
<AccountPageSlot
|
|
12
|
+
slug={PLACEHOLDER_SLUGS.accountContact}
|
|
13
|
+
path={ROUTES.ACCOUNT_CONTACT}
|
|
14
|
+
>
|
|
15
|
+
{children}
|
|
16
|
+
</AccountPageSlot>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PLACEHOLDER_SLUGS } from '@akinon/pz-theme/src/chrome/placeholder-slugs';
|
|
2
|
+
import { ROUTES } from 'routes';
|
|
3
|
+
import AccountPageSlot from '../account-page-slot';
|
|
4
|
+
|
|
5
|
+
export default function CouponsLayout({
|
|
6
|
+
children
|
|
7
|
+
}: {
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
}) {
|
|
10
|
+
return (
|
|
11
|
+
<AccountPageSlot
|
|
12
|
+
slug={PLACEHOLDER_SLUGS.accountCoupons}
|
|
13
|
+
path={ROUTES.ACCOUNT_COUPONS}
|
|
14
|
+
>
|
|
15
|
+
{children}
|
|
16
|
+
</AccountPageSlot>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { PLACEHOLDER_SLUGS } from '@akinon/pz-theme/src/chrome/placeholder-slugs';
|
|
2
|
+
import { ROUTES } from 'routes';
|
|
3
|
+
import AccountPageSlot from '../account-page-slot';
|
|
4
|
+
|
|
5
|
+
export default function FaqLayout({ children }: { children: React.ReactNode }) {
|
|
6
|
+
return (
|
|
7
|
+
<AccountPageSlot
|
|
8
|
+
slug={PLACEHOLDER_SLUGS.accountFaq}
|
|
9
|
+
path={ROUTES.ACCOUNT_FAQ}
|
|
10
|
+
>
|
|
11
|
+
{children}
|
|
12
|
+
</AccountPageSlot>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { PLACEHOLDER_SLUGS } from '@akinon/pz-theme/src/chrome/placeholder-slugs';
|
|
2
|
+
import { LiveWishlistPageContext } from '@akinon/pz-theme/src/chrome/live-wishlist-page-context';
|
|
3
|
+
import { ROUTES } from 'routes';
|
|
4
|
+
import AccountPageSlot from '../account-page-slot';
|
|
5
|
+
|
|
6
|
+
export default function FavouriteProductsLayout({
|
|
7
|
+
children
|
|
8
|
+
}: {
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
}) {
|
|
11
|
+
return (
|
|
12
|
+
<LiveWishlistPageContext>
|
|
13
|
+
<AccountPageSlot
|
|
14
|
+
slug={PLACEHOLDER_SLUGS.accountFavourites}
|
|
15
|
+
path={ROUTES.ACCOUNT_WISHLIST}
|
|
16
|
+
>
|
|
17
|
+
{children}
|
|
18
|
+
</AccountPageSlot>
|
|
19
|
+
</LiveWishlistPageContext>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import AccountBackButton from '@theme/views/account/back-button';
|
|
2
2
|
import AccountMenu from '@theme/views/account/account-menu';
|
|
3
|
+
import ChromeSlot from '@akinon/pz-theme/src/chrome/chrome-slot';
|
|
4
|
+
import { PLACEHOLDER_SLUGS } from '@akinon/pz-theme/src/chrome/placeholder-slugs';
|
|
5
|
+
import { buildAccountPageContext } from '@akinon/pz-theme/src/chrome/page-context';
|
|
3
6
|
import { getServerSession } from 'next-auth/next';
|
|
4
7
|
import { ROUTES } from 'routes';
|
|
5
8
|
import { redirect } from '@akinon/next/utils/redirect';
|
|
@@ -16,11 +19,41 @@ export default async function AccountLayout({
|
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
return (
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
// Stacked on mobile, two columns on desktop. The brand markup hides
|
|
23
|
+
// itself on the breakpoints it does not serve, but a COMPOSED menu or
|
|
24
|
+
// page body has no such classes — in a no-wrap row it would render
|
|
25
|
+
// crushed next to its sibling on a phone; in a column it stacks.
|
|
26
|
+
<div className="container flex flex-col lg:flex-row py-10 px-4 xl:px-0">
|
|
27
|
+
{/* The menu keeps its own responsive column classes (incl. hiding
|
|
28
|
+
itself on mobile subpages), so the slot chain must stay
|
|
29
|
+
layout-transparent — hence `contents` on both wrappers. A menu
|
|
30
|
+
takeover renders on every account screen and replaces the logout
|
|
31
|
+
button too; the designer rebuilds it from the block vocabulary. */}
|
|
32
|
+
<ChromeSlot
|
|
33
|
+
slug={PLACEHOLDER_SLUGS.accountMenu}
|
|
34
|
+
fallback={<AccountMenu />}
|
|
35
|
+
className="contents"
|
|
36
|
+
fallbackClassName="contents"
|
|
37
|
+
pageContext={buildAccountPageContext({
|
|
38
|
+
path: ROUTES.ACCOUNT,
|
|
39
|
+
sessionUser: session.user as unknown as Record<string, unknown>
|
|
40
|
+
})}
|
|
41
|
+
/>
|
|
21
42
|
<div className="w-full flex-1">
|
|
22
43
|
<AccountBackButton />
|
|
23
|
-
|
|
44
|
+
{/* The session is already awaited above, so the account context costs
|
|
45
|
+
no extra fetch. Profile-only fields (phone, gender) stay empty
|
|
46
|
+
until a live provider merges them in. */}
|
|
47
|
+
{/* Layout-level band on EVERY account screen. Never give this slot a
|
|
48
|
+
`fallback`: taking the shell over would replace `children` — and
|
|
49
|
+
with it every per-subpage slot mounted below. */}
|
|
50
|
+
<ChromeSlot
|
|
51
|
+
slug={PLACEHOLDER_SLUGS.accountShell}
|
|
52
|
+
pageContext={buildAccountPageContext({
|
|
53
|
+
path: ROUTES.ACCOUNT,
|
|
54
|
+
sessionUser: session.user as unknown as Record<string, unknown>
|
|
55
|
+
})}
|
|
56
|
+
/>
|
|
24
57
|
{children}
|
|
25
58
|
</div>
|
|
26
59
|
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { PLACEHOLDER_SLUGS } from '@akinon/pz-theme/src/chrome/placeholder-slugs';
|
|
2
|
+
import { ROUTES } from 'routes';
|
|
3
|
+
import AccountPageSlot from '../../account-page-slot';
|
|
4
|
+
|
|
5
|
+
// The order list lives in its own route group so its takeover slug cannot
|
|
6
|
+
// swallow the order detail and cancellation screens under the same segment.
|
|
7
|
+
export default function OrdersLayout({
|
|
8
|
+
children
|
|
9
|
+
}: {
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
}) {
|
|
12
|
+
return (
|
|
13
|
+
<AccountPageSlot
|
|
14
|
+
slug={PLACEHOLDER_SLUGS.accountOrders}
|
|
15
|
+
path={ROUTES.ACCOUNT_ORDERS}
|
|
16
|
+
>
|
|
17
|
+
{children}
|
|
18
|
+
</AccountPageSlot>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import ChromeSlot from '@akinon/pz-theme/src/chrome/chrome-slot';
|
|
3
|
+
import { PLACEHOLDER_SLUGS } from '@akinon/pz-theme/src/chrome/placeholder-slugs';
|
|
4
|
+
import { LiveAccountOrderPageContext } from '@akinon/pz-theme/src/chrome/live-order-page-context';
|
|
5
|
+
import { buildAccountPageContext } from '@akinon/pz-theme/src/chrome/page-context';
|
|
6
|
+
import { getServerSession } from 'next-auth/next';
|
|
7
|
+
import { ROUTES } from 'routes';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Account order detail. Publishes the SAME `order` root as the success page,
|
|
11
|
+
* so a composition authored on one resolves on the other. Scoped to its own
|
|
12
|
+
* route group so a composed detail page cannot swallow the cancellation
|
|
13
|
+
* screen under the same order segment.
|
|
14
|
+
*/
|
|
15
|
+
export default async function Layout({
|
|
16
|
+
children,
|
|
17
|
+
params
|
|
18
|
+
}: {
|
|
19
|
+
children: React.ReactNode;
|
|
20
|
+
params: { id: string };
|
|
21
|
+
}) {
|
|
22
|
+
const { id } = params;
|
|
23
|
+
const session = await getServerSession();
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div>
|
|
27
|
+
<LiveAccountOrderPageContext orderId={id}>
|
|
28
|
+
<ChromeSlot
|
|
29
|
+
slug={PLACEHOLDER_SLUGS.accountOrderDetail}
|
|
30
|
+
fallback={children}
|
|
31
|
+
pageContext={buildAccountPageContext({
|
|
32
|
+
path: ROUTES.ACCOUNT_ORDERS,
|
|
33
|
+
sessionUser:
|
|
34
|
+
(session?.user as unknown as Record<string, unknown>) ?? null
|
|
35
|
+
})}
|
|
36
|
+
/>
|
|
37
|
+
</LiveAccountOrderPageContext>
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PLACEHOLDER_SLUGS } from '@akinon/pz-theme/src/chrome/placeholder-slugs';
|
|
2
|
+
import { ROUTES } from 'routes';
|
|
3
|
+
import AccountPageSlot from '../account-page-slot';
|
|
4
|
+
|
|
5
|
+
export default function ProfileLayout({
|
|
6
|
+
children
|
|
7
|
+
}: {
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
}) {
|
|
10
|
+
return (
|
|
11
|
+
<AccountPageSlot
|
|
12
|
+
slug={PLACEHOLDER_SLUGS.accountProfile}
|
|
13
|
+
path={ROUTES.ACCOUNT_PROFILE}
|
|
14
|
+
>
|
|
15
|
+
{children}
|
|
16
|
+
</AccountPageSlot>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import ChromeSlot from '@akinon/pz-theme/src/chrome/chrome-slot';
|
|
2
|
+
import { PLACEHOLDER_SLUGS } from '@akinon/pz-theme/src/chrome/placeholder-slugs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The login screen is handed to the theme editor here rather than in page.tsx,
|
|
6
|
+
* because the slot is an async server component and the page is a client one.
|
|
7
|
+
* With no composition published the slot renders the page untouched.
|
|
8
|
+
*
|
|
9
|
+
* The slot lives in a `(login)` route group so the composition covers exactly
|
|
10
|
+
* this screen: `auth/oauth-login` is a provider callback, and a login body
|
|
11
|
+
* mounted one level up would replace it too.
|
|
12
|
+
*
|
|
13
|
+
* No `pageContext`: an auth screen fetches no commerce data, and the blocks a
|
|
14
|
+
* designer rebuilds it from (`auth-form`, `register-form`, `oauth-buttons`)
|
|
15
|
+
* read the session client-side.
|
|
16
|
+
*
|
|
17
|
+
* Login and register stay on this ONE screen. Whether they read as tabs or as
|
|
18
|
+
* two forms side by side is composed here (the starter templates ship both
|
|
19
|
+
* shapes), so no second route is involved.
|
|
20
|
+
*/
|
|
21
|
+
export default function LoginLayout({
|
|
22
|
+
children
|
|
23
|
+
}: {
|
|
24
|
+
children: React.ReactNode;
|
|
25
|
+
}) {
|
|
26
|
+
return (
|
|
27
|
+
// `contents` on both wrappers keeps the slot chain layout-transparent, so
|
|
28
|
+
// an uncomposed login page keeps its own box model even where a brand's
|
|
29
|
+
// <main> is a flex or grid container.
|
|
30
|
+
<ChromeSlot
|
|
31
|
+
slug={PLACEHOLDER_SLUGS.auth}
|
|
32
|
+
fallback={children}
|
|
33
|
+
className="contents"
|
|
34
|
+
fallbackClassName="contents"
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import ChromeSlot from '@akinon/pz-theme/src/chrome/chrome-slot';
|
|
2
|
+
import { LiveBasketPageContext } from '@akinon/pz-theme/src/chrome/live-basket-page-context';
|
|
3
|
+
import { PLACEHOLDER_SLUGS } from '@akinon/pz-theme/src/chrome/placeholder-slugs';
|
|
4
|
+
import { ROUTES } from '@theme/routes';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The basket body is handed to the theme editor here rather than in page.tsx,
|
|
8
|
+
* because the slot is an async server component and the page is a client one.
|
|
9
|
+
* With no composition published the slot renders the page untouched.
|
|
10
|
+
*
|
|
11
|
+
* The provider sits above the slot so the composition binds the shopper's live
|
|
12
|
+
* basket: the basket is session-scoped and has no server data module, so a
|
|
13
|
+
* server-built context would be a snapshot that never moves.
|
|
14
|
+
*/
|
|
15
|
+
export default function BasketLayout({
|
|
16
|
+
children
|
|
17
|
+
}: {
|
|
18
|
+
children: React.ReactNode;
|
|
19
|
+
}) {
|
|
20
|
+
return (
|
|
21
|
+
<LiveBasketPageContext path={ROUTES.BASKET}>
|
|
22
|
+
<ChromeSlot slug={PLACEHOLDER_SLUGS.basket} fallback={children} />
|
|
23
|
+
</LiveBasketPageContext>
|
|
24
|
+
);
|
|
25
|
+
}
|