@akinon/projectzero 2.0.32 → 2.0.33-beta.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.
Files changed (35) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/app-template/CHANGELOG.md +34 -0
  3. package/app-template/package.json +29 -29
  4. package/app-template/public/locales/en/checkout.json +50 -0
  5. package/app-template/public/locales/tr/checkout.json +50 -0
  6. package/app-template/src/app/[pz]/basket/page.tsx +33 -6
  7. package/app-template/src/app/[pz]/orders/checkout/page.tsx +57 -92
  8. package/app-template/src/app/api/theme-settings/route.ts +21 -2
  9. package/app-template/src/data/server/theme.ts +6 -25
  10. package/app-template/src/views/checkout/variants/basket-and-checkout/basket-section.tsx +149 -0
  11. package/app-template/src/views/checkout/variants/basket-and-checkout/index.tsx +132 -0
  12. package/app-template/src/views/checkout/variants/multi-step/index.tsx +73 -0
  13. package/app-template/src/views/checkout/variants/one-page/accordion-section.tsx +140 -0
  14. package/app-template/src/views/checkout/variants/one-page/hooks/use-checkout-funnel-gtm.ts +60 -0
  15. package/app-template/src/views/checkout/variants/one-page/hooks/use-section-state.ts +99 -0
  16. package/app-template/src/views/checkout/variants/one-page/index.tsx +125 -0
  17. package/app-template/src/views/checkout/variants/one-page/mobile-summary-sheet.tsx +109 -0
  18. package/app-template/src/views/checkout/variants/one-page/one-page-summary.tsx +237 -0
  19. package/app-template/src/views/checkout/variants/one-page/payment-options-grid.tsx +201 -0
  20. package/app-template/src/views/checkout/variants/one-page/sections/address-section.tsx +318 -0
  21. package/app-template/src/views/checkout/variants/one-page/sections/contact-section.tsx +62 -0
  22. package/app-template/src/views/checkout/variants/one-page/sections/payment-section.tsx +71 -0
  23. package/app-template/src/views/checkout/variants/one-page/sections/shipping-section.tsx +298 -0
  24. package/app-template/src/views/checkout/variants/one-page/skeletons/address-skeleton.tsx +25 -0
  25. package/app-template/src/views/checkout/variants/one-page/skeletons/checkout-skeleton.tsx +27 -0
  26. package/app-template/src/views/checkout/variants/one-page/skeletons/index.ts +6 -0
  27. package/app-template/src/views/checkout/variants/one-page/skeletons/payment-skeleton.tsx +23 -0
  28. package/app-template/src/views/checkout/variants/one-page/skeletons/section-skeleton.tsx +47 -0
  29. package/app-template/src/views/checkout/variants/one-page/skeletons/shipping-skeleton.tsx +20 -0
  30. package/app-template/src/views/checkout/variants/one-page/skeletons/summary-skeleton.tsx +38 -0
  31. package/app-template/src/views/checkout/variants/one-page/trust-badges.tsx +30 -0
  32. package/app-template/src/views/checkout/variants/registry.ts +32 -0
  33. package/app-template/src/views/checkout/variants/types.ts +30 -0
  34. package/app-template/src/views/checkout/variants/use-resolved-config.ts +89 -0
  35. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # @akinon/projectzero
2
2
 
3
+ ## 2.0.33-beta.0
4
+
3
5
  ## 2.0.32
4
6
 
5
7
  ## 2.0.31
@@ -1,9 +1,43 @@
1
1
  # projectzeronext
2
2
 
