@akinon/next 1.52.0 → 1.53.0-rc.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +489 -0
  2. package/api/client.ts +50 -17
  3. package/assets/styles/index.css +49 -0
  4. package/assets/styles/index.css.map +1 -0
  5. package/assets/styles/index.scss +50 -26
  6. package/bin/pz-generate-translations.js +41 -0
  7. package/bin/pz-prebuild.js +1 -0
  8. package/bin/pz-predev.js +1 -0
  9. package/components/file-input.tsx +8 -0
  10. package/components/index.ts +1 -0
  11. package/components/input.tsx +21 -7
  12. package/components/link.tsx +17 -13
  13. package/components/price.tsx +11 -4
  14. package/components/pz-root.tsx +15 -3
  15. package/components/selected-payment-option-view.tsx +26 -38
  16. package/data/client/account.ts +10 -9
  17. package/data/client/address.ts +32 -8
  18. package/data/client/api.ts +1 -1
  19. package/data/client/b2b.ts +35 -2
  20. package/data/client/basket.ts +6 -5
  21. package/data/client/checkout.ts +47 -4
  22. package/data/client/user.ts +3 -2
  23. package/data/client/wishlist.ts +1 -1
  24. package/data/server/category.ts +43 -19
  25. package/data/server/flatpage.ts +29 -7
  26. package/data/server/form.ts +29 -11
  27. package/data/server/landingpage.ts +26 -7
  28. package/data/server/list.ts +16 -6
  29. package/data/server/menu.ts +15 -2
  30. package/data/server/product.ts +46 -21
  31. package/data/server/seo.ts +17 -24
  32. package/data/server/special-page.ts +15 -5
  33. package/data/server/widget.ts +14 -7
  34. package/data/urls.ts +8 -1
  35. package/hocs/server/with-segment-defaults.tsx +4 -1
  36. package/hooks/index.ts +2 -1
  37. package/hooks/use-message-listener.ts +24 -0
  38. package/hooks/use-pagination.ts +2 -2
  39. package/hooks/use-payment-options.ts +2 -1
  40. package/lib/cache-handler.mjs +33 -0
  41. package/lib/cache.ts +8 -6
  42. package/middlewares/default.ts +87 -8
  43. package/middlewares/pretty-url.ts +11 -1
  44. package/middlewares/url-redirection.ts +4 -0
  45. package/package.json +4 -3
  46. package/plugins.d.ts +1 -0
  47. package/redux/middlewares/checkout.ts +70 -11
  48. package/redux/reducers/checkout.ts +24 -5
  49. package/redux/reducers/config.ts +2 -0
  50. package/routes/pretty-url.tsx +192 -0
  51. package/types/commerce/account.ts +1 -0
  52. package/types/commerce/address.ts +1 -1
  53. package/types/commerce/b2b.ts +12 -2
  54. package/types/commerce/checkout.ts +30 -0
  55. package/types/commerce/misc.ts +2 -0
  56. package/types/commerce/order.ts +5 -0
  57. package/types/index.ts +18 -2
  58. package/utils/app-fetch.ts +17 -8
  59. package/utils/generate-commerce-search-params.ts +3 -1
  60. package/utils/index.ts +27 -6
  61. package/utils/redirection-iframe.ts +85 -0
  62. package/utils/server-translation.ts +11 -1
  63. package/utils/server-variables.ts +2 -1
  64. package/with-pz-config.js +13 -2
