@evenicanpm/storefront-core 2.0.0 → 2.0.1

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 (125) hide show
  1. package/.storybook/main.ts +2 -3
  2. package/.storybook/preview.tsx +0 -2
  3. package/__mocks__/create-mutation.ts +16 -8
  4. package/__mocks__/next-image.tsx +12 -3
  5. package/package.json +2 -2
  6. package/src/api-manager/datasources/d365/d365-categories.datasource.ts +2 -3
  7. package/src/api-manager/datasources/d365/d365-order.datasource.ts +4 -4
  8. package/src/api-manager/datasources/d365/d365-organization.datasource.ts +15 -8
  9. package/src/api-manager/datasources/d365/d365-product.datasource.ts +31 -19
  10. package/src/api-manager/datasources/d365/d365-user.datasource.ts +47 -19
  11. package/src/api-manager/datasources/e4/address/e4-address.remaps.ts +2 -2
  12. package/src/api-manager/datasources/e4/cart/e4-cart.remaps.ts +1 -1
  13. package/src/api-manager/datasources/e4/product/e4-product.remaps.ts +3 -3
  14. package/src/api-manager/datasources/e4/user/e4-user.datasource.ts +4 -8
  15. package/src/api-manager/index.ts +10 -127
  16. package/src/api-manager/lib/get-graphql-client.ts +2 -2
  17. package/src/api-manager/schemas/product.schema.ts +9 -0
  18. package/src/api-manager/services/create-extension-query.ts +1 -1
  19. package/src/api-manager/services/create-query.ts +106 -266
  20. package/src/api-manager/types/Datasource.ts +0 -3
  21. package/src/cms/blocks/components/category-card.tsx +0 -1
  22. package/src/cms/blocks/components/category-carousel/index.tsx +0 -1
  23. package/src/cms/blocks/components/featured-categories.tsx +1 -2
  24. package/src/cms/blocks/components/featured-products.tsx +1 -2
  25. package/src/cms/blocks/components/footer/index.tsx +0 -1
  26. package/src/cms/blocks/components/footer/sections/footer-app-store.tsx +1 -1
  27. package/src/cms/blocks/components/footer/sections/footer-contact.tsx +0 -1
  28. package/src/cms/blocks/components/footer/sections/footer-links.tsx +1 -1
  29. package/src/cms/blocks/components/footer/sections/footer-logo.tsx +0 -1
  30. package/src/cms/blocks/components/footer/sections/footer-social-links.tsx +0 -1
  31. package/src/cms/blocks/components/footer.tsx +0 -1
  32. package/src/cms/blocks/components/hero-carousel/index.tsx +0 -1
  33. package/src/cms/blocks/components/hero.tsx +0 -1
  34. package/src/cms/blocks/components/image.tsx +0 -1
  35. package/src/cms/blocks/components/media-card.tsx +0 -1
  36. package/src/cms/blocks/components/product-carousel/index.tsx +0 -1
  37. package/src/cms/blocks/components/product-section-fullwidth/index.tsx +0 -1
  38. package/src/cms/blocks/components/rich-text.tsx +0 -1
  39. package/src/cms/blocks/components/seo/index.tsx +1 -2
  40. package/src/cms/blocks/components/services/index.tsx +0 -1
  41. package/src/cms/blocks/components/services/service-card.tsx +0 -1
  42. package/src/cms/blocks/components/shared/featured-product-card.tsx +0 -1
  43. package/src/cms/blocks/components/shared/product-category-item.tsx +1 -1
  44. package/src/cms/blocks/components/shared/product-grid.tsx +0 -1
  45. package/src/cms/blocks/components/shared/top-categories-card.tsx +0 -1
  46. package/src/cms/blocks/components/shared/top-rating-product-card.tsx +0 -1
  47. package/src/cms/blocks/icons/components/category.tsx +0 -1
  48. package/src/cms/blocks/icons/components/dotted-star.tsx +0 -1
  49. package/src/cms/blocks/icons/components/fallback-icon.tsx +0 -1
  50. package/src/cms/blocks/icons/components/gift-box.tsx +0 -1
  51. package/src/cms/blocks/icons/components/light.tsx +0 -1
  52. package/src/cms/blocks/icons/components/new-arrival.tsx +0 -1
  53. package/src/cms/blocks/icons/components/rank-badge.tsx +0 -1
  54. package/src/components/BazaarTextField.tsx +7 -7
  55. package/src/components/CountryInput.stories.tsx +4 -2
  56. package/src/components/T/__tests__/T.test.tsx +9 -13
  57. package/src/components/T/index.tsx +0 -1
  58. package/src/components/Typography.tsx +0 -1
  59. package/src/components/_tests_/site-logo.test.tsx +4 -5
  60. package/src/components/categories/category-list/category-list.tsx +1 -1
  61. package/src/components/countries-input.tsx +1 -1
  62. package/src/components/nav-link/nav-link.tsx +2 -8
  63. package/src/components/navbar/mega-menu/mega-menu.tsx +7 -1
  64. package/src/components/navbar/mobile-menu/mobile-menu.test.tsx +2 -1
  65. package/src/components/navbar/nav-list/cms-nav.test.tsx +0 -1
  66. package/src/components/no-records.tsx +0 -1
  67. package/src/components/product-cards/favorite-button.tsx +0 -1
  68. package/src/components/product-cards/product-card/styles/index.ts +2 -2
  69. package/src/components/product-cards/product-card-plp-list/ProductCardPlpList.stories.tsx +0 -1
  70. package/src/components/product-cards/product-card-search/ProductCardSearch.stories.tsx +0 -1
  71. package/src/components/product-dimensions/Dimensions.stories.tsx +2 -4
  72. package/src/components/product-dimensions/compound/dimensions-group-list-chip.tsx +1 -1
  73. package/src/components/product-dimensions/compound/dimensions.tsx +1 -1
  74. package/src/components/product-quantity-buttons/ProductQuantity.stories.tsx +1 -3
  75. package/src/components/product-quantity-buttons/__tests__/product-quantity-buttons.test.tsx +3 -2
  76. package/src/components/product-quantity-buttons/compound/quantity-buttons-root.tsx +1 -1
  77. package/src/components/product-quantity-buttons/index.tsx +0 -1
  78. package/src/components/product-quantity-variants/ProductQuantity.stories.tsx +1 -3
  79. package/src/components/products-view/ProductsGrid.stories.tsx +1 -3
  80. package/src/components/products-view/ProductsList.stories.tsx +1 -3
  81. package/src/components/products-view/__tests__/products-view.test.tsx +20 -9
  82. package/src/components/products-view/index.tsx +1 -1
  83. package/src/components/scrollbar/Scrollbar.stories.tsx +1 -3
  84. package/src/components/scrollbar/__tests__/scrollbar.test.tsx +7 -1
  85. package/src/components/search-bar/SearchBarLarge.stories.tsx +1 -3
  86. package/src/components/search-bar/compound/results-item-lg.tsx +0 -1
  87. package/src/components/search-bar/compound/results-item-sm.tsx +0 -1
  88. package/src/components/search-bar/compound/textfield-adornment-category.tsx +0 -1
  89. package/src/components/search-bar/compound/textfield.tsx +0 -1
  90. package/src/components/search-bar/utils/findCategoryNameById.ts +3 -3
  91. package/src/components/section/__tests__/section.test.tsx +14 -7
  92. package/src/components/side-nav/SideNav.stories.tsx +1 -1
  93. package/src/components/site-logo.tsx +8 -1
  94. package/src/components/wishlist-dialogs/add-to-wishlist/add-to-wishlist-button.tsx +1 -1
  95. package/src/components/wishlist-dialogs/add-to-wishlist/compound/add-to-wishlist-bottom-ui.tsx +1 -1
  96. package/src/components/wishlist-dialogs/add-to-wishlist/compound/wishlist-dialog-header.tsx +0 -1
  97. package/src/components/wishlist-dialogs/create-wishlist/compound/create-wishlist-bottom-ui.tsx +1 -1
  98. package/src/hooks/use-nextauth-session.ts +4 -1
  99. package/src/lib/lib.ts +1 -1
  100. package/src/lib/page-slugs.ts +0 -2
  101. package/src/lib/refiner-utils.ts +3 -3
  102. package/src/pages/account/account-navigation.tsx +17 -20
  103. package/src/pages/account/addresses/address-form.tsx +15 -7
  104. package/src/pages/account/dashboard-header.tsx +1 -1
  105. package/src/pages/cart/checkout-form.tsx +1 -1
  106. package/src/pages/checkout/checkout-alt-form/checkout-step.tsx +1 -1
  107. package/src/pages/checkout/checkout-alt-form/steps/address/new-address-form.tsx +1 -1
  108. package/src/pages/checkout/checkout-alt-form/steps/payment/payment-details.tsx +5 -2
  109. package/src/pages/checkout/checkout-alt-summary/cart-item.tsx +1 -1
  110. package/src/pages/checkout/checkout-alt-summary/checkout-alt-summary.tsx +1 -1
  111. package/src/pages/confirmation/address.tsx +1 -1
  112. package/src/pages/confirmation/confirmation-summary.tsx +1 -1
  113. package/src/pages/product-details/currency.ts +1 -1
  114. package/src/pages/product-details/product-intro/compound/thumbnail-with-skeleton.tsx +4 -1
  115. package/src/pages/product-list/breadcrumbs.tsx +0 -1
  116. package/src/pages/product-list/list-filter.tsx +0 -1
  117. package/src/pages/product-list/product-list-context.tsx +1 -1
  118. package/src/pages/product-list/product-list-view.tsx +2 -2
  119. package/src/pages/product-list/selected-facets.tsx +1 -1
  120. package/src/pages/quickorder/context.ts +8 -2
  121. package/src/pages/quickorder/order-upload.tsx +26 -8
  122. package/src/pages/quickorder/provider.tsx +8 -9
  123. package/src/pages/quickorder/quick-order.tsx +17 -11
  124. package/src/providers/nav-provider/index.tsx +1 -1
  125. package/tsconfig.json +0 -1