3
+ ## 2.0.33-beta.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [cbbbfd75]
8
+ - @akinon/next@2.0.33-beta.0
9
+ - @akinon/pz-theme@2.0.33-beta.0
10
+ - @akinon/pz-virtual-try-on@2.0.33-beta.0
11
+ - @akinon/pz-akifast@2.0.33-beta.0
12
+ - @akinon/pz-apple-pay@2.0.33-beta.0
13
+ - @akinon/pz-b2b@2.0.33-beta.0
14
+ - @akinon/pz-basket-gift-pack@2.0.33-beta.0
15
+ - @akinon/pz-bkm@2.0.33-beta.0
16
+ - @akinon/pz-checkout-gift-pack@2.0.33-beta.0
17
+ - @akinon/pz-click-collect@2.0.33-beta.0
18
+ - @akinon/pz-credit-payment@2.0.33-beta.0
19
+ - @akinon/pz-cybersource-uc@2.0.33-beta.0
20
+ - @akinon/pz-flow-payment@2.0.33-beta.0
21
+ - @akinon/pz-google-pay@2.0.33-beta.0
22
+ - @akinon/pz-gpay@2.0.33-beta.0
23
+ - @akinon/pz-haso@2.0.33-beta.0
24
+ - @akinon/pz-hepsipay@2.0.33-beta.0
25
+ - @akinon/pz-masterpass@2.0.33-beta.0
26
+ - @akinon/pz-masterpass-rest@2.0.33-beta.0
27
+ - @akinon/pz-multi-basket@2.0.33-beta.0
28
+ - @akinon/pz-one-click-checkout@2.0.33-beta.0
29
+ - @akinon/pz-otp@2.0.33-beta.0
30
+ - @akinon/pz-pay-on-delivery@2.0.33-beta.0
31
+ - @akinon/pz-saved-card@2.0.33-beta.0
32
+ - @akinon/pz-similar-products@2.0.33-beta.0
33
+ - @akinon/pz-tabby-extension@2.0.33-beta.0
34
+ - @akinon/pz-tamara-extension@2.0.33-beta.0
35
+
3
36
  ## 2.0.32
4
37
 
5
38
  ### Patch Changes
6
39
 
40
+ - 275fca44: ZERO-4429: Add settings-driven checkout variant system
7
41
  - Updated dependencies [239aa9d0]
8
42
  - @akinon/next@2.0.32
9
43
  - @akinon/pz-theme@2.0.32
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "projectzeronext",
3
- "version": "2.0.32",
3
+ "version": "2.0.33-beta.0",
4
4
  "private": true,
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -24,33 +24,33 @@
24
24
  "test:middleware": "jest middleware-matcher.test.ts --bail"
25
25
  },
26
26
  "dependencies": {
27
- "@akinon/next": "2.0.32",
28
- "@akinon/pz-akifast": "2.0.32",
29
- "@akinon/pz-apple-pay": "2.0.32",
30
- "@akinon/pz-b2b": "2.0.32",
31
- "@akinon/pz-basket-gift-pack": "2.0.32",
32
- "@akinon/pz-bkm": "2.0.32",
33
- "@akinon/pz-checkout-gift-pack": "2.0.32",
34
- "@akinon/pz-click-collect": "2.0.32",
35
- "@akinon/pz-credit-payment": "2.0.32",
36
- "@akinon/pz-cybersource-uc": "2.0.32",
37
- "@akinon/pz-flow-payment": "2.0.32",
38
- "@akinon/pz-google-pay": "2.0.32",
39
- "@akinon/pz-gpay": "2.0.32",
40
- "@akinon/pz-haso": "2.0.32",
41
- "@akinon/pz-hepsipay": "2.0.32",
42
- "@akinon/pz-masterpass": "2.0.32",
43
- "@akinon/pz-masterpass-rest": "2.0.32",
44
- "@akinon/pz-multi-basket": "2.0.32",
45
- "@akinon/pz-one-click-checkout": "2.0.32",
46
- "@akinon/pz-otp": "2.0.32",
47
- "@akinon/pz-pay-on-delivery": "2.0.32",
48
- "@akinon/pz-saved-card": "2.0.32",
49
- "@akinon/pz-similar-products": "2.0.32",
50
- "@akinon/pz-tabby-extension": "2.0.32",
51
- "@akinon/pz-tamara-extension": "2.0.32",
52
- "@akinon/pz-theme": "2.0.32",
53
- "@akinon/pz-virtual-try-on": "2.0.32",
27
+ "@akinon/next": "2.0.33-beta.0",
28
+ "@akinon/pz-akifast": "2.0.33-beta.0",
29
+ "@akinon/pz-apple-pay": "2.0.33-beta.0",
30
+ "@akinon/pz-b2b": "2.0.33-beta.0",
31
+ "@akinon/pz-basket-gift-pack": "2.0.33-beta.0",
32
+ "@akinon/pz-bkm": "2.0.33-beta.0",
33
+ "@akinon/pz-checkout-gift-pack": "2.0.33-beta.0",
34
+ "@akinon/pz-click-collect": "2.0.33-beta.0",
35
+ "@akinon/pz-credit-payment": "2.0.33-beta.0",
36
+ "@akinon/pz-cybersource-uc": "2.0.33-beta.0",
37
+ "@akinon/pz-flow-payment": "2.0.33-beta.0",
38
+ "@akinon/pz-google-pay": "2.0.33-beta.0",
39
+ "@akinon/pz-gpay": "2.0.33-beta.0",
40
+ "@akinon/pz-haso": "2.0.33-beta.0",
41
+ "@akinon/pz-hepsipay": "2.0.33-beta.0",
42
+ "@akinon/pz-masterpass": "2.0.33-beta.0",
43
+ "@akinon/pz-masterpass-rest": "2.0.33-beta.0",
44
+ "@akinon/pz-multi-basket": "2.0.33-beta.0",
45
+ "@akinon/pz-one-click-checkout": "2.0.33-beta.0",
46
+ "@akinon/pz-otp": "2.0.33-beta.0",
47
+ "@akinon/pz-pay-on-delivery": "2.0.33-beta.0",
48
+ "@akinon/pz-saved-card": "2.0.33-beta.0",
49
+ "@akinon/pz-similar-products": "2.0.33-beta.0",
50
+ "@akinon/pz-tabby-extension": "2.0.33-beta.0",
51
+ "@akinon/pz-tamara-extension": "2.0.33-beta.0",
52
+ "@akinon/pz-theme": "2.0.33-beta.0",
53
+ "@akinon/pz-virtual-try-on": "2.0.33-beta.0",
54
54
  "@hookform/resolvers": "2.9.0",
55
55
  "@next/third-parties": "16.2.6",
56
56
  "@react-google-maps/api": "2.17.1",
@@ -74,7 +74,7 @@
74
74
  "yup": "0.32.11"
75
75
  },
