@vtex/faststore-plugin-buyer-portal 1.0.29 → 1.0.30

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 (23) hide show
  1. package/package.json +1 -1
  2. package/plugin.config.js +4 -4
  3. package/src/clients/BuyerPortalClient.ts +38 -1
  4. package/src/features/contracts/components/ContractsCard/ContractsCard.tsx +18 -19
  5. package/src/features/contracts/hooks/index.ts +1 -0
  6. package/src/features/contracts/hooks/useUpdateContractStatus.ts +27 -0
  7. package/src/features/contracts/layouts/ContractsLayout/ContractsLayout.tsx +20 -2
  8. package/src/features/contracts/layouts/ContractsLayout/contracts-layout.scss +1 -0
  9. package/src/features/contracts/services/get-contract-details.service.ts +16 -0
  10. package/src/features/contracts/services/{get-contracts.service.ts → get-contracts-by-customer-id.service.ts} +5 -15
  11. package/src/features/contracts/services/get-contracts-org-by-unit-id.service.ts +40 -0
  12. package/src/features/contracts/services/index.ts +15 -3
  13. package/src/features/contracts/services/update-contract-status.service.ts +25 -0
  14. package/src/features/contracts/types/ContractData.ts +1 -1
  15. package/src/features/profile/components/ProfileCard/ProfileCard.tsx +2 -8
  16. package/src/features/profile/layouts/ProfileLayout/ProfileLayout.tsx +9 -5
  17. package/src/features/profile/layouts/ProfileLayout/profile-layout.scss +1 -1
  18. package/src/features/shared/components/BasicCard/BasicCard.tsx +3 -1
  19. package/src/features/shared/utils/cookie.ts +31 -6
  20. package/src/features/shared/utils/getClientContext.ts +3 -0
  21. package/src/pages/contracts.tsx +7 -2
  22. package/src/pages/org-units.tsx +2 -1
  23. package/src/pages/profile.tsx +20 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vtex/faststore-plugin-buyer-portal",
3
- "version": "1.0.29",
3
+ "version": "1.0.30",
4
4
  "description": "A plugin for faststore with buyer portal",
5
5
  "main": "index.js",
