@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.
Files changed (98) hide show
  1. package/.prettierrc +13 -0
  2. package/api/auth.ts +217 -0
  3. package/api/cache.ts +44 -0
  4. package/api/client.ts +157 -0
  5. package/api/logout.ts +42 -0
  6. package/assets/styles/index.scss +24 -0
  7. package/bin/pz-install-plugins.js +33 -0
  8. package/components/client-root.tsx +69 -0
  9. package/components/image.tsx +133 -0
  10. package/components/mobile-app-toggler.tsx +15 -0
  11. package/components/oauth-login.tsx +24 -0
  12. package/components/plugin-module.tsx +78 -0
  13. package/components/pz-providers.tsx +24 -0
  14. package/components/pz-root.tsx +21 -0
  15. package/components/redirect-three-d/content/index.tsx +64 -0
  16. package/components/redirect-three-d/index.tsx +17 -0
  17. package/components/selected-payment-option-view.tsx +66 -0
  18. package/components/trans.tsx +39 -0
  19. package/data/client/account.ts +188 -0
  20. package/data/client/address.ts +107 -0
  21. package/data/client/api.ts +42 -0
  22. package/data/client/basket.ts +85 -0
  23. package/data/client/checkout.ts +477 -0
  24. package/data/client/misc.ts +101 -0
  25. package/data/client/product.ts +90 -0
  26. package/data/client/user.ts +83 -0
  27. package/data/client/wishlist.ts +79 -0
  28. package/data/server/category.ts +121 -0
  29. package/data/server/flatpage.ts +21 -0
  30. package/data/server/index.ts +8 -0
  31. package/data/server/list.ts +56 -0
  32. package/data/server/menu.ts +35 -0
  33. package/data/server/product.ts +86 -0
  34. package/data/server/seo.ts +48 -0
  35. package/data/server/special-page.ts +42 -0
  36. package/data/server/widget.ts +27 -0
  37. package/data/urls.ts +184 -0
  38. package/hocs/client/index.ts +1 -0
  39. package/hocs/client/with-segment-defaults.tsx +26 -0
  40. package/hocs/server/index.ts +1 -0
  41. package/hocs/server/with-segment-defaults.tsx +83 -0
  42. package/hooks/index.ts +8 -0
  43. package/hooks/use-captcha.tsx +76 -0
  44. package/hooks/use-common-product-attributes.ts +36 -0
  45. package/hooks/use-debounce.ts +20 -0
  46. package/hooks/use-localization.ts +63 -0
  47. package/hooks/use-media-query.ts +36 -0
  48. package/hooks/use-on-click-outside.tsx +28 -0
  49. package/hooks/use-router.ts +45 -0
  50. package/hooks/use-translation.ts +14 -0
  51. package/lib/cache.ts +185 -0
  52. package/localization/index.ts +5 -0
  53. package/localization/provider.tsx +58 -0
  54. package/middlewares/currency.ts +55 -0
  55. package/middlewares/default.ts +224 -0
  56. package/middlewares/index.ts +29 -0
  57. package/middlewares/locale.ts +61 -0
  58. package/middlewares/oauth-login.ts +78 -0
  59. package/middlewares/pretty-url.ts +94 -0
  60. package/middlewares/redirection-payment.ts +117 -0
  61. package/middlewares/three-d-redirection.ts +122 -0
  62. package/middlewares/url-redirection.ts +61 -0
  63. package/package.json +20 -0
  64. package/plugins.js +7 -0
  65. package/redux/hooks.ts +7 -0
  66. package/redux/middlewares/checkout.ts +231 -0
  67. package/redux/middlewares/index.ts +50 -0
  68. package/redux/reducers/checkout.ts +164 -0
  69. package/redux/reducers/config.ts +28 -0
  70. package/redux/reducers/header.ts +59 -0
  71. package/redux/reducers/index.ts +15 -0
  72. package/redux/reducers/root.ts +61 -0
  73. package/tailwind/rtl.js +137 -0
  74. package/types/commerce/account.ts +68 -0
  75. package/types/commerce/address.ts +94 -0
  76. package/types/commerce/basket.ts +43 -0
  77. package/types/commerce/category.ts +114 -0
  78. package/types/commerce/checkout.ts +132 -0
  79. package/types/commerce/flatpage.ts +7 -0
  80. package/types/commerce/index.ts +10 -0
  81. package/types/commerce/misc.ts +127 -0
  82. package/types/commerce/order.ts +108 -0
  83. package/types/commerce/product.ts +110 -0
  84. package/types/commerce/widget.ts +28 -0
  85. package/types/gtm.ts +16 -0
  86. package/types/index.ts +207 -0
  87. package/types/next-auth.d.ts +24 -0
  88. package/utils/app-fetch.ts +62 -0
  89. package/utils/generate-commerce-search-params.ts +22 -0
  90. package/utils/get-currency.ts +29 -0
  91. package/utils/image-loader.ts +31 -0
  92. package/utils/index.ts +132 -0
  93. package/utils/localization.ts +29 -0
  94. package/utils/log.ts +138 -0
  95. package/utils/menu-generator.ts +27 -0
  96. package/utils/mobile-3d-iframe.ts +58 -0
  97. package/utils/server-translation.ts +57 -0
  98. package/utils/server-variables.ts +9 -0