76
76
  "devDependencies": {
77
- "@akinon/eslint-plugin-projectzero": "2.0.32",
77
+ "@akinon/eslint-plugin-projectzero": "2.0.33-beta.0",
78
78
  "@semantic-release/changelog": "6.0.2",
79
79
  "@semantic-release/exec": "6.0.3",
80
80
  "@semantic-release/git": "10.0.1",
@@ -161,5 +161,55 @@
161
161
  "processing": "Processing...",
162
162
  "pay_button": "Pay with Apple Pay",
163
163
  "payment_failed": "Payment failed"
164
+ },
165
+ "one_page": {
166
+ "edit": "Edit",
167
+ "continue_to_shipping": "Continue to shipping",
168
+ "continue_to_payment": "Continue to payment",
169
+ "contact": {
170
+ "title": "Contact information",
171
+ "guest_user": "Guest user",
172
+ "guest_badge": "Guest",
173
+ "guest_note": "You are continuing checkout as a guest."
174
+ },
175
+ "address": {
176
+ "title": "Delivery & billing address",
177
+ "shipping_label": "Delivery address",
178
+ "billing_label": "Billing address",
179
+ "use_for_billing": "Use the same address for billing",
180
+ "same_as_shipping": "Same as shipping",
181
+ "pick_different_billing": "Pick a different address if you'd like a separate billing destination."
182
+ },
183
+ "shipping": {
184
+ "title": "Shipping method"
185
+ },
186
+ "payment": {
187
+ "title": "Payment",
188
+ "select_method": "Please select a payment method to continue.",
189
+ "no_options": "No payment options are available at the moment."
190
+ },
191
+ "summary": {
192
+ "show_summary": "Show order summary",
193
+ "hide_summary": "Hide order summary",
194
+ "review_title": "Order details",
195
+ "deliver_to": "Deliver to",
196
+ "shipping_method": "Shipping method",
197
+ "payment_method": "Payment method"
198
+ },
199
+ "trust": {
200
+ "secure_title": "Secure checkout",
201
+ "secure_note": "Your payment is encrypted and processed securely. We never store your card details."
202
+ },
203
+ "basket": {
204
+ "title": "Your cart",
205
+ "empty": "Your cart is empty.",
206
+ "show": "Show items",
207
+ "hide": "Hide items",
208
+ "quantity": "Quantity",
209
+ "increase": "Increase quantity",
210
+ "decrease": "Decrease quantity",
211
+ "remove": "Remove from cart",
212
+ "update_error": "Could not update the cart. Please try again."
213
+ }
164
214
  }