@@ -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"}
@@ -1,29 +1,53 @@
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;
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
- iframe {
12
- width: 100%;
13
- height: 100%;
14
- border: none;
15
- background-color: white;
16
- }
11
+ iframe {
12
+ width: 100%;
13
+ height: 100%;
14
+ border: none;
15
+ background-color: white;
16
+ }
17
17
 
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
- }
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
+ }
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const localesPath = path.resolve(`public/locales/`);
6
+
7
+ async function generateTranslationIndex(locale_) {
8
+ let translations = {};
9
+
10
+ try {
11
+ const localeDirPath = path.resolve(`public/locales/${locale_}`);
12
+ const fileNames = fs.readdirSync(localeDirPath);
13
+
14
+ for await (const fileName of fileNames) {
15
+ if (fileName === 'index.json') {
16
+ continue;
17
+ }
18
+
19
+ const data = fs.readFileSync(
20
+ path.join(localeDirPath, `/${fileName}`),
21
+ 'utf-8'
22
+ );
23
+
24
+ translations[fileName.substring(0, fileName.lastIndexOf('.'))] =
25
+ JSON.parse(data);
26
+ }
27
+
28
+ fs.writeFileSync(
29
+ path.resolve(`public/locales/${locale_}/index.json`),
30
+ JSON.stringify(translations)
31
+ );
32
+ } catch (error) {
33
+ console.error(error);
34
+ }
35
+ }
36
+
37
+ const localePaths = fs.readdirSync(localesPath);
38
+
39
+ localePaths.forEach((localePath) => {
40
+ generateTranslationIndex(localePath);
41
+ });
@@ -4,3 +4,4 @@ const runScript = require('./run-script');
4
4
 
5
5
  runScript('pz-install-theme.js');
6
6
  runScript('pz-pre-check-dist.js');
7
+ runScript('pz-generate-translations.js');
package/bin/pz-predev.js CHANGED
@@ -5,3 +5,4 @@ const runScript = require('./run-script');
5
5
  runScript('pz-install-extensions.js');
6
6
  runScript('pz-check-env.js');
7
7
  runScript('pz-install-theme.js');
8
+ runScript('pz-generate-translations.js');
@@ -0,0 +1,8 @@
1
+ import { forwardRef } from 'react';
2
+ import { FileInputProps } from '../types/index';
3
+
4
+ export const FileInput = forwardRef<HTMLInputElement, FileInputProps>(
5
+ function fileInput(props, ref) {
6
+ return <input type="file" {...props} ref={ref} />;
7
+ }
8
+ );
@@ -19,3 +19,4 @@ export * from './trans';
19
19
  export * from './link';
20
20
  export * from './pagination';
21
21
  export * from './live-commerce';
22
+ export * from './file-input';
@@ -1,17 +1,30 @@
1
1
  import clsx from 'clsx';
2
- import { forwardRef, FocusEvent, useState } from 'react';
2
+ import { forwardRef, FocusEvent, useState, Ref } from 'react';
3
3
  import { Controller } from 'react-hook-form';
4
- import NumberFormat, { NumberFormatProps } from 'react-number-format';
4
+
5
+ // @ts-ignore
6
+ import { PatternFormat, PatternFormatProps } from 'react-number-format';
5
7
  import { InputProps } from '../types';
6
8
  import { twMerge } from 'tailwind-merge';
7
9
 
10
+ const PatternFormatWithRef = forwardRef(
11
+ (props: PatternFormatProps, ref: Ref<HTMLInputElement>) => {
12
+ return <PatternFormat {...props} getInputRef={ref} />;
13
+ }
14
+ );
15
+ PatternFormatWithRef.displayName = 'PatternFormatWithRef';
16
+
8
17
  export const Input = forwardRef<
9
18
  HTMLInputElement,
10
19
  InputProps &
11
20
  Pick<
12
- NumberFormatProps,
13
- 'format' | 'mask' | 'allowEmptyFormatting' | 'onValueChange'
14
- >
21
+ PatternFormatProps,
22
+ 'mask' | 'allowEmptyFormatting' | 'onValueChange'
23
+ > & {
24
+ format?: string;
25
+ defaultValue?: string;
26
+ type?: string;
27
+ }
15
28
  >((props, ref) => {
16
29
  const [focused, setFocused] = useState(false);
17
30
  const [hasValue, setHasValue] = useState(false);
@@ -37,6 +50,7 @@ export const Input = forwardRef<
37
50
  ),
38
51
  props.className
39
52
  );
