@akinon/next 1.0.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/.prettierrc +13 -0
- package/api/auth.ts +217 -0
- package/api/cache.ts +44 -0
- package/api/client.ts +157 -0
- package/api/logout.ts +42 -0
- package/assets/styles/index.scss +24 -0
- package/bin/pz-install-plugins.js +33 -0
- package/components/client-root.tsx +69 -0
- package/components/image.tsx +133 -0
- package/components/mobile-app-toggler.tsx +15 -0
- package/components/oauth-login.tsx +24 -0
- package/components/plugin-module.tsx +78 -0
- package/components/pz-providers.tsx +24 -0
- package/components/pz-root.tsx +21 -0
- package/components/redirect-three-d/content/index.tsx +64 -0
- package/components/redirect-three-d/index.tsx +17 -0
- package/components/selected-payment-option-view.tsx +66 -0
- package/components/trans.tsx +39 -0
- package/data/client/account.ts +188 -0
- package/data/client/address.ts +107 -0
- package/data/client/api.ts +42 -0
- package/data/client/basket.ts +85 -0
- package/data/client/checkout.ts +477 -0
- package/data/client/misc.ts +101 -0
- package/data/client/product.ts +90 -0
- package/data/client/user.ts +83 -0
- package/data/client/wishlist.ts +79 -0
- package/data/server/category.ts +121 -0
- package/data/server/flatpage.ts +21 -0
- package/data/server/index.ts +8 -0
- package/data/server/list.ts +56 -0
- package/data/server/menu.ts +35 -0
- package/data/server/product.ts +86 -0
- package/data/server/seo.ts +48 -0
- package/data/server/special-page.ts +42 -0
- package/data/server/widget.ts +27 -0
- package/data/urls.ts +184 -0
- package/hocs/client/index.ts +1 -0
- package/hocs/client/with-segment-defaults.tsx +26 -0
- package/hocs/server/index.ts +1 -0
- package/hocs/server/with-segment-defaults.tsx +83 -0
- package/hooks/index.ts +8 -0
- package/hooks/use-captcha.tsx +76 -0
- package/hooks/use-common-product-attributes.ts +36 -0
- package/hooks/use-debounce.ts +20 -0
- package/hooks/use-localization.ts +63 -0
- package/hooks/use-media-query.ts +36 -0
- package/hooks/use-on-click-outside.tsx +28 -0
- package/hooks/use-router.ts +45 -0
- package/hooks/use-translation.ts +14 -0
- package/lib/cache.ts +185 -0
- package/localization/index.ts +5 -0
- package/localization/provider.tsx +58 -0
- package/middlewares/currency.ts +55 -0
- package/middlewares/default.ts +224 -0
- package/middlewares/index.ts +29 -0
- package/middlewares/locale.ts +61 -0
- package/middlewares/oauth-login.ts +78 -0
- package/middlewares/pretty-url.ts +94 -0
- package/middlewares/redirection-payment.ts +117 -0
- package/middlewares/three-d-redirection.ts +122 -0
- package/middlewares/url-redirection.ts +61 -0
- package/package.json +20 -0
- package/plugins.js +7 -0
- package/redux/hooks.ts +7 -0
- package/redux/middlewares/checkout.ts +231 -0
- package/redux/middlewares/index.ts +50 -0
- package/redux/reducers/checkout.ts +164 -0
- package/redux/reducers/config.ts +28 -0
- package/redux/reducers/header.ts +59 -0
- package/redux/reducers/index.ts +15 -0
- package/redux/reducers/root.ts +61 -0
- package/tailwind/rtl.js +137 -0
- package/types/commerce/account.ts +68 -0
- package/types/commerce/address.ts +94 -0
- package/types/commerce/basket.ts +43 -0
- package/types/commerce/category.ts +114 -0
- package/types/commerce/checkout.ts +132 -0
- package/types/commerce/flatpage.ts +7 -0
- package/types/commerce/index.ts +10 -0
- package/types/commerce/misc.ts +127 -0
- package/types/commerce/order.ts +108 -0
- package/types/commerce/product.ts +110 -0
- package/types/commerce/widget.ts +28 -0
- package/types/gtm.ts +16 -0
- package/types/index.ts +207 -0
- package/types/next-auth.d.ts +24 -0
- package/utils/app-fetch.ts +62 -0
- package/utils/generate-commerce-search-params.ts +22 -0
- package/utils/get-currency.ts +29 -0
- package/utils/image-loader.ts +31 -0
- package/utils/index.ts +132 -0
- package/utils/localization.ts +29 -0
- package/utils/log.ts +138 -0
- package/utils/menu-generator.ts +27 -0
- package/utils/mobile-3d-iframe.ts +58 -0
- package/utils/server-translation.ts +57 -0
- package/utils/server-variables.ts +9 -0
package/.prettierrc
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bracketSameLine": false,
|
|
3
|
+
"tabWidth": 2,
|
|
4
|
+
"singleQuote": true,
|
|
5
|
+
"jsxSingleQuote": false,
|
|
6
|
+
"bracketSpacing": true,
|
|
7
|
+
"semi": true,
|
|
8
|
+
"useTabs": false,
|
|
9
|
+
"arrowParens": "always",
|
|
10
|
+
"endOfLine": "lf",
|
|
11
|
+
"proseWrap": "never",
|
|
12
|
+
"trailingComma": "none"
|
|
13
|
+
}
|
package/api/auth.ts
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { NextApiRequest, NextApiResponse } from 'next';
|
|
2
|
+
import NextAuth, { Session } from 'next-auth';
|
|
3
|
+
import CredentialProvider from 'next-auth/providers/credentials';
|
|
4
|
+
import { ROUTES } from 'routes';
|
|
5
|
+
import { URLS, user } from '../data/urls';
|
|
6
|
+
import Settings from 'settings';
|
|
7
|
+
import { urlLocaleMatcherRegex } from '../utils';
|
|
8
|
+
import logger from '@akinon/next/utils/log';
|
|
9
|
+
import { AuthError } from '../types';
|
|
10
|
+
|
|
11
|
+
async function getCurrentUser(sessionId: string) {
|
|
12
|
+
const currentUser = await (
|
|
13
|
+
await fetch(URLS.user.currentUser, {
|
|
14
|
+
headers: {
|
|
15
|
+
'Content-Type': 'application/json',
|
|
16
|
+
Cookie: `osessionid=${sessionId}`
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
).json();
|
|
20
|
+
|
|
21
|
+
logger.debug('Successfully fetched current user data', { currentUser });
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
pk: currentUser.pk,
|
|
25
|
+
firstName: currentUser.first_name,
|
|
26
|
+
lastName: currentUser.last_name,
|
|
27
|
+
email: currentUser.email,
|
|
28
|
+
phone: currentUser.phone,
|
|
29
|
+
emailAllowed: currentUser.email_allowed,
|
|
30
|
+
smsAllowed: currentUser.sms_allowed,
|
|
31
|
+
dateJoined: currentUser.date_joined,
|
|
32
|
+
lastLogin: currentUser.last_login,
|
|
33
|
+
dateOfBirth: currentUser.date_of_birth,
|
|
34
|
+
hashedEmail: currentUser.hashed_email,
|
|
35
|
+
gender: currentUser.gender,
|
|
36
|
+
token: ''
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const nextAuthOptions = (req: NextApiRequest, res: NextApiResponse) => {
|
|
41
|
+
return {
|
|
42
|
+
providers: [
|
|
43
|
+
CredentialProvider({
|
|
44
|
+
id: 'oauth',
|
|
45
|
+
name: 'credentials',
|
|
46
|
+
credentials: {},
|
|
47
|
+
authorize: async (credentials) => {
|
|
48
|
+
const sessionId = req.cookies['osessionid'];
|
|
49
|
+
|
|
50
|
+
if (!sessionId) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const currentUser = await getCurrentUser(sessionId);
|
|
55
|
+
return currentUser;
|
|
56
|
+
}
|
|
57
|
+
}),
|
|
58
|
+
CredentialProvider({
|
|
59
|
+
id: 'default',
|
|
60
|
+
name: 'credentials',
|
|
61
|
+
credentials: {
|
|
62
|
+
email: { label: 'Email', type: 'email', placeholder: 'Email' },
|
|
63
|
+
password: {
|
|
64
|
+
label: 'Password',
|
|
65
|
+
type: 'password',
|
|
66
|
+
placeholder: 'Password'
|
|
67
|
+
},
|
|
68
|
+
formType: {},
|
|
69
|
+
locale: {},
|
|
70
|
+
captchaValidated: {}
|
|
71
|
+
},
|
|
72
|
+
authorize: async (credentials) => {
|
|
73
|
+
const headers: HeadersInit = new Headers();
|
|
74
|
+
const language = Settings.localization.locales.find(
|
|
75
|
+
(item) => item.value === credentials.locale
|
|
76
|
+
).apiValue;
|
|
77
|
+
|
|
78
|
+
headers.set('Content-Type', 'application/json');
|
|
79
|
+
headers.set('cookie', `${req.headers.cookie}`);
|
|
80
|
+
headers.set('Accept-Language', `${language}`);
|
|
81
|
+
|
|
82
|
+
logger.debug('Trying to login/register', {
|
|
83
|
+
formType: credentials.formType
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const apiRequest = await fetch(
|
|
87
|
+
`${Settings.commerceUrl}${user[credentials.formType]}`,
|
|
88
|
+
{
|
|
89
|
+
method: 'POST',
|
|
90
|
+
headers,
|
|
91
|
+
body: JSON.stringify(credentials)
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
logger.info(`Login/Register request result: ${apiRequest.status}`);
|
|
96
|
+
|
|
97
|
+
const response = (await apiRequest.json()) as {
|
|
98
|
+
key: string;
|
|
99
|
+
non_field_errors: string[];
|
|
100
|
+
redirect_url: string;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
logger.debug(`Login/Register response: ${JSON.stringify(response)}`);
|
|
104
|
+
|
|
105
|
+
let sessionId = '';
|
|
106
|
+
const setCookieHeader = apiRequest.headers.get('set-cookie');
|
|
107
|
+
if (setCookieHeader) {
|
|
108
|
+
sessionId =
|
|
109
|
+
setCookieHeader
|
|
110
|
+
.match(/osessionid=\w+/)?.[0]
|
|
111
|
+
.replace(/osessionid=/, '') || '';
|
|
112
|
+
|
|
113
|
+
logger.debug(`Login/Register session id: ${sessionId}`);
|
|
114
|
+
} else {
|
|
115
|
+
logger.warn('No set-cookie header found in response');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (sessionId) {
|
|
119
|
+
res.setHeader('Set-Cookie', [
|
|
120
|
+
`osessionid=${sessionId}; Path=/; HttpOnly; Secure;`,
|
|
121
|
+
`sessionid=${sessionId}; Path=/; HttpOnly; Secure;` // required to get 3D redirection form
|
|
122
|
+
]);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (!response.key) {
|
|
126
|
+
let errors = [] as AuthError[];
|
|
127
|
+
|
|
128
|
+
const fieldErrors = Object.keys(response ?? {})
|
|
129
|
+
.filter((key) => key !== 'non_field_errors')
|
|
130
|
+
.map((key) => {
|
|
131
|
+
return {
|
|
132
|
+
name: key,
|
|
133
|
+
value: response[key]
|
|
134
|
+
};
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
if (response.redirect_url?.includes('captcha')) {
|
|
138
|
+
errors.push({
|
|
139
|
+
type: 'captcha'
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
logger.debug('Captcha required', {
|
|
143
|
+
email: credentials.email,
|
|
144
|
+
formType: credentials.formType
|
|
145
|
+
});
|
|
146
|
+
} else if (fieldErrors.length) {
|
|
147
|
+
errors.push({
|
|
148
|
+
type: 'field_errors',
|
|
149
|
+
data: fieldErrors
|
|
150
|
+
});
|
|
151
|
+
} else if (response.non_field_errors) {
|
|
152
|
+
errors.push({
|
|
153
|
+
type: 'non_field_errors',
|
|
154
|
+
data: response.non_field_errors
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (errors.length) {
|
|
159
|
+
throw new Error(JSON.stringify(errors));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const currentUser = await getCurrentUser(sessionId);
|
|
164
|
+
return currentUser;
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
],
|
|
168
|
+
callbacks: {
|
|
169
|
+
jwt: async ({ token, user }) => {
|
|
170
|
+
if (user) {
|
|
171
|
+
token.user = user;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return token;
|
|
175
|
+
},
|
|
176
|
+
async session({ session, user, token }) {
|
|
177
|
+
session.user = token.user as Session['user'];
|
|
178
|
+
return session;
|
|
179
|
+
},
|
|
180
|
+
async redirect({ url, baseUrl }: { url: string; baseUrl: string }) {
|
|
181
|
+
const pathname = url.startsWith('/') ? url : url.replace(baseUrl, '');
|
|
182
|
+
const pathnameWithoutLocale = pathname.replace(
|
|
183
|
+
urlLocaleMatcherRegex,
|
|
184
|
+
''
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
const localeResults = req.headers.referer
|
|
188
|
+
.replace(baseUrl, '')
|
|
189
|
+
.match(urlLocaleMatcherRegex);
|
|
190
|
+
|
|
191
|
+
return `${baseUrl}${localeResults?.[0] || ''}${pathnameWithoutLocale}`;
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
events: {
|
|
195
|
+
signIn: () => {
|
|
196
|
+
logger.debug('Successfully signed in');
|
|
197
|
+
},
|
|
198
|
+
signOut: () => {
|
|
199
|
+
res.setHeader('Set-Cookie', [
|
|
200
|
+
`osessionid=; Path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT`,
|
|
201
|
+
`sessionid=; Path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT`
|
|
202
|
+
]);
|
|
203
|
+
logger.debug('Successfully signed out');
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
pages: {
|
|
207
|
+
signIn: ROUTES.AUTH,
|
|
208
|
+
error: ROUTES.AUTH
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const Auth = (req, res) => {
|
|
214
|
+
return NextAuth(req, res, nextAuthOptions(req, res));
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
export default Auth;
|
package/api/cache.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Cache } from '../lib/cache';
|
|
2
|
+
import { NextResponse } from 'next/server';
|
|
3
|
+
import logger from '@akinon/next/utils/log';
|
|
4
|
+
|
|
5
|
+
export async function POST(...args) {
|
|
6
|
+
return handleRequest(...args);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function PUT(...args) {
|
|
10
|
+
return handleRequest(...args);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function handleRequest(...args) {
|
|
14
|
+
const [req] = args as [req: Request];
|
|
15
|
+
|
|
16
|
+
if (
|
|
17
|
+
!req.headers.get('authorization') ||
|
|
18
|
+
req.headers.get('authorization') !== process.env.CACHE_SECRET
|
|
19
|
+
) {
|
|
20
|
+
return NextResponse.next({ status: 403 });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const formData = await req.formData();
|
|
24
|
+
const body = {} as { key: string; value?: string; expire?: number };
|
|
25
|
+
|
|
26
|
+
formData.forEach((value, key) => {
|
|
27
|
+
body[key] = value;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const { key, value, expire } = body;
|
|
31
|
+
let response: string | boolean;
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
if (req.method === 'POST') {
|
|
35
|
+
response = await Cache.get(key);
|
|
36
|
+
} else if (req.method === 'PUT') {
|
|
37
|
+
response = await Cache.set(key, value, expire);
|
|
38
|
+
}
|
|
39
|
+
} catch (error) {
|
|
40
|
+
logger.error(error);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return NextResponse.json(response);
|
|
44
|
+
}
|
package/api/client.ts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { ClientRequestOptions } from '../types';
|
|
2
|
+
import { NextResponse } from 'next/server';
|
|
3
|
+
import settings from 'settings';
|
|
4
|
+
import logger from '../utils/log';
|
|
5
|
+
|
|
6
|
+
interface RouteParams {
|
|
7
|
+
params: {
|
|
8
|
+
slug: string[];
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async function proxyRequest(...args) {
|
|
13
|
+
const [req, { params }] = args as [req: Request, params: RouteParams];
|
|
14
|
+
const { searchParams } = new URL(req.url);
|
|
15
|
+
const commerceUrl = settings.commerceUrl;
|
|
16
|
+
|
|
17
|
+
if (commerceUrl === 'default') {
|
|
18
|
+
return NextResponse.json(
|
|
19
|
+
{ error: 'Commerce URL not found' },
|
|
20
|
+
{ status: 404 }
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const options: ClientRequestOptions = {
|
|
25
|
+
useTrailingSlash: true,
|
|
26
|
+
useFormData: false,
|
|
27
|
+
contentType: null,
|
|
28
|
+
accept: 'application/json',
|
|
29
|
+
responseType: 'json'
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const slug = params.slug.join('/');
|
|
33
|
+
const options_ = JSON.parse(
|
|
34
|
+
decodeURIComponent((searchParams.get('options') as string) ?? '{}')
|
|
35
|
+
);
|
|
36
|
+
const urlSearchParams = new URLSearchParams();
|
|
37
|
+
|
|
38
|
+
Object.assign(options, options_);
|
|
39
|
+
|
|
40
|
+
Array.from(searchParams.keys()).forEach((key) => {
|
|
41
|
+
if (key !== 'slug' && key !== 'options') {
|
|
42
|
+
urlSearchParams.append(key, `${searchParams.get(key)}`);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const fetchOptions = {
|
|
47
|
+
method: req.method,
|
|
48
|
+
headers: {
|
|
49
|
+
'X-Requested-With': 'XMLHttpRequest',
|
|
50
|
+
'X-CSRFToken': `${req.headers.get('x-csrftoken')}`,
|
|
51
|
+
'x-currency': `${req.headers.get('x-currency')}`,
|
|
52
|
+
'Accept-Language': `${req.headers.get('Accept-Language')}`,
|
|
53
|
+
'User-Agent': `${req.headers.get('User-Agent')}`,
|
|
54
|
+
Referer: commerceUrl,
|
|
55
|
+
Accept: options.accept,
|
|
56
|
+
Cookie: `${req.headers.get('cookie')}`
|
|
57
|
+
}
|
|
58
|
+
} as RequestInit;
|
|
59
|
+
|
|
60
|
+
if (options.contentType) {
|
|
61
|
+
fetchOptions.headers['Content-Type'] = options.contentType;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (req.method !== 'GET') {
|
|
65
|
+
const formData = new URLSearchParams();
|
|
66
|
+
let body = {};
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
body = await req.json();
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.log(error);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
Object.keys(body ?? {}).forEach((key) => {
|
|
75
|
+
if (body[key]) {
|
|
76
|
+
formData.append(key, body[key]);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
fetchOptions.body = !options.useFormData ? JSON.stringify(body) : formData;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let url = `${commerceUrl}/${slug.replace(/,/g, '/')}`;
|
|
84
|
+
|
|
85
|
+
if (options.useTrailingSlash) {
|
|
86
|
+
url += '/';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (urlSearchParams.toString().length) {
|
|
90
|
+
url += `?${urlSearchParams.toString()}`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const request = await fetch(url, fetchOptions);
|
|
95
|
+
let response = {} as any;
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
response = await (options.responseType === 'text'
|
|
99
|
+
? request.text()
|
|
100
|
+
: request.json());
|
|
101
|
+
} catch (error) {
|
|
102
|
+
logger.error(
|
|
103
|
+
`Client Proxy Request - Error while parsing response body to ${options.responseType}`,
|
|
104
|
+
{
|
|
105
|
+
url,
|
|
106
|
+
status: request.status,
|
|
107
|
+
fetchOptions: JSON.stringify(fetchOptions),
|
|
108
|
+
error
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const setCookieHeader = request.headers.get('set-cookie');
|
|
114
|
+
const responseHeaders: any = {};
|
|
115
|
+
|
|
116
|
+
if (setCookieHeader) {
|
|
117
|
+
responseHeaders['set-cookie'] = setCookieHeader;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const statusCode = new RegExp(/^20./).test(request.status.toString())
|
|
121
|
+
? 200
|
|
122
|
+
: request.status;
|
|
123
|
+
|
|
124
|
+
return NextResponse.json(
|
|
125
|
+
options.responseType === 'text' ? { result: response } : response,
|
|
126
|
+
{ status: statusCode, headers: responseHeaders }
|
|
127
|
+
);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
logger.error('Client proxy request failed', error);
|
|
130
|
+
|
|
131
|
+
return NextResponse.json({ error }, { status: 500 });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export async function GET(...args) {
|
|
136
|
+
return proxyRequest(...args);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export async function POST(...args) {
|
|
140
|
+
return proxyRequest(...args);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export async function PUT(...args) {
|
|
144
|
+
return proxyRequest(...args);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function PATCH(...args) {
|
|
148
|
+
return proxyRequest(...args);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export async function DELETE(...args) {
|
|
152
|
+
return proxyRequest(...args);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export async function HEAD(...args) {
|
|
156
|
+
return proxyRequest(...args);
|
|
157
|
+
}
|
package/api/logout.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { URLS } from '../data/urls';
|
|
2
|
+
import { NextResponse } from 'next/server';
|
|
3
|
+
|
|
4
|
+
export async function POST(req: Request) {
|
|
5
|
+
const regexText1 = /name=['|"]csrfmiddlewaretoken['|"] value=['|"]\w+/gi;
|
|
6
|
+
const regexText2 = /name=['|"]csrfmiddlewaretoken['|"] value=['|"]/gi;
|
|
7
|
+
let sessionCookie;
|
|
8
|
+
|
|
9
|
+
if (req.headers.get('osessionid')) {
|
|
10
|
+
sessionCookie = `osessionid=${req.headers.get('osessionid')}`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const requestLogoutStep1 = await fetch(URLS.user.logout, {
|
|
14
|
+
method: 'POST',
|
|
15
|
+
headers: {
|
|
16
|
+
Cookie: `${sessionCookie}`
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const responseHtml = await requestLogoutStep1.text();
|
|
21
|
+
const csrfTokenMatch = responseHtml.match(regexText1);
|
|
22
|
+
const csrfToken = csrfTokenMatch?.[0].replace(regexText2, '') || '';
|
|
23
|
+
const formData = new URLSearchParams();
|
|
24
|
+
|
|
25
|
+
formData.append('csrfmiddlewaretoken', csrfToken);
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const requestLogoutStep2 = await fetch(URLS.user.logout, {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: {
|
|
31
|
+
Cookie: `csrftoken=${csrfToken}; ${sessionCookie}`
|
|
32
|
+
},
|
|
33
|
+
body: formData
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return NextResponse.json(requestLogoutStep2, {
|
|
37
|
+
status: requestLogoutStep2.status
|
|
38
|
+
});
|
|
39
|
+
} catch (error) {
|
|
40
|
+
return NextResponse.json(error, { status: 500 });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
.checkout-payment-iframe-wrapper {
|
|
2
|
+
iframe {
|
|
3
|
+
position: fixed;
|
|
4
|
+
top: 0;
|
|
5
|
+
left: 0;
|
|
6
|
+
width: 100%;
|
|
7
|
+
height: 100%;
|
|
8
|
+
border: none;
|
|
9
|
+
z-index: 1000;
|
|
10
|
+
background-color: white;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.close-button {
|
|
14
|
+
position: fixed;
|
|
15
|
+
top: 16px;
|
|
16
|
+
right: 16px;
|
|
17
|
+
width: 32px;
|
|
18
|
+
height: 32px;
|
|
19
|
+
display: flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
justify-content: center;
|
|
22
|
+
z-index: 1001;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const rootDir = path.resolve(process.cwd());
|
|
6
|
+
const spawn = require('cross-spawn');
|
|
7
|
+
const availablePlugins = require('../plugins');
|
|
8
|
+
|
|
9
|
+
let plugins;
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
plugins = require(path.resolve(rootDir, './src/plugins.js'));
|
|
13
|
+
} catch (error) {}
|
|
14
|
+
|
|
15
|
+
let installCmd = [];
|
|
16
|
+
|
|
17
|
+
availablePlugins
|
|
18
|
+
.filter((p) => plugins.includes(p))
|
|
19
|
+
.forEach((name) => {
|
|
20
|
+
installCmd.push(`git+https://bitbucket.org/akinonteam/${name}`);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
spawn.sync('yarn', ['cache clean']);
|
|
24
|
+
spawn.sync('yarn', ['remove', ...availablePlugins]);
|
|
25
|
+
|
|
26
|
+
if (
|
|
27
|
+
installCmd.length > 0 &&
|
|
28
|
+
!fs.existsSync(path.resolve(rootDir, '../../turbo.json'))
|
|
29
|
+
) {
|
|
30
|
+
spawn.sync('yarn', ['add', ...installCmd, '--ignore-scripts'], {
|
|
31
|
+
stdio: 'inherit'
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { usePathname } from 'next/navigation';
|
|
4
|
+
import { useEffect } from 'react';
|
|
5
|
+
import { api } from '../data/client/api';
|
|
6
|
+
import {
|
|
7
|
+
useClearBasketMutation,
|
|
8
|
+
useGetBasketQuery
|
|
9
|
+
} from '../data/client/basket';
|
|
10
|
+
import { useAppDispatch, useAppSelector } from '../redux/hooks';
|
|
11
|
+
import { getCookie, removeCookie } from '../utils';
|
|
12
|
+
import { useRouter } from '../hooks';
|
|
13
|
+
|
|
14
|
+
export default function ClientRoot({
|
|
15
|
+
children,
|
|
16
|
+
sessionId
|
|
17
|
+
}: {
|
|
18
|
+
children: React.ReactNode;
|
|
19
|
+
sessionId?: string;
|
|
20
|
+
}) {
|
|
21
|
+
const dispatch = useAppDispatch();
|
|
22
|
+
const pathname = usePathname();
|
|
23
|
+
const router = useRouter();
|
|
24
|
+
const { isMobileApp } = useAppSelector((state) => state.root);
|
|
25
|
+
const { data: basketData } = useGetBasketQuery();
|
|
26
|
+
const [clearBasket] = useClearBasketMutation();
|
|
27
|
+
const resetClientCache = getCookie('pz-reset-client-cache') === 'true';
|
|
28
|
+
const resetBasket = getCookie('pz-reset-basket') === 'true';
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (basketData?.basketitem_set.length) {
|
|
32
|
+
dispatch(
|
|
33
|
+
api.util.invalidateTags([
|
|
34
|
+
'Checkout',
|
|
35
|
+
'Product',
|
|
36
|
+
'Addresses',
|
|
37
|
+
'Favorite',
|
|
38
|
+
'Basket'
|
|
39
|
+
])
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
if (resetBasket) {
|
|
43
|
+
clearBasket();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
removeCookie('pz-reset-basket');
|
|
48
|
+
}, [resetBasket]);
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (resetClientCache) {
|
|
52
|
+
removeCookie('pz-reset-client-cache');
|
|
53
|
+
location.reload();
|
|
54
|
+
}
|
|
55
|
+
}, [resetClientCache]);
|
|
56
|
+
|
|
57
|
+
if (isMobileApp && pathname.includes('/orders/completed')) {
|
|
58
|
+
((window.parent || window) as any)?.ReactNativeWebView?.postMessage?.(
|
|
59
|
+
JSON.stringify({
|
|
60
|
+
url: pathname,
|
|
61
|
+
sessionId
|
|
62
|
+
})
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return <>{children}</>;
|
|
69
|
+
}
|