165
215
  }
@@ -160,5 +160,55 @@
160
160
  "processing": "İşleniyor...",
161
161
  "pay_button": "Apple Pay ile Öde",
162
162
  "payment_failed": "Ödeme başarısız oldu"
163
+ },
164
+ "one_page": {
165
+ "edit": "Düzenle",
166
+ "continue_to_shipping": "Kargo seçimine geç",
167
+ "continue_to_payment": "Ödemeye geç",
168
+ "contact": {
169
+ "title": "İletişim bilgileri",
170
+ "guest_user": "Misafir kullanıcı",
171
+ "guest_badge": "Misafir",
172
+ "guest_note": "Alışverişe misafir olarak devam ediyorsunuz."
173
+ },
174
+ "address": {
175
+ "title": "Teslimat ve fatura adresi",
176
+ "shipping_label": "Teslimat adresi",
177
+ "billing_label": "Fatura adresi",
178
+ "use_for_billing": "Fatura adresi olarak da kullan",
179
+ "same_as_shipping": "Teslimat adresiyle aynı",
180
+ "pick_different_billing": "Faturayı farklı bir adrese istiyorsanız aşağıdan seçin."
181
+ },
182
+ "shipping": {
183
+ "title": "Kargo seçimi"
184
+ },
185
+ "payment": {
186
+ "title": "Ödeme",
187
+ "select_method": "Devam etmek için bir ödeme yöntemi seçin.",
188
+ "no_options": "Şu anda kullanılabilir bir ödeme yöntemi bulunmuyor."
189
+ },
190
+ "summary": {
191
+ "show_summary": "Sipariş özetini göster",
192
+ "hide_summary": "Sipariş özetini gizle",
193
+ "review_title": "Sipariş detayları",
194
+ "deliver_to": "Teslim adresi",
195
+ "shipping_method": "Kargo yöntemi",
196
+ "payment_method": "Ödeme yöntemi"
197
+ },
198
+ "trust": {
199
+ "secure_title": "Güvenli ödeme",
200
+ "secure_note": "Ödemeniz şifrelenir ve güvenli olarak işlenir. Kart bilgileriniz saklanmaz."
201
+ },
202
+ "basket": {
203
+ "title": "Sepetiniz",
204
+ "empty": "Sepetiniz boş.",
205
+ "show": "Ürünleri göster",
206
+ "hide": "Ürünleri gizle",
207
+ "quantity": "Adet",
208
+ "increase": "Adedi artır",
209
+ "decrease": "Adedi azalt",
210
+ "remove": "Sepetten çıkar",
211
+ "update_error": "Sepet güncellenemedi. Lütfen tekrar deneyin."
212
+ }
163
213
  }
164
214
  }
@@ -1,28 +1,55 @@
1
1
  'use client';
2
2
 
3
- import { useEffect } from 'react';
4
- import { ROUTES } from '@theme/routes';
3
+ import { useEffect, useMemo } from 'react';
4
+ import { ROUTES, ORDER_ROUTES } from '@theme/routes';
5
5
  import { useGetBasketQuery } from '@akinon/next/data/client/basket';
6
6
  import { pushCartView } from '@theme/utils/gtm';
7
7
  import { Button, LoaderSpinner, Link } from '@theme/components';
8
8
  import { BasketItem, Summary } from '@theme/views/basket';
9
- import { useLocalization } from '@akinon/next/hooks';
9
+ import { useLocalization, useRouter } from '@akinon/next/hooks';
10
10
  import PluginModule, { Component } from '@akinon/next/components/plugin-module';
11
11
  import settings from '@theme/settings';
12
+ import { UNIFIED_VARIANTS } from '@theme/views/checkout/variants/registry';
12
13
 
