@akinon/projectzero 2.0.0-beta.11 → 2.0.0-beta.13
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 +104 -21
- package/app-template/.env.example +1 -0
- package/app-template/.github/instructions/account.instructions.md +749 -0
- package/app-template/.github/instructions/checkout.instructions.md +678 -0
- package/app-template/.github/instructions/default.instructions.md +279 -0
- package/app-template/.github/instructions/edge-cases.instructions.md +73 -0
- package/app-template/.github/instructions/routing.instructions.md +603 -0
- package/app-template/.github/instructions/settings.instructions.md +338 -0
- package/app-template/.gitignore +3 -0
- package/app-template/AGENTS.md +7 -0
- package/app-template/CHANGELOG.md +1348 -284
- package/app-template/Procfile +1 -1
- package/app-template/akinon.json +0 -3
- package/app-template/build.sh +10 -0
- package/app-template/docs/advanced-usage.md +101 -0
- package/app-template/docs/sentry-usage.md +35 -0
- package/app-template/next-env.d.ts +1 -0
- package/app-template/{next.config.ts → next.config.mjs} +6 -6
- package/app-template/package.json +58 -51
- package/app-template/postcss.config.mjs +1 -4
- package/app-template/public/locales/en/checkout.json +6 -0
- package/app-template/public/locales/en/common.json +50 -1
- package/app-template/public/locales/en/product.json +62 -1
- package/app-template/public/locales/tr/checkout.json +6 -0
- package/app-template/public/locales/tr/common.json +50 -1
- package/app-template/public/locales/tr/product.json +63 -0
- package/app-template/public/masterpass-javascript-sdk-web.min.js +1 -0
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/[...prettyurl]/page.tsx +9 -9
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/layout.tsx +2 -2
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/cancellation/page.tsx +6 -6
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/page.tsx +6 -6
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/page.tsx +1 -1
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/profile/page.tsx +2 -2
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/address/stores/page.tsx +2 -2
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/auth/page.tsx +1 -1
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/basket/page.tsx +2 -2
- package/app-template/src/app/[pz]/category/[pk]/page.tsx +27 -0
- package/app-template/src/app/[pz]/flat-page/[pk]/page.tsx +23 -0
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/forms/[pk]/generate/page.tsx +2 -3
- package/app-template/src/app/[pz]/group-product/[pk]/page.tsx +93 -0
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/landing-page/[pk]/page.tsx +2 -4
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/layout.tsx +3 -10
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/list/page.tsx +2 -4
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/not-found.tsx +5 -7
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/completed/[token]/page.tsx +6 -4
- package/app-template/src/app/[pz]/product/[pk]/page.tsx +102 -0
- package/app-template/src/app/[pz]/special-page/[pk]/page.tsx +35 -0
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/email-set-primary/[[...id]]/page.tsx +3 -4
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/registration/account-confirm-email/[[...id]]/page.tsx +3 -3
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/reset/[[...id]]/page.tsx +6 -12
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/xml-sitemap/[node]/route.ts +2 -2
- package/app-template/src/app/api/auth/[...nextauth]/route.ts +3 -0
- package/app-template/src/app/api/form/[...id]/route.ts +1 -7
- package/app-template/src/app/api/image-proxy/route.ts +1 -0
- package/app-template/src/app/api/product-categories/route.ts +1 -0
- package/app-template/src/app/api/similar-product-list/route.ts +1 -0
- package/app-template/src/app/api/similar-products/route.ts +1 -0
- package/app-template/src/app/api/virtual-try-on/limited-categories/route.ts +1 -0
- package/app-template/src/app/api/virtual-try-on/route.ts +1 -0
- package/app-template/src/assets/globals.scss +4 -133
- package/app-template/src/auth.ts +3 -0
- package/app-template/src/components/__tests__/badge.test.tsx +2 -2
- package/app-template/src/components/__tests__/link.test.tsx +2 -0
- package/app-template/src/components/accordion.tsx +23 -20
- package/app-template/src/components/button.tsx +1 -1
- package/app-template/src/components/carousel-core.tsx +4 -11
- package/app-template/src/components/checkbox.tsx +1 -1
- package/app-template/src/components/currency-select.tsx +1 -0
- package/app-template/src/components/file-input.tsx +27 -7
- package/app-template/src/components/generate-form-fields.tsx +49 -10
- package/app-template/src/components/input.tsx +11 -5
- package/app-template/src/components/modal.tsx +32 -16
- package/app-template/src/components/pagination.tsx +1 -0
- package/app-template/src/components/price.tsx +1 -1
- package/app-template/src/components/pwa-tags.tsx +1 -0
- package/app-template/src/components/select.tsx +39 -27
- package/app-template/src/components/shimmer.tsx +1 -1
- package/app-template/src/components/types/index.ts +25 -1
- package/app-template/src/hooks/use-fav-button.tsx +4 -8
- package/app-template/src/hooks/use-product-cart.ts +77 -0
- package/app-template/src/hooks/use-stock-alert.ts +74 -0
- package/app-template/src/plugins.js +12 -2
- package/app-template/src/redux/middlewares/category.ts +5 -4
- package/app-template/src/redux/store.ts +21 -1
- package/app-template/src/routes/index.ts +2 -1
- package/app-template/src/settings.js +3 -1
- package/app-template/src/types/index.ts +74 -3
- package/app-template/src/types/next-auth.d.ts +2 -2
- package/app-template/src/utils/variant-validation.ts +41 -0
- package/app-template/src/views/account/address-form.tsx +8 -4
- package/app-template/src/views/account/contact-form.tsx +2 -2
- package/app-template/src/views/account/content-header.tsx +4 -3
- package/app-template/src/views/account/faq/faq-tabs.tsx +8 -2
- package/app-template/src/views/account/order.tsx +1 -1
- package/app-template/src/views/account/orders/order-cancellation-item.tsx +1 -1
- package/app-template/src/views/anonymous-tracking/order-detail/index.tsx +1 -1
- package/app-template/src/views/basket/basket-item.tsx +6 -1
- package/app-template/src/views/basket/summary.tsx +16 -0
- package/app-template/src/views/breadcrumb.tsx +2 -2
- package/app-template/src/views/category/category-info.tsx +2 -1
- package/app-template/src/views/category/filters/index.tsx +1 -1
- package/app-template/src/views/checkout/auth.tsx +1 -1
- package/app-template/src/views/checkout/layout/header.tsx +1 -1
- package/app-template/src/views/checkout/steps/payment/options/credit-card/index.tsx +1 -1
- package/app-template/src/views/checkout/steps/payment/options/store-credit.tsx +121 -0
- package/app-template/src/views/checkout/steps/payment/payment-option-buttons.tsx +4 -4
- package/app-template/src/views/checkout/steps/shipping/address-box.tsx +3 -3
- package/app-template/src/views/checkout/steps/shipping/addresses.tsx +1 -1
- package/app-template/src/views/checkout/summary.tsx +12 -2
- package/app-template/src/views/find-in-store/index.tsx +2 -2
- package/app-template/src/views/header/action-menu.tsx +2 -6
- package/app-template/src/views/header/band.tsx +2 -2
- package/app-template/src/views/header/index.tsx +1 -1
- package/app-template/src/views/header/mini-basket.tsx +2 -2
- package/app-template/src/views/header/mobile-menu.tsx +6 -6
- package/app-template/src/views/header/navbar.tsx +1 -1
- package/app-template/src/views/header/pwa-back-button.tsx +1 -1
- package/app-template/src/views/header/search/index.tsx +13 -3
- package/app-template/src/views/header/search/results.tsx +1 -1
- package/app-template/src/views/header/user-menu.tsx +1 -3
- package/app-template/src/views/login/index.tsx +14 -13
- package/app-template/src/views/otp-login/index.tsx +11 -6
- package/app-template/src/views/product/layout.tsx +15 -1
- package/app-template/src/views/product/product-actions.tsx +165 -0
- package/app-template/src/views/product/product-info.tsx +69 -261
- package/app-template/src/views/product/product-share.tsx +56 -0
- package/app-template/src/views/product/product-variants.tsx +26 -0
- package/app-template/src/views/product/slider.tsx +22 -1
- package/app-template/src/views/product-pointer-banner-item.tsx +1 -1
- package/app-template/src/views/register/index.tsx +17 -21
- package/app-template/src/views/sales-contract-modal/index.tsx +17 -17
- package/app-template/src/widgets/footer-info.tsx +1 -1
- package/app-template/src/widgets/footer-menu.tsx +7 -3
- package/app-template/src/widgets/footer-subscription/index.tsx +1 -1
- package/app-template/src/widgets/home-stories-eng.tsx +43 -35
- package/app-template/tailwind.config.js +129 -1
- package/app-template/tsconfig.json +29 -11
- package/codemods/migrate-segments/index.js +591 -0
- package/commands/plugins.ts +62 -14
- package/dist/commands/plugins.js +62 -14
- package/package.json +1 -1
- package/app-template/src/app/[commerce]/[locale]/[currency]/category/[pk]/page.tsx +0 -22
- package/app-template/src/app/[commerce]/[locale]/[currency]/flat-page/[pk]/page.tsx +0 -20
- package/app-template/src/app/[commerce]/[locale]/[currency]/group-product/[pk]/page.tsx +0 -74
- package/app-template/src/app/[commerce]/[locale]/[currency]/product/[pk]/page.tsx +0 -84
- package/app-template/src/app/[commerce]/[locale]/[currency]/special-page/[pk]/page.tsx +0 -27
- package/app-template/src/pages/api/auth/[...nextauth].ts +0 -3
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/address/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/change-email/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/change-password/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/contact/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/coupons/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/email-verification/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/faq/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/favourite-products/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/my-quotations/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/layout.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/anonymous-tracking/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/auth/oauth-login/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/basket-b2b/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/category/[pk]/loading.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/client-root.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/contact-us/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/error.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/flat-page/[pk]/loading.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/group-product/[pk]/loading.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/landing-page/[pk]/loading.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/list/loading.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/checkout/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/completed/[token]/layout.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/special-page/[pk]/loading.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/template.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/password/reset/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/xml-sitemap/route.ts +0 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import clsx from 'clsx';
|
|
2
|
+
import {
|
|
3
|
+
useGetCheckoutLoyaltyBalanceQuery,
|
|
4
|
+
usePayWithLoyaltyBalanceMutation
|
|
5
|
+
} from '@akinon/next/data/client/checkout';
|
|
6
|
+
import { useAppSelector } from '@akinon/next/redux/hooks';
|
|
7
|
+
import { useMemo, useState } from 'react';
|
|
8
|
+
import { useLocalization } from '@akinon/next/hooks';
|
|
9
|
+
import { twMerge } from 'tailwind-merge';
|
|
10
|
+
import { Icon, Price } from '@theme/components';
|
|
11
|
+
import { Trans } from '@akinon/next/components';
|
|
12
|
+
import { LoaderSpinner } from '@theme/components';
|
|
13
|
+
|
|
14
|
+
export const StoreCredits = () => {
|
|
15
|
+
const { t } = useLocalization();
|
|
16
|
+
|
|
17
|
+
const [payWithLoyaltyBalance, { isLoading: isPayWithLoyaltyBalanceLoading }] =
|
|
18
|
+
usePayWithLoyaltyBalanceMutation();
|
|
19
|
+
|
|
20
|
+
const { loyaltyBalance, preOrder } = useAppSelector(
|
|
21
|
+
(state) => state.checkout
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const { isLoading: isLoyaltyBalanceLoading } =
|
|
25
|
+
useGetCheckoutLoyaltyBalanceQuery(undefined, {
|
|
26
|
+
refetchOnMountOrArgChange: true,
|
|
27
|
+
skip: !preOrder?.payment_option
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const isLoyaltyBalanceUsed = useMemo(() => {
|
|
31
|
+
return parseFloat(preOrder?.loyalty_money ?? '0') > 0;
|
|
32
|
+
}, [preOrder?.loyalty_money]);
|
|
33
|
+
|
|
34
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
35
|
+
|
|
36
|
+
const handleClick = async () => {
|
|
37
|
+
if (isLoading) return;
|
|
38
|
+
setIsLoading(true);
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
await payWithLoyaltyBalance(isLoyaltyBalanceUsed ? '0' : loyaltyBalance);
|
|
42
|
+
} finally {
|
|
43
|
+
setIsLoading(false);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
if (preOrder?.is_guest) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (isLoyaltyBalanceLoading) {
|
|
52
|
+
return (
|
|
53
|
+
<div className="mb-3 px-4 py-3 xs:px-0">
|
|
54
|
+
<LoaderSpinner />
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (parseFloat(loyaltyBalance) <= 0) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
return (
|
|
63
|
+
<div
|
|
64
|
+
className={twMerge(
|
|
65
|
+
'hidden flex-col w-full mb-4 border border-solid border-gray-400 px-0 md:p-4',
|
|
66
|
+
isPayWithLoyaltyBalanceLoading && 'pointer-events-none opacity-30',
|
|
67
|
+
parseFloat(loyaltyBalance) > 0 && 'block'
|
|
68
|
+
)}
|
|
69
|
+
>
|
|
70
|
+
<div className="flex w-full items-center">
|
|
71
|
+
<button onClick={handleClick}>
|
|
72
|
+
<span
|
|
73
|
+
className={clsx(
|
|
74
|
+
'flex h-5 w-5 items-center justify-center rounded border border-solid border-primary',
|
|
75
|
+
isLoyaltyBalanceUsed ? 'bg-primary' : 'bg-white'
|
|
76
|
+
)}
|
|
77
|
+
>
|
|
78
|
+
<Icon
|
|
79
|
+
name={isLoyaltyBalanceUsed ? 'check' : ''}
|
|
80
|
+
size={10}
|
|
81
|
+
className={clsx({ 'text-white': isLoyaltyBalanceUsed })}
|
|
82
|
+
/>
|
|
83
|
+
</span>
|
|
84
|
+
</button>
|
|
85
|
+
|
|
86
|
+
<div className="w-full pl-4">
|
|
87
|
+
<p className="cursor-pointer text-sm" onClick={handleClick}>
|
|
88
|
+
{t('checkout.payment.store_credit.use_my_store_credits')}
|
|
89
|
+
</p>
|
|
90
|
+
<p className="flex text-sm text-[#606060]">
|
|
91
|
+
{t('checkout.payment.store_credit.available_balance')}:
|
|
92
|
+
<Price
|
|
93
|
+
value={loyaltyBalance}
|
|
94
|
+
currencyCode={preOrder?.currency_type_label}
|
|
95
|
+
className="pe-1 font-bold"
|
|
96
|
+
/>
|
|
97
|
+
</p>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
{isLoyaltyBalanceUsed && parseFloat(preOrder?.unpaid_amount) > 0 && (
|
|
102
|
+
<p className="my-4 text-[15px] font-light italic text-[#707070] max-xs:text-xs">
|
|
103
|
+
<Trans
|
|
104
|
+
i18nKey="checkout.payment.store_credit.insufficient_balance"
|
|
105
|
+
components={{
|
|
106
|
+
Amount: (
|
|
107
|
+
<div className="inline-flex">
|
|
108
|
+
<Price
|
|
109
|
+
value={preOrder?.unpaid_amount}
|
|
110
|
+
currencyCode={preOrder?.currency_type_label}
|
|
111
|
+
className="text-primary"
|
|
112
|
+
/>
|
|
113
|
+
</div>
|
|
114
|
+
)
|
|
115
|
+
}}
|
|
116
|
+
/>
|
|
117
|
+
</p>
|
|
118
|
+
)}
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
};
|
|
@@ -44,7 +44,7 @@ const PaymentOptionButtons = () => {
|
|
|
44
44
|
{displayedPaymentOptions.map((option) => (
|
|
45
45
|
<label
|
|
46
46
|
key={`payment-option-${option.pk}`}
|
|
47
|
-
className="border
|
|
47
|
+
className="border px-4 py-3 mt-3 flex h-12"
|
|
48
48
|
onClick={scrollToTop}
|
|
49
49
|
>
|
|
50
50
|
<Radio
|
|
@@ -69,10 +69,10 @@ const PaymentOptionButtons = () => {
|
|
|
69
69
|
onClick={() => onClickHandler(option)}
|
|
70
70
|
className={clsx(
|
|
71
71
|
'flex items-center justify-center border-r border-b border-solid',
|
|
72
|
-
'border-gray-400 text-xs uppercase text-black-800
|
|
73
|
-
'bg-white h-11 px-5 transition-colors sm:h-15 sm:px-8 sm:py-8 hover:text-secondary',
|
|
72
|
+
'border-gray-400 text-xs uppercase text-black-800 font-medium',
|
|
73
|
+
'text-opacity-60 bg-white h-11 px-5 transition-colors sm:h-15 sm:px-8 sm:py-8 hover:text-secondary',
|
|
74
74
|
{
|
|
75
|
-
'text-
|
|
75
|
+
'text-opacity-100 border-b-transparent':
|
|
76
76
|
preOrder?.payment_option?.pk === option.pk
|
|
77
77
|
}
|
|
78
78
|
)}
|
|
@@ -130,7 +130,7 @@ const AddressBox = ({
|
|
|
130
130
|
onClick={() => handleAddressClick(addressType, address)}
|
|
131
131
|
key={address.pk}
|
|
132
132
|
className={clsx(
|
|
133
|
-
'cursor-pointer relative w-full border
|
|
133
|
+
'cursor-pointer relative w-full border shadow p-4 min-h-[8rem]',
|
|
134
134
|
"hover:after:content-[''] hover:after:border-4 hover:after:opacity-30 hover:after:transition-opacity",
|
|
135
135
|
'after:border-secondary-400 after:absolute after:inset-0 after:duration-150 after:-z-10',
|
|
136
136
|
{
|
|
@@ -167,7 +167,7 @@ const AddressBox = ({
|
|
|
167
167
|
<div className="text-xs flex justify-between">
|
|
168
168
|
<Button
|
|
169
169
|
appearance="ghost"
|
|
170
|
-
className="italic underline hover:text-secondary-500 hover
|
|
170
|
+
className="italic underline hover:text-secondary-500 hover:!bg-white hover:!border-white p-0 h-auto"
|
|
171
171
|
onClick={() => setIsEditAddressModalOpen(true)}
|
|
172
172
|
data-testid="checkout-address-edit"
|
|
173
173
|
>
|
|
@@ -193,7 +193,7 @@ const AddressBox = ({
|
|
|
193
193
|
</Modal>
|
|
194
194
|
<Button
|
|
195
195
|
appearance="ghost"
|
|
196
|
-
className="italic underline hover:text-secondary-500 hover
|
|
196
|
+
className="italic underline hover:text-secondary-500 hover:!bg-white hover:!border-white p-0 h-auto"
|
|
197
197
|
onClick={() => setRemoveAddressModalOpen(true)}
|
|
198
198
|
data-testid="checkout-address-remove"
|
|
199
199
|
>
|
|
@@ -153,7 +153,7 @@ const Addresses = () => {
|
|
|
153
153
|
role="button"
|
|
154
154
|
onClick={() => setIsModalOpen(true)}
|
|
155
155
|
className={clsx(
|
|
156
|
-
'relative cursor-pointer w-full min-h-[8rem] border
|
|
156
|
+
'relative cursor-pointer w-full min-h-[8rem] border shadow p-4',
|
|
157
157
|
"hover:after:content-[''] hover:after:border-4 hover:after:opacity-30 hover:after:transition-opacity",
|
|
158
158
|
'after:border-secondary-400 after:absolute after:inset-0 after:opacity-0 after:duration-150 after:-z-10',
|
|
159
159
|
{
|
|
@@ -8,6 +8,7 @@ import PluginModule, { Component } from '@akinon/next/components/plugin-module';
|
|
|
8
8
|
import { twMerge } from 'tailwind-merge';
|
|
9
9
|
import { Image } from '@akinon/next/components/image';
|
|
10
10
|
import { Trans } from '@akinon/next/components/trans';
|
|
11
|
+
import { StoreCredits } from './steps/payment/options/store-credit';
|
|
11
12
|
|
|
12
13
|
export const Summary = () => {
|
|
13
14
|
const { t } = useLocalization();
|
|
@@ -38,6 +39,7 @@ export const Summary = () => {
|
|
|
38
39
|
'flex flex-col w-full mb-4 border border-solid border-gray-400'
|
|
39
40
|
}}
|
|
40
41
|
/>
|
|
42
|
+
<StoreCredits />
|
|
41
43
|
<div className="flex flex-col w-full border border-solid border-gray-400">
|
|
42
44
|
<div className="flex justify-between items-center flex-row border-b border-solid border-gray-400 px-4 py-2 sm:px-5 sm:py-4 sm:min-h-15">
|
|
43
45
|
<span className="text-black-800 text-xl font-light sm:text-2xl">
|
|
@@ -118,6 +120,14 @@ export const Summary = () => {
|
|
|
118
120
|
<Price value={preOrder?.shipping_amount} />
|
|
119
121
|
</span>
|
|
120
122
|
</div>
|
|
123
|
+
{parseFloat(preOrder?.loyalty_money) > 0 && (
|
|
124
|
+
<div className="flex items-center justify-between w-full text-xs text-black-800 py-1 px-4 sm:px-5">
|
|
125
|
+
<span>{t('checkout.summary.loyalty_money_total')}</span>
|
|
126
|
+
<span>
|
|
127
|
+
<Price value={preOrder?.loyalty_money} />
|
|
128
|
+
</span>
|
|
129
|
+
</div>
|
|
130
|
+
)}
|
|
121
131
|
<div className="flex items-center justify-between w-full text-xs text-black-800 py-1 px-4 sm:px-5">
|
|
122
132
|
<span>{t('checkout.summary.discounts_total')}</span>
|
|
123
133
|
<span>
|
|
@@ -149,7 +159,7 @@ export const Summary = () => {
|
|
|
149
159
|
</div>
|
|
150
160
|
</div>
|
|
151
161
|
<div className="flex flex-col py-4 px-4 text-black-800 text-xs sm:px-5">
|
|
152
|
-
<div className="w-full overflow-hidden
|
|
162
|
+
<div className="w-full overflow-hidden overflow-ellipsis mb-1 last:mb-0">
|
|
153
163
|
<Trans
|
|
154
164
|
i18nKey="checkout.summary.info"
|
|
155
165
|
components={{
|
|
@@ -162,7 +172,7 @@ export const Summary = () => {
|
|
|
162
172
|
}}
|
|
163
173
|
/>
|
|
164
174
|
</div>
|
|
165
|
-
<div className="w-full overflow-hidden
|
|
175
|
+
<div className="w-full overflow-hidden overflow-ellipsis mb-1 last:mb-0">
|
|
166
176
|
{preOrder.shipping_address?.line}{' '}
|
|
167
177
|
{preOrder.shipping_address?.postcode}{' '}
|
|
168
178
|
{preOrder.shipping_address?.district && (
|
|
@@ -123,14 +123,14 @@ export const FindInStore = ({ productPk, productName, variants }) => {
|
|
|
123
123
|
className="w-full"
|
|
124
124
|
options={retailStoreOptions}
|
|
125
125
|
{...register('city_id')}
|
|
126
|
-
error={errors.city_id}
|
|
126
|
+
error={errors.city_id as any}
|
|
127
127
|
/>
|
|
128
128
|
{sizeOptions.length > 1 && (
|
|
129
129
|
<Select
|
|
130
130
|
className="w-full"
|
|
131
131
|
options={sizeOptions}
|
|
132
132
|
{...register('size')}
|
|
133
|
-
error={errors.size}
|
|
133
|
+
error={errors.size as any}
|
|
134
134
|
/>
|
|
135
135
|
)}
|
|
136
136
|
</div>
|
|
@@ -76,7 +76,7 @@ export default function ActionMenu() {
|
|
|
76
76
|
: 'bg-secondary-500 text-white'
|
|
77
77
|
)}
|
|
78
78
|
>
|
|
79
|
-
{totalQuantity}
|
|
79
|
+
<span data-testid="header-basket-count">{totalQuantity}</span>
|
|
80
80
|
</Badge>
|
|
81
81
|
),
|
|
82
82
|
miniBasket: <MiniBasket />
|
|
@@ -92,11 +92,7 @@ export default function ActionMenu() {
|
|
|
92
92
|
ref={menu.miniBasket ? miniBasketRef : null}
|
|
93
93
|
>
|
|
94
94
|
{menu.action ? (
|
|
95
|
-
<button
|
|
96
|
-
onClick={menu.action}
|
|
97
|
-
data-testid={menu.dataTestId}
|
|
98
|
-
className="cursor-pointer"
|
|
99
|
-
>
|
|
95
|
+
<button onClick={menu.action} data-testid={menu.dataTestId}>
|
|
100
96
|
<Icon name={menu.icon} size={24} />
|
|
101
97
|
{menu.badge}
|
|
102
98
|
</button>
|
|
@@ -16,13 +16,13 @@ export default function HeaderBand() {
|
|
|
16
16
|
</div>
|
|
17
17
|
|
|
18
18
|
<div className="header-grid-area-nav bg-gray-100 h-auto p-3 sm:header-grid-area-band-m sm:h-9 sm:py-0">
|
|
19
|
-
<div className="text-center
|
|
19
|
+
<div className="text-center overflow-ellipsis line-clamp-2 h-full flex items-center justify-center">
|
|
20
20
|
<HeaderBandText />
|
|
21
21
|
</div>
|
|
22
22
|
</div>
|
|
23
23
|
|
|
24
24
|
<div className="header-grid-area-main-r h-full pr-4 sm:header-grid-area-band-r sm:pr-0">
|
|
25
|
-
<div className="flex items-center justify-end h-full
|
|
25
|
+
<div className="flex items-center justify-end h-full">
|
|
26
26
|
<UserMenu isMobile={false} />
|
|
27
27
|
<ActionMenu />
|
|
28
28
|
</div>
|
|
@@ -13,7 +13,7 @@ import { getMenu } from '@akinon/next/data/server';
|
|
|
13
13
|
import { Image } from '@akinon/next/components/image';
|
|
14
14
|
|
|
15
15
|
export default async function Header() {
|
|
16
|
-
const response = await getMenu();
|
|
16
|
+
const response = await getMenu({ depth: 3 });
|
|
17
17
|
const menu = menuGenerator(response);
|
|
18
18
|
|
|
19
19
|
return (
|
|
@@ -203,7 +203,7 @@ export default function MiniBasket() {
|
|
|
203
203
|
miniBasketOpen
|
|
204
204
|
? 'opacity-100 visible lg:invisible'
|
|
205
205
|
: 'opacity-0 invisible',
|
|
206
|
-
'fixed top-0 left-0 z-50 w-screen h-screen bg-black
|
|
206
|
+
'fixed top-0 left-0 z-50 w-screen h-screen bg-black bg-opacity-80 transition-all duration-300'
|
|
207
207
|
)}
|
|
208
208
|
onClick={() => {
|
|
209
209
|
dispatch(closeMiniBasket());
|
|
@@ -217,7 +217,7 @@ export default function MiniBasket() {
|
|
|
217
217
|
'fixed lg:absolute bottom-0 lg:-bottom-1 right-0 w-80 h-screen lg:h-auto bg-white lg:border-l lg:border-t lg:border-r-2 lg:border-b-2 lg:border-gray-500 p-5 z-50 transition-all duration-300'
|
|
218
218
|
)}
|
|
219
219
|
>
|
|
220
|
-
<header className="flex items-center gap-2 pb-3 border-b
|
|
220
|
+
<header className="flex items-center gap-2 pb-3 border-b">
|
|
221
221
|
<h3 className="text-xl font-bold">
|
|
222
222
|
{t('basket.mini_basket.my_bag')}
|
|
223
223
|
</h3>
|
|
@@ -58,9 +58,9 @@ export default function MobileMenu(props: MobileMenuProps) {
|
|
|
58
58
|
<>
|
|
59
59
|
<div
|
|
60
60
|
className={clsx(
|
|
61
|
-
'fixed top-0 left-0 z-30 w-screen h-screen invisible opacity-0 bg-black
|
|
61
|
+
'fixed top-0 left-0 z-30 w-screen h-screen invisible opacity-0 bg-black bg-opacity-80 transition duration-500',
|
|
62
62
|
{
|
|
63
|
-
'visible!
|
|
63
|
+
'!visible !opacity-100 scroll-lock': isMobileMenuOpen
|
|
64
64
|
}
|
|
65
65
|
)}
|
|
66
66
|
/>
|
|
@@ -70,7 +70,7 @@ export default function MobileMenu(props: MobileMenuProps) {
|
|
|
70
70
|
className={clsx(
|
|
71
71
|
'fixed top-0 left-0 z-50 flex flex-col bg-white w-72 pt-4 h-screen invisible opacity-0 transition duration-500 transform -translate-x-72',
|
|
72
72
|
{
|
|
73
|
-
'visible!
|
|
73
|
+
'!visible !opacity-100 translate-x-0': isMobileMenuOpen
|
|
74
74
|
}
|
|
75
75
|
)}
|
|
76
76
|
>
|
|
@@ -106,15 +106,15 @@ export default function MobileMenu(props: MobileMenuProps) {
|
|
|
106
106
|
className={clsx(
|
|
107
107
|
'absolute top-0 left-0 right-0 px-8 bg-white invisible opacity-0 transition duration-500 transform translate-x-full',
|
|
108
108
|
{
|
|
109
|
-
'visible!
|
|
109
|
+
'!visible !opacity-100 !translate-x-0': selectedSubMenu
|
|
110
110
|
}
|
|
111
111
|
)}
|
|
112
112
|
>
|
|
113
|
-
<header className="flex items-center justify-between border-b
|
|
113
|
+
<header className="flex items-center justify-between border-b h-[61px] py-4 mb-4">
|
|
114
114
|
<Button
|
|
115
115
|
appearance="ghost"
|
|
116
116
|
onClick={() => setSelectedSubMenu(null)}
|
|
117
|
-
className="underline text-xs font-semibold flex items-center gap-2 p-0
|
|
117
|
+
className="underline text-xs font-semibold flex items-center gap-2 !p-0"
|
|
118
118
|
>
|
|
119
119
|
<Icon name="chevron-start" size={12} className="shrink-0" />
|
|
120
120
|
{t('common.mobile_menu.back')}
|
|
@@ -34,7 +34,7 @@ export const PwaBackButton = () => {
|
|
|
34
34
|
return (
|
|
35
35
|
<div className="relative z-10 md:top-0 md:left-0 md:fixed">
|
|
36
36
|
<button
|
|
37
|
-
className="bg-secondary-600 text-white flex items-center justify-center shrink-0 w-12 h-12 md:w-10 md:h-9 active:bg-secondary-700"
|
|
37
|
+
className="bg-secondary-600 text-white flex items-center justify-center flex-shrink-0 w-12 h-12 md:w-10 md:h-9 active:bg-secondary-700"
|
|
38
38
|
onClick={() => router.back()}
|
|
39
39
|
>
|
|
40
40
|
<svg
|
|
@@ -9,6 +9,7 @@ import { Icon } from '@theme/components';
|
|
|
9
9
|
import Results from './results';
|
|
10
10
|
import { ROUTES } from '@theme/routes';
|
|
11
11
|
import { useLocalization, useRouter } from '@akinon/next/hooks';
|
|
12
|
+
import PluginModule, { Component } from '@akinon/next/components/plugin-module';
|
|
12
13
|
|
|
13
14
|
export default function Search() {
|
|
14
15
|
const { t } = useLocalization();
|
|
@@ -46,7 +47,7 @@ export default function Search() {
|
|
|
46
47
|
<div
|
|
47
48
|
className={clsx(
|
|
48
49
|
// 177px is the height of the header
|
|
49
|
-
'absolute bg-black
|
|
50
|
+
'absolute bg-black opacity-75 w-screen h-screen transition duration-500 left-0 bottom-0 translate-y-full z-30',
|
|
50
51
|
isSearchOpen && searchText
|
|
51
52
|
? 'visible opacity-100'
|
|
52
53
|
: 'invisible opacity-0'
|
|
@@ -60,7 +61,7 @@ export default function Search() {
|
|
|
60
61
|
isSearchOpen ? 'visible opacity-100' : 'invisible opacity-0'
|
|
61
62
|
)}
|
|
62
63
|
>
|
|
63
|
-
<div className="max-w-
|
|
64
|
+
<div className="max-w-screen-2xl mx-auto flex flex-col gap-12">
|
|
64
65
|
<div className="border-b border-gray-400 flex flex-col py-1.5 gap-2 self-center items-center md:flex-row">
|
|
65
66
|
<span className="text-xl lg:text-2xl">
|
|
66
67
|
{t('common.search.results_for')}
|
|
@@ -74,10 +75,19 @@ export default function Search() {
|
|
|
74
75
|
router.push(`${ROUTES.LIST}/?search_text=${searchText}`);
|
|
75
76
|
}
|
|
76
77
|
}}
|
|
77
|
-
className="border-0 text-2xl outline-
|
|
78
|
+
className="border-0 text-2xl outline-none text-secondary placeholder:text-xl placeholder:lg:text-2xl"
|
|
78
79
|
placeholder={t('common.search.placeholder')}
|
|
79
80
|
ref={inputRef}
|
|
80
81
|
/>
|
|
82
|
+
|
|
83
|
+
<PluginModule
|
|
84
|
+
component={Component.HeaderImageSearchFeature}
|
|
85
|
+
props={{
|
|
86
|
+
enableTextSearch: true,
|
|
87
|
+
isEnabled: true
|
|
88
|
+
}}
|
|
89
|
+
/>
|
|
90
|
+
|
|
81
91
|
<Icon
|
|
82
92
|
name="close"
|
|
83
93
|
size={14}
|
|
@@ -80,7 +80,7 @@ export default function Results(props: ResultsProps) {
|
|
|
80
80
|
<div className="grid grid-cols-2 sm:grid-cols-4 gap-8">
|
|
81
81
|
{products.map((product, index) => (
|
|
82
82
|
<Link href={product?.url} key={index} className="flex flex-col">
|
|
83
|
-
<div className="relative aspect-315/448">
|
|
83
|
+
<div className="relative aspect-[315/448]">
|
|
84
84
|
{product.extra.image ? (
|
|
85
85
|
<Image
|
|
86
86
|
src={product.extra.image}
|
|
@@ -36,9 +36,7 @@ export const UserMenu = (props: UserMenuProps) => {
|
|
|
36
36
|
<ul
|
|
37
37
|
className={clsx(
|
|
38
38
|
'items-center divide-x divide-black',
|
|
39
|
-
isMobile
|
|
40
|
-
? 'flex pt-2 text-sm pb-6 border-b border-gray-200 mx-8'
|
|
41
|
-
: 'hidden sm:flex'
|
|
39
|
+
isMobile ? 'flex pt-2 text-sm pb-6 border-b mx-8' : 'hidden sm:flex'
|
|
42
40
|
)}
|
|
43
41
|
id="user-menu"
|
|
44
42
|
>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { signIn
|
|
3
|
+
import { signIn } from 'next-auth/react';
|
|
4
4
|
import { useSearchParams } from 'next/navigation';
|
|
5
5
|
import { useState } from 'react';
|
|
6
6
|
import { ROUTES } from '@theme/routes';
|
|
7
|
-
import { LoginFormType } from '@theme/types';
|
|
7
|
+
import { LoginFormType, FormType, PzSignInOptions } from '@theme/types';
|
|
8
8
|
import { Button, Input, Link } from '@theme/components';
|
|
9
9
|
import { SubmitHandler, useForm } from 'react-hook-form';
|
|
10
10
|
import * as yup from 'yup';
|
|
@@ -79,11 +79,12 @@ export const Login = () => {
|
|
|
79
79
|
redirect: false,
|
|
80
80
|
callbackUrl: searchParams.get('callbackUrl') ?? '/',
|
|
81
81
|
captchaValidated,
|
|
82
|
-
...data
|
|
83
|
-
|
|
82
|
+
...data,
|
|
83
|
+
formType: FormType.login
|
|
84
|
+
} as PzSignInOptions & { redirect: false });
|
|
84
85
|
|
|
85
86
|
if (loginResponse.error) {
|
|
86
|
-
const errors: AuthError[] = JSON.parse(loginResponse.
|
|
87
|
+
const errors: AuthError[] = JSON.parse(loginResponse.code);
|
|
87
88
|
|
|
88
89
|
if (errors.find((error) => error.type === 'captcha')) {
|
|
89
90
|
if (await validateCaptcha()) {
|
|
@@ -109,25 +110,25 @@ export const Login = () => {
|
|
|
109
110
|
try {
|
|
110
111
|
parsedValue = JSON.parse(item.value);
|
|
111
112
|
} catch {
|
|
112
|
-
parsedValue = [item.value];
|
|
113
|
+
parsedValue = [item.value];
|
|
113
114
|
}
|
|
114
115
|
} else {
|
|
115
|
-
parsedValue = item.value;
|
|
116
|
+
parsedValue = item.value;
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
if (Array.isArray(parsedValue)) {
|
|
119
120
|
setError(item.name as keyof LoginFormType, {
|
|
120
121
|
type: 'custom',
|
|
121
|
-
message: parsedValue.join(', ')
|
|
122
|
+
message: parsedValue.join(', ')
|
|
122
123
|
});
|
|
123
124
|
} else {
|
|
124
125
|
Object.keys(parsedValue).forEach((key) => {
|
|
125
126
|
const fieldName = key as keyof LoginFormType;
|
|
126
127
|
const errorMessages = parsedValue[key] as string[];
|
|
127
|
-
|
|
128
|
+
|
|
128
129
|
setError(fieldName, {
|
|
129
130
|
type: 'custom',
|
|
130
|
-
message: errorMessages.join(', ')
|
|
131
|
+
message: errorMessages.join(', ')
|
|
131
132
|
});
|
|
132
133
|
});
|
|
133
134
|
}
|
|
@@ -161,7 +162,7 @@ export const Login = () => {
|
|
|
161
162
|
method="post"
|
|
162
163
|
onSubmit={handleSubmit(onSubmit)}
|
|
163
164
|
>
|
|
164
|
-
<input type="hidden" value=
|
|
165
|
+
<input type="hidden" value={FormType.login} {...register('formType')} />
|
|
165
166
|
<input type="hidden" value={locale} {...register('locale')} />
|
|
166
167
|
|
|
167
168
|
<div className={clsx(errors.email ? 'mb-8' : 'mb-4')}>
|
|
@@ -219,7 +220,7 @@ export const Login = () => {
|
|
|
219
220
|
{t('auth.login.form.submit')}
|
|
220
221
|
</Button>
|
|
221
222
|
|
|
222
|
-
<p className="relative text-gray-600 text-center my-4 before:absolute before:h-[1px] before:w-5/12 before:bg-gray-600
|
|
223
|
+
<p className="relative text-gray-600 text-center my-4 before:absolute before:h-[1px] before:w-5/12 before:bg-gray-600 before:bg-opacity-25 before:top-1/2 before:left-0 after:absolute after:h-[1px] after:w-5/12 after:bg-gray-600 after:bg-opacity-25 after:top-1/2 after:right-0">
|
|
223
224
|
{t('auth.login.form.or')}
|
|
224
225
|
</p>
|
|
225
226
|
|
|
@@ -248,7 +249,7 @@ export const Login = () => {
|
|
|
248
249
|
alt={provider.label}
|
|
249
250
|
width={provider.label === 'Facebook' ? 10 : 18}
|
|
250
251
|
height={18}
|
|
251
|
-
className="shrink-0"
|
|
252
|
+
className="flex-shrink-0"
|
|
252
253
|
/>
|
|
253
254
|
)}
|
|
254
255
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { signIn
|
|
3
|
+
import { signIn } from 'next-auth/react';
|
|
4
4
|
import { useState } from 'react';
|
|
5
|
-
import { OtpLoginFormType } from '@theme/types';
|
|
5
|
+
import { OtpLoginFormType, FormType, PzSignInOptions } from '@theme/types';
|
|
6
6
|
import { Button, Input } from '@theme/components';
|
|
7
7
|
import { SubmitHandler, useForm } from 'react-hook-form';
|
|
8
8
|
import * as yup from 'yup';
|
|
@@ -47,11 +47,12 @@ export const OtpLogin = () => {
|
|
|
47
47
|
const loginResponse = await signIn('default', {
|
|
48
48
|
redirect: false,
|
|
49
49
|
callbackUrl: '/',
|
|
50
|
-
...data
|
|
51
|
-
|
|
50
|
+
...data,
|
|
51
|
+
formType: FormType.otpLogin
|
|
52
|
+
} as PzSignInOptions & { redirect: false });
|
|
52
53
|
|
|
53
54
|
if (loginResponse.error) {
|
|
54
|
-
const errors: AuthError[] = JSON.parse(loginResponse.
|
|
55
|
+
const errors: AuthError[] = JSON.parse(loginResponse.code);
|
|
55
56
|
|
|
56
57
|
const fieldErrors = errors.find((error) => error.type === 'field_errors')
|
|
57
58
|
?.data as { name: string; value: string[] }[];
|
|
@@ -100,7 +101,11 @@ export const OtpLogin = () => {
|
|
|
100
101
|
{t('auth.login.title_gsm')}
|
|
101
102
|
</h2>
|
|
102
103
|
<form onSubmit={handleSubmit(onSubmit)}>
|
|
103
|
-
<input
|
|
104
|
+
<input
|
|
105
|
+
type="hidden"
|
|
106
|
+
value={FormType.otpLogin}
|
|
107
|
+
{...register('formType')}
|
|
108
|
+
/>
|
|
104
109
|
<input type="hidden" value={locale} {...register('locale')} />
|
|
105
110
|
|
|
106
111
|
<div className="mb-4">
|
|
@@ -22,6 +22,16 @@ export default async function ProductLayout({
|
|
|
22
22
|
breadcrumbData,
|
|
23
23
|
children
|
|
24
24
|
}: ProductPageProps) {
|
|
25
|
+
const categoryIds = breadcrumbData
|
|
26
|
+
?.map((item) => item.extra_context?.attributes?.category_id)
|
|
27
|
+
.filter(Boolean)
|
|
28
|
+
.join(',');
|
|
29
|
+
|
|
30
|
+
const categoryPaths = breadcrumbData
|
|
31
|
+
?.map((item) => item.path)
|
|
32
|
+
.filter(Boolean)
|
|
33
|
+
.join(',');
|
|
34
|
+
|
|
25
35
|
return (
|
|
26
36
|
<div className="container mx-auto">
|
|
27
37
|
<div className="max-w-5xl mx-auto my-5 px-7">
|
|
@@ -31,7 +41,11 @@ export default async function ProductLayout({
|
|
|
31
41
|
<div className="col-span-5 lg:col-span-3">
|
|
32
42
|
<ProductInfoSlider product={data.product} />
|
|
33
43
|
</div>
|
|
34
|
-
<div
|
|
44
|
+
<div
|
|
45
|
+
className="flex flex-col items-center col-span-5 lg:col-span-2"
|
|
46
|
+
data-category-ids={categoryIds}
|
|
47
|
+
data-category-paths={categoryPaths}
|
|
48
|
+
>
|
|
35
49
|
<div className="w-full">{children}</div>
|
|
36
50
|
</div>
|
|
37
51
|
</div>
|