@akinon/next 1.65.0 → 1.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/api/client.ts +23 -2
- package/assets/styles/index.css +49 -0
- package/assets/styles/index.css.map +1 -0
- package/assets/styles/index.scss +50 -26
- package/components/file-input.tsx +8 -0
- package/components/index.ts +1 -0
- package/data/client/api.ts +1 -1
- package/data/client/basket.ts +6 -5
- package/data/client/checkout.ts +38 -10
- package/data/client/user.ts +3 -2
- package/data/urls.ts +11 -3
- package/hooks/index.ts +2 -1
- package/hooks/use-message-listener.ts +24 -0
- package/hooks/use-pagination.ts +2 -2
- package/package.json +2 -2
- package/plugins.d.ts +1 -0
- package/redux/middlewares/checkout.ts +50 -12
- package/redux/reducers/checkout.ts +16 -3
- package/types/commerce/checkout.ts +13 -0
- package/types/index.ts +2 -0
- package/utils/redirection-iframe.ts +85 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @akinon/next
|
|
2
2
|
|
|
3
|
+
## 1.67.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- bc2b411: ZERO-2825: Add attribute-based shipping options to checkout page
|
|
8
|
+
- 3d2212a: ZERO-2745: Add multi basket support
|
|
9
|
+
- 8f47cca: ZERO-2829: fix and add nested JSON support for useFormData in api/client route
|
|
10
|
+
- 9e25a64: ZERO-2835: Update category page layout with breadcrumb
|
|
11
|
+
|
|
12
|
+
## 1.66.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- 572d2e8: ZERO-2667: Add iframe support for redirection payment methods
|
|
17
|
+
- 2e6104d: ZERO-2888:Edit the numbering in the pagination and the visibility of the prev and next buttons
|
|
18
|
+
- 7b05522: ZERO-2905: Fix resend and close button in otp package
|
|
19
|
+
- 29ead87: ZERO-2905: Fix resend and close button in otp package
|
|
20
|
+
- 12a873e: ZERO-2846:Edit the siteKey regex in the response from GetCaptcha
|
|
21
|
+
- f2c325c: ZERO-2838: Move file input component into @akinon/next
|
|
22
|
+
|
|
3
23
|
## 1.65.0
|
|
4
24
|
|
|
5
25
|
### Minor Changes
|
package/api/client.ts
CHANGED
|
@@ -4,6 +4,7 @@ import settings from 'settings';
|
|
|
4
4
|
import logger from '../utils/log';
|
|
5
5
|
import formatCookieString from '../utils/format-cookie-string';
|
|
6
6
|
import cookieParser from 'set-cookie-parser';
|
|
7
|
+
import { cookies } from 'next/headers';
|
|
7
8
|
|
|
8
9
|
interface RouteParams {
|
|
9
10
|
params: {
|
|
@@ -80,11 +81,27 @@ async function proxyRequest(...args) {
|
|
|
80
81
|
}
|
|
81
82
|
} as RequestInit;
|
|
82
83
|
|
|
84
|
+
const nextCookies = cookies();
|
|
85
|
+
const segment = nextCookies.get('pz-segment')?.value;
|
|
86
|
+
const currency = nextCookies.get('pz-external-currency')?.value;
|
|
87
|
+
|
|
88
|
+
if (segment) {
|
|
89
|
+
fetchOptions.headers['X-Segment-Id'] = segment;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (currency) {
|
|
93
|
+
fetchOptions.headers = Object.assign({}, fetchOptions.headers, {
|
|
94
|
+
'x-currency': currency
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
83
98
|
if (options.contentType) {
|
|
84
99
|
fetchOptions.headers['Content-Type'] = options.contentType;
|
|
85
100
|
}
|
|
86
101
|
|
|
87
|
-
const isMultipartFormData = req.headers
|
|
102
|
+
const isMultipartFormData = req.headers
|
|
103
|
+
.get('content-type')
|
|
104
|
+
?.includes('multipart/form-data;');
|
|
88
105
|
|
|
89
106
|
if (req.method !== 'GET') {
|
|
90
107
|
let body: Record<string, any> | FormData = {};
|
|
@@ -108,7 +125,11 @@ async function proxyRequest(...args) {
|
|
|
108
125
|
|
|
109
126
|
Object.keys(body ?? {}).forEach((key) => {
|
|
110
127
|
if (body[key]) {
|
|
111
|
-
|
|
128
|
+
if (typeof body[key] === 'object' && body[key] !== null) {
|
|
129
|
+
formData.append(key, JSON.stringify(body[key]));
|
|
130
|
+
} else {
|
|
131
|
+
formData.append(key, body[key]);
|
|
132
|
+
}
|
|
112
133
|
}
|
|
113
134
|
});
|
|
114
135
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
.checkout-payment-iframe-wrapper {
|
|
2
|
+
position: fixed;
|
|
3
|
+
top: 0;
|
|
4
|
+
left: 0;
|
|
5
|
+
width: 100%;
|
|
6
|
+
height: 100%;
|
|
7
|
+
border: none;
|
|
8
|
+
z-index: 1000;
|
|
9
|
+
background-color: white;
|
|
10
|
+
}
|
|
11
|
+
.checkout-payment-iframe-wrapper iframe {
|
|
12
|
+
width: 100%;
|
|
13
|
+
height: 100%;
|
|
14
|
+
border: none;
|
|
15
|
+
background-color: white;
|
|
16
|
+
}
|
|
17
|
+
.checkout-payment-iframe-wrapper .close-button {
|
|
18
|
+
position: fixed;
|
|
19
|
+
top: 16px;
|
|
20
|
+
right: 16px;
|
|
21
|
+
width: 32px;
|
|
22
|
+
height: 32px;
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
justify-content: center;
|
|
26
|
+
z-index: 1001;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.checkout-payment-redirection-iframe-wrapper {
|
|
30
|
+
width: 100%;
|
|
31
|
+
position: relative;
|
|
32
|
+
}
|
|
33
|
+
.checkout-payment-redirection-iframe-wrapper iframe {
|
|
34
|
+
width: 100%;
|
|
35
|
+
height: 100%;
|
|
36
|
+
border: none;
|
|
37
|
+
background-color: white;
|
|
38
|
+
}
|
|
39
|
+
.checkout-payment-redirection-iframe-wrapper .close-button {
|
|
40
|
+
position: absolute;
|
|
41
|
+
top: 16px;
|
|
42
|
+
right: 16px;
|
|
43
|
+
width: 32px;
|
|
44
|
+
height: 32px;
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
justify-content: center;
|
|
48
|
+
z-index: 1001;
|
|
49
|
+
}/*# sourceMappingURL=index.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["index.scss","index.css"],"names":[],"mappings":"AAAA;EACE,eAAA;EACA,MAAA;EACA,OAAA;EACA,WAAA;EACA,YAAA;EACA,YAAA;EACA,aAAA;EACA,uBAAA;ACCF;ADCE;EACE,WAAA;EACA,YAAA;EACA,YAAA;EACA,uBAAA;ACCJ;ADEE;EACE,eAAA;EACA,SAAA;EACA,WAAA;EACA,WAAA;EACA,YAAA;EACA,aAAA;EACA,mBAAA;EACA,uBAAA;EACA,aAAA;ACAJ;;ADIA;EACE,WAAA;EACA,kBAAA;ACDF;ADGE;EACE,WAAA;EACA,YAAA;EACA,YAAA;EACA,uBAAA;ACDJ;ADIE;EACE,kBAAA;EACA,SAAA;EACA,WAAA;EACA,WAAA;EACA,YAAA;EACA,aAAA;EACA,mBAAA;EACA,uBAAA;EACA,aAAA;ACFJ","file":"index.css"}
|
package/assets/styles/index.scss
CHANGED
|
@@ -1,29 +1,53 @@
|
|
|
1
1
|
.checkout-payment-iframe-wrapper {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
position: fixed;
|
|
3
|
+
top: 0;
|
|
4
|
+
left: 0;
|
|
5
|
+
width: 100%;
|
|
6
|
+
height: 100%;
|
|
7
|
+
border: none;
|
|
8
|
+
z-index: 1000;
|
|
9
|
+
background-color: white;
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
iframe {
|
|
12
|
+
width: 100%;
|
|
13
|
+
height: 100%;
|
|
14
|
+
border: none;
|
|
15
|
+
background-color: white;
|
|
16
|
+
}
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
18
|
+
.close-button {
|
|
19
|
+
position: fixed;
|
|
20
|
+
top: 16px;
|
|
21
|
+
right: 16px;
|
|
22
|
+
width: 32px;
|
|
23
|
+
height: 32px;
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
z-index: 1001;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.checkout-payment-redirection-iframe-wrapper {
|
|
32
|
+
width: 100%;
|
|
33
|
+
position: relative;
|
|
34
|
+
|
|
35
|
+
iframe {
|
|
36
|
+
width: 100%;
|
|
37
|
+
height: 100%;
|
|
38
|
+
border: none;
|
|
39
|
+
background-color: white;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.close-button {
|
|
43
|
+
position: absolute;
|
|
44
|
+
top: 16px;
|
|
45
|
+
right: 16px;
|
|
46
|
+
width: 32px;
|
|
47
|
+
height: 32px;
|
|
48
|
+
display: flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
justify-content: center;
|
|
51
|
+
z-index: 1001;
|
|
52
|
+
}
|
|
53
|
+
}
|
package/components/index.ts
CHANGED
package/data/client/api.ts
CHANGED
package/data/client/basket.ts
CHANGED
|
@@ -28,7 +28,7 @@ export const basketApi = api.injectEndpoints({
|
|
|
28
28
|
query: ({ namespace }) =>
|
|
29
29
|
buildClientRequestUrl(basket.getBasketDetail(namespace)),
|
|
30
30
|
transformResponse: (response: { basket: Basket }) => response.basket,
|
|
31
|
-
providesTags: ['
|
|
31
|
+
providesTags: ['MultiBasket']
|
|
32
32
|
}),
|
|
33
33
|
getAllBaskets: build.query<Basket[], void>({
|
|
34
34
|
query: () =>
|
|
@@ -36,7 +36,7 @@ export const basketApi = api.injectEndpoints({
|
|
|
36
36
|
contentType: 'application/json'
|
|
37
37
|
}),
|
|
38
38
|
transformResponse: (response: { baskets: Basket[] }) => response.baskets,
|
|
39
|
-
providesTags: ['
|
|
39
|
+
providesTags: ['MultiBasket']
|
|
40
40
|
}),
|
|
41
41
|
removeBasket: build.mutation<Basket, { pk: number }>({
|
|
42
42
|
query: ({ pk }) => ({
|
|
@@ -46,7 +46,7 @@ export const basketApi = api.injectEndpoints({
|
|
|
46
46
|
method: 'DELETE',
|
|
47
47
|
body: { pk }
|
|
48
48
|
}),
|
|
49
|
-
invalidatesTags: ['
|
|
49
|
+
invalidatesTags: ['MultiBasket', 'Basket']
|
|
50
50
|
}),
|
|
51
51
|
selectMainBasket: build.mutation<Basket, { pk: number }>({
|
|
52
52
|
query: ({ pk }) => ({
|
|
@@ -57,7 +57,7 @@ export const basketApi = api.injectEndpoints({
|
|
|
57
57
|
body: { pk }
|
|
58
58
|
}),
|
|
59
59
|
transformResponse: (response: { baskets: Basket }) => response.baskets,
|
|
60
|
-
invalidatesTags: ['
|
|
60
|
+
invalidatesTags: ['MultiBasket', 'Basket']
|
|
61
61
|
}),
|
|
62
62
|
updateQuantity: build.mutation<
|
|
63
63
|
UpdateQuantityResponse,
|
|
@@ -69,7 +69,8 @@ export const basketApi = api.injectEndpoints({
|
|
|
69
69
|
}),
|
|
70
70
|
method: 'PUT',
|
|
71
71
|
body
|
|
72
|
-
})
|
|
72
|
+
}),
|
|
73
|
+
invalidatesTags: ['MultiBasket', 'Basket']
|
|
73
74
|
}),
|
|
74
75
|
clearBasket: build.mutation<Basket, void>({
|
|
75
76
|
query: (body) => ({
|
package/data/client/checkout.ts
CHANGED
|
@@ -57,6 +57,7 @@ export interface CompleteCreditCardParams {
|
|
|
57
57
|
card_month: string;
|
|
58
58
|
card_year: string;
|
|
59
59
|
use_three_d?: boolean;
|
|
60
|
+
save?: boolean;
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
interface GetContractResponse {
|
|
@@ -228,7 +229,8 @@ export const checkoutApi = api.injectEndpoints({
|
|
|
228
229
|
card_number,
|
|
229
230
|
card_month,
|
|
230
231
|
card_year,
|
|
231
|
-
use_three_d = true
|
|
232
|
+
use_three_d = true,
|
|
233
|
+
save = undefined
|
|
232
234
|
}) => {
|
|
233
235
|
const paymentOption =
|
|
234
236
|
store.getState().checkout?.preOrder?.payment_option;
|
|
@@ -242,20 +244,26 @@ export const checkoutApi = api.injectEndpoints({
|
|
|
242
244
|
};
|
|
243
245
|
}
|
|
244
246
|
|
|
247
|
+
const body: Record<string, string> = {
|
|
248
|
+
agreement: '1',
|
|
249
|
+
use_three_d: use_three_d ? '1' : '0',
|
|
250
|
+
card_cvv,
|
|
251
|
+
card_holder,
|
|
252
|
+
card_month,
|
|
253
|
+
card_number,
|
|
254
|
+
card_year
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
if (save !== undefined) {
|
|
258
|
+
body.save = save ? '1' : '0';
|
|
259
|
+
}
|
|
260
|
+
|
|
245
261
|
return {
|
|
246
262
|
url: buildClientRequestUrl(checkout.completeCreditCardPayment, {
|
|
247
263
|
useFormData: true
|
|
248
264
|
}),
|
|
249
265
|
method: 'POST',
|
|
250
|
-
body
|
|
251
|
-
agreement: '1',
|
|
252
|
-
use_three_d: use_three_d ? '1' : '0',
|
|
253
|
-
card_cvv,
|
|
254
|
-
card_holder,
|
|
255
|
-
card_month,
|
|
256
|
-
card_number,
|
|
257
|
-
card_year
|
|
258
|
-
}
|
|
266
|
+
body
|
|
259
267
|
};
|
|
260
268
|
},
|
|
261
269
|
async onQueryStarted(args, { dispatch, queryFulfilled }) {
|
|
@@ -697,6 +705,25 @@ export const checkoutApi = api.injectEndpoints({
|
|
|
697
705
|
};
|
|
698
706
|
}
|
|
699
707
|
}),
|
|
708
|
+
setAttributeBasedShippingOptions: build.mutation<
|
|
709
|
+
CheckoutResponse,
|
|
710
|
+
Record<string, number>
|
|
711
|
+
>({
|
|
712
|
+
query: (options) => ({
|
|
713
|
+
url: buildClientRequestUrl(checkout.setAttributeBasedShippingOption, {
|
|
714
|
+
useFormData: true
|
|
715
|
+
}),
|
|
716
|
+
method: 'POST',
|
|
717
|
+
body: {
|
|
718
|
+
attribute_based_shipping_options: JSON.stringify(options)
|
|
719
|
+
}
|
|
720
|
+
}),
|
|
721
|
+
async onQueryStarted(arg, { dispatch, queryFulfilled }) {
|
|
722
|
+
dispatch(setShippingStepBusy(true));
|
|
723
|
+
await queryFulfilled;
|
|
724
|
+
dispatch(setShippingStepBusy(false));
|
|
725
|
+
}
|
|
726
|
+
}),
|
|
700
727
|
setOrderSelectionPage: build.mutation<
|
|
701
728
|
CheckoutResponse,
|
|
702
729
|
{ extra_field: ExtraField }
|
|
@@ -747,5 +774,6 @@ export const {
|
|
|
747
774
|
usePayWithLoyaltyBalanceMutation,
|
|
748
775
|
useSetOrderNoteMutation,
|
|
749
776
|
useSetDeliveryBagsMutation,
|
|
777
|
+
useSetAttributeBasedShippingOptionsMutation,
|
|
750
778
|
useSetOrderSelectionPageMutation
|
|
751
779
|
} = checkoutApi;
|
package/data/client/user.ts
CHANGED
|
@@ -22,11 +22,12 @@ const userApi = api.injectEndpoints({
|
|
|
22
22
|
getCaptcha: build.query<GetCaptchaResponse, void>({
|
|
23
23
|
query: () => buildClientRequestUrl(user.captcha),
|
|
24
24
|
transformResponse: (response: { html: string }) => {
|
|
25
|
-
const
|
|
25
|
+
const siteKey = response.html.match(/data-sitekey="([^"]+)"/i)[1];
|
|
26
|
+
|
|
26
27
|
const csrfTokenMatch = response.html.match(
|
|
27
28
|
/name=['|"]csrfmiddlewaretoken['|"] value=['|"][^'"]+/gi
|
|
28
29
|
);
|
|
29
|
-
|
|
30
|
+
|
|
30
31
|
const csrfToken =
|
|
31
32
|
csrfTokenMatch?.[0].replace(
|
|
32
33
|
/name=['|"]csrfmiddlewaretoken['|"] value=['|"]/gi,
|
package/data/urls.ts
CHANGED
|
@@ -17,16 +17,22 @@ export const account = {
|
|
|
17
17
|
page,
|
|
18
18
|
limit,
|
|
19
19
|
createdDate,
|
|
20
|
-
endDate
|
|
20
|
+
endDate,
|
|
21
|
+
shipping_option_slug
|
|
21
22
|
}: {
|
|
22
23
|
page?: number;
|
|
23
24
|
limit?: number;
|
|
24
25
|
createdDate?: string;
|
|
25
26
|
endDate?: string;
|
|
27
|
+
shipping_option_slug?: string;
|
|
26
28
|
}) =>
|
|
27
|
-
`/users/orders/?page=${page || 1}&limit=${limit || 12}
|
|
29
|
+
`/users/orders/?page=${page || 1}&limit=${limit || 12}${
|
|
28
30
|
createdDate ? `&created_date__gte=${createdDate}` : ''
|
|
29
|
-
}
|
|
31
|
+
}${endDate ? `&created_date__lte=${endDate}` : ''}${
|
|
32
|
+
shipping_option_slug
|
|
33
|
+
? `&shipping_option_slug=${shipping_option_slug}`
|
|
34
|
+
: ''
|
|
35
|
+
}`,
|
|
30
36
|
getQuotations: (page?: number, status?: string, limit?: number) =>
|
|
31
37
|
`/b2b/my-quotations/?page=${page || 1}` +
|
|
32
38
|
(status ? `&status=${status}` : '') +
|
|
@@ -111,6 +117,8 @@ export const checkout = {
|
|
|
111
117
|
loyaltyMoneyUsage: '/orders/checkout/?page=LoyaltyMoneyUsagePage',
|
|
112
118
|
setOrderNote: '/orders/checkout/?page=OrderNotePage',
|
|
113
119
|
couponSelectionPage: '/orders/checkout/?page=CouponSelectionPage',
|
|
120
|
+
setAttributeBasedShippingOption:
|
|
121
|
+
'/orders/checkout/?page=AttributeBasedShippingOptionSelectionPage',
|
|
114
122
|
deliveryBagsPage: '/orders/checkout/?page=DeliveryBagsPage',
|
|
115
123
|
setOrderSelectionPage: '/orders/checkout/?page=OrderSelectionPage'
|
|
116
124
|
};
|
package/hooks/index.ts
CHANGED
|
@@ -8,4 +8,5 @@ export * from './use-media-query';
|
|
|
8
8
|
export * from './use-on-click-outside';
|
|
9
9
|
export * from './use-mobile-iframe-handler';
|
|
10
10
|
export * from './use-payment-options';
|
|
11
|
-
export * from './use-pagination';
|
|
11
|
+
export * from './use-pagination';
|
|
12
|
+
export * from './use-message-listener';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
export const useMessageListener = () => {
|
|
4
|
+
useEffect(() => {
|
|
5
|
+
const handleMessage = (event: MessageEvent) => {
|
|
6
|
+
if (event.origin !== window.location.origin) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (event.data && typeof event.data === 'string') {
|
|
11
|
+
const messageData = JSON.parse(event.data);
|
|
12
|
+
if (messageData?.url) {
|
|
13
|
+
window.location.href = messageData.url;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
window.addEventListener('message', handleMessage);
|
|
19
|
+
|
|
20
|
+
return () => {
|
|
21
|
+
window.removeEventListener('message', handleMessage);
|
|
22
|
+
};
|
|
23
|
+
}, []);
|
|
24
|
+
};
|
package/hooks/use-pagination.ts
CHANGED
|
@@ -116,7 +116,7 @@ export default function usePagination(
|
|
|
116
116
|
urlSearchParams.set('page', (Number(state.page) - 1).toString());
|
|
117
117
|
return `${pathname}?${urlSearchParams.toString()}`;
|
|
118
118
|
}
|
|
119
|
-
return
|
|
119
|
+
return null;
|
|
120
120
|
}, [state.page, pathname, urlSearchParams]);
|
|
121
121
|
|
|
122
122
|
const next = useMemo(() => {
|
|
@@ -124,7 +124,7 @@ export default function usePagination(
|
|
|
124
124
|
urlSearchParams.set('page', (Number(state.page) + 1).toString());
|
|
125
125
|
return `${pathname}?${urlSearchParams.toString()}`;
|
|
126
126
|
}
|
|
127
|
-
return
|
|
127
|
+
return null;
|
|
128
128
|
}, [state.page, state.last, pathname, urlSearchParams]);
|
|
129
129
|
|
|
130
130
|
return {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akinon/next",
|
|
3
3
|
"description": "Core package for Project Zero Next",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.67.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"set-cookie-parser": "2.6.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@akinon/eslint-plugin-projectzero": "1.
|
|
33
|
+
"@akinon/eslint-plugin-projectzero": "1.67.0",
|
|
34
34
|
"@types/react-redux": "7.1.30",
|
|
35
35
|
"@types/set-cookie-parser": "2.4.7",
|
|
36
36
|
"@typescript-eslint/eslint-plugin": "6.7.4",
|
package/plugins.d.ts
CHANGED
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
import { Middleware } from '@reduxjs/toolkit';
|
|
4
4
|
import {
|
|
5
5
|
setAddressList,
|
|
6
|
+
setAttributeBasedShippingOptions,
|
|
6
7
|
setBankAccounts,
|
|
7
8
|
setCanGuestPurchase,
|
|
8
9
|
setCardType,
|
|
10
|
+
setCreditPaymentOptions,
|
|
11
|
+
setDataSourceShippingOptions,
|
|
9
12
|
setDeliveryOptions,
|
|
10
13
|
setErrors,
|
|
11
14
|
setHasGiftBox,
|
|
@@ -16,9 +19,7 @@ import {
|
|
|
16
19
|
setPreOrder,
|
|
17
20
|
setRetailStores,
|
|
18
21
|
setShippingOptions,
|
|
19
|
-
|
|
20
|
-
setShippingStepCompleted,
|
|
21
|
-
setCreditPaymentOptions
|
|
22
|
+
setShippingStepCompleted
|
|
22
23
|
} from '../../redux/reducers/checkout';
|
|
23
24
|
import { RootState, TypedDispatch } from 'redux/store';
|
|
24
25
|
import { checkoutApi } from '../../data/client/checkout';
|
|
@@ -27,6 +28,7 @@ import { getCookie, setCookie } from '../../utils';
|
|
|
27
28
|
import settings from 'settings';
|
|
28
29
|
import { LocaleUrlStrategy } from '../../localization';
|
|
29
30
|
import { showMobile3dIframe } from '../../utils/mobile-3d-iframe';
|
|
31
|
+
import { showRedirectionIframe } from '../../utils/redirection-iframe';
|
|
30
32
|
|
|
31
33
|
interface CheckoutResult {
|
|
32
34
|
payload: {
|
|
@@ -76,7 +78,8 @@ export const preOrderMiddleware: Middleware = ({
|
|
|
76
78
|
shippingOptions,
|
|
77
79
|
dataSourceShippingOptions,
|
|
78
80
|
paymentOptions,
|
|
79
|
-
installmentOptions
|
|
81
|
+
installmentOptions,
|
|
82
|
+
attributeBasedShippingOptions
|
|
80
83
|
} = getState().checkout;
|
|
81
84
|
const { endpoints: apiEndpoints } = checkoutApi;
|
|
82
85
|
|
|
@@ -144,11 +147,33 @@ export const preOrderMiddleware: Middleware = ({
|
|
|
144
147
|
);
|
|
145
148
|
}
|
|
146
149
|
|
|
150
|
+
if (
|
|
151
|
+
Object.keys(attributeBasedShippingOptions).length > 0 &&
|
|
152
|
+
!preOrder.attribute_based_shipping_options
|
|
153
|
+
) {
|
|
154
|
+
const initialSelectedOptions: Record<string, number> = Object.fromEntries(
|
|
155
|
+
Object.entries(attributeBasedShippingOptions).map(([key, options]) => [
|
|
156
|
+
key,
|
|
157
|
+
options.attribute_based_shipping_options[0].pk
|
|
158
|
+
])
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
dispatch(
|
|
162
|
+
apiEndpoints.setAttributeBasedShippingOptions.initiate(
|
|
163
|
+
initialSelectedOptions
|
|
164
|
+
)
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
147
168
|
if (!preOrder.payment_option && paymentOptions.length > 0) {
|
|
148
169
|
dispatch(apiEndpoints.setPaymentOption.initiate(paymentOptions[0].pk));
|
|
149
170
|
}
|
|
150
171
|
|
|
151
|
-
if (
|
|
172
|
+
if (
|
|
173
|
+
!preOrder.installment &&
|
|
174
|
+
preOrder.payment_option?.payment_type !== 'saved_card' &&
|
|
175
|
+
installmentOptions.length > 0
|
|
176
|
+
) {
|
|
152
177
|
dispatch(
|
|
153
178
|
apiEndpoints.setInstallmentOption.initiate(installmentOptions[0].pk)
|
|
154
179
|
);
|
|
@@ -182,6 +207,8 @@ export const contextListMiddleware: Middleware = ({
|
|
|
182
207
|
if (result?.payload?.context_list) {
|
|
183
208
|
result.payload.context_list.forEach((context) => {
|
|
184
209
|
const redirectUrl = context.page_context.redirect_url;
|
|
210
|
+
const isIframe = context.page_context.is_frame ?? false;
|
|
211
|
+
|
|
185
212
|
if (redirectUrl) {
|
|
186
213
|
const currentLocale = getCookie('pz-locale');
|
|
187
214
|
|
|
@@ -199,16 +226,19 @@ export const contextListMiddleware: Middleware = ({
|
|
|
199
226
|
}
|
|
200
227
|
|
|
201
228
|
const urlObj = new URL(url, window.location.origin);
|
|
229
|
+
const isMobileDevice =
|
|
230
|
+
isMobileApp ||
|
|
231
|
+
/iPad|iPhone|iPod|Android/i.test(navigator.userAgent);
|
|
232
|
+
const isIframePaymentOptionExcluded =
|
|
233
|
+
settings.checkout?.iframeExcludedPaymentOptions?.includes(
|
|
234
|
+
result.payload?.pre_order?.payment_option?.slug
|
|
235
|
+
);
|
|
202
236
|
urlObj.searchParams.set('t', new Date().getTime().toString());
|
|
203
237
|
|
|
204
|
-
if (
|
|
205
|
-
(isMobileApp ||
|
|
206
|
-
/iPad|iPhone|iPod|Android/i.test(navigator.userAgent)) &&
|
|
207
|
-
!settings.checkout?.iframeExcludedPaymentOptions?.includes(
|
|
208
|
-
result.payload?.pre_order?.payment_option?.slug
|
|
209
|
-
)
|
|
210
|
-
) {
|
|
238
|
+
if (isMobileDevice && !isIframePaymentOptionExcluded) {
|
|
211
239
|
showMobile3dIframe(urlObj.toString());
|
|
240
|
+
} else if (isIframe && !isIframePaymentOptionExcluded) {
|
|
241
|
+
showRedirectionIframe(urlObj.toString());
|
|
212
242
|
} else {
|
|
213
243
|
window.location.href = urlObj.toString();
|
|
214
244
|
}
|
|
@@ -244,6 +274,14 @@ export const contextListMiddleware: Middleware = ({
|
|
|
244
274
|
);
|
|
245
275
|
}
|
|
246
276
|
|
|
277
|
+
if (context.page_context.attribute_based_shipping_options) {
|
|
278
|
+
dispatch(
|
|
279
|
+
setAttributeBasedShippingOptions(
|
|
280
|
+
context.page_context.attribute_based_shipping_options
|
|
281
|
+
)
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
|
|
247
285
|
if (context.page_context.payment_options) {
|
|
248
286
|
dispatch(setPaymentOptions(context.page_context.payment_options));
|
|
249
287
|
}
|
|
@@ -15,7 +15,8 @@ import {
|
|
|
15
15
|
PreOrder,
|
|
16
16
|
RetailStore,
|
|
17
17
|
ShippingOption,
|
|
18
|
-
DataSource
|
|
18
|
+
DataSource,
|
|
19
|
+
AttributeBasedShippingOption
|
|
19
20
|
} from '../../types';
|
|
20
21
|
|
|
21
22
|
export interface CheckoutState {
|
|
@@ -48,6 +49,8 @@ export interface CheckoutState {
|
|
|
48
49
|
selectedBankAccountPk: number;
|
|
49
50
|
loyaltyBalance?: string;
|
|
50
51
|
retailStores: RetailStore[];
|
|
52
|
+
attributeBasedShippingOptions: AttributeBasedShippingOption[];
|
|
53
|
+
selectedShippingOptions: Record<string, number>;
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
const initialState: CheckoutState = {
|
|
@@ -78,7 +81,9 @@ const initialState: CheckoutState = {
|
|
|
78
81
|
installmentOptions: [],
|
|
79
82
|
bankAccounts: [],
|
|
80
83
|
selectedBankAccountPk: null,
|
|
81
|
-
retailStores: []
|
|
84
|
+
retailStores: [],
|
|
85
|
+
attributeBasedShippingOptions: [],
|
|
86
|
+
selectedShippingOptions: {}
|
|
82
87
|
};
|
|
83
88
|
|
|
84
89
|
const checkoutSlice = createSlice({
|
|
@@ -156,6 +161,12 @@ const checkoutSlice = createSlice({
|
|
|
156
161
|
},
|
|
157
162
|
setRetailStores(state, { payload }) {
|
|
158
163
|
state.retailStores = payload;
|
|
164
|
+
},
|
|
165
|
+
setAttributeBasedShippingOptions(state, { payload }) {
|
|
166
|
+
state.attributeBasedShippingOptions = payload;
|
|
167
|
+
},
|
|
168
|
+
setSelectedShippingOptions: (state, { payload }) => {
|
|
169
|
+
state.selectedShippingOptions = payload;
|
|
159
170
|
}
|
|
160
171
|
}
|
|
161
172
|
});
|
|
@@ -184,7 +195,9 @@ export const {
|
|
|
184
195
|
setBankAccounts,
|
|
185
196
|
setSelectedBankAccountPk,
|
|
186
197
|
setLoyaltyBalance,
|
|
187
|
-
setRetailStores
|
|
198
|
+
setRetailStores,
|
|
199
|
+
setAttributeBasedShippingOptions,
|
|
200
|
+
setSelectedShippingOptions
|
|
188
201
|
} = checkoutSlice.actions;
|
|
189
202
|
|
|
190
203
|
export default checkoutSlice.reducer;
|
|
@@ -86,6 +86,7 @@ export interface PreOrder {
|
|
|
86
86
|
total_amount?: string;
|
|
87
87
|
total_amount_with_interest?: string;
|
|
88
88
|
unpaid_amount?: string;
|
|
89
|
+
notes?: string;
|
|
89
90
|
user_phone_number?: string;
|
|
90
91
|
loyalty_money?: string;
|
|
91
92
|
currency_type_label?: string;
|
|
@@ -97,6 +98,7 @@ export interface PreOrder {
|
|
|
97
98
|
gift_box?: GiftBox;
|
|
98
99
|
credit_payment_option?: CheckoutCreditPaymentOption;
|
|
99
100
|
data_source_shipping_options: any;
|
|
101
|
+
attribute_based_shipping_options: any;
|
|
100
102
|
bags?: Product[];
|
|
101
103
|
bags_fee?: string;
|
|
102
104
|
extra_field?: ExtraField;
|
|
@@ -141,6 +143,7 @@ export interface CheckoutContext {
|
|
|
141
143
|
redirect_url?: string;
|
|
142
144
|
context_data?: any;
|
|
143
145
|
balance?: string;
|
|
146
|
+
attribute_based_shipping_options?: AttributeBasedShippingOption[];
|
|
144
147
|
[key: string]: any;
|
|
145
148
|
};
|
|
146
149
|
}
|
|
@@ -166,3 +169,13 @@ export interface BankAccount {
|
|
|
166
169
|
pk: number;
|
|
167
170
|
sort_order: number;
|
|
168
171
|
}
|
|
172
|
+
|
|
173
|
+
export interface AttributeBasedShippingOption {
|
|
174
|
+
pk: number;
|
|
175
|
+
shipping_amount: string | null;
|
|
176
|
+
shipping_option_name: string | null;
|
|
177
|
+
shipping_option_logo: string | null;
|
|
178
|
+
attribute_value: string | null;
|
|
179
|
+
attribute_key: string;
|
|
180
|
+
[key: string]: any;
|
|
181
|
+
}
|
package/types/index.ts
CHANGED
|
@@ -269,6 +269,8 @@ export interface ButtonProps
|
|
|
269
269
|
appearance?: 'filled' | 'outlined' | 'ghost';
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
+
export type FileInputProps = React.HTMLProps<HTMLInputElement>;
|
|
273
|
+
|
|
272
274
|
export interface PriceProps {
|
|
273
275
|
currencyCode?: string;
|
|
274
276
|
useCurrencySymbol?: boolean;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const iframeURLChange = (iframe, callback) => {
|
|
2
|
+
iframe.addEventListener('load', () => {
|
|
3
|
+
setTimeout(() => {
|
|
4
|
+
if (iframe?.contentWindow?.location) {
|
|
5
|
+
callback(iframe.contentWindow.location);
|
|
6
|
+
}
|
|
7
|
+
}, 0);
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const removeIframe = async () => {
|
|
12
|
+
const iframeSelector = document.querySelector(
|
|
13
|
+
'.checkout-payment-redirection-iframe-wrapper'
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const redirectionPaymentWrapper = document.querySelector(
|
|
17
|
+
'.checkout-redirection-payment-wrapper'
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const form = redirectionPaymentWrapper.querySelector('form') as HTMLElement;
|
|
21
|
+
|
|
22
|
+
if (!iframeSelector) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
iframeSelector.remove();
|
|
27
|
+
|
|
28
|
+
if (form) {
|
|
29
|
+
form.style.display = 'block';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
location.reload();
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const showRedirectionIframe = (redirectUrl: string) => {
|
|
36
|
+
const iframeWrapper = document.createElement('div');
|
|
37
|
+
const iframe = document.createElement('iframe');
|
|
38
|
+
const closeButton = document.createElement('div');
|
|
39
|
+
const redirectionPaymentWrapper = document.querySelector(
|
|
40
|
+
'.checkout-redirection-payment-wrapper'
|
|
41
|
+
);
|
|
42
|
+
const form = redirectionPaymentWrapper.querySelector('form') as HTMLElement;
|
|
43
|
+
|
|
44
|
+
iframeWrapper.className = 'checkout-payment-redirection-iframe-wrapper';
|
|
45
|
+
closeButton.className = 'close-button';
|
|
46
|
+
|
|
47
|
+
iframe.setAttribute('src', redirectUrl);
|
|
48
|
+
closeButton.innerHTML = '✕';
|
|
49
|
+
closeButton.addEventListener('click', removeIframe);
|
|
50
|
+
|
|
51
|
+
iframeWrapper.append(iframe, closeButton);
|
|
52
|
+
|
|
53
|
+
if (form) {
|
|
54
|
+
form.style.display = 'none';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
redirectionPaymentWrapper.appendChild(iframeWrapper);
|
|
58
|
+
|
|
59
|
+
iframeURLChange(iframe, (location) => {
|
|
60
|
+
if (location.origin !== window.location.origin) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const searchParams = new URLSearchParams(location.search);
|
|
65
|
+
const isOrderCompleted = location.href.includes('/orders/completed');
|
|
66
|
+
|
|
67
|
+
if (isOrderCompleted) {
|
|
68
|
+
(window.parent as any)?.postMessage?.(
|
|
69
|
+
JSON.stringify({
|
|
70
|
+
url: location.pathname
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (
|
|
76
|
+
searchParams.has('success') ||
|
|
77
|
+
isOrderCompleted ||
|
|
78
|
+
location.href.includes('/orders/checkout')
|
|
79
|
+
) {
|
|
80
|
+
setTimeout(() => {
|
|
81
|
+
removeIframe();
|
|
82
|
+
}, 0);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
};
|