13
14
  export default function Page() {
14
15
  const { data: basket, isLoading, isSuccess } = useGetBasketQuery();
15
16
  const { t } = useLocalization();
17
+ const router = useRouter();
16
18
  const multiBasket = settings.plugins?.multiBasket ?? false;
17
19
 
20
+ const checkoutVariant = (settings as { checkout?: { variant?: string } })
21
+ ?.checkout?.variant;
22
+ const isUnifiedCheckout = useMemo(
23
+ () => UNIFIED_VARIANTS.has(checkoutVariant ?? ''),
24
+ [checkoutVariant]
25
+ );
26
+
27
+ const hasItems = Boolean(
28
+ basket?.basketitem_set && basket.basketitem_set.length > 0
29
+ );
30
+
18
31
  useEffect(() => {
19
- if (isSuccess) {
32
+ if (isUnifiedCheckout && isSuccess && hasItems) {
33
+ router.replace(ORDER_ROUTES.CHECKOUT);
34
+ }
35
+ }, [isUnifiedCheckout, isSuccess, hasItems, router]);
36
+
37
+ useEffect(() => {
38
+ if (isSuccess && hasItems) {
20
39
  const products = basket.basketitem_set.map((basketItem) => ({
21
40
  ...basketItem.product
22
41
  }));
23
42
  pushCartView(products);
24
43
  }
25
- }, [basket, isSuccess]);
44
+ }, [basket, isSuccess, hasItems]);
45
+
46
+ if (isUnifiedCheckout && (isLoading || (isSuccess && hasItems))) {
47
+ return (
48
+ <div className="flex w-full justify-center py-20">
49
+ <LoaderSpinner />
50
+ </div>
51
+ );
52
+ }
26
53
 
27
54
  return (
28
55
  <div className="max-w-screen-xl p-4 flex flex-col text-primary-800 lg:p-8 xl:flex-row xl:mx-auto">
@@ -32,7 +59,7 @@ export default function Page() {
32
59
  </div>
33
60
  )}
