@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.
- package/package.json +1 -1
- package/plugin.config.js +4 -4
- package/src/clients/BuyerPortalClient.ts +38 -1
- package/src/features/contracts/components/ContractsCard/ContractsCard.tsx +18 -19
- package/src/features/contracts/hooks/index.ts +1 -0
- package/src/features/contracts/hooks/useUpdateContractStatus.ts +27 -0
- package/src/features/contracts/layouts/ContractsLayout/ContractsLayout.tsx +20 -2
- package/src/features/contracts/layouts/ContractsLayout/contracts-layout.scss +1 -0
- package/src/features/contracts/services/get-contract-details.service.ts +16 -0
- package/src/features/contracts/services/{get-contracts.service.ts → get-contracts-by-customer-id.service.ts} +5 -15
- package/src/features/contracts/services/get-contracts-org-by-unit-id.service.ts +40 -0
- package/src/features/contracts/services/index.ts +15 -3
- package/src/features/contracts/services/update-contract-status.service.ts +25 -0
- package/src/features/contracts/types/ContractData.ts +1 -1
- package/src/features/profile/components/ProfileCard/ProfileCard.tsx +2 -8
- package/src/features/profile/layouts/ProfileLayout/ProfileLayout.tsx +9 -5
- package/src/features/profile/layouts/ProfileLayout/profile-layout.scss +1 -1
- package/src/features/shared/components/BasicCard/BasicCard.tsx +3 -1
- package/src/features/shared/utils/cookie.ts +31 -6
- package/src/features/shared/utils/getClientContext.ts +3 -0
- package/src/pages/contracts.tsx +7 -2
- package/src/pages/org-units.tsx +2 -1
- package/src/pages/profile.tsx +20 -8
package/package.json
CHANGED
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
|
|
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>
|
|
@@ -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
|
|
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
|
|
12
|
+
export const getContractsByCustomerIdService = async ({
|
|
14
13
|
search = "",
|
|
15
14
|
customerId,
|
|
16
15
|
status,
|
|
17
16
|
sort,
|
|
18
17
|
cookie,
|
|
19
|
-
}:
|
|
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
|
-
|
|
3
|
-
type
|
|
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,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
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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,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
|
|
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
|
-
|
|
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.
|
|
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,
|
package/src/pages/contracts.tsx
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type ClientContext, getClientContext } from "../features/shared/utils";
|
|
2
2
|
import { ContractsLayout } from "../features/contracts/layouts";
|
|
3
|
-
import {
|
|
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
|
|
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
|
}
|
package/src/pages/org-units.tsx
CHANGED
|
@@ -23,7 +23,8 @@ export async function loader(
|
|
|
23
23
|
return {
|
|
24
24
|
data: orgUnit
|
|
25
25
|
? { organizationalUnits: [], total: 0 }
|
|
26
|
-
:
|
|
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
|
}
|
package/src/pages/profile.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
19
|
+
contractId?: string[];
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
export async function loader(
|
|
22
23
|
data: LoaderData<ProfilePageQuery>
|
|
23
24
|
): Promise<ProfilePageData> {
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
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:
|
|
32
|
-
clientContext:
|
|
43
|
+
data: contract,
|
|
44
|
+
clientContext: { customerId, cookie, ...clientContext },
|
|
33
45
|
};
|
|
34
46
|
}
|
|
35
47
|
|