@@ -12,7 +12,7 @@ import {
12
12
  import useCurrencyFormatter from "@evenicanpm/storefront-core/src/lib/currency-formatter";
13
13
  import { Card, Divider } from "@mui/material";
14
14
  import { useTranslations } from "next-intl";
15
- import React, { createContext, type ReactNode, useContext } from "react";
15
+ import { createContext, type ReactNode, useContext } from "react";
16
16
 
17
17
  type SummaryValues = {
18
18
  order: SalesOrder;
@@ -13,7 +13,7 @@ import { formatDistanceStrict } from "date-fns";
13
13
 
14
14
  function getDateDifference(date: string | number | Date) {
15
15
  const distance = formatDistanceStrict(new Date(), new Date(date));
16
- return distance + " ago";
16
+ return `${distance} ago`;
17
17
  }
18
18
 
19
19
  /**
@@ -1,4 +1,5 @@
1
1
  import { Skeleton } from "@mui/material";
2
+ import Image from "next/image";
2
3
  import { useState } from "react";
3
4
 
4
5
  /**
@@ -11,9 +12,11 @@ function ThumbnailWithSkeleton({ src }: Readonly<{ src: string }>) {
11
12
  return (
12
13
  <>
13
14
  {!loaded && <Skeleton variant="rounded" width={50} height={50} />}
14
- <img
15
+ <Image
15
16
  src={src}
16
17
  alt="Product thumbnail"
18
+ width={50}
19
+ height={50}
17
20
  onLoad={() => setLoaded(true)}
18
21
  style={{
19
22
  display: loaded ? "block" : "none",
@@ -1,7 +1,6 @@
1
1
  import type { CategoryHierarchy } from "@evenicanpm/storefront-core/src/lib/category-helpers";
2
2
  import { Breadcrumbs, Typography } from "@mui/material";
3
3
  import Link from "next/link";
4
- import React from "react";
5
4
  import {
6
5
  getCategoryTranslatedName,
7
6
  getCategoryUrl,
@@ -4,7 +4,6 @@ import {
4
4
  } from "@evenicanpm/storefront-core/src/components/flex-box";
5
5
  import { Span } from "@evenicanpm/storefront-core/src/components/Typography";
6
6
  import type { ProductRefinerValue } from "@msdyn365-commerce/retail-proxy";
7
- import React from "react";
8
7
  import CheckboxLabel from "./checkbox-label";
9
8
  import type { RenderedFacetProps } from "./facet-group";
10
9
 
@@ -151,7 +151,7 @@ const ProductListProvider = ({ children }: { children: React.ReactNode }) => {
151
151
 
152
152
  const { data, isLoading } = getProductList.useData(inputParams);
153
153
  const { data: productPrices } = getProductPrices.useSuspenseData({
154
- productIds: data?.products.map((product) => product.RecordId) || [],
154
+ productIds: (data?.products ?? []).map((product) => product.RecordId),
155
155
  });
156
156
  const handleRefinerChange = useCallback(
157
157
  (refiner: ProductRefinerValue) => {
@@ -18,7 +18,7 @@ import { usePreviousRefiners } from "@evenicanpm/storefront-core/src/pages/produ
18
18
  import { Box, CircularProgress, Paper, Typography } from "@mui/material";
19
19
  import Grid from "@mui/material/Grid2";
20
20
  import { useLocale, useTranslations } from "next-intl";
21
- import React, { createContext, type ReactNode, useContext } from "react";
21
+ import { createContext, type ReactNode, useContext } from "react";
22
22
 
23
23
  type PLViewCtx = { categoryId: number };
24
24
  const ProductListViewContext = createContext<PLViewCtx | null>(null);
@@ -61,7 +61,7 @@ ProductListView.Header = function Header() {
61
61
  <Box>
62
62
  <CategoryBreadcrumbs breadcrumbs={breadcrumbs} locale={locale} />
63
63
  <Paragraph color="grey.600" sx={{ mt: 1 }}>
64
- {(productData?.count ?? 0) + " " + t("results")}
64
+ {`${productData?.count ?? 0} ${t("results")}`}
65
65
  </Paragraph>
66
66
  </Box>
67
67
  );
@@ -5,7 +5,7 @@ import {
5
5
  } from "@msdyn365-commerce/retail-proxy";
6
6
  import { Button, Chip, Stack } from "@mui/material";
7
7
  import { useTranslations } from "next-intl";
8
- import React, { useEffect, useState } from "react";
8
+ import { useEffect, useState } from "react";
9
9
  import useProductList from "./use-product-list";
10
10
 
11
11
  export default function SelectedFacets() {
@@ -1,8 +1,14 @@
1
1
  "use client";
2
2
 
3
+ import type { Cart } from "@evenicanpm/storefront-core/src/api-manager/schemas/cart.schema";
3
4
  import { createContext, useContext } from "react";
4
5
  import type { QuickOrderRowData } from "./quick-order-row";
5
6
 
7
+ export type UploadedItem = {
8
+ itemId: string | number;
9
+ qty?: number;
10
+ };
11
+
6
12
  export enum RowError {
7
13
  ProductNotFound,
8
14
  InvalidQuantity,
@@ -12,7 +18,7 @@ export enum RowError {
12
18
 
13
19
  export type QuickOrderContextType = {
14
20
  rows: QuickOrderRowData[];
15
- cart: any;
21
+ cart: Cart | undefined;
16
22
  handleRowUpdate: (
17
23
  id: number,
18
24
  value: string,
@@ -21,7 +27,7 @@ export type QuickOrderContextType = {
21
27
  handleRowDelete: (id: number) => void;
22
28
  handleAddRows: () => void;
23
29
  handleAddToCart: () => Promise<void>;
24
- handleUploadedItems: (items: any[]) => Promise<void>;
30
+ handleUploadedItems: (items: UploadedItem[]) => Promise<void>;
25
31
  resetForm: () => void;
26
32
  generateFile: () => void;
27
33
  };
@@ -15,8 +15,26 @@ export interface OrderUploadProps {
15
15
  onUploadItems: (data: OrderUploadItem[]) => void;
16
16
  }
17
17
 
18
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
- declare const XLSX: any;
18
+ type XlsxCellValue = string | number | boolean | null;
19
+
20
+ interface XlsxCell {
21
+ v?: XlsxCellValue;
22
+ }
23
+
24
+ interface XlsxSheet {
25
+ "!ref"?: string;
26
+ [key: string]: XlsxCell | string | undefined;
27
+ }
28
+
29
+ declare const XLSX: {
30
+ read(
31
+ data: string | ArrayBuffer,
32
+ opts: { type: string },
33
+ ): { SheetNames: string[]; Sheets: Record<string, XlsxSheet> };
34
+ utils: {
35
+ sheet_to_json<T>(ws: XlsxSheet, opts?: { header?: number }): T[];
36
+ };
37
+ };
20
38
 
21
39
  export default function OrderUpload({
22
40
  onUploadItems,
@@ -110,8 +128,7 @@ function readFirstSheet(binary: string | ArrayBuffer) {
110
128
  }
111
129
 
112
130
  //Extract Items
113
- // biome-ignore lint/suspicious/noExplicitAny: <explanation> This is required as the XLSX library returns a sheet as an object with dynamic keys based on the cell positions (e.g., A1, B2, etc.), which cannot be typed more specifically without extensive type definitions that may not be practical. --- IGNORE ---
114
- function extractItemsFromSheet(ws: Record<string, any>): OrderUploadItem[] {
131
+ function extractItemsFromSheet(ws: XlsxSheet): OrderUploadItem[] {
115
132
  const ref = ws["!ref"];
116
133
  let data: OrderUploadItem[] = [];
117
134
 
@@ -121,16 +138,17 @@ function extractItemsFromSheet(ws: Record<string, any>): OrderUploadItem[] {
121
138
  const rowCount = Number(end.substring(1));
122
139
 
123
140
  for (let i = 2; i < rowCount + 1; i++) {
124
- const qty = ws[`B${i}`]?.v;
125
- const itemId = ws[`A${i}`]?.v;
141
+ const qty = (ws[`B${i}`] as XlsxCell | undefined)?.v;
142
+ const itemId = (ws[`A${i}`] as XlsxCell | undefined)?.v;
126
143
 
127
- if (itemId) data.push({ itemId, qty });
144
+ if (itemId != null)
145
+ data.push({ itemId: String(itemId), qty: Number(qty) });
128
146
  }
129
147
  }
130
148
  } catch {}
131
149
 
132
150
  if (data.length === 0) {
133
- data = XLSX.utils.sheet_to_json(ws, { header: 0 });
151
+ data = XLSX.utils.sheet_to_json<OrderUploadItem>(ws, { header: 0 });
134
152
  }
135
153
 
136
154
  return data;
@@ -5,7 +5,7 @@ import getCart from "@evenicanpm/storefront-core/src/api-manager/services/cart/q
5
5
  import useSearchProducts from "@evenicanpm/storefront-core/src/api-manager/services/product/mutations/search-products";
6
6
  import type React from "react";
7
7
  import { useCallback, useEffect, useState } from "react";
8
- import { QuickOrderContext, RowError } from "./context";
8
+ import { QuickOrderContext, RowError, type UploadedItem } from "./context";
9
9
  import type { QuickOrderRowData } from "./quick-order-row";
10
10
 
11
11
  const generateEmptyRow = (id: number): QuickOrderRowData => ({
@@ -35,7 +35,7 @@ export default function QuickOrderProvider({
35
35
 
36
36
  const generateRowData = useCallback(
37
37
  (
38
- product: any,
38
+ product: QuickOrderRowData["product"],
39
39
  rowId: number,
40
40
  value: string,
41
41
  found: boolean,
@@ -135,24 +135,23 @@ export default function QuickOrderProvider({
135
135
  }
136
136
  };
137
137
 
138
- const handleUploadedItems = async (items: any[]) => {
139
- const itemIds = items.map((it: any) => it.itemId.toString());
138
+ const handleUploadedItems = async (items: UploadedItem[]) => {
139
+ const itemIds = items.map((it) => it.itemId.toString());
140
140
  const response = await getProductSearchResults(itemIds);
141
141
 
142
142
  const updated = rows.filter((r) => r.value);
143
143
  let rowId = updated.reduce((max, r) => Math.max(max, r.id), 0) + 1;
144
144
 
145
- items.forEach((it: any) => {
145
+ items.forEach((it) => {
146
146
  const product = response?.find(
147
- (r: any) =>
148
- r.ItemId?.toLowerCase() === it.itemId.toString().toLowerCase(),
147
+ (r) => r.ItemId?.toLowerCase() === it.itemId.toString().toLowerCase(),
149
148
  );
150
149
  const qty = it.qty || 1;
151
150
  updated.push(
152
151
  generateRowData(
153
152
  product || null,
154
153
  rowId++,
155
- it.itemId,
154
+ it.itemId.toString(),
156
155
  !!product,
157
156
  qty.toString(),
158
157
  ),
@@ -172,7 +171,7 @@ export default function QuickOrderProvider({
172
171
  const csv =
173
172
  header +
174
173
  rows.map(({ value, quantity }) => `${value},${quantity}`).join("\n");
175
- const uri = "data:text/csv;charset=utf-8," + csv;
174
+ const uri = `data:text/csv;charset=utf-8,${csv}`;
176
175
 
177
176
  const link = document.createElement("a");
178
177
  link.setAttribute("href", encodeURI(uri));
@@ -59,6 +59,10 @@ export interface QuickOrderRowData {
59
59
  rowError: RowError;
60
60
  }
61
61
 
62
+ type SearchableProduct = {
63
+ ItemId?: string;
64
+ };
65
+
62
66
  type Ctx = {
63
67
  rows: QuickOrderRowData[];
64
68
  setRows: React.Dispatch<React.SetStateAction<QuickOrderRowData[]>>;
@@ -189,7 +193,7 @@ const QuickOrder = ({ children }: { children?: ReactNode }) => {
189
193
  const csv =
190
194
  header +
191
195
  rows.map(({ value, quantity }) => `${value},${quantity}`).join("\n");
192
- const encoded = encodeURI("data:text/csv;charset=utf-8," + csv);
196
+ const encoded = encodeURI(`data:text/csv;charset=utf-8,${csv}`);
193
197
 
194
198
  const link = document.createElement("a");
195
199
  link.setAttribute("href", encoded);
@@ -218,21 +222,23 @@ const QuickOrder = ({ children }: { children?: ReactNode }) => {
218
222
  };
219
223
 
220
224
  const handleUploadedItems = useCallback(
221
- async (items: OrderUploadItem[]) => {
222
- const ids = items.map((it) => it.itemId.toString());
223
- const response = await searchProductsMultiple(ids);
225
+ async (items: OrderUploadItem[]): Promise<void> => {
226
+ const ids: string[] = items.map((it) => it.itemId.toString());
227
+ const response: ProductSearchResult[] | undefined =
228
+ await searchProductsMultiple(ids);
224
229
 
225
- let curr = [...rows];
226
- const firstEmptyIdx = curr.findIndex((r) => !r.value);
230
+ let curr: QuickOrderRowData[] = [...rows];
231
+ const firstEmptyIdx: number = curr.findIndex((r) => !r.value);
227
232
  if (firstEmptyIdx > -1) curr = curr.slice(0, firstEmptyIdx);
228
233
 
229
- let rowId = curr.reduce((m, r) => Math.max(m, r.id), 0) + 1;
234
+ let rowId: number = curr.reduce((m, r) => Math.max(m, r.id), 0) + 1;
230
235
 
231
- items.forEach((it) => {
232
- const product = response?.find(
233
- (r) => it.itemId.toString().toLowerCase() === r.ItemId?.toLowerCase(),
236
+ items.forEach((it: OrderUploadItem): void => {
237
+ const product: ProductSearchResult | undefined = response?.find(
238
+ (r: SearchableProduct) =>
239
+ it.itemId.toString().toLowerCase() === r.ItemId?.toLowerCase(),
234
240
  );
235
- const qty = it.qty || 1;
241
+ const qty: number = it.qty || 1;
236
242
  curr.push(
237
243
  generateRowData(
238
244
  product || null,
@@ -2,7 +2,7 @@
2
2
  import type { CategoryHierarchy } from "@evenicanpm/storefront-core/src/lib/category-helpers";
3
3
  import { createLink } from "@evenicanpm/storefront-core/src/providers/nav-provider/utils/createLink";
4
4
  import { useTranslations } from "next-intl";
5
- import React, { createContext, type PropsWithChildren, useState } from "react";
5
+ import { createContext, type PropsWithChildren, useState } from "react";
6
6
  import type { CmsNavItem } from "@/cms/interfaces/navigation";
7
7
 
8
8
  type NavContextType = {
package/tsconfig.json CHANGED
@@ -10,7 +10,6 @@
10
10
  "moduleResolution": "node",
11
11
  "resolveJsonModule": true,
12
12
  "outDir": "./dist",
13
- "baseUrl": "./",
14
13
  "jsx": "preserve",
15
14
  "typeRoots": ["../../../../storefront/node_modules/@types"],
16
15
  "paths": {