34
61
  {isSuccess &&
35
- (basket && basket.basketitem_set && basket.basketitem_set.length > 0 ? (
62
+ (hasItems ? (
36
63
  <>
37
64
  <div className="flex-1 xl:mr-16">
38
65
  <div className="flex items-center justify-between py-2 border-b border-gray-200 lg:py-3">
@@ -1,66 +1,53 @@
1
1
  'use client';
2
2
 
3
- import { CheckoutStepList, Summary } from '@theme/views/checkout';
4
- import PaymentStep from '@theme/views/checkout/steps/payment';
5
- import ShippingStep from '@theme/views/checkout/steps/shipping';
6
- import { useEffect, useMemo, useRef } from 'react';
7
- import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
3
+ import { useEffect, useMemo } from 'react';
4
+ import dynamic from 'next/dynamic';
5
+ import { useAppDispatch } from '@akinon/next/redux/hooks';
6
+ import { resetCheckoutState } from '@akinon/next/redux/reducers/checkout';
8
7
  import {
9
- resetCheckoutState,
10
- setCurrentStep
11
- } from '@akinon/next/redux/reducers/checkout';
12
- import { RootState } from '@theme/redux/store';
13
- import { ROUTES } from '@theme/routes';
14
- import { useFetchCheckoutQuery, useResetCheckoutStateQuery } from '@akinon/next/data/client/checkout';
15
- import { Button, LoaderSpinner } from '@theme/components';
16
- import { pushAddPaymentInfo, pushAddShippingInfo } from '@theme/utils/gtm';
17
- import { CheckoutStep } from '@akinon/next/types';
8
+ useFetchCheckoutQuery,
9
+ useResetCheckoutStateQuery
10
+ } from '@akinon/next/data/client/checkout';
18
11
  import { useRouter, useLocalization } from '@akinon/next/hooks';
19
- import dynamic from 'next/dynamic';
20
- import PluginModule, { Component } from '@akinon/next/components/plugin-module';
12
+ import { Button, LoaderSpinner } from '@theme/components';
13
+ import { ROUTES } from '@theme/routes';
14
+ import settings from '@theme/settings';
15
+ import {
16
+ getCheckoutVariant,
17
+ UNIFIED_VARIANTS
18
+ } from '@theme/views/checkout/variants/registry';
19
+ import { CheckoutOnePageSkeleton } from '@theme/views/checkout/variants/one-page/skeletons';
20
+ import { useResolvedCheckoutConfig } from '@theme/views/checkout/variants/use-resolved-config';
21
21
 
22
22
  const Checkout = () => {
23
23
  const { t } = useLocalization();
24
- const { steps, preOrder } = useAppSelector(
25
- (state: RootState) => state.checkout
26
- );
24
+ const router = useRouter();
25
+ const dispatch = useAppDispatch();
27
26
 
28
- const { data: indexData, isLoading: isResetStateLoading } = useResetCheckoutStateQuery(null);
27
+ const { data: indexData, isLoading: isResetStateLoading } =
28
+ useResetCheckoutStateQuery(null);
29
29
 
30
30
  const {
31
31
  data: checkoutData,
32
- isFetching,
32
+ isLoading: isCheckoutLoading,
33
33
  isError,
34
- isSuccess,
35
34
  refetch: refetchCheckout
36
35
  } = useFetchCheckoutQuery(null, {
37
36
  refetchOnMountOrArgChange: true,
38
37
  skip: isResetStateLoading || !indexData
39
38
  });
40
- const initialStepChanged = useRef<boolean>(false);
41
- const router = useRouter();
42
- const dispatch = useAppDispatch();
39
+
40
+ const { variantId, options: variantOptions } = useResolvedCheckoutConfig();
43
41
 
44
42
  const CheckoutAuth = useMemo(
45
- () =>
46
- dynamic(() => {
47
- return import('@theme/views/checkout/auth');
48
- }),
43
+ () => dynamic(() => import('@theme/views/checkout/auth')),
49
44
  []
50
45
  );
51
46
 
52
- useEffect(() => {
53
- if (steps.shipping.completed && !initialStepChanged.current) {
54
- dispatch(setCurrentStep(CheckoutStep.Payment));
55
- initialStepChanged.current = true;
56
- }
57
- }, [steps.shipping.completed]); // eslint-disable-line react-hooks/exhaustive-deps
58
-
59
- useEffect(() => {
60
- if (preOrder && !preOrder.shipping_option) {
61
- initialStepChanged.current = true;
62
- }
63
- }, [preOrder]);
47
+ const CheckoutVariant = useMemo(
48
+ () => getCheckoutVariant(variantId),
49
+ [variantId]
50
+ );
64
51
 
65
52
  useEffect(() => {
66
53
  return () => {
@@ -68,23 +55,18 @@ const Checkout = () => {
68
55
  };
69
56
  }, []); // eslint-disable-line react-hooks/exhaustive-deps
70
57
 
71
- useEffect(() => {
72
- if (isSuccess) {
73
- const products = checkoutData?.pre_order?.basket?.basketitem_set.map(
74
- (basketItem) => ({
75
- ...basketItem.product
76
- })
77
- );
78
- if (steps.current === 'shipping') {
79
- pushAddShippingInfo(products);
80
- }
81
- if (steps.current === 'payment') {
82
- pushAddPaymentInfo(products, String(preOrder?.payment_option?.name));
83
- }
84
- }
85
- }, [isSuccess, steps, checkoutData, preOrder?.payment_option?.name]);
86
-
87
- if (checkoutData?.redirect_url?.includes('basket')) {
58
+ // In unified mode the basket lives inside the checkout page and the basket
59
+ // page auto-redirects here while it has items — following the backend's
60
+ // basket redirect would bounce between the two pages forever. Check the
61
+ // settings.js baseline as well, since the basket page redirects based on it
62
+ // even when the async theme-settings override resolves to another variant.
63
+ const baselineVariant = (settings as { checkout?: { variant?: string } })
64
+ ?.checkout?.variant;
65
+ const isUnifiedCheckout =
66
+ UNIFIED_VARIANTS.has(variantId) ||
67
+ UNIFIED_VARIANTS.has(baselineVariant ?? '');
68
+
69
+ if (!isUnifiedCheckout && checkoutData?.redirect_url?.includes('basket')) {
88
70
  router.push(ROUTES.BASKET);
89
71
  return null;
90
72
  }
@@ -97,47 +79,30 @@ const Checkout = () => {
97
79
  );
98
80
  }
99
81
 
100
- if (isResetStateLoading || isFetching || isError) {
82
+ if (isError) {
101
83
  return (
102
84
  <div className="flex flex-col items-center justify-center h-80">
103
- {isResetStateLoading || isFetching ? (
104
- <LoaderSpinner />
105
- ) : (
106
- <>
107
- <div>{t('checkout.error.title')}</div>
108
- <div className="mt-5">
109
- <Button onClick={refetchCheckout}>
110
- {t('checkout.error.button')}
111
- </Button>
112
- </div>
113
- </>
114
- )}
85
+ <div>{t('checkout.error.title')}</div>
86
+ <div className="mt-5">
87
+ <Button onClick={refetchCheckout}>
88
+ {t('checkout.error.button')}
89
+ </Button>
90
+ </div>
115
91
  </div>
116
92
  );
117
93
  }
118
94
 
119
- return (
120
- <PluginModule component={Component.MasterpassProvider}>
121
- <PluginModule component={Component.MasterpassDeleteConfirmationModal} />
122
- <PluginModule component={Component.MasterpassOtpModal} />
123
- <PluginModule component={Component.MasterpassLinkModal} />
124
-
125
- <div className="container flex flex-col flex-wrap w-full px-4 md:px-0">
126
- <CheckoutStepList />
127
-
128
- <div className="w-full flex flex-wrap">
129
- <div className="w-full h-fit-content lg:w-2/3">
130
- {steps.current === CheckoutStep.Shipping && <ShippingStep />}
131
- {steps.current === CheckoutStep.Payment && <PaymentStep />}
132
- </div>
133
-
134
- <div className="w-full h-fit-content mt-6 lg:w-1/3 lg:pl-8 lg:mt-0">
135
- <Summary />
136
- </div>
137
- </div>
95
+ if (isResetStateLoading || isCheckoutLoading) {
96
+ return variantId === 'multi-step' ? (
97
+ <div className="flex flex-col items-center justify-center h-80">
98
+ <LoaderSpinner />
138
99
  </div>
139
- </PluginModule>
140
- );
100
+ ) : (
101
+ <CheckoutOnePageSkeleton />
102
+ );
103
+ }
104
+
105
+ return <CheckoutVariant options={variantOptions} />;
141
106
  };
142
107
 
143
108
  export default Checkout;
@@ -1,12 +1,31 @@
1
1
  import { NextResponse } from 'next/server';
2
2
  import { getThemeSettings } from '@theme/data/server/theme';
3
3
 
4
+ export const dynamic = 'force-dynamic';
5
+ export const revalidate = 0;
6
+
4
7
  export async function GET() {
5
8
  try {
6
9
  const settings = await getThemeSettings();
7
- return NextResponse.json(settings);
10
+ return NextResponse.json(settings, {
11
+ headers: {
12
+ 'Cache-Control': 'no-store, must-revalidate',
13
+ 'Pragma': 'no-cache'
14
+ }
15
+ });
8
16
  } catch (error) {
9
17
  console.error('Error in theme-settings API:', error);
10
- return NextResponse.json({}, { status: 500 });
18
+ // Return empty object with 200 so checkout falls back to settings.js silently
19
+ // without surfacing as a 5xx in monitoring tools.
20
+ return NextResponse.json(
21
+ {},
22
+ {
23
+ status: 200,
24
+ headers: {
25
+ 'Cache-Control': 'no-store, must-revalidate',
26
+ 'Pragma': 'no-cache'
27
+ }
28
+ }
29
+ );
11
30
  }
12
31
  }
@@ -2,6 +2,11 @@ import 'server-only';
2
2
 
3
3
  import { getWidgetData } from '@akinon/next/data/server';
4
4
 
5
+ export interface ThemeCheckoutSettings {
6
+ variant?: string;
7
+ options?: Record<string, unknown>;
8
+ }
9
+
5
10
  interface ThemeSettings {
6
11
  logo?: string;
7
12
  favicon?: string;
@@ -16,31 +21,7 @@ interface ThemeSettings {
16
21
  mainMenuSticky?: boolean;
17
22
  breadcrumbSeparator?: string;
18
23
  socialNetworks?: Record<string, { url?: string; icon?: string }>;
19
- }
20
-
21
- interface ThemeConfigWidget {
22
- attributes?: {
23
- theme_name?: {
24
- value?: string;
25
- kwargs?: Record<string, unknown>;
26
- };
27
- theme_slug?: {
28
- value?: string;
29
- kwargs?: Record<string, unknown>;
30
- };
31
- theme_settings?: {
32
- value?: string;
33
- kwargs?: Record<string, unknown>;
34
- };
35
- theme_breakpoints?: {
36
- value?: string;
37
- kwargs?: Record<string, unknown>;
38
- };
39
- theme_dataSources?: {
40
- value?: string;
41
- kwargs?: Record<string, unknown>;
42
- };
43
- };
24
+ checkout?: ThemeCheckoutSettings;
44
25
  }
45
26
 
46
27
  /**