@@ -0,0 +1,101 @@
1
+ import {
2
+ EmailSubscriptionType,
3
+ MenuItemType,
4
+ WidgetResultType
5
+ } from '../../types';
6
+ import { buildClientRequestUrl } from '../../utils';
7
+ import { misc, widgets } from '../urls';
8
+ import { api } from './api';
9
+
10
+ type CategoryExtraType = {
11
+ category_id: number;
12
+ parent_categories: Array<string>;
13
+ };
14
+
15
+ type ProductExtraType = {
16
+ image: string;
17
+ price: number;
18
+ product_type: string;
19
+ retail_price: number;
20
+ };
21
+
22
+ export interface AutocompleteResponse {
23
+ groups: Array<{
24
+ entries: Array<{
25
+ extra: CategoryExtraType & ProductExtraType;
26
+ label: string;
27
+ suggestion_type: string;
28
+ url: string;
29
+ }>;
30
+ suggestion_type: 'Category' | 'Product';
31
+ }>;
32
+ }
33
+
34
+ export interface GetLanguageResponse {
35
+ active_language: string;
36
+ default_language: string;
37
+ available_languages: {
38
+ [key: string]: string;
39
+ };
40
+ }
41
+
42
+ export interface SetLanguageResponse {
43
+ success: boolean;
44
+ }
45
+
46
+ export const miscApi = api.injectEndpoints({
47
+ endpoints: (builder) => ({
48
+ autocomplete: builder.query<AutocompleteResponse, string>({
49
+ query: (query: string) => ({
50
+ url: buildClientRequestUrl(`${misc.autocomplete}?search_text=${query}`)
51
+ })
52
+ }),
53
+ emailSubscription: builder.mutation<void, EmailSubscriptionType>({
54
+ query: (body) => ({
55
+ url: buildClientRequestUrl(misc.emailSubscription, {
56
+ contentType: 'application/json'
57
+ }),
58
+ method: 'POST',
59
+ body
60
+ })
61
+ }),
62
+ setLanguage: builder.mutation<any, { language: string }>({
63
+ query: (body) => ({
64
+ url: buildClientRequestUrl('/i18n/setlang', {
65
+ useFormData: true,
66
+ responseType: 'text'
67
+ }),
68
+ method: 'POST',
69
+ body
70
+ }),
71
+ transformResponse: (response, meta) => {
72
+ return {
73
+ success: meta.response.status === 200,
74
+ osessionid: meta.response.headers.get('osessionid')
75
+ };
76
+ }
77
+ }),
78
+ getWidget: builder.query<WidgetResultType<any>, string>({
79
+ query: (slug: string) => ({
80
+ url: buildClientRequestUrl(widgets.getWidgets(slug))
81
+ })
82
+ }),
83
+ getMenu: builder.query<MenuItemType[], number>({
84
+ query: (depth) => ({
85
+ url: buildClientRequestUrl(misc.menus(depth))
86
+ }),
87
+ transformResponse: (response: { menu: MenuItemType[] }) => {
88
+ return response.menu;
89
+ }
90
+ })
91
+ }),
92
+ overrideExisting: true
93
+ });
94
+
95
+ export const {
96
+ useAutocompleteQuery,
97
+ useEmailSubscriptionMutation,
98
+ useSetLanguageMutation,
99
+ useGetWidgetQuery,
100
+ useGetMenuQuery
101
+ } = miscApi;
@@ -0,0 +1,90 @@
1
+ import {
2
+ Basket,
3
+ FindInStoreFormType,
4
+ ProductResult,
5
+ StockResultType
6
+ } from '../../types';
7
+ import { buildClientRequestUrl } from '../../utils';
8
+ import { api } from './api';
9
+ import { product } from '../urls';
10
+
11
+ export type AddProductResponse = {
12
+ basket: Basket;
13
+ osessionid: string;
14
+ };
15
+
16
+ export type AddProductRequest = {
17
+ product: number;
18
+ quantity: number;
19
+ attributes: any;
20
+ };
21
+
22
+ type GetProduct = {
23
+ pk: number;
24
+ searchParams?: URLSearchParams;
25
+ groupProduct?: boolean;
26
+ [key:string]: any;
27
+ };
28
+
29
+ export const productApi = api.injectEndpoints({
30
+ endpoints: (build) => ({
31
+ getProductByPk: build.query<ProductResult, number>({
32
+ query: (pk) => ({
33
+ url: buildClientRequestUrl(product.getProductByPk(pk))
34
+ })
35
+ }),
36
+ getProductByParams: build.query<ProductResult, GetProduct>({
37
+ query: ({pk, searchParams, groupProduct, ...params}) => {
38
+ let url = groupProduct
39
+ ? product.getGroupProductByPk(pk)
40
+ : product.getProductByPk(pk);
41
+
42
+ if (params) {
43
+ url = `${url}?${new URLSearchParams(params).toString()}`;
44
+ }
45
+
46
+ return {
47
+ url: buildClientRequestUrl(url)
48
+ };
49
+ }
50
+ }),
51
+ getRetailStoreStock: build.mutation<StockResultType, FindInStoreFormType>({
52
+ query: (body) => {
53
+ const { productPk, store, variant } = body;
54
+ const hasVariant = variant ? `&integration_beden=${variant}` : '';
55
+ return {
56
+ url: buildClientRequestUrl(
57
+ product.getRetailStoreStock(productPk, store, hasVariant),
58
+ {
59
+ contentType: 'application/json'
60
+ }
61
+ ),
62
+ method: 'GET'
63
+ };
64
+ }
65
+ }),
66
+ addProduct: build.mutation<AddProductResponse, AddProductRequest>({
67
+ query: (body) => ({
68
+ url: buildClientRequestUrl(product.addProduct, {
69
+ contentType: 'application/json'
70
+ }),
71
+ method: 'POST',
72
+ body
73
+ })
74
+ }),
75
+ getInstallments: build.query<any, any>({
76
+ query: (productPk) => ({
77
+ url: buildClientRequestUrl(product.installments(productPk))
78
+ })
79
+ })
80
+ }),
81
+ overrideExisting: true
82
+ });
83
+
84
+ export const {
85
+ useAddProductMutation,
86
+ useGetProductByPkQuery,
87
+ useGetRetailStoreStockMutation,
88
+ useGetInstallmentsQuery,
89
+ useGetProductByParamsQuery
90
+ } = productApi;
@@ -0,0 +1,83 @@
1
+ import { api } from './api';
2
+ import { user } from '../urls';
3
+ import { ForgotPasswordFormType } from '../../types';
4
+ import { buildClientRequestUrl } from '../../utils';
5
+
6
+ interface GetCaptchaResponse {
7
+ siteKey: string;
8
+ csrfToken: string;
9
+ }
10
+
11
+ interface ValidateCaptchaRequest {
12
+ captchaResponse: string;
13
+ csrfToken: string;
14
+ }
15
+
16
+ interface ValidateCaptchaResponse {
17
+ success: boolean;
18
+ }
19
+
20
+ const userApi = api.injectEndpoints({
21
+ endpoints: (build) => ({
22
+ getCaptcha: build.query<GetCaptchaResponse, void>({
23
+ query: () => buildClientRequestUrl(user.captcha),
24
+ transformResponse: (response: { html: string }) => {
25
+ const siteKeyMatch = response.html.match(/sitekey=["|']\w+/gi);
26
+ const csrfTokenMatch = response.html.match(
27
+ /name=['|"]csrfmiddlewaretoken['|"] value=['|"]\w+/gi
28
+ );
29
+ const siteKey = siteKeyMatch?.[0].replace(/sitekey=["|']/, '') || '';
30
+ const csrfToken =
31
+ csrfTokenMatch?.[0].replace(
32
+ /name=['|"]csrfmiddlewaretoken['|"] value=['|"]/gi,
33
+ ''
34
+ ) || '';
35
+
36
+ return {
37
+ siteKey,
38
+ csrfToken
39
+ };
40
+ }
41
+ }),
42
+ validateCaptcha: build.mutation<
43
+ ValidateCaptchaResponse,
44
+ ValidateCaptchaRequest
45
+ >({
46
+ query: (body) => ({
47
+ url: buildClientRequestUrl(user.captcha, {
48
+ useFormData: true
49
+ }),
50
+ method: 'POST',
51
+ body: {
52
+ 'g-recaptcha-response': body.captchaResponse
53
+ }
54
+ }),
55
+ transformResponse: (response: { location: string }) => ({
56
+ success: response.location === '/'
57
+ })
58
+ }),
59
+ logout: build.mutation<string, void>({
60
+ query: () => ({
61
+ url: '/api/logout',
62
+ method: 'POST'
63
+ })
64
+ }),
65
+ forgotPassword: build.mutation<void, ForgotPasswordFormType>({
66
+ query: (body) => ({
67
+ url: buildClientRequestUrl(user.forgotPassword, {
68
+ contentType: 'application/json'
69
+ }),
70
+ method: 'POST',
71
+ body
72
+ })
73
+ })
74
+ }),
75
+ overrideExisting: false
76
+ });
77
+
78
+ export const {
79
+ useGetCaptchaQuery,
80
+ useValidateCaptchaMutation,
81
+ useLogoutMutation,
82
+ useForgotPasswordMutation
83
+ } = userApi;
@@ -0,0 +1,79 @@
1
+ import { FavoriteItem } from '../../types';
2
+ import { buildClientRequestUrl } from '../../utils';
3
+ import { api } from './api';
4
+ import { URLS, wishlist } from '../urls';
5
+
6
+ export type AddProductRequest = {
7
+ product: number;
8
+ quantity: number;
9
+ attributes: any;
10
+ };
11
+
12
+ interface GetFavoritesParams {
13
+ limit?: number;
14
+ page?: number;
15
+ }
16
+
17
+ interface GetFavoritesResponse {
18
+ count: number;
19
+ results: FavoriteItem[];
20
+ }
21
+
22
+ interface AddFavoriteResponse {
23
+ pk: number;
24
+ product: number;
25
+ }
26
+
27
+ interface RemoteFavoriteResponse {
28
+ success: boolean;
29
+ }
30
+
31
+ export const wishlistApi = api.injectEndpoints({
32
+ endpoints: (build) => ({
33
+ getFavorites: build.query<GetFavoritesResponse, GetFavoritesParams>({
34
+ query: ({ limit, page }) =>
35
+ buildClientRequestUrl(wishlist.getFavorites({ page, limit })),
36
+ providesTags: ['Favorite']
37
+ }),
38
+ addFavorite: build.mutation<AddFavoriteResponse, number>({
39
+ query: (productPk: number) => ({
40
+ url: buildClientRequestUrl(wishlist.addFavorite, {
41
+ useFormData: true
42
+ }),
43
+ method: 'POST',
44
+ body: {
45
+ product: productPk
46
+ }
47
+ }),
48
+ invalidatesTags: ['Favorite']
49
+ }),
50
+ removeFavorite: build.mutation<RemoteFavoriteResponse, number>({
51
+ query: (favPk: number) => ({
52
+ url: buildClientRequestUrl(wishlist.removeFavorite(favPk)),
53
+ method: 'DELETE'
54
+ }),
55
+ invalidatesTags: ['Favorite']
56
+ }),
57
+ // TODO: Add stock alert response type
58
+ addStockAlert: build.mutation<any, number>({
59
+ query: (productPk: number) => ({
60
+ url: buildClientRequestUrl(wishlist.addStockAlert, {
61
+ useFormData: true,
62
+ contentType: 'application/json'
63
+ }),
64
+ method: 'POST',
65
+ body: {
66
+ product: productPk
67
+ }
68
+ })
69
+ })
70
+ }),
71
+ overrideExisting: true
72
+ });
73
+
74
+ export const {
75
+ useGetFavoritesQuery,
76
+ useAddFavoriteMutation,
77
+ useRemoveFavoriteMutation,
78
+ useAddStockAlertMutation
79
+ } = wishlistApi;
@@ -0,0 +1,121 @@
1
+ import { GetCategoryResponse } from '../../types';
2
+ import { generateCommerceSearchParams } from '../../utils';
3
+ import appFetch, { FetchResponseType } from '../../utils/app-fetch';
4
+ import { category, product } from '../urls';
5
+ import { Cache, CacheKey } from '../../lib/cache';
6
+ import { parse } from 'lossless-json';
7
+ import logger from '../../utils/log';
8
+
9
+ function getCategoryDataHandler(pk: number, searchParams?: URLSearchParams) {
10
+ return async function () {
11
+ const params = generateCommerceSearchParams(searchParams);
12
+
13
+ const rawData = await appFetch<string>(
14
+ `${category.getCategoryByPk(pk)}${params ? params : ''}`,
15
+ {
16
+ headers: {
17
+ Accept: 'application/json',
18
+ 'Content-Type': 'application/json'
19
+ }
20
+ },
21
+ FetchResponseType.TEXT
22
+ );
23
+
24
+ let data: GetCategoryResponse;
25
+
26
+ try {
27
+ const numberValueParser = (value) => {
28
+ return String(value);
29
+ };
30
+
31
+ data = parse(
32
+ rawData,
33
+ undefined,
34
+ numberValueParser
35
+ ) as GetCategoryResponse;
36
+ } catch (error) {
37
+ logger.error('Error while parsing category data', {
38
+ handler: 'getCategoryDataHandler',
39
+ error,
40
+ rawData
41
+ });
42
+ }
43
+
44
+ const menuItemModel = data?.category?.menuitemmodel;
45
+
46
+ const breadcrumbData = await appFetch<any>(
47
+ product.breadcrumbUrl(menuItemModel),
48
+ {
49
+ headers: {
50
+ Accept: 'application/json',
51
+ 'Content-Type': 'application/json'
52
+ }
53
+ }
54
+ );
55
+
56
+ return { data, breadcrumbData: breadcrumbData?.menu };
57
+ };
58
+ }
59
+
60
+ export const getCategoryData = ({
61
+ pk,
62
+ searchParams
63
+ }: {
64
+ pk: number;
65
+ searchParams?: URLSearchParams;
66
+ }) => {
67
+ return Cache.wrap(
68
+ CacheKey.Category(pk, searchParams),
69
+ getCategoryDataHandler(pk, searchParams),
70
+ {
71
+ expire: 300
72
+ }
73
+ );
74
+ };
75
+
76
+ function getCategoryBySlugDataHandler(slug: string) {
77
+ return async function () {
78
+ let rawData = await appFetch<string>(
79
+ category.getCategoryBySlug(slug),
80
+ {
81
+ headers: {
82
+ Accept: 'application/json',
83
+ 'Content-Type': 'application/json'
84
+ }
85
+ },
86
+ FetchResponseType.TEXT
87
+ );
88
+
89
+ let data: GetCategoryResponse;
90
+
91
+ try {
92
+ const numberValueParser = (value) => {
93
+ return String(value);
94
+ };
95
+
96
+ data = parse(
97
+ rawData,
98
+ undefined,
99
+ numberValueParser
100
+ ) as GetCategoryResponse;
101
+ } catch (error) {
102
+ logger.error('Error while parsing category data', {
103
+ handler: 'getCategoryBySlugDataHandler',
104
+ error,
105
+ rawData
106
+ });
107
+ }
108
+
109
+ return data;
110
+ };
111
+ }
112
+
113
+ export const getCategoryBySlugData = async ({ slug }) => {
114
+ return Cache.wrap(
115
+ CacheKey.CategorySlug(slug),
116
+ getCategoryBySlugDataHandler(slug),
117
+ {
118
+ expire: 300
119
+ }
120
+ );
121
+ };
@@ -0,0 +1,21 @@
1
+ import { flatpage } from '../urls';
2
+ import { FlatPage } from '../../types';
3
+ import appFetch from '../../utils/app-fetch';
4
+ import { Cache, CacheKey } from '../../lib/cache';
5
+
6
+ const getFlatPageDataHandler = (pk: number) => {
7
+ return async function () {
8
+ const data = await appFetch<FlatPage>(flatpage.getFlatPageByPk(pk), {
9
+ headers: {
10
+ Accept: 'application/json',
11
+ 'Content-Type': 'application/json'
12
+ }
13
+ });
14
+
15
+ return data;
16
+ };
17
+ };
18
+
19
+ export const getFlatPageData = ({ pk }: { pk: number }) => {
20
+ return Cache.wrap(CacheKey.FlatPage(pk), getFlatPageDataHandler(pk));
21
+ };
@@ -0,0 +1,8 @@
1
+ export * from './list';
2
+ export * from './category';
3
+ export * from './product';
4
+ export * from './flatpage';
5
+ export * from './special-page';
6
+ export * from './widget';
7
+ export * from './seo';
8
+ export * from './menu';
@@ -0,0 +1,56 @@
1
+ import { Cache, CacheKey } from '../../lib/cache';
2
+ import { category } from '../urls';
3
+ import { GetCategoryResponse } from '../../types';
4
+ import { generateCommerceSearchParams } from '../../utils';
5
+ import appFetch, { FetchResponseType } from '../../utils/app-fetch';
6
+ import { parse } from 'lossless-json';
7
+ import logger from '../../utils/log';
8
+
9
+ const getListDataHandler = (searchParams: URLSearchParams) => {
10
+ return async function () {
11
+ const params = generateCommerceSearchParams(searchParams);
12
+
13
+ const rawData = await appFetch<string>(
14
+ `${category.list}${params}`,
15
+ {
16
+ headers: {
17
+ Accept: 'application/json',
18
+ 'Content-Type': 'application/json'
19
+ }
20
+ },
21
+ FetchResponseType.TEXT
22
+ );
23
+
24
+ let data: GetCategoryResponse;
25
+
26
+ try {
27
+ const numberValueParser = (value) => {
28
+ return String(value);
29
+ };
30
+
31
+ data = parse(
32
+ rawData,
33
+ undefined,
34
+ numberValueParser
35
+ ) as GetCategoryResponse;
36
+ } catch (error) {
37
+ logger.error('Error while parsing list data', { error, rawData });
38
+ }
39
+
40
+ return data;
41
+ };
42
+ };
43
+
44
+ export const getListData = async ({
45
+ searchParams
46
+ }: {
47
+ searchParams: URLSearchParams;
48
+ }) => {
49
+ return Cache.wrap(
50
+ CacheKey.List(searchParams),
51
+ getListDataHandler(searchParams),
52
+ {
53
+ expire: 300
54
+ }
55
+ );
56
+ };
@@ -0,0 +1,35 @@
1
+ import { Cache, CacheKey } from '../../lib/cache';
2
+ import { MenuItemType } from '../../types';
3
+ import appFetch from '../../utils/app-fetch';
4
+ import { misc } from '../urls';
5
+
6
+ interface MenuResponse {
7
+ menu: MenuItemType[];
8
+ }
9
+
10
+ interface MenuHandlerParams {
11
+ depth?: number;
12
+ parent?: string;
13
+ }
14
+
15
+ const DEFAULT_DEPTH = 3;
16
+
17
+ const getMenuHandler =
18
+ ({ depth, parent }: MenuHandlerParams = { depth: DEFAULT_DEPTH }) =>
19
+ async () => {
20
+ const response = await appFetch<MenuResponse>(misc.menus(depth, parent));
21
+
22
+ return response?.menu;
23
+ };
24
+
25
+ /**
26
+ * Returns menu data.
27
+ *
28
+ * Default depth is 3
29
+ */
30
+ export const getMenu = async (params?: MenuHandlerParams) => {
31
+ return Cache.wrap(
32
+ CacheKey.Menu(params?.depth ?? DEFAULT_DEPTH, params?.parent),
33
+ getMenuHandler(params)
34
+ );
35
+ };
@@ -0,0 +1,86 @@
1
+ import { Cache, CacheKey } from '../../lib/cache';
2
+ import { product } from '../urls';
3
+ import {
4
+ BreadcrumbResultType,
5
+ ProductCategoryResult,
6
+ ProductResult
7
+ } from '../../types';
8
+ import appFetch from '../../utils/app-fetch';
9
+
10
+ type GetProduct = {
11
+ pk: number;
12
+ searchParams?: URLSearchParams;
13
+ groupProduct?: boolean;
14
+ };
15
+
16
+ const getProductDataHandler = ({
17
+ pk,
18
+ searchParams,
19
+ groupProduct
20
+ }: GetProduct) => {
21
+ return async function () {
22
+ let url = groupProduct
23
+ ? product.getGroupProductByPk(pk)
24
+ : product.getProductByPk(pk);
25
+
26
+ if (searchParams) {
27
+ url +=
28
+ '?' +
29
+ Object.keys(searchParams)
30
+ .map((key) => `${key}=${searchParams[key]}`)
31
+ .join('&');
32
+ }
33
+
34
+ const data = await appFetch<ProductResult>(url, {
35
+ headers: {
36
+ Accept: 'application/json',
37
+ 'Content-Type': 'application/json'
38
+ }
39
+ });
40
+
41
+ const categoryUrl = product.categoryUrl(data.product.pk);
42
+
43
+ const productCategoryData = await appFetch<ProductCategoryResult>(
44
+ categoryUrl,
45
+ {
46
+ headers: {
47
+ Accept: 'application/json',
48
+ 'Content-Type': 'application/json'
49
+ }
50
+ }
51
+ );
52
+
53
+ const breadcrumbUrl = product.breadcrumbUrl(
54
+ productCategoryData.results[0].menuitemmodel
55
+ );
56
+
57
+ const breadcrumbData = await appFetch<any>(breadcrumbUrl, {
58
+ headers: {
59
+ Accept: 'application/json',
60
+ 'Content-Type': 'application/json'
61
+ }
62
+ });
63
+
64
+ return {
65
+ data,
66
+ breadcrumbData: breadcrumbData?.menu
67
+ };
68
+ };
69
+ };
70
+
71
+ export const getProductData = async ({
72
+ pk,
73
+ searchParams,
74
+ groupProduct
75
+ }: GetProduct) => {
76
+ return Cache.wrap(
77
+ CacheKey[groupProduct ? 'GroupProduct' : 'Product'](
78
+ pk,
79
+ searchParams ?? new URLSearchParams()
80
+ ),
81
+ getProductDataHandler({ pk, searchParams, groupProduct }),
82
+ {
83
+ expire: 300
84
+ }
85
+ );
86
+ };