6
6
  "dependencies": {
package/plugin.config.js CHANGED
@@ -17,16 +17,16 @@ module.exports = {
17
17
  path: "/user/[userId]",
18
18
  appLayout: false,
19
19
  },
20
+ profile: {
21
+ path: "/profile/[[...contractId]]",
22
+ appLayout: false,
23
+ },
20
24
 
21
25
  // Shared pages
22
26
  "org-units": {
23
27
  path: "/org-units/[[...orgUnitId]]",
24
28
  appLayout: false,
25
29
  },
26
- profile: {
27
- path: "/profile/[[...orgUnitId]]",
28
- appLayout: false,
29
- },
30
30
  contracts: {
31
31
  path: "/contracts/[[...orgUnitId]]",
32
32
  appLayout: false,
@@ -16,7 +16,7 @@ class BuyerPortalClient extends Client {
16
16
  // Contracts
17
17
  getContractsByCustomerId(customerId: string, cookie: string) {
18
18
  return this.get<{ data: { contracts: ContractData[]; total: number } }>(
19
- `contracts/${customerId}`,
19
+ `contracts/${customerId}/list`,
20
20
  {
21
21
  headers: {
22
22
  Cookie: cookie,
@@ -25,6 +25,25 @@ class BuyerPortalClient extends Client {
25
25
  );
26
26
  }
27
27
 
28
+ getContractsByOrgUnitId(orgUnitId: string, cookie: string) {
29
+ return this.get<{ contracts: ContractData[]; total: number }>(
30
+ `contracts/${orgUnitId}`,
31
+ {
32
+ headers: {
33
+ Cookie: cookie,
34
+ },
35
+ }
36
+ );
37
+ }
38
+
39
+ getContractDetails(contractId: string, cookie: string) {
40
+ return this.get<{ contract: ContractData }>(`contract/${contractId}`, {
41
+ headers: {
42
+ Cookie: cookie,
43
+ },
44
+ });
45
+ }
46
+
28
47
  getContracts(
29
48
  cookie: string,
30
49
  params?: {
@@ -42,6 +61,24 @@ class BuyerPortalClient extends Client {
42
61
  });
43
62
  }
44
63
 
64
+ updateContractStatus(
65
+ data: { contractId: string; isActive: boolean },
66
+ cookie: string
67
+ ) {
68
+ const { contractId, isActive } = data;
69
+
70
+ return this.post<null, { isActive: boolean }>(
71
+ `contracts/status/${contractId}`,
72
+ { isActive },
73
+ {
74
+ headers: {
75
+ Cookie: cookie,
76
+ },
77
+ data: { isActive },
78
+ }
79
+ );
80
+ }
81
+
45
82
  //Addresses
46
83
  getAddressesByCustomerId(customerId: string, cookie: string) {
47
84
  return this.get<{ addresses: AddressData[] }>(`addresses/${customerId}`, {
@@ -8,6 +8,8 @@ import {
8
8
  } from "@faststore/ui";
9
9
  import type { ContractData } from "../../types";
10
10
  import { BasicCard, Icon } from "../../../shared/components";
11
+ import { useRouter } from "next/router";
12
+ import { useUpdateContractStatus } from "../../hooks";
11
13
 
12
14
  type ContractsCardProps = {
13
15
  orgUnitData?: {
@@ -21,12 +23,17 @@ export default function ContractsCard({
21
23
  contracts,
22
24
  orgUnitData,
23
25
  }: ContractsCardProps) {
26
+ const route = useRouter();
27
+
28
+ const { updateContractStatus } = useUpdateContractStatus();
29
+
24
30
  return (
25
31
  <BasicCard
26
32
  footerLink={`/contracts${orgUnitData?.id ? `/${orgUnitData.id}` : ""}`}
27
33
  footerMessage="View contracts"
28
34
  title="Contracts"
29
35
  subTitle={contracts.length ?? 0}
36
+ icon={<Icon name="Info" width={20} height={20} />}
30
37
  onPlusIconClick={() => {}}
31
38
  >
32
39
  {contracts.length &&
@@ -48,6 +55,12 @@ export default function ContractsCard({
48
55
  <Toggle
49
56
  id="contractActive"
50
57
  defaultChecked={contract.isActive}
58
+ onChange={(event) => {
59
+ updateContractStatus({
60
+ contractId: contract.id,
61
+ isActive: event.target.checked,
62
+ });
63
+ }}
51
64
  />
52
65
 
53
66
  <Dropdown>
@@ -55,7 +68,11 @@ export default function ContractsCard({
55
68
  <Icon name="MoreVert" data-fs-menu-action-button />
56
69
  </DropdownButton>
57
70
  <DropdownMenu align="right" data-fs-dropdown-menu>
58
- <DropdownItem>
71
+ <DropdownItem
72
+ onClick={() => {
73
+ route.push(`/contract/${contract.id}`);
74
+ }}
75
+ >
59
76
  <UIIcon name="ArrowSquareOut" data-fs-dropdown-icon />
60
77
  Open
61
78
  </DropdownItem>
@@ -77,24 +94,6 @@ export default function ContractsCard({
77
94
  />{" "}
78
95
  Delete
79
96
  </DropdownItem>
80
- <DropdownItem dismissOnClick={false}>
81
- <div data-fs-dropdown-active-item>
82
- <div data-fs-dropdown-active-item-label>
83
- <Icon
84
- name="Active"
85
- width={24}
86
- height={24}
87
- data-fs-dropdown-icon
88
- />{" "}
89
- Active
90
- </div>
91
- <Toggle
92
- id="contractActiveMenu"
93
- defaultChecked={contract.isActive}
94
- data-fs-internal-toggle
95
- />
96
- </div>
97
- </DropdownItem>
98
97
  </DropdownMenu>
99
98
  </Dropdown>
100
99
  </div>
@@ -0,0 +1 @@
1
+ export { useUpdateContractStatus } from "./useUpdateContractStatus";
@@ -0,0 +1,27 @@
1
+ import { type MutationOptions, useMutation } from "../../shared/hooks";
2
+ import {
3
+ updateContractStatusService,
4
+ type UpdateContractStatusServiceProps,
5
+ } from "../services";
6
+
7
+ export const useUpdateContractStatus = (
8
+ options?: MutationOptions<AwaitedType<typeof updateContractStatusService>>
9
+ ) => {
10
+ const { mutate, isLoading, error } = useMutation<
11
+ AwaitedType<typeof updateContractStatusService>,
12
+ Omit<UpdateContractStatusServiceProps, "cookie">
13
+ >(
14
+ (variables, clientContext) =>
15
+ updateContractStatusService({
16
+ ...variables,
17
+ cookie: clientContext.cookie,
18
+ }),
19
+ options
20
+ );
21
+
22
+ return {
23
+ updateContractStatus: mutate,
24
+ isUpdateContractStatusLoading: isLoading,
25
+ hasUpdateContractStatusError: error,
26
+ };
27
+ };
@@ -12,14 +12,20 @@ import {
12
12
  import { useQueryParams } from "../../../shared/hooks";
13
13
  import { GlobalLayout } from "../../../shared/layouts";
14
14
  import { statusFilters } from "../../../shared/utils";
15
+ import { useUpdateContractStatus } from "../../hooks";
16
+ import { useRouter } from "next/router";
15
17
 
16
18
  export type ContractsLayoutProps = {
17
19
  data: ContractData[];
18
20
  };
19
21
 
20
22
  export const ContractsLayout = ({ data }: ContractsLayoutProps) => {
23
+ const route = useRouter();
24
+
21
25
  const { setQueryString, removeQueryString } = useQueryParams();
22
26
 
27
+ const { updateContractStatus } = useUpdateContractStatus();
28
+
23
29
  return (
24
30
  <GlobalLayout>
25
31
  <section data-fs-contracts-section>
@@ -58,15 +64,27 @@ export const ContractsLayout = ({ data }: ContractsLayoutProps) => {
58
64
  {data.map((contract) => (
59
65
  <div key={contract.id}>
60
66
  <div data-fs-contract-row>
61
- <div data-fs-contract-row-information>
67
+ <div
68
+ data-fs-contract-row-information
69
+ onClick={() => {
70
+ route.push(`/profile/${contract.id}`);
71
+ }}
72
+ >
62
73
  <Icon name="Address" width={32} height={32} />
63
- {contract.name}
74
+ {contract.name ?? contract.email}
64
75
  </div>
65
76
  <div data-fs-contract-row-action>
66
77
  <Toggle
67
78
  id="isContractActive"
68
79
  aria-label="is contract active"
69
80
  defaultChecked={contract.isActive}
81
+ onChange={(event) => {
82
+ event.stopPropagation();
83
+ updateContractStatus({
84
+ contractId: contract.id,
85
+ isActive: event.target.checked,
86
+ });
87
+ }}
70
88
  />
71
89
  </div>
72
90
  </div>
@@ -36,6 +36,7 @@
36
36
  gap: var(--fs-spacing-3);
37
37
  margin-left: var(--fs-spacing-3);
38
38
  padding: var(--fs-spacing-2);
39
+ width: 100%;
39
40
 
40
41
  svg {
41
42
  color: #0366dd;
@@ -0,0 +1,16 @@
1
+ import { buyerPortalClient } from "../../../clients/BuyerPortalClient";
2
+
3
+ export const getContractDetailsService = async ({
4
+ contractId,
5
+ cookie,
6
+ }: {
7
+ contractId: string;
8
+ cookie: string;
9
+ }) => {
10
+ const { contract } = await buyerPortalClient.getContractDetails(
11
+ contractId,
12
+ cookie
13
+ );
14
+
15
+ return contract;
16
+ };
@@ -1,8 +1,7 @@
1
1
  import { buyerPortalClient } from "../../../clients/BuyerPortalClient";
2
- import { compareItems, statusFilters } from "../../shared/utils";
3
2
  import type { ContractData } from "../types";
4
3
 
5
- export type GetContractsServiceProps = {
4
+ export type GetContractsByCustomerIdServiceProps = {
6
5
  search?: string;
7
6
  customerId?: string;
8
7
  status?: string;
@@ -10,13 +9,13 @@ export type GetContractsServiceProps = {
10
9
  cookie: string;
11
10
  };
12
11
 
13
- export const getContractsService = async ({
12
+ export const getContractsByCustomerIdService = async ({
14
13
  search = "",
15
14
  customerId,
16
15
  status,
17
16
  sort,
18
17
  cookie,
19
- }: GetContractsServiceProps): Promise<ContractData[]> => {
18
+ }: GetContractsByCustomerIdServiceProps): Promise<ContractData[]> => {
20
19
  const contractsData: ContractData[] = [];
21
20
 
22
21
  if (!customerId) {
@@ -27,21 +26,12 @@ export const getContractsService = async ({
27
26
  const {
28
27
  data: { contracts },
29
28
  } = await buyerPortalClient.getContractsByCustomerId(customerId, cookie);
29
+
30
30
  contractsData.push(...contracts);
31
31
  } catch (err) {
32
32
  console.error("Failed to fetch contracts", err);
33
33
  return contractsData;
34
34
  }
35
35
 
36
- return contractsData
37
- .filter((contract) => {
38
- const matchesName = contract.name
39
- .toLowerCase()
40
- .includes(search.toLowerCase());
41
- const matchesStatus =
42
- !status || contract.isActive === statusFilters[status];
43
-
44
- return matchesName && matchesStatus;
45
- })
46
- .sort((a, b) => compareItems(a, b, sort));
36
+ return contractsData;
47
37
  };
@@ -0,0 +1,40 @@
1
+ import { buyerPortalClient } from "../../../clients/BuyerPortalClient";
2
+ import { compareItems, statusFilters } from "../../shared/utils";
3
+ import type { ContractData } from "../types";
4
+
5
+ export type GetContractsByOrgUnitIdServiceProps = {
6
+ search?: string;
7
+ orgUnitId?: string;
8
+ status?: string;
9
+ sort?: string;
10
+ cookie: string;
11
+ };
12
+
13
+ export const getContractsByOrgUnitIdService = async ({
14
+ search = "",
15
+ orgUnitId,
16
+ status,
17
+ sort,
18
+ cookie,
19
+ }: GetContractsByOrgUnitIdServiceProps): Promise<ContractData[]> => {
20
+ const contractsData: ContractData[] = [];
21
+
22
+ if (!orgUnitId) {
23
+ return contractsData;
24
+ }
25
+
26
+ try {
27
+ const { contracts } = await buyerPortalClient.getContractsByOrgUnitId(
28
+ orgUnitId,
29
+ cookie
30
+ );
31
+ contractsData.push(...contracts);
32
+ } catch (err) {
33
+ console.error("Failed to fetch contracts", err);
34
+ return contractsData;
35
+ }
36
+
37
+ console.log("Contracts Data: ", contractsData);
38
+
39
+ return contractsData;
40
+ };
@@ -1,4 +1,16 @@
1
1
  export {
2
- getContractsService,
3
- type GetContractsServiceProps,
4
- } from "./get-contracts.service";
2
+ getContractsByCustomerIdService,
3
+ type GetContractsByCustomerIdServiceProps,
4
+ } from "./get-contracts-by-customer-id.service";
5
+
6
+ export {
7
+ getContractsByOrgUnitIdService,
8
+ type GetContractsByOrgUnitIdServiceProps,
9
+ } from "./get-contracts-org-by-unit-id.service";
10
+
11
+ export {
12
+ updateContractStatusService,
13
+ UpdateContractStatusServiceProps,
14
+ } from "./update-contract-status.service";
15
+
16
+ export { getContractDetailsService } from "./get-contract-details.service";
@@ -0,0 +1,25 @@
1
+ import { buyerPortalClient } from "../../../clients/BuyerPortalClient";
2
+
3
+ export type UpdateContractStatusServiceProps = {
4
+ contractId: string;
5
+ isActive: boolean;
6
+ cookie: string;
7
+ };
8
+
9
+ export const updateContractStatusService = async ({
10
+ contractId,
11
+ isActive,
12
+ cookie,
13
+ }: UpdateContractStatusServiceProps): Promise<null> => {
14
+ try {
15
+ const data = await buyerPortalClient.updateContractStatus(
16
+ { contractId, isActive },
17
+ cookie
18
+ );
19
+ } catch (err) {
20
+ console.error("Failed to fetch contracts", err);
21
+ return null;
22
+ }
23
+
24
+ return null;
25
+ };
@@ -1,5 +1,5 @@
1
1
  export type ContractData = {
2
- name: string;
2
+ name: string | null;
3
3
  id: string;
4
4
  email: string;
5
5
  isActive: boolean;
@@ -1,16 +1,11 @@
1
1
  import { BasicCard } from "../../../shared/components";
2
2
 
3
3
  type ProfileCardProps = {
4
- name: string;
4
+ name: string | null;
5
5
  email: string;
6
6
  id: string;
7
7
 
8
8
  imageUrl?: string;
9
-
10
- orgUnitData?: {
11
- id: string | null;
12
- name: string;
13
- };
14
9
  };
15
10
 
16
11
  export default function ProfileCard({
@@ -18,11 +13,10 @@ export default function ProfileCard({
18
13
  email,
19
14
  id,
20
15
  imageUrl,
21
- orgUnitData,
22
16
  }: ProfileCardProps) {
23
17
  return (
24
18
  <BasicCard
25
- footerLink={`/profile${orgUnitData?.id ? `/${orgUnitData.id}` : ""}`}
19
+ footerLink={`/profile/${id}`}
26
20
  footerMessage="View profile"
27
21
  title="Profile"
28
22
  >
@@ -22,12 +22,16 @@ export const ProfileLayout = ({ data }: ProfileLayoutProps) => {
22
22
  {data && (
23
23
  <div data-fs-bp-profile-details>
24
24
  <span data-fs-bp-profile-details-title>Details</span>
25
- <hr data-fs-bp-profile-divider />
26
25
 
27
- <div data-fs-bp-profile-details-row>
28
- <span data-fs-bp-profile-details-row-label>Name</span>
29
- <span data-fs-bp-profile-details-row-value>{data.name}</span>
30
- </div>
26
+ {!!data.name && (
27
+ <>
28
+ <hr data-fs-bp-profile-divider />
29
+ <div data-fs-bp-profile-details-row>
30
+ <span data-fs-bp-profile-details-row-label>Name</span>
31
+ <span data-fs-bp-profile-details-row-value>{data.name}</span>
32
+ </div>
33
+ </>
34
+ )}
31
35
 
32
36
  <hr data-fs-bp-profile-divider />
33
37
 
@@ -13,7 +13,7 @@
13
13
 
14
14
  display: flex;
15
15
  justify-content: space-between;
16
- padding: var(--fs-spacing-4);
16
+ padding: var(--fs-spacing-4) 0;
17
17
  align-items: center;
18
18
  }
19
19
 
@@ -13,6 +13,7 @@ export type BasicCardProps = {
13
13
  footerMessage: string;
14
14
  footerLink: string;
15
15
  onPlusIconClick?: () => void;
16
+ icon?: ReactNode;
16
17
  };
17
18
 
18
19
  export const BasicCard = ({
@@ -22,6 +23,7 @@ export const BasicCard = ({
22
23
  onPlusIconClick,
23
24
  footerMessage,
24
25
  footerLink,
26
+ icon,
25
27
  }: BasicCardProps) => {
26
28
  const { push } = useRouter();
27
29
 
@@ -36,7 +38,7 @@ export const BasicCard = ({
36
38
  </div>
37
39
  {onPlusIconClick && (
38
40
  <IconButton
39
- icon={<UIIcon name="PlusCircle" width={20} height={20} />}
41
+ icon={icon ?? <UIIcon name="PlusCircle" width={20} height={20} />}
40
42
  aria-label={"addresses action"}
41
43
  onClick={onPlusIconClick}
42
44
  />
@@ -1,6 +1,21 @@
1
1
  import { AUT_COOKIE_KEY } from "./constants";
2
2
  import storeConfig from "discovery.config";
3
- import { LoaderData } from "../types/LoaderData";
3
+ import type { LoaderData } from "../types/LoaderData";
4
+
5
+ export interface ParsedCookie {
6
+ sub: string;
7
+ account: string;
8
+ audience: string;
9
+ sess: string;
10
+ exp: number;
11
+ type: string;
12
+ userId: string;
13
+ iat: number;
14
+ customerId: string;
15
+ isRepresentative: boolean;
16
+ iss: string;
17
+ jti: string;
18
+ }
4
19
 
5
20
  export function getAuthCookie(data: LoaderData) {
6
21
  const authCookie =
@@ -9,22 +24,32 @@ export function getAuthCookie(data: LoaderData) {
9
24
  return authCookie;
10
25
  }
11
26
 
12
- export function getCustomerIdFromCookieServerSide(data: LoaderData) {
27
+ export function getParsedJWT(data: LoaderData): ParsedCookie | "" {
13
28
  const authCookie = getAuthCookie(data);
14
29
 
15
30
  if (!authCookie || authCookie === "") {
16
31
  return "";
17
32
  }
18
33
 
19
- const parsedCookie = parseJwt(authCookie);
34
+ return parseJwt(authCookie);
35
+ }
36
+
37
+ export function getCustomerIdFromCookieServerSide(data: LoaderData): string {
38
+ const parsedCookie = getParsedJWT(data);
39
+
40
+ return parsedCookie ? String(parsedCookie.customerId) : "";
41
+ }
42
+
43
+ export function getUserIdFromCookieServerSide(data: LoaderData): string {
44
+ const parsedCookie = getParsedJWT(data);
20
45
 
21
- return String(parsedCookie.customerId)
46
+ return parsedCookie ? String(parsedCookie.userId) : "";
22
47
  }
23
48
 
24
- export function getCookieAsString(cookie: Record<string, string>) {
49
+ export function getCookieAsString(cookie: Record<string, string>): string {
25
50
  return JSON.stringify(cookie).replace(/[{}]/g, "") ?? "";
26
51
  }
27
52
 
28
- function parseJwt(token: string) {
53
+ function parseJwt(token: string): ParsedCookie {
29
54
  return JSON.parse(Buffer.from(token.split(".")[1], "base64").toString());
30
55
  }
@@ -5,12 +5,14 @@ import {
5
5
  getAuthCookie,
6
6
  getCookieAsString,
7
7
  getCustomerIdFromCookieServerSide,
8
+ getUserIdFromCookieServerSide,
8
9
  } from "./cookie";
9
10
 
10
11
  export type ClientContext = {
11
12
  vtexIdclientAutCookie: string;
12
13
  cookie: string;
13
14
  customerId: string;
15
+ userId: string;
14
16
  orgUnit?: OrgUnitBasicData | null;
15
17
  };
16
18
 
@@ -32,6 +34,7 @@ export const getClientContext = async ({
32
34
  }),
33
35
  cookie,
34
36
  customerId: getCustomerIdFromCookieServerSide({ req }),
37
+ userId: getUserIdFromCookieServerSide({ req }),
35
38
  orgUnit: orgUnitId
36
39
  ? await getOrgUnitBasicData({ id: orgUnitId, cookie })
37
40
  : null,
@@ -1,6 +1,9 @@
1
1
  import { type ClientContext, getClientContext } from "../features/shared/utils";
2
2
  import { ContractsLayout } from "../features/contracts/layouts";
3
- import { getContractsService } from "../features/contracts/services";
3
+ import {
4
+ getContractsByCustomerIdService,
5
+ getContractsByOrgUnitIdService,
6
+ } from "../features/contracts/services";
4
7
  import type { ContractData } from "../features/contracts/types";
5
8
  import { BuyerPortalProvider } from "../features/shared/components";
6
9
  import type { LoaderData } from "../features/shared/types";
@@ -21,7 +24,9 @@ export async function loader(
21
24
  await getClientContext(data);
22
25
 
23
26
  return {
24
- data: orgUnit ? [] : await getContractsService({ customerId, cookie }),
27
+ data: orgUnit
28
+ ? await getContractsByOrgUnitIdService({ orgUnitId: orgUnit.id, cookie })
29
+ : await getContractsByCustomerIdService({ customerId, cookie }),
25
30
  clientContext: { customerId, cookie, orgUnit, ...clientContext },
26
31
  };
27
32
  }
@@ -23,7 +23,8 @@ export async function loader(
23
23
  return {
24
24
  data: orgUnit
25
25
  ? { organizationalUnits: [], total: 0 }
26
- : await getRootOrgUnitByCustomerIdService({ customerId }, cookie),
26
+ : // TODO: Implement Pegar org unit baseado no usuario
27
+ await getRootOrgUnitByCustomerIdService({ customerId }, cookie),
27
28
  clientContext: { cookie, customerId, orgUnit, ...clientContext },
28
29
  };
29
30
  }
@@ -1,4 +1,5 @@
1
- import { getContractsService } from "../features/contracts/services/get-contracts.service";
1
+ import { getContractDetailsService } from "../features/contracts/services";
2
+ import { getContractsByCustomerIdService } from "../features/contracts/services/get-contracts-by-customer-id.service";
2
3
  import type { ContractData } from "../features/contracts/types";
3
4
  import { ProfileLayout } from "../features/profile/layouts";
4
5
  import { BuyerPortalProvider } from "../features/shared/components";
@@ -15,21 +16,32 @@ export type ProfilePageData = {
15
16
  };
16
17
 
17
18
  export type ProfilePageQuery = {
18
- orgUnitId?: string[];
19
+ contractId?: string[];
19
20
  };
20
21
 
21
22
  export async function loader(
22
23
  data: LoaderData<ProfilePageQuery>
23
24
  ): Promise<ProfilePageData> {
24
- const contracts = await getContractsService({
25
- customerId: getCustomerIdFromCookieServerSide(data),
26
- cookie: JSON.stringify(data?.req?.cookies).replace(/[{}]/g, ""),
27
- });
25
+ const { customerId, cookie, ...clientContext } = await getClientContext(data);
26
+
27
+ const contractId = data.query.contractId?.[0];
28
+
29
+ const contract = contractId
30
+ ? await getContractDetailsService({
31
+ contractId,
32
+ cookie,
33
+ })
34
+ : (
35
+ await getContractsByCustomerIdService({
36
+ customerId,
37
+ cookie,
38
+ })
39
+ )[0];
28
40
 
29
41
  // We should deal with a better error boundary here later, this is just so an empty array doesn't break the render
30
42
  return {
31
- data: contracts?.length ? contracts[0] : null,
32
- clientContext: await getClientContext(data),
43
+ data: contract,
44
+ clientContext: { customerId, cookie, ...clientContext },
33
45
  };
34
46
  }
35
47