@akinon/projectzero 2.0.0-beta.19 → 2.0.0-beta.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 +9 -7
- package/app-template/CHANGELOG.md +251 -204
- package/app-template/akinon.json +1 -1
- package/app-template/package.json +28 -28
- package/app-template/public/amex.svg +12 -0
- package/app-template/public/apple-pay.svg +16 -0
- package/app-template/public/assets/images/product-placeholder-1.jpg +0 -0
- package/app-template/public/assets/images/product-placeholder-2.jpg +0 -0
- package/app-template/public/assets/images/product-placeholder-3.jpg +0 -0
- package/app-template/public/assets/images/product-placeholder-4.jpg +0 -0
- package/app-template/public/google-pay.svg +16 -0
- package/app-template/public/locales/en/account.json +6 -3
- package/app-template/public/locales/en/auth.json +6 -7
- package/app-template/public/locales/en/basket.json +6 -6
- package/app-template/public/locales/en/blog.json +7 -0
- package/app-template/public/locales/en/category.json +3 -1
- package/app-template/public/locales/en/checkout.json +5 -4
- package/app-template/public/locales/en/common.json +11 -2
- package/app-template/public/locales/en/forgot_password.json +6 -7
- package/app-template/public/locales/en/product.json +4 -3
- package/app-template/public/locales/tr/account.json +6 -3
- package/app-template/public/locales/tr/auth.json +16 -17
- package/app-template/public/locales/tr/basket.json +4 -4
- package/app-template/public/locales/tr/blog.json +7 -0
- package/app-template/public/locales/tr/category.json +3 -1
- package/app-template/public/locales/tr/checkout.json +39 -38
- package/app-template/public/locales/tr/common.json +10 -1
- package/app-template/public/locales/tr/forgot_password.json +12 -13
- package/app-template/public/locales/tr/product.json +1 -0
- package/app-template/public/logo.svg +3 -27
- package/app-template/public/mastercard.svg +14 -0
- package/app-template/public/promotion-banner.jpg +0 -0
- package/app-template/public/shop-pay.svg +12 -0
- package/app-template/public/visa.svg +12 -0
- package/app-template/src/app/[commerce]/[locale]/[currency]/blog/[slug]/page.tsx +118 -0
- package/app-template/src/app/[commerce]/[locale]/[currency]/pages/[slug]/page.tsx +15 -0
- package/app-template/src/app/api/theme-settings/route.ts +12 -0
- package/app-template/src/assets/fonts/pz-icon.css +211 -49
- package/app-template/src/assets/fonts/pz-icon.eot +0 -0
- package/app-template/src/assets/fonts/pz-icon.html +486 -0
- package/app-template/src/assets/fonts/pz-icon.scss +373 -49
- package/app-template/src/assets/fonts/pz-icon.svg +215 -53
- package/app-template/src/assets/fonts/pz-icon.ttf +0 -0
- package/app-template/src/assets/fonts/pz-icon.woff +0 -0
- package/app-template/src/assets/fonts/pz-icon.woff2 +0 -0
- package/app-template/src/assets/globals.scss +4 -0
- package/app-template/src/assets/icons/arrow-right.svg +3 -0
- package/app-template/src/assets/icons/cart.svg +4 -12
- package/app-template/src/assets/icons/check.svg +2 -18
- package/app-template/src/assets/icons/chevron-down.svg +2 -7
- package/app-template/src/assets/icons/delete.svg +3 -0
- package/app-template/src/assets/icons/facebook.svg +2 -8
- package/app-template/src/assets/icons/fav-off.svg +5 -0
- package/app-template/src/assets/icons/fav-on.svg +5 -0
- package/app-template/src/assets/icons/filter-and-sort.svg +3 -0
- package/app-template/src/assets/icons/heart.svg +3 -0
- package/app-template/src/assets/icons/instagram.svg +2 -13
- package/app-template/src/assets/icons/materials.svg +3 -0
- package/app-template/src/assets/icons/person.svg +4 -0
- package/app-template/src/assets/icons/pinterest.svg +5 -11
- package/app-template/src/assets/icons/ruler.svg +3 -0
- package/app-template/src/assets/icons/search.svg +8 -11
- package/app-template/src/assets/icons/share.svg +2 -9
- package/app-template/src/assets/icons/snapchat.svg +3 -0
- package/app-template/src/assets/icons/tiktok.svg +3 -0
- package/app-template/src/assets/icons/tumblr.svg +6 -0
- package/app-template/src/assets/icons/twitter.svg +2 -10
- package/app-template/src/assets/icons/vimeo.svg +3 -0
- package/app-template/src/assets/icons/youtube.svg +3 -0
- package/app-template/src/assets/icons/zoom.svg +8 -0
- package/app-template/src/components/accordion.tsx +33 -11
- package/app-template/src/components/action-tooltip.tsx +160 -0
- package/app-template/src/components/currency-select.tsx +149 -4
- package/app-template/src/components/icon.tsx +5 -6
- package/app-template/src/components/index.ts +4 -1
- package/app-template/src/components/language-select.tsx +88 -2
- package/app-template/src/components/pagination.tsx +132 -20
- package/app-template/src/components/quantity-input.tsx +63 -0
- package/app-template/src/components/quantity-selector.tsx +203 -0
- package/app-template/src/components/route-handler.tsx +50 -0
- package/app-template/src/components/select.tsx +89 -69
- package/app-template/src/components/types/index.ts +26 -0
- package/app-template/src/components/widget-content.tsx +323 -0
- package/app-template/src/data/server/theme.ts +70 -0
- package/app-template/src/hooks/use-fav-button.tsx +5 -2
- package/app-template/src/hooks/use-product-cart.ts +11 -8
- package/app-template/src/hooks/use-theme-settings.ts +42 -0
- package/app-template/src/lib/fonts.ts +149 -0
- package/app-template/src/settings.js +2 -2
- package/app-template/src/types/hookform-resolvers-yup.d.ts +28 -0
- package/app-template/src/types/widget.ts +169 -0
- package/app-template/src/utils/formatDate.ts +48 -0
- package/app-template/src/utils/styles.ts +71 -0
- package/app-template/src/views/account/contact-form.tsx +147 -130
- package/app-template/src/views/basket/basket-item.tsx +691 -107
- package/app-template/src/views/basket/basket-summary-context.tsx +560 -0
- package/app-template/src/views/basket/designer-context.tsx +617 -0
- package/app-template/src/views/basket/index.ts +2 -0
- package/app-template/src/views/basket/summary.tsx +496 -75
- package/app-template/src/views/breadcrumb/breadcrumb-client.tsx +190 -0
- package/app-template/src/views/breadcrumb/breadcrumb-registrar.tsx +286 -0
- package/app-template/src/views/breadcrumb/constants.ts +15 -0
- package/app-template/src/views/breadcrumb/index.tsx +127 -0
- package/app-template/src/views/breadcrumb.tsx +13 -38
- package/app-template/src/views/category/category-banner.tsx +4 -23
- package/app-template/src/views/category/category-header.tsx +289 -66
- package/app-template/src/views/category/category-info.tsx +173 -24
- package/app-template/src/views/category/filters/filter-item.tsx +138 -42
- package/app-template/src/views/category/filters/index.tsx +208 -48
- package/app-template/src/views/category/layout.tsx +7 -4
- package/app-template/src/views/category/native-widget-context.tsx +257 -0
- package/app-template/src/views/category/product-list-registrar.tsx +665 -0
- package/app-template/src/views/checkout/auth.tsx +64 -40
- package/app-template/src/views/checkout/checkout-address-registrar.tsx +254 -0
- package/app-template/src/views/checkout/checkout-buttons-registrar.tsx +183 -0
- package/app-template/src/views/checkout/checkout-delivery-method-registrar.tsx +259 -0
- package/app-template/src/views/checkout/checkout-payment-options-registrar.tsx +253 -0
- package/app-template/src/views/checkout/checkout-summary-registrar.tsx +183 -0
- package/app-template/src/views/checkout/constants.ts +5 -0
- package/app-template/src/views/checkout/index.tsx +5 -0
- package/app-template/src/views/checkout/layout/header.tsx +9 -5
- package/app-template/src/views/checkout/steps/payment/index.tsx +5 -2
- package/app-template/src/views/checkout/steps/payment/options/credit-card/index.tsx +72 -1
- package/app-template/src/views/checkout/steps/payment/options/masterpass-rest.tsx +15 -0
- package/app-template/src/views/checkout/steps/payment/options/saved-card.tsx +18 -0
- package/app-template/src/views/checkout/steps/payment/payment-option-buttons.tsx +171 -40
- package/app-template/src/views/checkout/steps/shipping/address-box.tsx +74 -12
- package/app-template/src/views/checkout/steps/shipping/addresses.tsx +128 -45
- package/app-template/src/views/checkout/steps/shipping/shipping-options.tsx +232 -27
- package/app-template/src/views/checkout/summary.tsx +303 -29
- package/app-template/src/views/footer/footer-app-banner-context.tsx +326 -0
- package/app-template/src/views/footer/footer-bottom-context.tsx +215 -0
- package/app-template/src/views/footer/footer-bottom-wrapper.tsx +74 -0
- package/app-template/src/views/footer/footer-layout-constants.ts +35 -0
- package/app-template/src/views/footer/footer-layout-registrar.tsx +342 -0
- package/app-template/src/views/footer/footer-layout-switcher.tsx +110 -0
- package/app-template/src/views/footer/footer-menu-context.tsx +211 -0
- package/app-template/src/views/footer/footer-native-widgets.tsx +60 -0
- package/app-template/src/views/footer/footer-social-context.tsx +254 -0
- package/app-template/src/views/footer/footer-subscription-context.tsx +210 -0
- package/app-template/src/views/footer/footer-utils.ts +43 -0
- package/app-template/src/views/footer/footer-value-props-context.tsx +326 -0
- package/app-template/src/views/footer/logo-settings.ts +183 -0
- package/app-template/src/views/footer/native-widget-config.ts +262 -0
- package/app-template/src/views/footer/subscription-settings.ts +122 -0
- package/app-template/src/views/footer/use-footer-logo.ts +162 -0
- package/app-template/src/views/footer.tsx +415 -13
- package/app-template/src/views/guest-login/index.tsx +62 -58
- package/app-template/src/views/header/action-menu.tsx +277 -45
- package/app-template/src/views/header/band.tsx +6 -21
- package/app-template/src/views/header/designer-context.tsx +261 -0
- package/app-template/src/views/header/header-announcement-registrar.tsx +267 -0
- package/app-template/src/views/header/header-client-wrapper.tsx +496 -0
- package/app-template/src/views/header/header-content.tsx +1026 -0
- package/app-template/src/views/header/header-currency-registrar.tsx +348 -0
- package/app-template/src/views/header/header-icons-context.tsx +262 -0
- package/app-template/src/views/header/header-language-registrar.tsx +348 -0
- package/app-template/src/views/header/header-layout-context.tsx +143 -0
- package/app-template/src/views/header/header-layout-registrar.tsx +658 -0
- package/app-template/src/views/header/header-logo-context.tsx +228 -0
- package/app-template/src/views/header/header-logo.tsx +118 -0
- package/app-template/src/views/header/header-mini-basket-context.tsx +524 -0
- package/app-template/src/views/header/header-search-registrar.tsx +511 -0
- package/app-template/src/views/header/header-text-slider-registrar.tsx +382 -0
- package/app-template/src/views/header/index.tsx +109 -47
- package/app-template/src/views/header/inline-search.tsx +262 -0
- package/app-template/src/views/header/mini-basket.tsx +819 -44
- package/app-template/src/views/header/mobile-hamburger-button.tsx +5 -8
- package/app-template/src/views/header/mobile-menu.tsx +12 -0
- package/app-template/src/views/header/navbar-menu-context.tsx +219 -0
- package/app-template/src/views/header/navbar.tsx +178 -111
- package/app-template/src/views/header/search/index.tsx +71 -32
- package/app-template/src/views/header/search/results.tsx +127 -65
- package/app-template/src/views/header/search/search-input.tsx +61 -0
- package/app-template/src/views/header/server-settings-parser.ts +1105 -0
- package/app-template/src/views/header/use-header-icons.ts +241 -0
- package/app-template/src/views/header/use-header-logo.ts +213 -0
- package/app-template/src/views/header/use-navbar-menu.ts +179 -0
- package/app-template/src/views/login/index.tsx +54 -46
- package/app-template/src/views/product/accordion-section.tsx +61 -0
- package/app-template/src/views/product/accordion-wrapper.tsx +135 -43
- package/app-template/src/views/product/custom-button-group.tsx +69 -0
- package/app-template/src/views/product/favorites-button-section.tsx +69 -0
- package/app-template/src/views/product/find-in-store-section.tsx +60 -0
- package/app-template/src/views/product/index.ts +1 -0
- package/app-template/src/views/product/layout.tsx +6 -5
- package/app-template/src/views/product/misc-buttons.tsx +339 -25
- package/app-template/src/views/product/price-wrapper.tsx +3 -29
- package/app-template/src/views/product/product-actions.tsx +137 -8
- package/app-template/src/views/product/product-info-section.tsx +140 -0
- package/app-template/src/views/product/product-info.tsx +69 -31
- package/app-template/src/views/product/product-share.tsx +13 -8
- package/app-template/src/views/product/product-variants.tsx +2 -2
- package/app-template/src/views/product/quantity-section.tsx +73 -0
- package/app-template/src/views/product/sale-tag.tsx +10 -0
- package/app-template/src/views/product/share-section.tsx +357 -0
- package/app-template/src/views/product/slider.tsx +117 -79
- package/app-template/src/views/product/variant.tsx +69 -41
- package/app-template/src/views/product/variants-section.tsx +126 -0
- package/app-template/src/views/product-detail/constants.ts +272 -0
- package/app-template/src/views/product-detail/index.ts +10 -0
- package/app-template/src/views/product-detail/product-detail-registrar.tsx +616 -0
- package/app-template/src/views/product-item/index.tsx +119 -46
- package/app-template/src/views/register/index.tsx +14 -25
- package/app-template/src/views/share/index.tsx +9 -6
- package/app-template/src/views/widgets/home-hero-slider-content.tsx +41 -39
- package/app-template/src/widgets/flatpages/about-us/index.tsx +78 -0
- package/app-template/src/widgets/flatpages/blog-list/index.tsx +129 -0
- package/app-template/src/widgets/footer-app-banner.tsx +444 -0
- package/app-template/src/widgets/footer-bottom.tsx +127 -0
- package/app-template/src/widgets/footer-menu-compact.tsx +238 -0
- package/app-template/src/widgets/footer-menu-two.tsx +298 -0
- package/app-template/src/widgets/footer-social-client.tsx +251 -0
- package/app-template/src/widgets/footer-social.tsx +47 -16
- package/app-template/src/widgets/footer-subscription/footer-subscription-form.tsx +17 -14
- package/app-template/src/widgets/footer-subscription/index.tsx +183 -17
- package/app-template/src/widgets/footer-value-props.tsx +201 -0
- package/app-template/src/widgets/index.ts +7 -0
- package/app-template/src/widgets/schemas/about-us.json +46 -0
- package/app-template/src/widgets/schemas/blog-list.json +37 -0
- package/app-template/src/widgets/schemas/blog.json +29 -0
- package/app-template/tailwind.config.js +18 -2
- package/package.json +1 -1
|
@@ -1,54 +1,78 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import GuestLogin from '@theme/views/guest-login';
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
4
3
|
import { Login } from '@theme/views/login';
|
|
5
|
-
import {
|
|
6
|
-
import { ROUTES } from 'routes';
|
|
4
|
+
import { Register } from '@theme/views/register';
|
|
7
5
|
import { useSession } from 'next-auth/react';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
6
|
+
import { useSearchParams } from 'next/navigation';
|
|
7
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
8
|
+
import { useLocalization, useRouter } from '@akinon/next/hooks';
|
|
9
|
+
import clsx from 'clsx';
|
|
10
|
+
import { twMerge } from 'tailwind-merge';
|
|
11
|
+
import { Button } from '@theme/components';
|
|
12
|
+
import GuestLogin from '@theme/views/guest-login';
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
const {
|
|
14
|
+
export default function CheckoutAuth() {
|
|
15
|
+
const { data: session } = useSession();
|
|
13
16
|
const router = useRouter();
|
|
14
|
-
const
|
|
15
|
-
const
|
|
17
|
+
const searchParams = useSearchParams();
|
|
18
|
+
const { t } = useLocalization();
|
|
19
|
+
const [activeTab, setActiveTab] = useState('login');
|
|
20
|
+
|
|
21
|
+
const tabClass = (tabName) => {
|
|
22
|
+
return twMerge(
|
|
23
|
+
clsx(
|
|
24
|
+
'text-base font-normal text-black-750/50 bg-transparent border-0 border-primary px-6 transition-all hover:border-b hover:text-black-750',
|
|
25
|
+
{
|
|
26
|
+
'border-b text-black-750': activeTab === tabName
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const pageTitle = useMemo(() => {
|
|
33
|
+
return {
|
|
34
|
+
login: t('auth.login.title'),
|
|
35
|
+
register: t('auth.register.title'),
|
|
36
|
+
guest: t('checkout.auth.guest_checkout')
|
|
37
|
+
}[activeTab];
|
|
38
|
+
}, [activeTab]);
|
|
16
39
|
|
|
17
40
|
useEffect(() => {
|
|
18
|
-
if (
|
|
19
|
-
|
|
20
|
-
} else if (status === 'unauthenticated') {
|
|
21
|
-
router.replace(ROUTES.CHECKOUT + `?callbackUrl=${ROUTES.CHECKOUT}`);
|
|
41
|
+
if (session?.user) {
|
|
42
|
+
router.push(searchParams.get('callbackUrl') ?? '/');
|
|
22
43
|
}
|
|
23
|
-
}, [
|
|
44
|
+
}, [session?.user]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
24
45
|
|
|
25
46
|
return (
|
|
26
|
-
<
|
|
27
|
-
<div className="
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
<span>
|
|
31
|
-
{t('checkout.auth.title')}
|
|
32
|
-
<Link
|
|
33
|
-
href={ROUTES.AUTH + `?callbackUrl=${ROUTES.CHECKOUT}`}
|
|
34
|
-
className="ml-1 text-black underline"
|
|
35
|
-
>
|
|
36
|
-
{t('checkout.auth.signup')}
|
|
37
|
-
</Link>
|
|
38
|
-
</span>
|
|
47
|
+
<section className="container my-7 lg:my-24">
|
|
48
|
+
<div className="max-w-lg mx-auto">
|
|
49
|
+
<div className="text-black-750 text-[40px] font-normal">
|
|
50
|
+
{pageTitle}
|
|
39
51
|
</div>
|
|
40
|
-
|
|
52
|
+
{activeTab !== 'guest' && (
|
|
53
|
+
<div className="w-full grid grid-cols-2 justify-center gap-4 lg:gap-6 mt-8">
|
|
54
|
+
<button
|
|
55
|
+
className={tabClass('login')}
|
|
56
|
+
onClick={() => setActiveTab('login')}
|
|
57
|
+
>
|
|
58
|
+
{t('auth.login.mobile_title')}
|
|
59
|
+
</button>
|
|
60
|
+
<Button
|
|
61
|
+
className={tabClass('register')}
|
|
62
|
+
onClick={() => setActiveTab('register')}
|
|
63
|
+
>
|
|
64
|
+
{t('auth.register.mobile_title')}
|
|
65
|
+
</Button>
|
|
66
|
+
</div>
|
|
67
|
+
)}
|
|
68
|
+
<div className="w-full flex flex-wrap">
|
|
69
|
+
{activeTab === 'register' && <Register />}
|
|
70
|
+
|
|
71
|
+
{activeTab === 'login' && <Login setActiveTab={setActiveTab} />}
|
|
41
72
|
|
|
42
|
-
|
|
43
|
-
<div className="px-5 lg:px-16">
|
|
44
|
-
<h2 className="mb-3 text-lg text-start text-black-800 font-light md:mb-9 md:text-2xl">
|
|
45
|
-
{t('checkout.auth.guest_checkout')}
|
|
46
|
-
</h2>
|
|
47
|
-
<GuestLogin />
|
|
73
|
+
{activeTab === 'guest' && <GuestLogin />}
|
|
48
74
|
</div>
|
|
49
75
|
</div>
|
|
50
|
-
</
|
|
76
|
+
</section>
|
|
51
77
|
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export default CheckoutAuth;
|
|
78
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Checkout Address Section Registrar
|
|
5
|
+
*
|
|
6
|
+
* This component registers the "Address" section for the checkout placeholder.
|
|
7
|
+
* It provides the current address view type to child components via context.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
createContext,
|
|
12
|
+
useContext,
|
|
13
|
+
useEffect,
|
|
14
|
+
useRef,
|
|
15
|
+
useState,
|
|
16
|
+
ReactNode
|
|
17
|
+
} from 'react';
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
CHECKOUT_PLACEHOLDER_ID,
|
|
21
|
+
CHECKOUT_ADDRESS_SECTION_ID
|
|
22
|
+
} from './constants';
|
|
23
|
+
|
|
24
|
+
// View types
|
|
25
|
+
export type AddressViewType = 'box' | 'dropdown';
|
|
26
|
+
|
|
27
|
+
// Global flag to track if registration has been done (survives component remount)
|
|
28
|
+
declare global {
|
|
29
|
+
interface Window {
|
|
30
|
+
__checkoutAddressRegistered?: boolean;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Check if running inside designer iframe
|
|
36
|
+
*/
|
|
37
|
+
function isInDesignerMode(): boolean {
|
|
38
|
+
if (typeof window === 'undefined') return false;
|
|
39
|
+
return window.self !== window.top;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface CheckoutAddressProperties {
|
|
43
|
+
viewType?: AddressViewType | Record<string, string>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface CheckoutAddressStyles {
|
|
47
|
+
[key: string]: string | number;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Context for sharing view type with other components
|
|
51
|
+
interface CheckoutAddressContextValue {
|
|
52
|
+
viewType: AddressViewType;
|
|
53
|
+
isDesigner: boolean;
|
|
54
|
+
sectionStyles: CheckoutAddressStyles;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const CheckoutAddressContext = createContext<CheckoutAddressContextValue>({
|
|
58
|
+
viewType: 'box',
|
|
59
|
+
isDesigner: false,
|
|
60
|
+
sectionStyles: {}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
export const useCheckoutAddress = () => useContext(CheckoutAddressContext);
|
|
64
|
+
|
|
65
|
+
interface CheckoutAddressRegistrarProps {
|
|
66
|
+
children?: ReactNode;
|
|
67
|
+
initialViewType?: AddressViewType;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function CheckoutAddressRegistrar({
|
|
71
|
+
children,
|
|
72
|
+
initialViewType = 'box'
|
|
73
|
+
}: CheckoutAddressRegistrarProps) {
|
|
74
|
+
const isDesignerRef = useRef(false);
|
|
75
|
+
|
|
76
|
+
const [sectionProperties, setSectionProperties] =
|
|
77
|
+
useState<CheckoutAddressProperties>({
|
|
78
|
+
viewType: initialViewType
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const [sectionStyles, setSectionStyles] = useState<CheckoutAddressStyles>({});
|
|
82
|
+
|
|
83
|
+
const [isSectionSelected, setIsSectionSelected] = useState(false);
|
|
84
|
+
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
isDesignerRef.current = isInDesignerMode();
|
|
87
|
+
}, []);
|
|
88
|
+
|
|
89
|
+
const isDesigner = isDesignerRef.current;
|
|
90
|
+
|
|
91
|
+
// Register native widget with Theme Editor
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
const isInIframe =
|
|
94
|
+
typeof window !== 'undefined' && window.self !== window.top;
|
|
95
|
+
if (!isInIframe || !window.parent) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// If already registered, skip
|
|
100
|
+
if (typeof window !== 'undefined' && window.__checkoutAddressRegistered) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const nativeWidgetConfig = {
|
|
105
|
+
placeholderId: CHECKOUT_PLACEHOLDER_ID,
|
|
106
|
+
section: {
|
|
107
|
+
id: CHECKOUT_ADDRESS_SECTION_ID,
|
|
108
|
+
type: 'native',
|
|
109
|
+
label: 'Addresses',
|
|
110
|
+
blocks: []
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
window.parent.postMessage(
|
|
115
|
+
{
|
|
116
|
+
type: 'REGISTER_NATIVE_WIDGETS',
|
|
117
|
+
data: { widgets: [nativeWidgetConfig] }
|
|
118
|
+
},
|
|
119
|
+
'*'
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
window.__checkoutAddressRegistered = true;
|
|
123
|
+
}, []);
|
|
124
|
+
|
|
125
|
+
// Listen for theme updates and selection changes from Theme Editor
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
if (typeof window === 'undefined') return;
|
|
128
|
+
|
|
129
|
+
const handleMessage = (event: MessageEvent) => {
|
|
130
|
+
const { type, data } = event.data || {};
|
|
131
|
+
|
|
132
|
+
// Handle theme updates
|
|
133
|
+
if (
|
|
134
|
+
(type === 'UPDATE_THEME' || type === 'LOAD_THEME') &&
|
|
135
|
+
data?.theme?.placeholders
|
|
136
|
+
) {
|
|
137
|
+
const placeholder = data.theme.placeholders?.find(
|
|
138
|
+
(p: { slug: string }) => p.slug === CHECKOUT_PLACEHOLDER_ID
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const section = placeholder?.sections?.find(
|
|
142
|
+
(s: { id: string }) => s.id === CHECKOUT_ADDRESS_SECTION_ID
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
if (section) {
|
|
146
|
+
if (section.properties) {
|
|
147
|
+
setSectionProperties(section.properties);
|
|
148
|
+
}
|
|
149
|
+
if (section.styles) {
|
|
150
|
+
// Flatten responsive styles to current breakpoint (desktop by default)
|
|
151
|
+
const flatStyles: CheckoutAddressStyles = {};
|
|
152
|
+
Object.entries(section.styles).forEach(([key, value]) => {
|
|
153
|
+
if (typeof value === 'object' && value !== null) {
|
|
154
|
+
// Get desktop value first, fallback to any available value
|
|
155
|
+
const responsiveValue = value as Record<
|
|
156
|
+
string,
|
|
157
|
+
string | number
|
|
158
|
+
>;
|
|
159
|
+
flatStyles[key] =
|
|
160
|
+
responsiveValue.desktop ||
|
|
161
|
+
responsiveValue.mobile ||
|
|
162
|
+
responsiveValue.tablet ||
|
|
163
|
+
Object.values(responsiveValue)[0] ||
|
|
164
|
+
'';
|
|
165
|
+
} else {
|
|
166
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
167
|
+
flatStyles[key] = value;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
setSectionStyles(flatStyles);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Handle property updates
|
|
177
|
+
if (type === 'UPDATE_SECTION_PROPERTY' || type === 'UPDATE_PROPERTY') {
|
|
178
|
+
const { sectionId, placeholderId, key, value, properties } = data || {};
|
|
179
|
+
|
|
180
|
+
if (
|
|
181
|
+
sectionId === CHECKOUT_ADDRESS_SECTION_ID ||
|
|
182
|
+
placeholderId === CHECKOUT_PLACEHOLDER_ID
|
|
183
|
+
) {
|
|
184
|
+
if (key && value !== undefined) {
|
|
185
|
+
setSectionProperties((prev) => ({
|
|
186
|
+
...prev,
|
|
187
|
+
[key]: value
|
|
188
|
+
}));
|
|
189
|
+
}
|
|
190
|
+
if (properties) {
|
|
191
|
+
setSectionProperties(properties);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Handle selection
|
|
197
|
+
if (type === 'SELECT_SECTION') {
|
|
198
|
+
const { placeholderId, sectionId } = data || {};
|
|
199
|
+
setIsSectionSelected(
|
|
200
|
+
placeholderId === CHECKOUT_PLACEHOLDER_ID &&
|
|
201
|
+
sectionId === CHECKOUT_ADDRESS_SECTION_ID
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (type === 'DESELECT' || type === 'CLEAR_SELECTION') {
|
|
206
|
+
setIsSectionSelected(false);
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
window.addEventListener('message', handleMessage);
|
|
211
|
+
return () => window.removeEventListener('message', handleMessage);
|
|
212
|
+
}, []);
|
|
213
|
+
|
|
214
|
+
// Extraction helper
|
|
215
|
+
const extractViewType = (prop: unknown): AddressViewType => {
|
|
216
|
+
if (!prop) return 'box';
|
|
217
|
+
|
|
218
|
+
if (typeof prop === 'string') {
|
|
219
|
+
return prop as AddressViewType;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (typeof prop === 'object' && prop !== null) {
|
|
223
|
+
const obj = prop as Record<string, string>;
|
|
224
|
+
return (obj.desktop ||
|
|
225
|
+
obj.mobile ||
|
|
226
|
+
Object.values(obj)[0] ||
|
|
227
|
+
'box') as AddressViewType;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return 'box';
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const currentViewType = extractViewType(sectionProperties.viewType);
|
|
234
|
+
|
|
235
|
+
return (
|
|
236
|
+
<CheckoutAddressContext.Provider
|
|
237
|
+
value={{
|
|
238
|
+
viewType: currentViewType,
|
|
239
|
+
isDesigner,
|
|
240
|
+
sectionStyles
|
|
241
|
+
}}
|
|
242
|
+
>
|
|
243
|
+
<div
|
|
244
|
+
style={
|
|
245
|
+
isSectionSelected
|
|
246
|
+
? { outline: '2px solid #3b82f6', outlineOffset: '2px' }
|
|
247
|
+
: undefined
|
|
248
|
+
}
|
|
249
|
+
>
|
|
250
|
+
{children}
|
|
251
|
+
</div>
|
|
252
|
+
</CheckoutAddressContext.Provider>
|
|
253
|
+
);
|
|
254
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Checkout Buttons Section Registrar
|
|
5
|
+
*
|
|
6
|
+
* This component registers the "Buttons" section for the checkout placeholder.
|
|
7
|
+
* It provides button styles to child components via context.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
createContext,
|
|
12
|
+
useContext,
|
|
13
|
+
useEffect,
|
|
14
|
+
useRef,
|
|
15
|
+
useState,
|
|
16
|
+
ReactNode
|
|
17
|
+
} from 'react';
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
CHECKOUT_PLACEHOLDER_ID,
|
|
21
|
+
CHECKOUT_BUTTONS_SECTION_ID
|
|
22
|
+
} from './constants';
|
|
23
|
+
|
|
24
|
+
// Global flag to track if registration has been done (survives component remount)
|
|
25
|
+
declare global {
|
|
26
|
+
interface Window {
|
|
27
|
+
__checkoutButtonsRegistered?: boolean;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Check if running inside designer iframe
|
|
33
|
+
*/
|
|
34
|
+
function isInDesignerMode(): boolean {
|
|
35
|
+
if (typeof window === 'undefined') return false;
|
|
36
|
+
return window.self !== window.top;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface CheckoutButtonsStyles {
|
|
40
|
+
[key: string]: string | number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Context for sharing styles with other components
|
|
44
|
+
interface CheckoutButtonsContextValue {
|
|
45
|
+
isDesigner: boolean;
|
|
46
|
+
sectionStyles: CheckoutButtonsStyles;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const CheckoutButtonsContext = createContext<CheckoutButtonsContextValue>({
|
|
50
|
+
isDesigner: false,
|
|
51
|
+
sectionStyles: {}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export const useCheckoutButtons = () => useContext(CheckoutButtonsContext);
|
|
55
|
+
|
|
56
|
+
interface CheckoutButtonsRegistrarProps {
|
|
57
|
+
children?: ReactNode;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function CheckoutButtonsRegistrar({
|
|
61
|
+
children
|
|
62
|
+
}: CheckoutButtonsRegistrarProps) {
|
|
63
|
+
const isDesignerRef = useRef(false);
|
|
64
|
+
const [sectionStyles, setSectionStyles] = useState<CheckoutButtonsStyles>({});
|
|
65
|
+
const [isSectionSelected, setIsSectionSelected] = useState(false);
|
|
66
|
+
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
isDesignerRef.current = isInDesignerMode();
|
|
69
|
+
}, []);
|
|
70
|
+
|
|
71
|
+
const isDesigner = isDesignerRef.current;
|
|
72
|
+
|
|
73
|
+
// Register native widget with Theme Editor
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
const isInIframe =
|
|
76
|
+
typeof window !== 'undefined' && window.self !== window.top;
|
|
77
|
+
if (!isInIframe || !window.parent) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// If already registered, skip
|
|
82
|
+
if (typeof window !== 'undefined' && window.__checkoutButtonsRegistered) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const nativeWidgetConfig = {
|
|
87
|
+
placeholderId: CHECKOUT_PLACEHOLDER_ID,
|
|
88
|
+
section: {
|
|
89
|
+
id: CHECKOUT_BUTTONS_SECTION_ID,
|
|
90
|
+
type: 'native',
|
|
91
|
+
label: 'Buttons',
|
|
92
|
+
blocks: []
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
window.parent.postMessage(
|
|
97
|
+
{
|
|
98
|
+
type: 'REGISTER_NATIVE_WIDGETS',
|
|
99
|
+
data: { widgets: [nativeWidgetConfig] }
|
|
100
|
+
},
|
|
101
|
+
'*'
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
window.__checkoutButtonsRegistered = true;
|
|
105
|
+
}, []);
|
|
106
|
+
|
|
107
|
+
// Listen for theme updates and selection changes from Theme Editor
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
if (typeof window === 'undefined') return;
|
|
110
|
+
|
|
111
|
+
const handleMessage = (event: MessageEvent) => {
|
|
112
|
+
const { type, data } = event.data || {};
|
|
113
|
+
|
|
114
|
+
// Handle theme updates
|
|
115
|
+
if (
|
|
116
|
+
(type === 'UPDATE_THEME' || type === 'LOAD_THEME') &&
|
|
117
|
+
data?.theme?.placeholders
|
|
118
|
+
) {
|
|
119
|
+
const placeholder = data.theme.placeholders?.find(
|
|
120
|
+
(p: { slug: string }) => p.slug === CHECKOUT_PLACEHOLDER_ID
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const section = placeholder?.sections?.find(
|
|
124
|
+
(s: { id: string }) => s.id === CHECKOUT_BUTTONS_SECTION_ID
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
if (section && section.styles) {
|
|
128
|
+
// Flatten responsive styles to current breakpoint (desktop by default)
|
|
129
|
+
const flatStyles: CheckoutButtonsStyles = {};
|
|
130
|
+
Object.entries(section.styles).forEach(([key, value]) => {
|
|
131
|
+
if (typeof value === 'object' && value !== null) {
|
|
132
|
+
const responsiveValue = value as Record<string, string | number>;
|
|
133
|
+
flatStyles[key] =
|
|
134
|
+
responsiveValue.desktop ||
|
|
135
|
+
responsiveValue.mobile ||
|
|
136
|
+
responsiveValue.tablet ||
|
|
137
|
+
Object.values(responsiveValue)[0] ||
|
|
138
|
+
'';
|
|
139
|
+
} else if (typeof value === 'string' || typeof value === 'number') {
|
|
140
|
+
flatStyles[key] = value;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
setSectionStyles(flatStyles);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Handle section selection
|
|
148
|
+
if (type === 'SECTION_SELECTED') {
|
|
149
|
+
const isSelected =
|
|
150
|
+
data?.placeholderId === CHECKOUT_PLACEHOLDER_ID &&
|
|
151
|
+
data?.sectionId === CHECKOUT_BUTTONS_SECTION_ID;
|
|
152
|
+
setIsSectionSelected(isSelected);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (type === 'SECTION_DESELECTED') {
|
|
156
|
+
setIsSectionSelected(false);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
window.addEventListener('message', handleMessage);
|
|
161
|
+
return () => window.removeEventListener('message', handleMessage);
|
|
162
|
+
}, []);
|
|
163
|
+
|
|
164
|
+
return (
|
|
165
|
+
<CheckoutButtonsContext.Provider
|
|
166
|
+
value={{
|
|
167
|
+
isDesigner,
|
|
168
|
+
sectionStyles
|
|
169
|
+
}}
|
|
170
|
+
>
|
|
171
|
+
<div
|
|
172
|
+
data-native-section={CHECKOUT_BUTTONS_SECTION_ID}
|
|
173
|
+
data-placeholder={CHECKOUT_PLACEHOLDER_ID}
|
|
174
|
+
style={{
|
|
175
|
+
outline: isSectionSelected ? '2px solid #2359C4' : 'none',
|
|
176
|
+
outlineOffset: '2px'
|
|
177
|
+
}}
|
|
178
|
+
>
|
|
179
|
+
{children}
|
|
180
|
+
</div>
|
|
181
|
+
</CheckoutButtonsContext.Provider>
|
|
182
|
+
);
|
|
183
|
+
}
|