@akinon/next 1.10.0 → 1.11.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 +12 -0
- package/components/icon.tsx +18 -0
- package/components/loader-spinner.tsx +23 -0
- package/components/radio.tsx +18 -0
- package/data/client/api.ts +51 -9
- package/data/client/b2b.ts +67 -5
- package/data/server/form.ts +22 -0
- package/data/server/index.ts +1 -0
- package/data/urls.ts +6 -1
- package/lib/cache.ts +2 -1
- package/middlewares/redirection-payment.ts +23 -6
- package/middlewares/three-d-redirection.ts +23 -1
- package/package.json +1 -1
- package/types/commerce/b2b.ts +53 -1
- package/types/commerce/form.ts +66 -0
- package/types/commerce/index.ts +1 -0
- package/types/index.ts +8 -0
- package/utils/index.ts +12 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @akinon/next
|
|
2
2
|
|
|
3
|
+
## 1.11.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- ZERO-2355: Add LoaderSpinner component
|
|
8
|
+
- ZERO-2305: Add endpoints for B2B Basket
|
|
9
|
+
- ZERO-2319: Show 3D & redirection payment errors
|
|
10
|
+
- ZERO-2353: Add Icon component
|
|
11
|
+
- ZERO-2357: Add Radio component
|
|
12
|
+
- ZERO-2307: Prevent multiple mutation calls
|
|
13
|
+
- ZERO-2240: Add endpoints and types for dynamic forms
|
|
14
|
+
|
|
3
15
|
## 1.10.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { IconProps } from '../types/index';
|
|
2
|
+
import clsx from 'clsx';
|
|
3
|
+
|
|
4
|
+
export const Icon = (props: IconProps) => {
|
|
5
|
+
const { name, size, className, ...rest } = props;
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<i
|
|
9
|
+
className={clsx(`flex pz-icon-${name}`, className)}
|
|
10
|
+
{...rest}
|
|
11
|
+
style={
|
|
12
|
+
size && {
|
|
13
|
+
fontSize: `${size}px`
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { twMerge } from 'tailwind-merge';
|
|
2
|
+
|
|
3
|
+
type LoaderSpinnerProps = {
|
|
4
|
+
className?: string;
|
|
5
|
+
borderType?: 'solid' | 'dotted' | 'dashed';
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const LoaderSpinner: React.FC<LoaderSpinnerProps> = ({
|
|
9
|
+
borderType = 'solid',
|
|
10
|
+
className
|
|
11
|
+
}) => {
|
|
12
|
+
return (
|
|
13
|
+
<div className="w-full h-full flex justify-center items-center">
|
|
14
|
+
<div
|
|
15
|
+
className={twMerge(
|
|
16
|
+
'w-8 h-8 border-2 border-primary border-t-transparent rounded-full animate-spin',
|
|
17
|
+
`border-${borderType}`,
|
|
18
|
+
className
|
|
19
|
+
)}
|
|
20
|
+
/>
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { forwardRef } from 'react';
|
|
2
|
+
import { RadioProps } from '../types/index';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
|
+
|
|
5
|
+
const Radio = forwardRef<HTMLInputElement, RadioProps>((props, ref) => {
|
|
6
|
+
const { children, ...rest } = props;
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<label className={twMerge('flex items-center text-xs', props.className)}>
|
|
10
|
+
<input type="radio" {...rest} ref={ref} className="w-4 h-4" />
|
|
11
|
+
{children && <span className="text-xs ml-2">{children}</span>}
|
|
12
|
+
</label>
|
|
13
|
+
);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
Radio.displayName = 'Radio';
|
|
17
|
+
|
|
18
|
+
export { Radio };
|
package/data/client/api.ts
CHANGED
|
@@ -1,10 +1,42 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createApi,
|
|
3
|
+
fetchBaseQuery,
|
|
4
|
+
retry,
|
|
5
|
+
BaseQueryFn,
|
|
6
|
+
FetchBaseQueryError,
|
|
7
|
+
FetchBaseQueryMeta,
|
|
8
|
+
FetchArgs,
|
|
9
|
+
BaseQueryApi
|
|
10
|
+
} from '@reduxjs/toolkit/query/react';
|
|
2
11
|
import settings from 'settings';
|
|
3
12
|
import { getCookie } from '../../utils';
|
|
13
|
+
import { RootState } from '@theme/redux/store';
|
|
4
14
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
15
|
+
interface CustomBaseQueryApi extends BaseQueryApi {
|
|
16
|
+
getState: () => RootState;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const customBaseQuery: BaseQueryFn<
|
|
20
|
+
string | FetchArgs,
|
|
21
|
+
unknown,
|
|
22
|
+
FetchBaseQueryError,
|
|
23
|
+
{},
|
|
24
|
+
FetchBaseQueryMeta
|
|
25
|
+
> = async (args, api: CustomBaseQueryApi, extraOptions) => {
|
|
26
|
+
const mutations = Object.entries(api.getState()?.api?.mutations ?? {}).map(
|
|
27
|
+
(x) => x[1]
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
if (
|
|
31
|
+
api.type === 'mutation' &&
|
|
32
|
+
mutations.filter(
|
|
33
|
+
(m) => m.status === 'pending' && m.endpointName === api.endpoint
|
|
34
|
+
).length > 1
|
|
35
|
+
) {
|
|
36
|
+
api.abort('Mutation already in progress.');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const baseQuery = fetchBaseQuery({
|
|
8
40
|
prepareHeaders: async (headers) => {
|
|
9
41
|
const csrfCookie = getCookie('csrftoken');
|
|
10
42
|
const activeLocale = getCookie('pz-locale');
|
|
@@ -19,22 +51,32 @@ export const api = createApi({
|
|
|
19
51
|
if (csrfCookie) {
|
|
20
52
|
headers.set('x-csrftoken', `${csrfCookie}`);
|
|
21
53
|
}
|
|
22
|
-
|
|
23
54
|
return headers;
|
|
24
55
|
},
|
|
25
56
|
credentials: 'include'
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
|
|
57
|
+
});
|
|
58
|
+
try {
|
|
59
|
+
const result = await baseQuery(args, api, extraOptions);
|
|
60
|
+
return result;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
return { error };
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const api = createApi({
|
|
67
|
+
reducerPath: 'api',
|
|
68
|
+
baseQuery: retry(customBaseQuery, { maxRetries: 3 }),
|
|
29
69
|
tagTypes: [
|
|
30
70
|
'Basket',
|
|
71
|
+
'BasketB2b',
|
|
72
|
+
'DraftsB2b',
|
|
31
73
|
'Product',
|
|
32
74
|
'Checkout',
|
|
33
75
|
'Favorite',
|
|
34
76
|
'Addresses',
|
|
35
77
|
'Profile'
|
|
36
78
|
],
|
|
37
|
-
endpoints: () => ({})
|
|
79
|
+
endpoints: () => ({})
|
|
38
80
|
});
|
|
39
81
|
|
|
40
82
|
export const {
|
package/data/client/b2b.ts
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
import { buildClientRequestUrl } from '../../utils';
|
|
2
2
|
import { api } from './api';
|
|
3
3
|
import { b2b } from '../urls';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
Basket,
|
|
6
|
+
BasketParams,
|
|
7
|
+
BasketResponse,
|
|
8
|
+
Division,
|
|
9
|
+
DraftResponse,
|
|
10
|
+
GetResponse,
|
|
11
|
+
LoadBasketParams,
|
|
12
|
+
SaveBasketParams,
|
|
13
|
+
updateProduct,
|
|
14
|
+
CreateQuotation
|
|
15
|
+
} from '../../types';
|
|
5
16
|
|
|
6
17
|
const b2bApi = api.injectEndpoints({
|
|
7
18
|
endpoints: (build) => ({
|
|
8
|
-
|
|
19
|
+
getBasketB2b: build.query<BasketResponse, void>({
|
|
9
20
|
query: () =>
|
|
10
21
|
buildClientRequestUrl(b2b.basket, {
|
|
11
22
|
contentType: 'application/json'
|
|
12
23
|
}),
|
|
13
|
-
|
|
14
|
-
providesTags: ['Basket']
|
|
24
|
+
providesTags: ['BasketB2b']
|
|
15
25
|
}),
|
|
16
26
|
getDivisions: build.query<GetResponse<Division>, void>({
|
|
17
27
|
query: () => buildClientRequestUrl(b2b.divisions)
|
|
@@ -25,8 +35,60 @@ const b2bApi = api.injectEndpoints({
|
|
|
25
35
|
body
|
|
26
36
|
})
|
|
27
37
|
}),
|
|
38
|
+
saveBasket: build.mutation<BasketResponse, SaveBasketParams>({
|
|
39
|
+
query: (body) => ({
|
|
40
|
+
url: buildClientRequestUrl(b2b.saveBasket, {
|
|
41
|
+
contentType: 'application/json'
|
|
42
|
+
}),
|
|
43
|
+
method: 'POST',
|
|
44
|
+
body
|
|
45
|
+
}),
|
|
46
|
+
invalidatesTags: ['BasketB2b', 'DraftsB2b']
|
|
47
|
+
}),
|
|
48
|
+
getDrafts: build.query<DraftResponse[], void>({
|
|
49
|
+
query: () => buildClientRequestUrl(b2b.draftBaskets),
|
|
50
|
+
providesTags: ['DraftsB2b']
|
|
51
|
+
}),
|
|
52
|
+
loadBasket: build.mutation<string, number>({
|
|
53
|
+
query: (id) => ({
|
|
54
|
+
url: buildClientRequestUrl(b2b.loadBasket(id), {
|
|
55
|
+
contentType: 'application/json'
|
|
56
|
+
}),
|
|
57
|
+
method: 'POST'
|
|
58
|
+
}),
|
|
59
|
+
invalidatesTags: ['BasketB2b']
|
|
60
|
+
}),
|
|
61
|
+
updateProduct: build.mutation<Basket, updateProduct>({
|
|
62
|
+
query: (body) => ({
|
|
63
|
+
url: buildClientRequestUrl(b2b.basket, {
|
|
64
|
+
contentType: 'application/json'
|
|
65
|
+
}),
|
|
66
|
+
method: 'PUT',
|
|
67
|
+
body
|
|
68
|
+
}),
|
|
69
|
+
invalidatesTags: ['BasketB2b']
|
|
70
|
+
}),
|
|
71
|
+
createQuotation: build.mutation<BasketResponse, CreateQuotation>({
|
|
72
|
+
query: (body) => ({
|
|
73
|
+
url: buildClientRequestUrl(b2b.myQuotations, {
|
|
74
|
+
contentType: 'application/json'
|
|
75
|
+
}),
|
|
76
|
+
method: 'POST',
|
|
77
|
+
body
|
|
78
|
+
}),
|
|
79
|
+
invalidatesTags: ['BasketB2b', 'DraftsB2b']
|
|
80
|
+
}),
|
|
28
81
|
}),
|
|
29
82
|
overrideExisting: true
|
|
30
83
|
});
|
|
31
84
|
|
|
32
|
-
export const {
|
|
85
|
+
export const {
|
|
86
|
+
useGetBasketB2bQuery,
|
|
87
|
+
useLazyGetDivisionsQuery,
|
|
88
|
+
useAddToBasketMutation,
|
|
89
|
+
useSaveBasketMutation,
|
|
90
|
+
useGetDraftsQuery,
|
|
91
|
+
useLoadBasketMutation,
|
|
92
|
+
useUpdateProductMutation,
|
|
93
|
+
useCreateQuotationMutation
|
|
94
|
+
} = b2bApi;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Cache, CacheKey } from "../../lib/cache";
|
|
2
|
+
import { FormType } from "../../types/commerce/form";
|
|
3
|
+
|
|
4
|
+
import appFetch from "../../utils/app-fetch";
|
|
5
|
+
import { form } from "../urls";
|
|
6
|
+
|
|
7
|
+
const getFormDataHandler = (pk: number) => {
|
|
8
|
+
return async function () {
|
|
9
|
+
const data = await appFetch<FormType>(form.getForm(pk), {
|
|
10
|
+
headers: {
|
|
11
|
+
Accept: 'application/json',
|
|
12
|
+
'Content-Type': 'application/json'
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
return data;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const getFormData = ({ pk }: { pk: number }) => {
|
|
21
|
+
return Cache.wrap(CacheKey.Form(pk), getFormDataHandler(pk));
|
|
22
|
+
};
|
package/data/server/index.ts
CHANGED
package/data/urls.ts
CHANGED
|
@@ -169,6 +169,10 @@ export const widgets = {
|
|
|
169
169
|
getWidget: (slug: string) => `/widgets/${slug}/`
|
|
170
170
|
};
|
|
171
171
|
|
|
172
|
+
export const form = {
|
|
173
|
+
getForm: (pk: number) => `/forms/${pk}/generate/`,
|
|
174
|
+
};
|
|
175
|
+
|
|
172
176
|
const URLS = {
|
|
173
177
|
account,
|
|
174
178
|
address,
|
|
@@ -180,7 +184,8 @@ const URLS = {
|
|
|
180
184
|
product,
|
|
181
185
|
wishlist,
|
|
182
186
|
user,
|
|
183
|
-
widgets
|
|
187
|
+
widgets,
|
|
188
|
+
form
|
|
184
189
|
};
|
|
185
190
|
|
|
186
191
|
const UrlProxyHandler = {
|
package/lib/cache.ts
CHANGED
|
@@ -51,7 +51,8 @@ export const CacheKey = {
|
|
|
51
51
|
Menu: (depth: number, parent?: string) =>
|
|
52
52
|
`menu_${depth}${parent ? `_${parent}` : ''}`,
|
|
53
53
|
Seo: (url: string) => `seo_${url}`,
|
|
54
|
-
RootSeo: 'root_seo'
|
|
54
|
+
RootSeo: 'root_seo',
|
|
55
|
+
Form: (pk: number) => `form_${pk}`
|
|
55
56
|
};
|
|
56
57
|
|
|
57
58
|
export class Cache {
|
|
@@ -4,7 +4,6 @@ import Settings from 'settings';
|
|
|
4
4
|
import logger from '../utils/log';
|
|
5
5
|
import { PzNextRequest } from '.';
|
|
6
6
|
import { getUrlPathWithLocale } from '../utils/localization';
|
|
7
|
-
import { urlLocaleMatcherRegex } from '../utils';
|
|
8
7
|
|
|
9
8
|
const streamToString = async (stream: ReadableStream<Uint8Array> | null) => {
|
|
10
9
|
if (stream) {
|
|
@@ -33,10 +32,6 @@ const withRedirectionPayment =
|
|
|
33
32
|
(middleware: NextMiddleware) =>
|
|
34
33
|
async (req: PzNextRequest, event: NextFetchEvent) => {
|
|
35
34
|
const url = req.nextUrl.clone();
|
|
36
|
-
const pathnameWithoutLocale = url.pathname.replace(
|
|
37
|
-
urlLocaleMatcherRegex,
|
|
38
|
-
''
|
|
39
|
-
);
|
|
40
35
|
const searchParams = new URLSearchParams(url.search);
|
|
41
36
|
const ip = req.headers.get('x-forwarded-for') ?? '';
|
|
42
37
|
|
|
@@ -70,12 +65,34 @@ const withRedirectionPayment =
|
|
|
70
65
|
|
|
71
66
|
const response = await request.json();
|
|
72
67
|
|
|
73
|
-
const { context_list: contextList } = response;
|
|
68
|
+
const { context_list: contextList, errors } = response;
|
|
74
69
|
const redirectionContext = contextList?.find(
|
|
75
70
|
(context) => context.page_context?.redirect_url
|
|
76
71
|
);
|
|
77
72
|
const redirectUrl = redirectionContext?.page_context?.redirect_url;
|
|
78
73
|
|
|
74
|
+
if (errors && Object.keys(errors).length) {
|
|
75
|
+
logger.error('Error while completing redirection payment', {
|
|
76
|
+
middleware: 'redirection-payment',
|
|
77
|
+
errors,
|
|
78
|
+
requestHeaders,
|
|
79
|
+
ip
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return NextResponse.redirect(
|
|
83
|
+
`${url.origin}${getUrlPathWithLocale(
|
|
84
|
+
'/orders/checkout/',
|
|
85
|
+
req.cookies.get('pz-locale')?.value
|
|
86
|
+
)}`,
|
|
87
|
+
{
|
|
88
|
+
status: 303,
|
|
89
|
+
headers: {
|
|
90
|
+
'Set-Cookie': `pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
79
96
|
logger.info('Order success page context list', {
|
|
80
97
|
middleware: 'redirection-payment',
|
|
81
98
|
contextList,
|
|
@@ -64,12 +64,34 @@ const withThreeDRedirection =
|
|
|
64
64
|
|
|
65
65
|
const response = await request.json();
|
|
66
66
|
|
|
67
|
-
const { context_list: contextList } = response;
|
|
67
|
+
const { context_list: contextList, errors } = response;
|
|
68
68
|
const redirectionContext = contextList?.find(
|
|
69
69
|
(context) => context.page_context?.redirect_url
|
|
70
70
|
);
|
|
71
71
|
const redirectUrl = redirectionContext?.page_context?.redirect_url;
|
|
72
72
|
|
|
73
|
+
if (errors && Object.keys(errors).length) {
|
|
74
|
+
logger.error('Error while completing 3D payment', {
|
|
75
|
+
middleware: 'three-d-redirection',
|
|
76
|
+
errors,
|
|
77
|
+
requestHeaders,
|
|
78
|
+
ip
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return NextResponse.redirect(
|
|
82
|
+
`${url.origin}${getUrlPathWithLocale(
|
|
83
|
+
'/orders/checkout/',
|
|
84
|
+
req.cookies.get('pz-locale')?.value
|
|
85
|
+
)}`,
|
|
86
|
+
{
|
|
87
|
+
status: 303,
|
|
88
|
+
headers: {
|
|
89
|
+
'Set-Cookie': `pz-pos-error=${JSON.stringify(errors)}; path=/;`
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
73
95
|
logger.info('Order success page context list', {
|
|
74
96
|
middleware: 'three-d-redirection',
|
|
75
97
|
contextList,
|
package/package.json
CHANGED
package/types/commerce/b2b.ts
CHANGED
|
@@ -23,6 +23,10 @@ export type Division = {
|
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
interface ProductB2b extends Product {
|
|
26
|
+
sku: string;
|
|
27
|
+
name: string;
|
|
28
|
+
price: string;
|
|
29
|
+
base_code: string;
|
|
26
30
|
asorti: string;
|
|
27
31
|
category: string;
|
|
28
32
|
currency: string;
|
|
@@ -41,21 +45,69 @@ export type BasketResponse = {
|
|
|
41
45
|
total_amount: string;
|
|
42
46
|
price: string;
|
|
43
47
|
quantity: number;
|
|
44
|
-
divisions:
|
|
48
|
+
divisions: BasketItemDivision[];
|
|
45
49
|
product: ProductB2b;
|
|
50
|
+
product_remote_id: number;
|
|
46
51
|
}
|
|
47
52
|
];
|
|
48
53
|
};
|
|
49
54
|
|
|
55
|
+
export interface QuotationErrorType {
|
|
56
|
+
data: {
|
|
57
|
+
non_field_errors: string[];
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface BasketItemDivision {
|
|
62
|
+
id: number;
|
|
63
|
+
name: string;
|
|
64
|
+
erp_code: string;
|
|
65
|
+
quantity: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type BasketItemType = {
|
|
69
|
+
total_amount: string;
|
|
70
|
+
price: string;
|
|
71
|
+
quantity: number;
|
|
72
|
+
divisions: BasketItemDivision[];
|
|
73
|
+
product: ProductB2b;
|
|
74
|
+
product_remote_id: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
50
77
|
export type BasketParams = {
|
|
51
78
|
division: string;
|
|
52
79
|
product_remote_id: string;
|
|
53
80
|
quantity: string;
|
|
54
81
|
};
|
|
55
82
|
|
|
83
|
+
export type SaveBasketParams = {
|
|
84
|
+
name: string;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export type CreateQuotation = {
|
|
88
|
+
name: string;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export type updateProduct = {
|
|
92
|
+
product_remote_id: number;
|
|
93
|
+
division: number;
|
|
94
|
+
quantity: number
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export type LoadBasketParams = {
|
|
98
|
+
id: number;
|
|
99
|
+
};
|
|
100
|
+
|
|
56
101
|
export interface GetResponse<T> {
|
|
57
102
|
count: number;
|
|
58
103
|
next: null;
|
|
59
104
|
previous: null;
|
|
60
105
|
results: T[];
|
|
61
106
|
}
|
|
107
|
+
|
|
108
|
+
export type DraftResponse = {
|
|
109
|
+
id: number;
|
|
110
|
+
name: string;
|
|
111
|
+
total_amount: number;
|
|
112
|
+
total_quantity: number;
|
|
113
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { InputHTMLAttributes, HTMLAttributes } from 'react';
|
|
2
|
+
|
|
3
|
+
export type Validator = {
|
|
4
|
+
regex: {
|
|
5
|
+
regex: string;
|
|
6
|
+
message: string;
|
|
7
|
+
inverse_match: boolean;
|
|
8
|
+
};
|
|
9
|
+
max_length: number;
|
|
10
|
+
required: boolean;
|
|
11
|
+
min_length: number;
|
|
12
|
+
max_value: number;
|
|
13
|
+
min_value: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type FormField = {
|
|
17
|
+
chosen: boolean;
|
|
18
|
+
input_type: string;
|
|
19
|
+
id: string;
|
|
20
|
+
key: string;
|
|
21
|
+
validators: Validator;
|
|
22
|
+
label: string;
|
|
23
|
+
order: number;
|
|
24
|
+
class?: string;
|
|
25
|
+
attributes?: object | null;
|
|
26
|
+
labelClass?: string;
|
|
27
|
+
wrapperClass?: string;
|
|
28
|
+
placeholder?: string;
|
|
29
|
+
choices?: string[];
|
|
30
|
+
[key: string]: any;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type Schema = FormField[];
|
|
34
|
+
|
|
35
|
+
export type FormType = {
|
|
36
|
+
pk: number;
|
|
37
|
+
schema: Schema;
|
|
38
|
+
template: string;
|
|
39
|
+
is_active: boolean;
|
|
40
|
+
url: string;
|
|
41
|
+
name: string;
|
|
42
|
+
pretty_url: any;
|
|
43
|
+
created_date: string;
|
|
44
|
+
modified_date: string;
|
|
45
|
+
formprettyurl_set: any[];
|
|
46
|
+
translations: null | any;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type FieldPropertiesType = {
|
|
50
|
+
key?: string;
|
|
51
|
+
className?: string | Record<string, boolean>;
|
|
52
|
+
attributes?: InputHTMLAttributes<object> | HTMLAttributes<object>;
|
|
53
|
+
labelClassName?: string;
|
|
54
|
+
wrapperClassName?: string;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export type AllFieldClassesType = {
|
|
58
|
+
className?: string | undefined;
|
|
59
|
+
labelClassName?: string | undefined;
|
|
60
|
+
wrapperClassName?: string | undefined;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export type FormPropertiesType = {
|
|
64
|
+
actionUrl: string;
|
|
65
|
+
className?: string;
|
|
66
|
+
};
|
package/types/commerce/index.ts
CHANGED
package/types/index.ts
CHANGED
|
@@ -222,7 +222,15 @@ export interface RootLayoutProps<
|
|
|
222
222
|
};
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
+
export type RadioProps = React.HTMLProps<HTMLInputElement>;
|
|
226
|
+
|
|
225
227
|
export interface AuthError {
|
|
226
228
|
type: string;
|
|
227
229
|
data?: any;
|
|
228
230
|
}
|
|
231
|
+
|
|
232
|
+
export interface IconProps extends React.ComponentPropsWithRef<'i'> {
|
|
233
|
+
name: string;
|
|
234
|
+
size?: number;
|
|
235
|
+
className?: string;
|
|
236
|
+
}
|
package/utils/index.ts
CHANGED
|
@@ -32,7 +32,7 @@ export function setCookie(name: string, val: string) {
|
|
|
32
32
|
export function removeCookie(name: string) {
|
|
33
33
|
const date = 'Thu, 01 Jan 1970 00:00:00 UTC';
|
|
34
34
|
|
|
35
|
-
document.cookie = name
|
|
35
|
+
document.cookie = `${name}=; expires=${date}; path=/;`;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -137,3 +137,14 @@ export const urlLocaleMatcherRegex = new RegExp(
|
|
|
137
137
|
.map((l) => l.value)
|
|
138
138
|
.join('|')})`
|
|
139
139
|
);
|
|
140
|
+
|
|
141
|
+
export const getPosError = () => {
|
|
142
|
+
const error = JSON.parse(getCookie('pz-pos-error') ?? '{}');
|
|
143
|
+
|
|
144
|
+
// delete 'pz-pos-error' cookie when refreshing or closing page
|
|
145
|
+
window.addEventListener('beforeunload', () => {
|
|
146
|
+
removeCookie('pz-pos-error');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
return error;
|
|
150
|
+
};
|