@evenicanpm/storefront-core 2.3.1 → 2.4.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 (90) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/package.json +42 -9
  3. package/src/api-manager/datasources/d365/d365-address.datasource.ts +148 -61
  4. package/src/api-manager/datasources/d365/d365-cart.datasource.ts +23 -1
  5. package/src/api-manager/datasources/d365/d365-order.datasource.ts +6 -1
  6. package/src/api-manager/datasources/d365/d365-user.datasource.ts +109 -37
  7. package/src/api-manager/datasources/d365/utils/get-context-cookie.ts +44 -10
  8. package/src/api-manager/index.ts +2 -1
  9. package/src/api-manager/lib/get-graphql-client.ts +35 -7
  10. package/src/api-manager/schemas/product.schema.ts +1 -1
  11. package/src/api-manager/services/create-query.ts +36 -3
  12. package/src/api-manager/services/get-query-client.ts +10 -0
  13. package/src/auth/better-auth.ts +282 -15
  14. package/src/cms/blocks/block-manager.tsx +1 -1
  15. package/src/cms/blocks/components/product-section-fullwidth/index.tsx +3 -1
  16. package/src/cms/endpoints.ts +7 -2
  17. package/src/components/BazaarMenu.tsx +1 -1
  18. package/src/components/Typography.tsx +4 -2
  19. package/src/components/carousel-cards/carousel-card-1/CarouselCard1.stories.tsx +1 -1
  20. package/src/components/categories/category-list/category-list.tsx +9 -5
  21. package/src/components/categories/category-menu.tsx +1 -1
  22. package/src/components/countries-input.tsx +4 -0
  23. package/src/components/header/__tests__/user.test.tsx +5 -107
  24. package/src/components/header/components/user.tsx +72 -45
  25. package/src/components/header/sticky-header.tsx +0 -1
  26. package/src/components/navbar/mobile-menu/mobile-menu.test.tsx +1 -1
  27. package/src/components/navbar/utils/transform-nav.test.ts +1 -1
  28. package/src/components/navbar/utils/transform-nav.ts +1 -1
  29. package/src/components/product-cards/product-card/product-card.tsx +5 -2
  30. package/src/components/product-cards/product-card/styles/index.ts +1 -5
  31. package/src/components/products-view/compound/products-grid-view.tsx +5 -1
  32. package/src/components/products-view/compound/products-list-view.tsx +5 -1
  33. package/src/global.d.ts +3 -0
  34. package/src/hooks/use-nextauth-session.ts +0 -33
  35. package/src/lib/auth-client.ts +14 -0
  36. package/src/lib/auth.ts +4 -0
  37. package/src/lib/entra-native-auth.ts +138 -0
  38. package/src/lib/native-session.ts +434 -0
  39. package/src/pages/account/addresses/address-form.tsx +20 -2
  40. package/src/pages/account/profile/__tests__/profile-form.test.tsx +173 -0
  41. package/src/pages/account/profile/profile-form.tsx +285 -0
  42. package/src/pages/account/profile/profile-validation.ts +52 -0
  43. package/src/pages/account/wishlist/wishlist-item.tsx +1 -2
  44. package/src/pages/auth/auth-activate-page.tsx +509 -0
  45. package/src/pages/auth/auth-layout.tsx +73 -0
  46. package/src/pages/auth/auth-login-page.tsx +241 -0
  47. package/src/pages/auth/auth-reset-password-page.tsx +487 -0
  48. package/src/pages/auth/compound/auth-form.tsx +182 -0
  49. package/src/pages/auth/compound/auth-pages.tsx +21 -0
  50. package/src/pages/auth/lib/friendly-error.ts +70 -0
  51. package/src/pages/auth/lib/index.ts +2 -0
  52. package/src/pages/auth/lib/types.ts +5 -0
  53. package/src/pages/cart/cart-item.tsx +1 -7
  54. package/src/pages/checkout/checkout-alt-form/checkout-form.tsx +14 -3
  55. package/src/pages/checkout/checkout-alt-form/steps/address/address-card.tsx +5 -3
  56. package/src/pages/checkout/checkout-alt-form/steps/address/delivery-address.tsx +20 -6
  57. package/src/pages/checkout/checkout-alt-form/steps/address/new-address-form.tsx +1 -1
  58. package/src/pages/checkout/checkout-alt-form/steps/customer-info/customer-information.tsx +1 -1
  59. package/src/pages/confirmation/ordered-products.tsx +3 -1
  60. package/src/pages/product-details/bopis/find-in-store-modal.tsx +4 -4
  61. package/src/pages/product-details/bopis/pickup-option-select.tsx +2 -2
  62. package/src/pages/product-details/bopis/search-header.tsx +2 -2
  63. package/src/pages/product-details/product-intro/compound/context.ts +8 -3
  64. package/src/pages/product-details/product-intro/compound/product-info.tsx +25 -19
  65. package/src/pages/product-list/product-list-view.tsx +2 -1
  66. package/src/providers/nav-provider/index.tsx +1 -1
  67. package/src/providers/nav-provider/utils/createLink.ts +1 -1
  68. package/tsconfig.json +20 -15
  69. package/__mocks__/countries.ts +0 -11
  70. package/__mocks__/create-mutation.ts +0 -68
  71. package/__mocks__/create-query.ts +0 -94
  72. package/__mocks__/data/categories.json +0 -795
  73. package/__mocks__/get-product-by-id.ts +0 -6
  74. package/__mocks__/next-auth-react.ts +0 -9
  75. package/__mocks__/next-font.js +0 -4
  76. package/__mocks__/next-headers.js +0 -13
  77. package/__mocks__/next-image.tsx +0 -18
  78. package/__mocks__/next-link.js +0 -19
  79. package/__mocks__/next-navigation.ts +0 -29
  80. package/__mocks__/product-dimensions.ts +0 -635
  81. package/__mocks__/products.ts +0 -533
  82. package/__mocks__/query-client.ts +0 -3
  83. package/__mocks__/wishlists.json +0 -408
  84. package/src/auth/msal.ts +0 -68
  85. package/src/cms/blog.ts +0 -229
  86. package/src/cms/interfaces/navigation.ts +0 -52
  87. package/src/cms/interfaces/product-data.ts +0 -83
  88. package/src/cms/pages.ts +0 -149
  89. package/src/pages/account/profile/profile-button.test.tsx +0 -59
  90. package/src/pages/account/profile/profile-button.tsx +0 -51