53
+
40
54
  const inputProps: any = {
41
55
  id,
42
56
  ref,
@@ -79,14 +93,14 @@ export const Input = forwardRef<
79
93
  <Controller
80
94
  name={props.name ?? ''}
81
95
  control={props.control}
82
- defaultValue={false}
83
96
  render={({ field }) => (
84
- <NumberFormat
97
+ <PatternFormatWithRef
85
98
  format={format}
86
99
  mask={mask ?? ''}
87
100
  {...rest}
88
101
  {...field}
89
102
  {...inputProps}
103
+ type={props.type as 'text' | 'password' | 'tel'}
90
104
  />
91
105
  )}
92
106
  />
@@ -10,28 +10,32 @@ type LinkProps = Omit<
10
10
  React.AnchorHTMLAttributes<HTMLAnchorElement>,
11
11
  keyof NextLinkProps
12
12
  > &
13
- NextLinkProps;
13
+ NextLinkProps & {
14
+ href: string;
15
+ };
14
16
 
15
17
  export const Link = ({ children, href, ...rest }: LinkProps) => {
16
18
  const { locale, defaultLocaleValue, localeUrlStrategy } = useLocalization();
17
19
  const formattedHref = useMemo(() => {
18
- if (typeof href !== 'string' || href.startsWith('http')) {
19
- return href;
20
+ if (!href) {
21
+ return '#';
20
22
  }
21
23
 
22
- const pathnameWithoutLocale = href.replace(urlLocaleMatcherRegex, '');
23
- const hrefWithLocale = `/${locale}${pathnameWithoutLocale}`;
24
+ if (typeof href === 'string' && !href.startsWith('http')) {
25
+ const pathnameWithoutLocale = href.replace(urlLocaleMatcherRegex, '');
26
+ const hrefWithLocale = `/${locale}${pathnameWithoutLocale}`;
24
27
 
25
- if (localeUrlStrategy === LocaleUrlStrategy.ShowAllLocales) {
26
- return hrefWithLocale;
27
- } else if (
28
- localeUrlStrategy === LocaleUrlStrategy.HideDefaultLocale &&
29
- locale !== defaultLocaleValue
30
- ) {
31
- return hrefWithLocale;
28
+ if (localeUrlStrategy === LocaleUrlStrategy.ShowAllLocales) {
29
+ return hrefWithLocale;
30
+ } else if (
31
+ localeUrlStrategy === LocaleUrlStrategy.HideDefaultLocale &&
32
+ locale !== defaultLocaleValue
33
+ ) {
34
+ return hrefWithLocale;
35
+ }
32
36
  }
33
37
 
34
- return href || '#';
38
+ return href;
35
39
  }, [href, defaultLocaleValue, locale, localeUrlStrategy]);
36
40
 
37
41
  return (
@@ -1,11 +1,14 @@
1
1
  import { useMemo } from 'react';
2
- import NumberFormat, { NumberFormatProps } from 'react-number-format';
2
+
3
+ // @ts-ignore
4
+ import { NumericFormat, NumericFormatProps } from 'react-number-format';
3
5
  import { getCurrency } from '@akinon/next/utils';
4
6
 
5
7
  import { useLocalization } from '@akinon/next/hooks';
6
8
  import { PriceProps } from '../types';
9
+ import Settings from 'settings';
7
10
 
8
- export const Price = (props: NumberFormatProps & PriceProps) => {
11
+ export const Price = (props: NumericFormatProps & PriceProps) => {
9
12
  const {
10
13
  value,
11
14
  currencyCode,
@@ -27,6 +30,10 @@ export const Price = (props: NumberFormatProps & PriceProps) => {
27
30
  // TODO: This is very bad practice. It broke decimalScale.
28
31
  const _value = value?.toString().replace('.', ',');
29
32
 
33
+ const currentCurrencyDecimalScale = Settings.localization.currencies.find(
34
+ (currency) => currency.code === currencyCode_
35
+ ).decimalScale;
36
+
30
37
  const currency = useMemo(
31
38
  () =>
32
39
  getCurrency({
@@ -39,14 +46,14 @@ export const Price = (props: NumberFormatProps & PriceProps) => {
39
46
  );
40
47
 
41
48
  return (
42
- <NumberFormat
49
+ <NumericFormat
43
50
  value={useNegative ? `-${useNegativeSpace}${_value}` : _value}
44
51
  {...{
45
52
  [useCurrencyAfterPrice ? 'suffix' : 'prefix']: currency
46
53
  }}
47
54
  displayType={displayType}
48
55
  thousandSeparator={thousandSeparator}
49
- decimalScale={decimalScale}
56
+ decimalScale={currentCurrencyDecimalScale ?? decimalScale}
50
57
  decimalSeparator={decimalSeparator}
51
58
  fixedDecimalScale={fixedDecimalScale}
52
59
  {...rest}
@@ -3,17 +3,29 @@ import ClientRoot from './client-root';
3
3
  import { cookies } from 'next/headers';
4
4
  import PzProviders from './pz-providers';
5
5
  import { WebVitals } from './web-vitals';
6
+ import settings from 'settings';
6
7
 
7
- export default function PzRoot({
8
+ export default async function PzRoot({
8
9
  translations,
9
- children
10
+ children,
11
+ locale
10
12
  }: {
11
- translations: any;
13
+ translations?: any;
12
14
  children: React.ReactNode;
15
+ locale?: string;
13
16
  }) {
14
17
  const nextCookies = cookies();
15
18
  const sessionid = nextCookies.get('osessionid')?.value;
16
19
 
20
+ if (!translations) {
21
+ const { getTranslations } =
22
+ settings.useOptimizedTranslations && locale
23
+ ? require('translations')
24
+ : require('../utils/server-translation');
25
+
26
+ translations = await getTranslations(locale);
27
+ }
28
+
17
29
  return (
18
30
  <PzProviders translations={translations}>
19
31
  <WebVitals />
@@ -6,6 +6,21 @@ import dynamic from 'next/dynamic';
6
6
  import { PaymentOptionViews } from 'views/checkout/steps/payment';
7
7
  import { useMemo } from 'react';
8
8
 
9
+ const fallbackView = () => <div />;
10
+
11
+ const paymentTypeToView = {
12
+ bkm_express: 'bkm',
13
+ credit_card: 'credit-card',
14
+ credit_payment: 'credit-payment',
15
+ funds_transfer: 'funds-transfer',
16
+ gpay: 'gpay',
17
+ loyalty_money: 'loyalty',
18
+ masterpass: 'credit-card',
19
+ pay_on_delivery: 'pay-on-delivery',
20
+ redirection: 'redirection'
21
+ // Add other mappings as needed
22
+ };
23
+
9
24
  export default function SelectedPaymentOptionView() {
10
25
  const { payment_option } = useAppSelector(
11
26
  (state: RootState) => state.checkout.preOrder
@@ -14,7 +29,7 @@ export default function SelectedPaymentOptionView() {
14
29
  const Component = useMemo(
15
30
  () =>
16
31
  dynamic(
17
- () => {
32
+ async () => {
18
33
  const customOption = PaymentOptionViews.find(
19
34
  (opt) => opt.slug === payment_option.slug
20
35
  );
@@ -29,46 +44,19 @@ export default function SelectedPaymentOptionView() {
29
44
  });
30
45
  }
31
46
 
32
- let promise: any;
33
-
34
- try {
35
- if (payment_option.payment_type === 'credit_card') {
36
- promise = import(
37
- `views/checkout/steps/payment/options/credit-card`
38
- );
39
- } else if (payment_option.payment_type === 'funds_transfer') {
40
- promise = import(
41
- `views/checkout/steps/payment/options/funds-transfer`
42
- );
43
- } else if (payment_option.payment_type === 'redirection') {
44
- promise = import(
45
- `views/checkout/steps/payment/options/redirection`
46
- );
47
- } else if (payment_option.payment_type === 'pay_on_delivery') {
48
- promise = import(
49
- `views/checkout/steps/payment/options/pay-on-delivery`
50
- );
51
- } else if (payment_option.payment_type === 'loyalty_money') {
52
- promise = import(`views/checkout/steps/payment/options/loyalty`);
53
- } else if (payment_option.payment_type === 'masterpass') {
54
- promise = import(
55
- `views/checkout/steps/payment/options/credit-card`
47
+ const view = paymentTypeToView[payment_option.payment_type];
48
+ if (view) {
49
+ try {
50
+ const mod = await import(
51
+ `views/checkout/steps/payment/options/${view}`
56
52
  );
53
+ return mod.default || fallbackView;
54
+ } catch (error) {
55
+ return fallbackView;
57
56
  }
58
- // else if (payment_option.payment_type === 'credit_payment') {
59
- // promise = import(`views/checkout/steps/payment/options/credit-payment`);
60
- // }
61
- // else if (payment_option.payment_type === 'gpay') {
62
- // promise = import(`views/checkout/steps/payment/options/gpay`);
63
- // }
64
- // else if (payment_option.payment_type === 'bkm_express') {
65
- // promise = import(`views/checkout/steps/payment/options/bkm`);
66
- // }
67
- } catch (error) {}
57
+ }
68
58
 
69
- return promise
70
- ? promise.then((mod) => mod.default).catch(() => () => null)
71
- : new Promise<any>((resolve) => resolve(() => null));
59
+ return fallbackView;
72
60
  },
73
61
  { ssr: false }
74
62
  ),
@@ -123,15 +123,16 @@ const accountApi = api.injectEndpoints({
123
123
  query: ({ page, status, limit }) =>
124
124
  buildClientRequestUrl(account.getQuotations(page, status, limit))
125
125
  }),
126
- sendContact: builder.mutation<void, ContactFormType>({
127
- query: (body) => ({
128
- url: buildClientRequestUrl(account.sendContact, {
129
- contentType: 'application/json',
130
- responseType: 'text'
131
- }),
132
- method: 'POST',
133
- body
134
- })
126
+ sendContact: builder.mutation<void, FormData>({
127
+ query: (body) => {
128
+ return {
129
+ url: buildClientRequestUrl(account.sendContact, {
130
+ useFormData: true
131
+ }),
132
+ method: 'POST',
133
+ body
134
+ };
135
+ }
135
136
  }),
136
137
  cancelOrder: builder.mutation<void, AccountOrderCancellation>({
137
138
  query: ({ id, ...body }) => ({
@@ -39,7 +39,10 @@ const addressApi = api.injectEndpoints({
39
39
  query: (city) =>
40
40
  buildClientRequestUrl(address.getRetailStoreTownships(city))
41
41
  }),
42
- addAddress: builder.mutation<Address, Partial<Address>>({
42
+ addAddress: builder.mutation<
43
+ Address,
44
+ Partial<Address> & { invalidateTag?: 'Addresses' | 'Checkout' }
45
+ >({
43
46
  query: (body) => ({
44
47
  url: buildClientRequestUrl(address.base, {
45
48
  contentType: 'application/json'
@@ -50,9 +53,16 @@ const addressApi = api.injectEndpoints({
50
53
  type: body.is_corporate === 'true' ? 'corporate' : 'personal'
51
54
  }
52
55
  }),
53
- invalidatesTags: (_, error) => (error ? [] : ['Addresses', 'Checkout'])
56
+ invalidatesTags: (_, error, arg) => {
57
+ if (error) return [];
58
+ if (arg.invalidateTag) return [arg.invalidateTag];
59
+ return ['Addresses', 'Checkout'];
60
+ }
54
61
  }),
55
- editAddress: builder.mutation<Address, Partial<Address>>({
62
+ editAddress: builder.mutation<
63
+ Address,
64
+ Partial<Address> & { invalidateTag?: 'Addresses' | 'Checkout' }
65
+ >({
56
66
  query: ({ pk, ...body }) => ({
57
67
  url: buildClientRequestUrl(address.editAddress(pk), {
58
68
  contentType: 'application/json'
@@ -64,14 +74,28 @@ const addressApi = api.injectEndpoints({
64
74
  type: body.is_corporate === 'true' ? 'corporate' : 'personal'
65
75
  }
66
76
  }),
67
- invalidatesTags: (_, error) => (error ? [] : ['Addresses', 'Checkout']) // TODO: Invalidate one of these tags when necessary (e.g. Address page invalidates Addresses tag, Checkout page invalidates Checkout tag)
77
+ invalidatesTags: (_, error, arg) => {
78
+ if (error) return [];
79
+ if (arg.invalidateTag) return [arg.invalidateTag];
80
+ return ['Addresses', 'Checkout'];
81
+ }
68
82
  }),
69
- removeAddress: builder.mutation<void, number>({
70
- query: (id) => ({
71
- url: buildClientRequestUrl(address.removeAddress(id)),
83
+ removeAddress: builder.mutation<
84
+ void,
85
+ number | { id: number; invalidateTag: 'Addresses' | 'Checkout' }
86
+ >({
87
+ query: (arg) => ({
88
+ url: buildClientRequestUrl(
89
+ address.removeAddress(typeof arg === 'number' ? arg : arg.id)
90
+ ),
72
91
  method: 'DELETE'
73
92
  }),
74
- invalidatesTags: (_, error) => (error ? [] : ['Addresses', 'Checkout']) // TODO: Invalidate one of these tags when necessary (e.g. Address page invalidates Addresses tag, Checkout page invalidates Checkout tag)
93
+ invalidatesTags: (_, error, arg) => {
94
+ if (error) return [];
95
+ if (typeof arg === 'object' && arg.invalidateTag)
96
+ return [arg.invalidateTag];
97
+ return ['Addresses', 'Checkout'];
98
+ }
75
99
  }),
76
100
  setDefaultAddress: builder.mutation<Address, Partial<Address>>({
77
101
  query: ({ pk, primary }) => ({
@@ -67,7 +67,7 @@ export const api = createApi({
67
67
  baseQuery: customBaseQuery,
68
68
  tagTypes: [
69
69
  'Basket',
70
- 'AllBaskets',
70
+ 'MultiBasket',
71
71
  'BasketB2b',
72
72
  'DraftsB2b',
73
73
  'Product',
@@ -12,7 +12,9 @@ import {
12
12
  SaveBasketParams,
13
13
  UpdateProductParams,
14
14
  DeleteProductParams,
15
- CreateQuotationParams
15
+ CreateQuotationParams,
16
+ BasketStatusResponse,
17
+ ExportBasketResponse
16
18
  } from '../../types';
17
19
 
18
20
  const b2bApi = api.injectEndpoints({
@@ -89,6 +91,34 @@ const b2bApi = api.injectEndpoints({
89
91
  }),
90
92
  invalidatesTags: ['BasketB2b', 'DraftsB2b']
91
93
  }),
94
+ exportBasket: build.mutation<ExportBasketResponse, string>({
95
+ query: (queryString) => {
96
+ return {
97
+ url: buildClientRequestUrl(b2b.basketExport(queryString)),
98
+ method: 'GET'
99
+ };
100
+ }
101
+ }),
102
+ getBasketStatus: build.mutation<BasketStatusResponse, string>({
103
+ query: (cacheKey) => {
104
+ return {
105
+ url: buildClientRequestUrl(b2b.statusBasket(cacheKey)),
106
+ method: 'GET'
107
+ };
108
+ }
109
+ }),
110
+ uploadFile: build.mutation<void, FormData>({
111
+ query: (body) => {
112
+ return {
113
+ url: buildClientRequestUrl(b2b.basketImport, {
114
+ useFormData: true
115
+ }),
116
+ method: 'POST',
117
+ body
118
+ };
119
+ },
120
+ invalidatesTags: ['BasketB2b']
121
+ })
92
122
  }),
93
123
  overrideExisting: true
94
124
  });
@@ -102,5 +132,8 @@ export const {
102
132
  useLoadBasketMutation,
103
133
  useUpdateProductMutation,
104
134
  useDeleteProductMutation,
105
- useCreateQuotationMutation
135
+ useCreateQuotationMutation,
136
+ useGetBasketStatusMutation,
137
+ useExportBasketMutation,
138
+ useUploadFileMutation
106
139
  } = b2bApi;
@@ -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: ['AllBaskets']
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: ['AllBaskets']
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: ['AllBaskets', 'Basket']
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: ['AllBaskets', 'Basket']
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) => ({