@akinon/next 1.5.0 → 1.7.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 +22 -0
- package/api/auth.ts +5 -1
- package/assets/styles/index.scss +9 -4
- package/components/client-root.tsx +3 -12
- package/components/mobile-app-toggler.tsx +12 -1
- package/components/plugin-module.tsx +9 -4
- package/components/redirect-three-d/content/index.tsx +13 -3
- package/components/selected-payment-option-view.tsx +1 -1
- package/data/client/checkout.ts +4 -2
- package/data/client/user.ts +8 -0
- package/data/urls.ts +1 -0
- package/hooks/index.ts +1 -0
- package/hooks/use-mobile-iframe-handler.ts +23 -0
- package/middlewares/currency.ts +15 -4
- package/middlewares/default.ts +56 -11
- package/middlewares/locale.ts +9 -2
- package/middlewares/pretty-url.ts +31 -27
- package/middlewares/redirection-payment.ts +81 -56
- package/middlewares/three-d-redirection.ts +11 -5
- package/middlewares/url-redirection.ts +5 -1
- package/package.json +1 -1
- package/plugins.js +2 -1
- package/redux/middlewares/checkout.ts +19 -1
- package/types/commerce/checkout.ts +3 -1
- package/types/metadata.ts +2 -2
- package/utils/app-fetch.ts +9 -4
- package/utils/mobile-3d-iframe.ts +28 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @akinon/next
|
|
2
2
|
|
|
3
|
+
## 1.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Reset pre-order is_redirected state
|
|
8
|
+
- Show IP addresses in logs
|
|
9
|
+
|
|
10
|
+
## 1.6.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- ZERO-2286: Find custom payment option view by slug instead of pk
|
|
15
|
+
- ZERO-2169: Add OTP plugin module support
|
|
16
|
+
- ZERO-2250: Show checkout iframe on mobile web
|
|
17
|
+
- ZERO-2288: Allow custom response in middleware.ts
|
|
18
|
+
- ZERO-2272: Add confirm email services
|
|
19
|
+
- ZERO-2250: Add expire date to currency and locale cookies
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Fix Metadata type
|
|
24
|
+
|
|
3
25
|
## 1.5.0
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
package/api/auth.ts
CHANGED
|
@@ -130,7 +130,7 @@ const nextAuthOptions = (req: NextApiRequest, res: NextApiResponse) => {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
if (!response.key) {
|
|
133
|
-
|
|
133
|
+
const errors = [] as AuthError[];
|
|
134
134
|
|
|
135
135
|
const fieldErrors = Object.keys(response ?? {})
|
|
136
136
|
.filter((key) => key !== 'non_field_errors')
|
|
@@ -150,6 +150,10 @@ const nextAuthOptions = (req: NextApiRequest, res: NextApiResponse) => {
|
|
|
150
150
|
email: credentials.email,
|
|
151
151
|
formType: credentials.formType
|
|
152
152
|
});
|
|
153
|
+
} else if (apiRequest.status === 202) {
|
|
154
|
+
errors.push({
|
|
155
|
+
type: 'otp'
|
|
156
|
+
});
|
|
153
157
|
} else if (fieldErrors.length) {
|
|
154
158
|
errors.push({
|
|
155
159
|
type: 'field_errors',
|
package/assets/styles/index.scss
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
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
|
+
|
|
2
11
|
iframe {
|
|
3
|
-
position: fixed;
|
|
4
|
-
top: 0;
|
|
5
|
-
left: 0;
|
|
6
12
|
width: 100%;
|
|
7
13
|
height: 100%;
|
|
8
14
|
border: none;
|
|
9
|
-
z-index: 1000;
|
|
10
15
|
background-color: white;
|
|
11
16
|
}
|
|
12
17
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { useAppSelector } from '../redux/hooks';
|
|
3
|
+
import { useMobileIframeHandler } from '../hooks';
|
|
5
4
|
|
|
6
5
|
export default function ClientRoot({
|
|
7
6
|
children,
|
|
@@ -10,17 +9,9 @@ export default function ClientRoot({
|
|
|
10
9
|
children: React.ReactNode;
|
|
11
10
|
sessionId?: string;
|
|
12
11
|
}) {
|
|
13
|
-
const
|
|
14
|
-
const { isMobileApp } = useAppSelector((state) => state.root);
|
|
15
|
-
|
|
16
|
-
if (isMobileApp && pathname.includes('/orders/completed')) {
|
|
17
|
-
((window.parent || window) as any)?.ReactNativeWebView?.postMessage?.(
|
|
18
|
-
JSON.stringify({
|
|
19
|
-
url: pathname,
|
|
20
|
-
sessionId
|
|
21
|
-
})
|
|
22
|
-
);
|
|
12
|
+
const { preventPageRender } = useMobileIframeHandler({ sessionId });
|
|
23
13
|
|
|
14
|
+
if (preventPageRender) {
|
|
24
15
|
return null;
|
|
25
16
|
}
|
|
26
17
|
|
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useAppSelector } from '../redux/hooks';
|
|
4
|
+
import { useState, useEffect } from 'react';
|
|
5
|
+
import { useSearchParams } from 'next/navigation';
|
|
4
6
|
|
|
5
7
|
export default function MobileAppToggler({
|
|
6
8
|
children
|
|
7
9
|
}: {
|
|
8
10
|
children: React.ReactNode;
|
|
9
11
|
}) {
|
|
12
|
+
const searchParams = useSearchParams();
|
|
10
13
|
const { isMobileApp } = useAppSelector((state) => state.root);
|
|
14
|
+
const [isInIframe, setIsInIframe] = useState(false);
|
|
11
15
|
|
|
12
|
-
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (window.frameElement) {
|
|
18
|
+
setIsInIframe(true);
|
|
19
|
+
}
|
|
20
|
+
}, []);
|
|
21
|
+
|
|
22
|
+
if (isMobileApp || isInIframe || searchParams.get('iframe') === 'true')
|
|
23
|
+
return null;
|
|
13
24
|
|
|
14
25
|
return <>{children}</>;
|
|
15
26
|
}
|
|
@@ -9,7 +9,8 @@ enum Plugin {
|
|
|
9
9
|
OneClickCheckout = 'pz-one-click-checkout',
|
|
10
10
|
PayOnDelivery = 'pz-pay-on-delivery',
|
|
11
11
|
CheckoutGiftPack = 'pz-checkout-gift-pack',
|
|
12
|
-
GPay = 'pz-gpay'
|
|
12
|
+
GPay = 'pz-gpay',
|
|
13
|
+
Otp = 'pz-otp'
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export enum Component {
|
|
@@ -18,7 +19,8 @@ export enum Component {
|
|
|
18
19
|
OneClickCheckoutButtons = 'OneClickCheckoutButtons',
|
|
19
20
|
PayOnDelivery = 'PayOnDelivery',
|
|
20
21
|
CheckoutGiftPack = 'CheckoutGiftPack',
|
|
21
|
-
GPay = 'GPayOption'
|
|
22
|
+
GPay = 'GPayOption',
|
|
23
|
+
Otp = 'Otp'
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
const PluginComponents = new Map([
|
|
@@ -27,11 +29,12 @@ const PluginComponents = new Map([
|
|
|
27
29
|
[Plugin.OneClickCheckout, [Component.OneClickCheckoutButtons]],
|
|
28
30
|
[Plugin.PayOnDelivery, [Component.PayOnDelivery]],
|
|
29
31
|
[Plugin.CheckoutGiftPack, [Component.CheckoutGiftPack]],
|
|
30
|
-
[Plugin.GPay, [Component.GPay]]
|
|
32
|
+
[Plugin.GPay, [Component.GPay]],
|
|
33
|
+
[Plugin.Otp, [Component.Otp]]
|
|
31
34
|
]);
|
|
32
35
|
|
|
33
36
|
const getPlugin = (component: Component) => {
|
|
34
|
-
for (
|
|
37
|
+
for (const [key, value] of Array.from(PluginComponents.entries())) {
|
|
35
38
|
if (value.includes(component)) return key;
|
|
36
39
|
}
|
|
37
40
|
|
|
@@ -70,6 +73,8 @@ export default function PluginModule({
|
|
|
70
73
|
promise = import(`${'pz-checkout-gift-pack'}`);
|
|
71
74
|
} else if (plugin === Plugin.GPay) {
|
|
72
75
|
promise = import(`${'pz-gpay'}`);
|
|
76
|
+
} else if (plugin === Plugin.Otp) {
|
|
77
|
+
promise = import(`${'pz-otp'}`);
|
|
73
78
|
}
|
|
74
79
|
} catch (error) {
|
|
75
80
|
logger.error(error);
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useRouter } from '@akinon/next/hooks';
|
|
4
3
|
import { useEffect, useState } from 'react';
|
|
5
4
|
import { ROUTES } from 'routes';
|
|
6
5
|
import { useGet3dRedirectFormQuery } from '@akinon/next/data/client/checkout';
|
|
7
6
|
import { LoaderSpinner } from 'components';
|
|
8
7
|
import { useLocalization } from '../../../hooks/use-localization';
|
|
8
|
+
import { getUrlPathWithLocale } from '../../../utils/localization';
|
|
9
|
+
import { useSearchParams } from 'next/navigation';
|
|
9
10
|
|
|
10
11
|
interface RedirectThreeDContentProps {
|
|
11
12
|
sessionId: string;
|
|
@@ -14,9 +15,9 @@ interface RedirectThreeDContentProps {
|
|
|
14
15
|
export default function RedirectThreeDContent({
|
|
15
16
|
sessionId
|
|
16
17
|
}: RedirectThreeDContentProps) {
|
|
18
|
+
const searchParams = useSearchParams();
|
|
17
19
|
const { data } = useGet3dRedirectFormQuery();
|
|
18
20
|
const [error, setError] = useState(null);
|
|
19
|
-
const router = useRouter();
|
|
20
21
|
const { locale } = useLocalization();
|
|
21
22
|
|
|
22
23
|
useEffect(() => {
|
|
@@ -31,7 +32,16 @@ export default function RedirectThreeDContent({
|
|
|
31
32
|
setError('Redirecting to checkout page. Please wait...');
|
|
32
33
|
|
|
33
34
|
setTimeout(() => {
|
|
34
|
-
|
|
35
|
+
let checkoutUrl = `${ROUTES.CHECKOUT}`;
|
|
36
|
+
|
|
37
|
+
// iframe param is used to prevent header and footer rendering
|
|
38
|
+
if (searchParams.get('iframe') === 'true') {
|
|
39
|
+
checkoutUrl = `${checkoutUrl}?iframe=true`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Use `window.location.href` instead of `router.push`
|
|
43
|
+
// to capture the url change event in iframe
|
|
44
|
+
location.href = getUrlPathWithLocale(checkoutUrl, locale);
|
|
35
45
|
}, 3000);
|
|
36
46
|
return;
|
|
37
47
|
}
|
package/data/client/checkout.ts
CHANGED
|
@@ -42,6 +42,7 @@ interface CompleteCreditCardParams {
|
|
|
42
42
|
card_number: string;
|
|
43
43
|
card_month: string;
|
|
44
44
|
card_year: string;
|
|
45
|
+
use_three_d?: boolean;
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
interface GetContractResponse {
|
|
@@ -96,7 +97,8 @@ export const checkoutApi = api.injectEndpoints({
|
|
|
96
97
|
card_cvv,
|
|
97
98
|
card_number,
|
|
98
99
|
card_month,
|
|
99
|
-
card_year
|
|
100
|
+
card_year,
|
|
101
|
+
use_three_d = true
|
|
100
102
|
}) => ({
|
|
101
103
|
url: buildClientRequestUrl(checkout.completeCreditCardPayment, {
|
|
102
104
|
useFormData: true
|
|
@@ -104,7 +106,7 @@ export const checkoutApi = api.injectEndpoints({
|
|
|
104
106
|
method: 'POST',
|
|
105
107
|
body: {
|
|
106
108
|
agreement: '1',
|
|
107
|
-
use_three_d: '1',
|
|
109
|
+
use_three_d: use_three_d ? '1' : '0',
|
|
108
110
|
card_cvv,
|
|
109
111
|
card_holder,
|
|
110
112
|
card_month,
|
package/data/client/user.ts
CHANGED
|
@@ -78,6 +78,13 @@ const userApi = api.injectEndpoints({
|
|
|
78
78
|
})
|
|
79
79
|
})
|
|
80
80
|
}),
|
|
81
|
+
confirmEmailVerification: build.query<void, string>({
|
|
82
|
+
query: (token) => ({
|
|
83
|
+
url: buildClientRequestUrl(user.confirmEmailVerification(token), {
|
|
84
|
+
contentType: 'application/json'
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
})
|
|
81
88
|
}),
|
|
82
89
|
overrideExisting: false
|
|
83
90
|
});
|
|
@@ -85,6 +92,7 @@ const userApi = api.injectEndpoints({
|
|
|
85
92
|
export const {
|
|
86
93
|
useGetCaptchaQuery,
|
|
87
94
|
useChangeEmailVerificationQuery,
|
|
95
|
+
useConfirmEmailVerificationQuery,
|
|
88
96
|
useValidateCaptchaMutation,
|
|
89
97
|
useLogoutMutation,
|
|
90
98
|
useForgotPasswordMutation
|
package/data/urls.ts
CHANGED
|
@@ -143,6 +143,7 @@ export const user = {
|
|
|
143
143
|
profiles: '/users/profile',
|
|
144
144
|
forgotPassword: '/users/password/reset',
|
|
145
145
|
changeEmailVerification: (token: string) => `/users/email-set-primary/${token}`,
|
|
146
|
+
confirmEmailVerification: (token: string) => `/users/registration/account-confirm-email/${token}`,
|
|
146
147
|
csrfToken: '/csrf_token'
|
|
147
148
|
};
|
|
148
149
|
|
package/hooks/index.ts
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { usePathname } from 'next/navigation';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { useAppSelector } from '../redux/hooks';
|
|
4
|
+
|
|
5
|
+
export function useMobileIframeHandler({ sessionId }: { sessionId: string }) {
|
|
6
|
+
const pathname = usePathname();
|
|
7
|
+
const { isMobileApp } = useAppSelector((state) => state.root);
|
|
8
|
+
const [preventPageRender, setPreventPageRender] = useState(false);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (
|
|
12
|
+
pathname.includes('/orders/completed') &&
|
|
13
|
+
(isMobileApp || /iPad|iPhone|iPod|Android/i.test(navigator.userAgent)) &&
|
|
14
|
+
window.frameElement // Check if the page is inside an iframe
|
|
15
|
+
) {
|
|
16
|
+
setPreventPageRender(true);
|
|
17
|
+
}
|
|
18
|
+
}, [pathname]);
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
preventPageRender
|
|
22
|
+
};
|
|
23
|
+
}
|
package/middlewares/currency.ts
CHANGED
|
@@ -20,6 +20,8 @@ const resetBasket = async (req: PzNextRequest) => {
|
|
|
20
20
|
const withCurrency =
|
|
21
21
|
(middleware: NextMiddleware) =>
|
|
22
22
|
async (req: PzNextRequest, event: NextFetchEvent) => {
|
|
23
|
+
const ip = req.headers.get('x-forwarded-for') ?? '';
|
|
24
|
+
|
|
23
25
|
try {
|
|
24
26
|
const { currencies, defaultCurrencyCode, defaultLocaleValue } =
|
|
25
27
|
settings.localization;
|
|
@@ -27,7 +29,9 @@ const withCurrency =
|
|
|
27
29
|
const url = req.nextUrl.clone();
|
|
28
30
|
|
|
29
31
|
if (!defaultCurrencyCode) {
|
|
30
|
-
logger.error('Default currency code is not defined in settings.'
|
|
32
|
+
logger.error('Default currency code is not defined in settings.', {
|
|
33
|
+
ip
|
|
34
|
+
});
|
|
31
35
|
throw new Error(
|
|
32
36
|
'Default currency code is not defined. Use `defaultCurrencyCode` property in `localization` object in `settings.js` file.'
|
|
33
37
|
);
|
|
@@ -57,7 +61,10 @@ const withCurrency =
|
|
|
57
61
|
!currencies.find((c) => c.code === activeCurrency)
|
|
58
62
|
) {
|
|
59
63
|
logger.warn(
|
|
60
|
-
`Currency ${activeCurrency} is not defined in settings. Using default currency ${defaultCurrencyCode} instead
|
|
64
|
+
`Currency ${activeCurrency} is not defined in settings. Using default currency ${defaultCurrencyCode} instead.`,
|
|
65
|
+
{
|
|
66
|
+
ip
|
|
67
|
+
}
|
|
61
68
|
);
|
|
62
69
|
activeCurrency = defaultCurrencyCode;
|
|
63
70
|
}
|
|
@@ -72,7 +79,8 @@ const withCurrency =
|
|
|
72
79
|
logger.info('Currency changed. Resetting basket...', {
|
|
73
80
|
sessionid: req.cookies.get('osessionid')?.value ?? '',
|
|
74
81
|
oldCurrency: req.cookies.get('pz-currency')?.value,
|
|
75
|
-
newCurrency: activeCurrency
|
|
82
|
+
newCurrency: activeCurrency,
|
|
83
|
+
ip
|
|
76
84
|
});
|
|
77
85
|
|
|
78
86
|
resetBasket(req);
|
|
@@ -80,7 +88,10 @@ const withCurrency =
|
|
|
80
88
|
|
|
81
89
|
req.middlewareParams.rewrites.currency = activeCurrency;
|
|
82
90
|
} catch (error) {
|
|
83
|
-
logger.error('withCurrency error',
|
|
91
|
+
logger.error('withCurrency error', {
|
|
92
|
+
error,
|
|
93
|
+
ip
|
|
94
|
+
});
|
|
84
95
|
}
|
|
85
96
|
|
|
86
97
|
return middleware(req, event);
|
package/middlewares/default.ts
CHANGED
|
@@ -13,6 +13,7 @@ import withCurrency from './currency';
|
|
|
13
13
|
import withLocale from './locale';
|
|
14
14
|
import logger from '../utils/log';
|
|
15
15
|
import { user } from '../data/urls';
|
|
16
|
+
import { getUrlPathWithLocale } from '../utils/localization';
|
|
16
17
|
|
|
17
18
|
const withPzDefault =
|
|
18
19
|
(middleware: NextMiddleware) =>
|
|
@@ -20,10 +21,12 @@ const withPzDefault =
|
|
|
20
21
|
const url = req.nextUrl.clone();
|
|
21
22
|
const commerceUrl = encodeURIComponent(decodeURI(Settings.commerceUrl)); // encodeURI doesn't work as expected in middleware
|
|
22
23
|
const searchParams = new URLSearchParams(url.search);
|
|
24
|
+
const ip = req.headers.get('x-forwarded-for') ?? '';
|
|
23
25
|
|
|
24
26
|
logger.debug('withPzDefault', {
|
|
25
27
|
url: url.href,
|
|
26
|
-
middlewareParams: req.middlewareParams
|
|
28
|
+
middlewareParams: req.middlewareParams,
|
|
29
|
+
ip
|
|
27
30
|
});
|
|
28
31
|
|
|
29
32
|
// Support legacy ?format=json query param
|
|
@@ -50,7 +53,10 @@ const withPzDefault =
|
|
|
50
53
|
|
|
51
54
|
return NextResponse.json(await request.json());
|
|
52
55
|
} catch (error) {
|
|
53
|
-
logger.error('?format=json error',
|
|
56
|
+
logger.error('?format=json error', {
|
|
57
|
+
error,
|
|
58
|
+
ip
|
|
59
|
+
});
|
|
54
60
|
return NextResponse.next();
|
|
55
61
|
}
|
|
56
62
|
}
|
|
@@ -87,6 +93,23 @@ const withPzDefault =
|
|
|
87
93
|
);
|
|
88
94
|
}
|
|
89
95
|
|
|
96
|
+
// If commerce redirects to /orders/checkout/ without locale
|
|
97
|
+
if (
|
|
98
|
+
req.nextUrl.pathname.match(new RegExp('^/orders/checkout/$')) &&
|
|
99
|
+
req.nextUrl.searchParams.size === 0 &&
|
|
100
|
+
getUrlPathWithLocale(
|
|
101
|
+
'/orders/checkout/',
|
|
102
|
+
req.cookies.get('pz-locale')?.value
|
|
103
|
+
) !== req.nextUrl.pathname
|
|
104
|
+
) {
|
|
105
|
+
const redirectUrlWithLocale = `${url.origin}${getUrlPathWithLocale(
|
|
106
|
+
'/orders/checkout/',
|
|
107
|
+
req.cookies.get('pz-locale')?.value
|
|
108
|
+
)}`;
|
|
109
|
+
|
|
110
|
+
return NextResponse.redirect(redirectUrlWithLocale, 303);
|
|
111
|
+
}
|
|
112
|
+
|
|
90
113
|
req.middlewareParams = {
|
|
91
114
|
commerceUrl,
|
|
92
115
|
rewrites: {}
|
|
@@ -130,12 +153,23 @@ const withPzDefault =
|
|
|
130
153
|
event
|
|
131
154
|
)) as NextResponse | void;
|
|
132
155
|
|
|
156
|
+
// if middleware.ts has a return value for current url
|
|
133
157
|
if (middlewareResult instanceof NextResponse) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
158
|
+
// pz-override-response header is used to prevent 404 page for custom responses.
|
|
159
|
+
if (
|
|
160
|
+
middlewareResult.headers.get(
|
|
161
|
+
'pz-override-response'
|
|
162
|
+
) !== 'true'
|
|
163
|
+
) {
|
|
164
|
+
middlewareResult.headers.set(
|
|
165
|
+
'x-middleware-rewrite',
|
|
166
|
+
url.href
|
|
167
|
+
);
|
|
168
|
+
}
|
|
138
169
|
} else {
|
|
170
|
+
// if middleware.ts doesn't have a return value.
|
|
171
|
+
// e.g. NextResponse.next() doesn't exist in middleware.ts
|
|
172
|
+
|
|
139
173
|
middlewareResult = NextResponse.rewrite(url);
|
|
140
174
|
}
|
|
141
175
|
|
|
@@ -145,13 +179,17 @@ const withPzDefault =
|
|
|
145
179
|
locale?.length > 0 ? locale : defaultLocaleValue,
|
|
146
180
|
{
|
|
147
181
|
sameSite: 'none',
|
|
148
|
-
secure: true
|
|
182
|
+
secure: true,
|
|
183
|
+
expires: new Date(
|
|
184
|
+
Date.now() + 1000 * 60 * 60 * 24 * 7
|
|
185
|
+
) // 7 days
|
|
149
186
|
}
|
|
150
187
|
);
|
|
151
188
|
}
|
|
152
189
|
middlewareResult.cookies.set('pz-currency', currency, {
|
|
153
190
|
sameSite: 'none',
|
|
154
|
-
secure: true
|
|
191
|
+
secure: true,
|
|
192
|
+
expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 7) // 7 days
|
|
155
193
|
});
|
|
156
194
|
|
|
157
195
|
if (
|
|
@@ -160,7 +198,8 @@ const withPzDefault =
|
|
|
160
198
|
) {
|
|
161
199
|
logger.debug('Locale changed', {
|
|
162
200
|
locale,
|
|
163
|
-
oldLocale: req.cookies.get('pz-locale')?.value
|
|
201
|
+
oldLocale: req.cookies.get('pz-locale')?.value,
|
|
202
|
+
ip
|
|
164
203
|
});
|
|
165
204
|
}
|
|
166
205
|
|
|
@@ -191,10 +230,16 @@ const withPzDefault =
|
|
|
191
230
|
middlewareResult.cookies.set('csrftoken', csrf_token);
|
|
192
231
|
}
|
|
193
232
|
} catch (error) {
|
|
194
|
-
logger.error('CSRF Error',
|
|
233
|
+
logger.error('CSRF Error', {
|
|
234
|
+
error,
|
|
235
|
+
ip
|
|
236
|
+
});
|
|
195
237
|
}
|
|
196
238
|
} catch (error) {
|
|
197
|
-
logger.error('withPzDefault Error',
|
|
239
|
+
logger.error('withPzDefault Error', {
|
|
240
|
+
error,
|
|
241
|
+
ip
|
|
242
|
+
});
|
|
198
243
|
}
|
|
199
244
|
|
|
200
245
|
return middlewareResult;
|
package/middlewares/locale.ts
CHANGED
|
@@ -24,6 +24,8 @@ const getMatchedLocale = (pathname: string) => {
|
|
|
24
24
|
const withLocale =
|
|
25
25
|
(middleware: NextMiddleware) =>
|
|
26
26
|
async (req: PzNextRequest, event: NextFetchEvent) => {
|
|
27
|
+
const ip = req.headers.get('x-forwarded-for') ?? '';
|
|
28
|
+
|
|
27
29
|
try {
|
|
28
30
|
const url = req.nextUrl.clone();
|
|
29
31
|
const matchedLocale = getMatchedLocale(url.pathname);
|
|
@@ -34,7 +36,9 @@ const withLocale =
|
|
|
34
36
|
localeUrlStrategy ?? LocaleUrlStrategy.HideDefaultLocale;
|
|
35
37
|
|
|
36
38
|
if (!defaultLocaleValue) {
|
|
37
|
-
logger.error('Default locale value is not defined in settings.'
|
|
39
|
+
logger.error('Default locale value is not defined in settings.', {
|
|
40
|
+
ip
|
|
41
|
+
});
|
|
38
42
|
throw new Error(
|
|
39
43
|
'Default locale value is not defined. Use `defaultLocaleValue` property in `localization` object in `settings.js` file.'
|
|
40
44
|
);
|
|
@@ -52,7 +56,10 @@ const withLocale =
|
|
|
52
56
|
|
|
53
57
|
req.middlewareParams.rewrites.locale = matchedLocale;
|
|
54
58
|
} catch (error) {
|
|
55
|
-
logger.error('withLocale error',
|
|
59
|
+
logger.error('withLocale error', {
|
|
60
|
+
error,
|
|
61
|
+
ip
|
|
62
|
+
});
|
|
56
63
|
}
|
|
57
64
|
|
|
58
65
|
return middleware(req, event);
|
|
@@ -12,40 +12,41 @@ type PrettyUrlResult = {
|
|
|
12
12
|
path?: string;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
const resolvePrettyUrlHandler =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
const resolvePrettyUrlHandler =
|
|
16
|
+
(pathname: string, ip: string | null) => async () => {
|
|
17
|
+
let results = <{ old_path: string }[]>[];
|
|
18
|
+
let prettyUrlResult: PrettyUrlResult = {
|
|
19
|
+
matched: false
|
|
20
|
+
};
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
try {
|
|
23
|
+
const requestUrl = URLS.misc.prettyUrls(pathname);
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
logger.debug(`Resolving pretty url`, { pathname, requestUrl, ip });
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
const apiResponse = await fetch(requestUrl);
|
|
28
|
+
const data = await apiResponse.json();
|
|
29
|
+
({ results } = data);
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
const matched = results.length > 0;
|
|
32
|
+
const [{ old_path: path } = { old_path: '' }] = results;
|
|
33
|
+
prettyUrlResult = {
|
|
34
|
+
matched,
|
|
35
|
+
path
|
|
36
|
+
};
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
logger.trace('Pretty url result', { prettyUrlResult, ip });
|
|
39
|
+
} catch (error) {
|
|
40
|
+
logger.error('Error resolving pretty url', { error, pathname, ip });
|
|
41
|
+
}
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
};
|
|
43
|
+
return prettyUrlResult;
|
|
44
|
+
};
|
|
44
45
|
|
|
45
|
-
const resolvePrettyUrl = async (pathname: string) => {
|
|
46
|
+
const resolvePrettyUrl = async (pathname: string, ip: string | null) => {
|
|
46
47
|
return Cache.wrap(
|
|
47
48
|
CacheKey.PrettyUrl(pathname),
|
|
48
|
-
resolvePrettyUrlHandler(pathname),
|
|
49
|
+
resolvePrettyUrlHandler(pathname, ip),
|
|
49
50
|
{
|
|
50
51
|
useProxy: true
|
|
51
52
|
}
|
|
@@ -68,6 +69,7 @@ const withPrettyUrl =
|
|
|
68
69
|
)
|
|
69
70
|
);
|
|
70
71
|
};
|
|
72
|
+
const ip = req.headers.get('x-forwarded-for') ?? '';
|
|
71
73
|
|
|
72
74
|
if (
|
|
73
75
|
!isValidPrettyUrlPath(prettyUrlPathname) ||
|
|
@@ -81,14 +83,16 @@ const withPrettyUrl =
|
|
|
81
83
|
prettyUrlPathname
|
|
82
84
|
)
|
|
83
85
|
? url.pathname
|
|
84
|
-
: prettyUrlPathname
|
|
86
|
+
: prettyUrlPathname,
|
|
87
|
+
ip
|
|
85
88
|
);
|
|
86
89
|
|
|
87
90
|
if (prettyUrlResult.matched) {
|
|
88
91
|
req.middlewareParams.rewrites.prettyUrl = prettyUrlResult.path;
|
|
89
92
|
logger.debug('Resolved pretty url', {
|
|
90
93
|
source: prettyUrlPathname,
|
|
91
|
-
dest: prettyUrlResult.path
|
|
94
|
+
dest: prettyUrlResult.path,
|
|
95
|
+
ip
|
|
92
96
|
});
|
|
93
97
|
|
|
94
98
|
return middleware(req, event);
|
|
@@ -38,81 +38,106 @@ const withRedirectionPayment =
|
|
|
38
38
|
''
|
|
39
39
|
);
|
|
40
40
|
const searchParams = new URLSearchParams(url.search);
|
|
41
|
+
const ip = req.headers.get('x-forwarded-for') ?? '';
|
|
41
42
|
|
|
42
|
-
if (
|
|
43
|
-
!pathnameWithoutLocale.startsWith('/orders') ||
|
|
44
|
-
searchParams.get('page') !== 'RedirectionPageCompletePage' ||
|
|
45
|
-
req.method !== 'POST'
|
|
46
|
-
) {
|
|
43
|
+
if (searchParams.get('page') !== 'RedirectionPageCompletePage') {
|
|
47
44
|
return middleware(req, event);
|
|
48
45
|
}
|
|
49
46
|
|
|
50
|
-
const body = await streamToString(req.body);
|
|
51
47
|
const requestUrl = `${Settings.commerceUrl}/orders/checkout/${url.search}`;
|
|
48
|
+
const requestHeaders = {
|
|
49
|
+
'X-Requested-With': 'XMLHttpRequest',
|
|
50
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
51
|
+
Cookie: req.headers.get('cookie') ?? '',
|
|
52
|
+
'x-currency': req.cookies.get('pz-currency')?.value ?? ''
|
|
53
|
+
};
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
55
|
+
try {
|
|
56
|
+
const body = await streamToString(req.body);
|
|
57
|
+
|
|
58
|
+
const request = await fetch(requestUrl, {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
headers: requestHeaders,
|
|
61
|
+
body
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
logger.info('Complete redirection payment request', {
|
|
65
|
+
requestUrl,
|
|
66
|
+
status: request.status,
|
|
67
|
+
requestHeaders,
|
|
68
|
+
ip
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const response = await request.json();
|
|
72
|
+
|
|
73
|
+
const { context_list: contextList } = response;
|
|
74
|
+
const redirectionContext = contextList?.find(
|
|
75
|
+
(context) => context.page_context?.redirect_url
|
|
76
|
+
);
|
|
77
|
+
const redirectUrl = redirectionContext?.page_context?.redirect_url;
|
|
76
78
|
|
|
77
|
-
if (!redirectUrl) {
|
|
78
79
|
logger.info('Order success page context list', {
|
|
79
80
|
middleware: 'redirection-payment',
|
|
80
|
-
contextList
|
|
81
|
+
contextList,
|
|
82
|
+
ip
|
|
81
83
|
});
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
if (!redirectUrl) {
|
|
86
|
+
logger.warn(
|
|
87
|
+
'No redirection url for order success page found in page_context',
|
|
88
|
+
{
|
|
89
|
+
middleware: 'redirection-payment',
|
|
90
|
+
requestHeaders,
|
|
91
|
+
response: JSON.stringify(response),
|
|
92
|
+
ip
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const redirectUrlWithLocale = `${url.origin}${getUrlPathWithLocale(
|
|
97
|
+
'/orders/checkout/',
|
|
98
|
+
req.cookies.get('pz-locale')?.value
|
|
99
|
+
)}`;
|
|
100
|
+
|
|
101
|
+
return NextResponse.redirect(redirectUrlWithLocale, 303);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const redirectUrlWithLocale = `${url.origin}${getUrlPathWithLocale(
|
|
105
|
+
redirectUrl,
|
|
106
|
+
req.cookies.get('pz-locale')?.value
|
|
107
|
+
)}`;
|
|
108
|
+
|
|
109
|
+
logger.info('Redirecting to order success page', {
|
|
110
|
+
middleware: 'redirection-payment',
|
|
111
|
+
redirectUrlWithLocale,
|
|
112
|
+
ip
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Using POST method while redirecting causes an error,
|
|
116
|
+
// So we use 303 status code to change the method to GET
|
|
117
|
+
const nextResponse = NextResponse.redirect(redirectUrlWithLocale, 303);
|
|
118
|
+
|
|
119
|
+
nextResponse.headers.set(
|
|
120
|
+
'Set-Cookie',
|
|
121
|
+
request.headers.get('set-cookie') ?? ''
|
|
86
122
|
);
|
|
123
|
+
|
|
124
|
+
return nextResponse;
|
|
125
|
+
} catch (error) {
|
|
126
|
+
logger.error('Error while completing redirection payment', {
|
|
127
|
+
middleware: 'redirection-payment',
|
|
128
|
+
error,
|
|
129
|
+
requestHeaders,
|
|
130
|
+
ip
|
|
131
|
+
});
|
|
132
|
+
|
|
87
133
|
return NextResponse.redirect(
|
|
88
134
|
`${url.origin}${getUrlPathWithLocale(
|
|
89
|
-
|
|
135
|
+
'/orders/checkout/',
|
|
90
136
|
req.cookies.get('pz-locale')?.value
|
|
91
137
|
)}`,
|
|
92
138
|
303
|
|
93
139
|
);
|
|
94
140
|
}
|
|
95
|
-
|
|
96
|
-
const redirectUrlWithLocale = `${url.origin}${getUrlPathWithLocale(
|
|
97
|
-
redirectUrl,
|
|
98
|
-
req.cookies.get('pz-locale')?.value
|
|
99
|
-
)}`;
|
|
100
|
-
|
|
101
|
-
logger.info('Redirecting to order success page', {
|
|
102
|
-
middleware: 'redirection-payment',
|
|
103
|
-
redirectUrlWithLocale
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
// Using POST method while redirecting causes an error,
|
|
107
|
-
// So we use 303 status code to change the method to GET
|
|
108
|
-
const nextResponse = NextResponse.redirect(redirectUrlWithLocale, 303);
|
|
109
|
-
|
|
110
|
-
nextResponse.headers.set(
|
|
111
|
-
'Set-Cookie',
|
|
112
|
-
request.headers.get('set-cookie') ?? ''
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
return nextResponse;
|
|
116
141
|
};
|
|
117
142
|
|
|
118
143
|
export default withRedirectionPayment;
|
|
@@ -32,6 +32,7 @@ const withThreeDRedirection =
|
|
|
32
32
|
(middleware: NextMiddleware) =>
|
|
33
33
|
async (req: PzNextRequest, event: NextFetchEvent) => {
|
|
34
34
|
const url = req.nextUrl.clone();
|
|
35
|
+
const ip = req.headers.get('x-forwarded-for') ?? '';
|
|
35
36
|
|
|
36
37
|
if (url.search.indexOf('CreditCardThreeDSecurePage') === -1) {
|
|
37
38
|
return middleware(req, event);
|
|
@@ -57,7 +58,8 @@ const withThreeDRedirection =
|
|
|
57
58
|
logger.info('Complete 3D payment request', {
|
|
58
59
|
requestUrl,
|
|
59
60
|
status: request.status,
|
|
60
|
-
requestHeaders
|
|
61
|
+
requestHeaders,
|
|
62
|
+
ip
|
|
61
63
|
});
|
|
62
64
|
|
|
63
65
|
const response = await request.json();
|
|
@@ -70,7 +72,8 @@ const withThreeDRedirection =
|
|
|
70
72
|
|
|
71
73
|
logger.info('Order success page context list', {
|
|
72
74
|
middleware: 'three-d-redirection',
|
|
73
|
-
contextList
|
|
75
|
+
contextList,
|
|
76
|
+
ip
|
|
74
77
|
});
|
|
75
78
|
|
|
76
79
|
if (!redirectUrl) {
|
|
@@ -79,7 +82,8 @@ const withThreeDRedirection =
|
|
|
79
82
|
{
|
|
80
83
|
middleware: 'three-d-redirection',
|
|
81
84
|
requestHeaders,
|
|
82
|
-
response: JSON.stringify(response)
|
|
85
|
+
response: JSON.stringify(response),
|
|
86
|
+
ip
|
|
83
87
|
}
|
|
84
88
|
);
|
|
85
89
|
|
|
@@ -98,7 +102,8 @@ const withThreeDRedirection =
|
|
|
98
102
|
|
|
99
103
|
logger.info('Redirecting to order success page', {
|
|
100
104
|
middleware: 'three-d-redirection',
|
|
101
|
-
redirectUrlWithLocale
|
|
105
|
+
redirectUrlWithLocale,
|
|
106
|
+
ip
|
|
102
107
|
});
|
|
103
108
|
|
|
104
109
|
// Using POST method while redirecting causes an error,
|
|
@@ -115,7 +120,8 @@ const withThreeDRedirection =
|
|
|
115
120
|
logger.error('Error while completing 3D payment', {
|
|
116
121
|
middleware: 'three-d-redirection',
|
|
117
122
|
error,
|
|
118
|
-
requestHeaders
|
|
123
|
+
requestHeaders,
|
|
124
|
+
ip
|
|
119
125
|
});
|
|
120
126
|
|
|
121
127
|
return NextResponse.redirect(
|
|
@@ -12,6 +12,7 @@ const withUrlRedirection =
|
|
|
12
12
|
(middleware: NextMiddleware) =>
|
|
13
13
|
async (req: PzNextRequest, event: NextFetchEvent) => {
|
|
14
14
|
const url = req.nextUrl.clone();
|
|
15
|
+
const ip = req.headers.get('x-forwarded-for') ?? '';
|
|
15
16
|
const pathnameWithoutLocale = url.pathname.replace(
|
|
16
17
|
urlLocaleMatcherRegex,
|
|
17
18
|
''
|
|
@@ -52,7 +53,10 @@ const withUrlRedirection =
|
|
|
52
53
|
return Response.redirect(redirectUrl.toString(), request.status);
|
|
53
54
|
}
|
|
54
55
|
} catch (error) {
|
|
55
|
-
logger.error('withUrlRedirection error',
|
|
56
|
+
logger.error('withUrlRedirection error', {
|
|
57
|
+
error,
|
|
58
|
+
ip
|
|
59
|
+
});
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
return middleware(req, event);
|
package/package.json
CHANGED
package/plugins.js
CHANGED
|
@@ -77,6 +77,21 @@ export const preOrderMiddleware: Middleware = ({
|
|
|
77
77
|
} = getState().checkout;
|
|
78
78
|
const { endpoints: apiEndpoints } = checkoutApi;
|
|
79
79
|
|
|
80
|
+
if (preOrder.is_redirected) {
|
|
81
|
+
const contextList = result?.payload?.context_list;
|
|
82
|
+
|
|
83
|
+
if (
|
|
84
|
+
contextList.find(
|
|
85
|
+
(ctx) => ctx.page_name === 'RedirectionPaymentSelectedPage'
|
|
86
|
+
)
|
|
87
|
+
) {
|
|
88
|
+
dispatch(
|
|
89
|
+
apiEndpoints.setPaymentOption.initiate(preOrder.payment_option?.pk)
|
|
90
|
+
);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
80
95
|
dispatch(setPreOrder(preOrder));
|
|
81
96
|
|
|
82
97
|
if (!preOrder.delivery_option && deliveryOptions.length > 0) {
|
|
@@ -164,7 +179,10 @@ export const contextListMiddleware: Middleware = ({
|
|
|
164
179
|
: `/${currentLocale}${redirectUrl}`;
|
|
165
180
|
}
|
|
166
181
|
|
|
167
|
-
if (
|
|
182
|
+
if (
|
|
183
|
+
isMobileApp ||
|
|
184
|
+
/iPad|iPhone|iPod|Android/i.test(navigator.userAgent)
|
|
185
|
+
) {
|
|
168
186
|
showMobile3dIframe(url);
|
|
169
187
|
} else {
|
|
170
188
|
window.location.href = url;
|
|
@@ -41,7 +41,8 @@ export interface CheckoutAddressType {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
export interface CheckoutPaymentOption {
|
|
44
|
-
pk
|
|
44
|
+
pk?: number;
|
|
45
|
+
slug?: string;
|
|
45
46
|
view?: (...args) => JSX.Element;
|
|
46
47
|
viewProps?: any;
|
|
47
48
|
}
|
|
@@ -71,6 +72,7 @@ export interface PreOrder {
|
|
|
71
72
|
currency_type_label?: string;
|
|
72
73
|
is_guest?: boolean;
|
|
73
74
|
is_post_order?: boolean;
|
|
75
|
+
is_redirected?: boolean;
|
|
74
76
|
installment: InstallmentOption;
|
|
75
77
|
retail_store?: RetailStore;
|
|
76
78
|
gift_box?: GiftBox;
|
package/types/metadata.ts
CHANGED
package/utils/app-fetch.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Settings from 'settings';
|
|
2
2
|
import { ServerVariables } from './server-variables';
|
|
3
3
|
import logger from '../utils/log';
|
|
4
|
+
import { headers } from 'next/headers';
|
|
4
5
|
|
|
5
6
|
export enum FetchResponseType {
|
|
6
7
|
JSON = 'json',
|
|
@@ -14,8 +15,12 @@ const appFetch = async <T>(
|
|
|
14
15
|
) => {
|
|
15
16
|
let response: T;
|
|
16
17
|
let status: number;
|
|
18
|
+
let ip = '';
|
|
17
19
|
|
|
18
20
|
try {
|
|
21
|
+
const nextHeaders = headers();
|
|
22
|
+
ip = nextHeaders.get('x-forwarded-for') ?? '';
|
|
23
|
+
|
|
19
24
|
const commerceUrl = Settings.commerceUrl;
|
|
20
25
|
const currentLocale = Settings.localization.locales.find(
|
|
21
26
|
(locale) => locale.value === ServerVariables.locale
|
|
@@ -38,10 +43,10 @@ const appFetch = async <T>(
|
|
|
38
43
|
revalidate: 60
|
|
39
44
|
};
|
|
40
45
|
|
|
41
|
-
logger.debug(`FETCH START ${url}`, { requestURL, init });
|
|
46
|
+
logger.debug(`FETCH START ${url}`, { requestURL, init, ip });
|
|
42
47
|
const req = await fetch(requestURL, init);
|
|
43
48
|
status = req.status;
|
|
44
|
-
logger.debug(`FETCH END ${url}`, { status: req.status });
|
|
49
|
+
logger.debug(`FETCH END ${url}`, { status: req.status, ip });
|
|
45
50
|
|
|
46
51
|
const rawData = await req.text();
|
|
47
52
|
|
|
@@ -51,9 +56,9 @@ const appFetch = async <T>(
|
|
|
51
56
|
response = rawData as unknown as T;
|
|
52
57
|
}
|
|
53
58
|
|
|
54
|
-
logger.trace(`FETCH RESPONSE`, { url, response });
|
|
59
|
+
logger.trace(`FETCH RESPONSE`, { url, response, ip });
|
|
55
60
|
} catch (error) {
|
|
56
|
-
logger.error(`FETCH FAILED`, { url, status, error });
|
|
61
|
+
logger.error(`FETCH FAILED`, { url, status, error, ip });
|
|
57
62
|
}
|
|
58
63
|
|
|
59
64
|
return response;
|
|
@@ -18,6 +18,7 @@ const removeIframe = async () => {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
iframeSelector.remove();
|
|
21
|
+
document.body.style.overflow = 'auto';
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
export const showMobile3dIframe = (redirectUrl: string) => {
|
|
@@ -27,12 +28,20 @@ export const showMobile3dIframe = (redirectUrl: string) => {
|
|
|
27
28
|
|
|
28
29
|
iframeWrapper.className = 'checkout-payment-iframe-wrapper';
|
|
29
30
|
closeButton.className = 'close-button';
|
|
30
|
-
|
|
31
|
+
|
|
32
|
+
// iframe param is used to prevent header and footer rendering
|
|
33
|
+
iframe.setAttribute(
|
|
34
|
+
'src',
|
|
35
|
+
redirectUrl.match(new RegExp(`^/orders/redirect-three-d/$`))
|
|
36
|
+
? `${redirectUrl}?iframe=true`
|
|
37
|
+
: redirectUrl
|
|
38
|
+
);
|
|
31
39
|
closeButton.innerHTML = '✕';
|
|
32
40
|
closeButton.addEventListener('click', removeIframe);
|
|
33
41
|
|
|
34
42
|
iframeWrapper.append(iframe, closeButton);
|
|
35
43
|
document.body.appendChild(iframeWrapper);
|
|
44
|
+
document.body.style.overflow = 'hidden';
|
|
36
45
|
|
|
37
46
|
iframeURLChange(iframe, (location) => {
|
|
38
47
|
if (location.origin !== window.location.origin) {
|
|
@@ -41,18 +50,28 @@ export const showMobile3dIframe = (redirectUrl: string) => {
|
|
|
41
50
|
|
|
42
51
|
const searchParams = new URLSearchParams(location.search);
|
|
43
52
|
const isOrderCompleted = location.href.includes('/orders/completed');
|
|
44
|
-
const data = {
|
|
45
|
-
url: location.pathname
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
if (searchParams.has('success') || isOrderCompleted) {
|
|
49
|
-
removeIframe();
|
|
50
|
-
}
|
|
51
53
|
|
|
52
54
|
if (isOrderCompleted) {
|
|
53
55
|
(window.parent as any)?.ReactNativeWebView?.postMessage?.(
|
|
54
|
-
JSON.stringify(
|
|
56
|
+
JSON.stringify({
|
|
57
|
+
url: location.pathname
|
|
58
|
+
})
|
|
55
59
|
);
|
|
60
|
+
|
|
61
|
+
if (localStorage.isMobileApp !== 'true') {
|
|
62
|
+
window.location.href = location.pathname;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (
|
|
68
|
+
searchParams.has('success') ||
|
|
69
|
+
isOrderCompleted ||
|
|
70
|
+
location.href.includes('/orders/checkout')
|
|
71
|
+
) {
|
|
72
|
+
setTimeout(() => {
|
|
73
|
+
removeIframe();
|
|
74
|
+
}, 0);
|
|
56
75
|
}
|
|
57
76
|
});
|
|
58
77
|
};
|