@@ -1,52 +0,0 @@
1
- // cms internal interfaces
2
- export interface CmsNavigation {
3
- nodes: {
4
- name: string;
5
- id: number;
6
- items: (CmsPage | CmsSubMenu)[];
7
- }[];
8
- }
9
-
10
- export interface CmsPage {
11
- type: string;
12
- id: number;
13
- name: string;
14
- slug: string;
15
- }
16
-
17
- export interface CmsSubMenu {
18
- type: string;
19
- name: string;
20
- pages: CmsPage[];
21
- }
22
-
23
- export interface CmsNavRelated {
24
- id: number;
25
- title: string;
26
- slug: string;
27
- createdAt: string;
28
- updatedAt: string;
29
- publishedAt?: string | null;
30
-
31
- /** Optional content‑type hint Strapi adds when `populate=*` */
32
- __contentType?: string;
33
-
34
- /**
35
- * Any other attributes your model exposes (e.g., SEO fields,
36
- * coverImage, etc.). Keep this open so the type stays valid
37
- * if the Strapi model grows.
38
- */
39
- [key: string]: unknown;
40
- }
41
-
42
- export interface CmsNavItem {
43
- title: string;
44
- menuAttached: boolean;
45
- path: string;
46
- type: "INTERNAL" | "EXTERNAL" | "WRAPPER";
47
- uiRouterKey: string;
48
- slug: string;
49
- related: CmsNavRelated | null;
50
- external: boolean;
51
- items: CmsNavItem[];
52
- }
@@ -1,83 +0,0 @@
1
- export interface ProductData {
2
- data: Array<{
3
- id: number;
4
- name: string;
5
- description: string;
6
- sku: string;
7
- createdAt: string;
8
- keywords: string;
9
- updatedAt: string;
10
- publishedAt: string;
11
- image: ProductImage[];
12
- }>;
13
- meta: {
14
- pagination: {
15
- page: number;
16
- pageSize: number;
17
- pageCount: number;
18
- total: number;
19
- };
20
- };
21
- }
22
-
23
- export interface ProductImage {
24
- id: number;
25
- name: string;
26
- alternativeText: string | null;
27
- caption: string | null;
28
- width: number;
29
- height: number;
30
- url: string;
31
- ext: string;
32
- mime: string;
33
- size: number;
34
- hash: string;
35
- provider: string;
36
- provider_metadata: Record<string, unknown> | null;
37
- previewUrl: string | null;
38
- createdAt: string;
39
- updatedAt: string;
40
- formats?: Formats;
41
- }
42
-
43
- export interface ImageFormat {
44
- ext: string;
45
- url: string;
46
- hash: string;
47
- mime: string;
48
- name: string;
49
- path: string | null;
50
- size: number;
51
- width: number;
52
- height: number;
53
- }
54
-
55
- export interface Formats {
56
- /** Strapi generates only the sizes you configure.
57
- Keep this flexible by using an index signature. */
58
- [size: string]: ImageFormat;
59
- }
60
-
61
- interface ImageAttributes {
62
- name: string;
63
- alternativeText: string | null;
64
- caption: string | null;
65
- width: number;
66
- height: number;
67
- formats: Formats;
68
- hash: string;
69
- ext: string;
70
- mime: string;
71
- size: number;
72
- url: string;
73
- previewUrl: string | null;
74
- provider: string;
75
- provider_metadata: Record<string, unknown> | null;
76
- createdAt: string;
77
- updatedAt: string;
78
- }
79
-
80
- export interface ImageData {
81
- id: number;
82
- attributes: ImageAttributes;
83
- }
package/src/cms/pages.ts DELETED
@@ -1,149 +0,0 @@
1
- import cmsEndPoints from "@/cms/endpoints";
2
-
3
- // TODO -> No types should be in CMS folder -> setup strapi codegen
4
- export interface Pages {
5
- data: Array<{
6
- id: number;
7
- attributes: {
8
- title: string;
9
- slug: string;
10
- content: string;
11
- isBlog: boolean;
12
- createdAt: string;
13
- updatedAt: string;
14
- publishedAt: string;
15
- };
16
- }>;
17
- meta: {
18
- pagination: {
19
- page: number;
20
- pageSize: number;
21
- pageCount: number;
22
- total: number;
23
- };
24
- };
25
- }
26
-
27
- export interface TransformedPages {
28
- __typename: string;
29
- recordCount: number;
30
- pageInfo: {
31
- __typename: string;
32
- top: number;
33
- skip: number;
34
- sort: string;
35
- sortDesc: boolean;
36
- search: string;
37
- };
38
- nodes: Array<{
39
- __typename: string;
40
- id: string;
41
- title: string;
42
- slug: string;
43
- content: string;
44
- isBlog: boolean;
45
- modified: string;
46
- modifiedBy: null;
47
- created: string;
48
- }>;
49
- }
50
-
51
- export const transformPages = (strapiResponse: Pages): TransformedPages => {
52
- const { data, meta } = strapiResponse;
53
- const nodes = data.map((item) => ({
54
- __typename: "Page",
55
- id: item.id.toString(),
56
- slug: item.attributes.slug,
57
- title: item.attributes.title,
58
- content: item.attributes.content,
59
- isBlog: item.attributes.isBlog,
60
- modified: item.attributes.updatedAt,
61
- modifiedBy: null,
62
- created: item.attributes.createdAt,
63
- }));
64
-
65
- return {
66
- __typename: "PageConnection",
67
- recordCount: meta.pagination.total,
68
- pageInfo: {
69
- __typename: "PageInfo",
70
- top: 50,
71
- skip: 0,
72
- sort: "modified",
73
- sortDesc: false,
74
- search: "",
75
- },
76
- nodes: nodes,
77
- };
78
- };
79
-
80
- export interface Page {
81
- data: {
82
- id: number;
83
- attributes: {
84
- title: string;
85
- content: string;
86
- isBlog: boolean;
87
- createdAt: string;
88
- updatedAt: string;
89
- publishedAt: string;
90
- };
91
- };
92
- meta: {
93
- pagination: {
94
- page: number;
95
- pageSize: number;
96
- pageCount: number;
97
- total: number;
98
- };
99
- };
100
- }
101
-
102
- export interface TransformedPage {
103
- __typename: string;
104
- id: string;
105
- title: string;
106
- content: string;
107
- isBlog: boolean;
108
- created: string;
109
- }
110
-
111
- export const transformPage = (response: Page): TransformedPage => {
112
- const { data } = response;
113
-
114
- return {
115
- __typename: "Page",
116
- id: data.id.toString(),
117
- title: data.attributes.title,
118
- content: data.attributes.content,
119
- isBlog: data.attributes.isBlog,
120
- created: data.attributes.createdAt,
121
- };
122
- };
123
-
124
- interface PageData {
125
- title: string;
126
- content: string;
127
- isBlog: boolean;
128
- }
129
-
130
- export const createPage = async (pageData: PageData) => {
131
- try {
132
- const response = await fetch(cmsEndPoints.getCmsApiUrl("pages"), {
133
- method: "POST",
134
- headers: { "Content-Type": "application/json" },
135
- body: JSON.stringify({
136
- data: pageData,
137
- }),
138
- });
139
-
140
- if (!response.ok) {
141
- throw new Error(`HTTP error! Status: ${response.status}`);
142
- }
143
-
144
- return await response.json();
145
- } catch (error) {
146
- console.error("Error creating page:", error);
147
- throw error;
148
- }
149
- };
@@ -1,59 +0,0 @@
1
- import ProfileButton from "@evenicanpm/storefront-core/src/pages/account/profile/profile-button";
2
- import { fireEvent, render, screen, waitFor } from "@testing-library/react";
3
- import { vi } from "vitest";
4
- import { getMsalInstance, getRequestConfig, initializeMsal } from "@/auth/msal";
5
-
6
- vi.mock("@/auth/msal", () => ({
7
- initializeMsal: vi.fn(),
8
- getMsalInstance: vi.fn(),
9
- getRequestConfig: vi.fn(),
10
- }));
11
-
12
- vi.mock("@evenicanpm/storefront-core/src/components/T/index", () => ({
13
- default: ({ path }: { path: string }) => <span>{path}</span>,
14
- }));
15
-
16
- describe("ProfileButton Component", () => {
17
- afterEach(() => {
18
- vi.restoreAllMocks();
19
- });
20
-
21
- it("renders disabled button initially (MSAL not ready)", () => {
22
- render(<ProfileButton type="edit" path="Account.Profile.btnEditProfile" />);
23
- const button = screen.getByRole("button");
24
- expect(button).toBeDisabled();
25
- });
26
-
27
- it("initializes MSAL on mount", async () => {
28
- render(<ProfileButton type="edit" path="Account.Profile.btnEditProfile" />);
29
- await waitFor(() => {
30
- expect(initializeMsal).toHaveBeenCalled();
31
- });
32
- });
33
-
34
- it("calls MSAL loginRedirect when clicked", async () => {
35
- (initializeMsal as ReturnType<typeof vi.fn>).mockImplementation(() =>
36
- Promise.resolve(),
37
- );
38
- (getRequestConfig as ReturnType<typeof vi.fn>).mockReturnValue({
39
- scopes: ["user.read"],
40
- });
41
- (getMsalInstance as ReturnType<typeof vi.fn>).mockReturnValue({
42
- loginRedirect: vi.fn(),
43
- });
44
- render(<ProfileButton type="edit" path="Account.Profile.btnEditProfile" />);
45
-
46
- await waitFor(() => {
47
- expect(initializeMsal).toHaveBeenCalled();
48
- });
49
-
50
- const button = screen.getByRole("button");
51
- fireEvent.click(button);
52
-
53
- await waitFor(() => {
54
- expect(getMsalInstance().loginRedirect).toHaveBeenCalledWith({
55
- scopes: ["user.read"],
56
- });
57
- });
58
- });
59
- });
@@ -1,51 +0,0 @@
1
- "use client";
2
-
3
- import type { RedirectRequest } from "@azure/msal-browser";
4
- import T from "@evenicanpm/storefront-core/src/components/T/index";
5
- import { Button } from "@mui/material";
6
- import { useEffect, useState } from "react";
7
- import { getMsalInstance, getRequestConfig, initializeMsal } from "@/auth/msal";
8
-
9
- interface Props {
10
- type: string;
11
- path: string;
12
- }
13
-
14
- const ProfileButton = ({ type, path }: Props) => {
15
- const [isMsalReady, setIsMsalReady] = useState(false);
16
-
17
- useEffect(() => {
18
- const initMsal = async () => {
19
- await initializeMsal();
20
- setIsMsalReady(true);
21
- };
22
- initMsal();
23
- }, []);
24
-
25
- const handleProfile = async () => {
26
- if (!isMsalReady) {
27
- console.error("MSAL is not initialized yet.");
28
- return;
29
- }
30
-
31
- try {
32
- const req = getRequestConfig(type);
33
- await getMsalInstance().loginRedirect(req as RedirectRequest); // "handleRedirectPromise" is in user component.
34
- } catch (error) {
35
- console.error("Profile update through MSAL failed", error);
36
- }
37
- };
38
-
39
- return (
40
- <Button
41
- onClick={() => handleProfile()}
42
- disabled={!isMsalReady}
43
- color="primary"
44
- sx={{ bgcolor: "primary.light", px: 4 }}
45
- >
46
- <T path={path} />
47
- </Button>
48
- );
49
- };
50
-
51
- export default ProfileButton;