@vtex/faststore-plugin-buyer-portal 1.1.115 → 1.1.116-poc
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/src/features/addresses/layouts/AddressDetailsLayout/AddressDetailsLayout.tsx +1 -0
- package/src/features/addresses/layouts/AddressesLayout/AddressesLayout.tsx +1 -0
- package/src/features/budgets/layouts/BudgetsDetailsLayout/BudgetsDetailsLayout.tsx +1 -0
- package/src/features/collections/layouts/CollectionsLayout/CollectionsLayout.tsx +1 -0
- package/src/features/contracts/hooks/index.ts +2 -0
- package/src/features/contracts/hooks/useContractDetails.ts +22 -0
- package/src/features/contracts/hooks/useContractsByOrgUnitId.ts +20 -0
- package/src/features/credit-cards/layouts/CreditCardsLayout/CreditCardLayout.tsx +1 -0
- package/src/features/custom-fields/layouts/CustomFieldsLayout/CustomFieldsLayout.tsx +1 -0
- package/src/features/org-units/hooks/index.ts +1 -0
- package/src/features/org-units/hooks/useOrgUnitBasicData.ts +20 -0
- package/src/features/org-units/layouts/OrgUnitDetailsLayout/OrgUnitDetailsLayout.tsx +31 -28
- package/src/features/payment-methods/layouts/PaymentMethodsLayout/PaymentMethodsLayout.tsx +1 -0
- package/src/features/profile/layouts/ProfileLayout/ProfileLayout.tsx +33 -16
- package/src/features/shared/components/withErrorBoundary/withErrorBoundary.tsx +6 -7
- package/src/features/shared/hooks/useCookieMonitor.ts +2 -6
- package/src/features/shared/layouts/ContractTabsLayout/ContractTabsLayout.tsx +6 -4
- package/src/features/shared/layouts/ErrorTabsLayout/ErrorTabsLayout.tsx +1 -0
- package/src/features/shared/layouts/LoadingTabsLayout/LoadingTabsLayout.tsx +2 -27
- package/src/features/shared/types/AuthRouteProps.ts +2 -8
- package/src/features/shared/utils/withAuth.tsx +10 -62
- package/src/features/shared/utils/withAuthLoader.ts +0 -28
- package/src/features/shared/utils/withAuthProvider.tsx +11 -81
- package/src/pages/org-unit-details.tsx +9 -61
- package/src/pages/profile.tsx +28 -71
package/package.json
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type QueryOptions, useQuery } from "../../shared/hooks";
|
|
2
|
+
import { getContractDetailsService } from "../services";
|
|
3
|
+
|
|
4
|
+
export const useContractDetails = (
|
|
5
|
+
contractId: string,
|
|
6
|
+
unitId: string,
|
|
7
|
+
options?: QueryOptions<AwaitedType<typeof getContractDetailsService>>
|
|
8
|
+
) => {
|
|
9
|
+
const { data, error, isLoading, refetch } = useQuery(
|
|
10
|
+
`api/contract-details/${unitId}`,
|
|
11
|
+
({ cookie }) =>
|
|
12
|
+
getContractDetailsService({ contractId, cookie, unitId: unitId }),
|
|
13
|
+
options
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
contract: data,
|
|
18
|
+
hasContractError: error,
|
|
19
|
+
isContractLoading: isLoading,
|
|
20
|
+
refetchContract: refetch,
|
|
21
|
+
};
|
|
22
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type QueryOptions, useQuery } from "../../shared/hooks";
|
|
2
|
+
import { getContractsByOrgUnitIdService } from "../services";
|
|
3
|
+
|
|
4
|
+
export const useContractsByOrgUnitId = (
|
|
5
|
+
orgUnitId: string,
|
|
6
|
+
options?: QueryOptions<AwaitedType<typeof getContractsByOrgUnitIdService>>
|
|
7
|
+
) => {
|
|
8
|
+
const { data, error, isLoading, refetch } = useQuery(
|
|
9
|
+
`api/contracts-by-org-unit-id/${orgUnitId}`,
|
|
10
|
+
({ cookie }) => getContractsByOrgUnitIdService({ orgUnitId, cookie }),
|
|
11
|
+
options
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
contracts: data ?? [],
|
|
16
|
+
hasContractsError: error,
|
|
17
|
+
isContractsLoading: isLoading,
|
|
18
|
+
refetchContracts: refetch,
|
|
19
|
+
};
|
|
20
|
+
};
|
|
@@ -5,3 +5,4 @@ export { useUpdateOrgUnit } from "./useUpdateOrgUnit";
|
|
|
5
5
|
export { useChildrenOrgUnits } from "./useChildrenOrgUnits";
|
|
6
6
|
export { useOrgUnitByUser } from "./useOrgUnitByUser";
|
|
7
7
|
export { useSearchOrgUnits } from "./useSearchOrgUnits";
|
|
8
|
+
export { useOrgUnitBasicData } from "./useOrgUnitBasicData";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type QueryOptions, useQuery } from "../../shared/hooks";
|
|
2
|
+
import { getOrgUnitBasicDataService } from "../services";
|
|
3
|
+
|
|
4
|
+
export const useOrgUnitBasicData = (
|
|
5
|
+
id: string,
|
|
6
|
+
options?: QueryOptions<AwaitedType<typeof getOrgUnitBasicDataService>>
|
|
7
|
+
) => {
|
|
8
|
+
const { data, error, isLoading, refetch } = useQuery(
|
|
9
|
+
`api/org-unit-basic-data/${id}`,
|
|
10
|
+
({ cookie }) => getOrgUnitBasicDataService({ id, cookie }),
|
|
11
|
+
options
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
orgUnit: data,
|
|
16
|
+
hasOrgUnitError: error,
|
|
17
|
+
isOrgUnitLoading: isLoading,
|
|
18
|
+
refetchOrgUnit: refetch,
|
|
19
|
+
};
|
|
20
|
+
};
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
Skeleton,
|
|
6
6
|
} from "@faststore/ui";
|
|
7
7
|
|
|
8
|
+
import { useContractsByOrgUnitId } from "../../../contracts/hooks";
|
|
8
9
|
import {
|
|
9
10
|
BasicCard,
|
|
10
11
|
BasicDropdownMenu,
|
|
@@ -21,13 +22,14 @@ import {
|
|
|
21
22
|
getOrganizationSettingsLinks,
|
|
22
23
|
} from "../../../shared/utils";
|
|
23
24
|
import { buyerPortalRoutes } from "../../../shared/utils/buyerPortalRoutes";
|
|
25
|
+
import { useGetUserById } from "../../../users/hooks";
|
|
24
26
|
import {
|
|
25
27
|
AddAllToOrgUnitDropdown,
|
|
26
28
|
OrgUnitBreadcrumb,
|
|
27
29
|
OrgUnitDetailsNavbar,
|
|
28
30
|
OrgUnitsDropdownMenu,
|
|
29
31
|
} from "../../components";
|
|
30
|
-
import { useOrgUnitByUser } from "../../hooks";
|
|
32
|
+
import { useOrgUnitBasicData, useOrgUnitByUser } from "../../hooks";
|
|
31
33
|
|
|
32
34
|
import {
|
|
33
35
|
MAX_DESKTOP_BREADCRUMB_ITEMS,
|
|
@@ -35,28 +37,29 @@ import {
|
|
|
35
37
|
QUERY_TABLET,
|
|
36
38
|
} from "./utils";
|
|
37
39
|
|
|
38
|
-
import type { ContractData } from "../../../contracts/types";
|
|
39
|
-
import type { UserData } from "../../../users/types";
|
|
40
|
-
import type { OrgUnitBasicData } from "../../types";
|
|
41
|
-
|
|
42
40
|
export type OrgUnitsDetailsLayoutProps = {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
contracts: ContractData[];
|
|
46
|
-
user: UserData | null;
|
|
47
|
-
};
|
|
41
|
+
orgUnitId: string;
|
|
42
|
+
userId: string;
|
|
48
43
|
loading?: boolean;
|
|
49
44
|
};
|
|
50
45
|
|
|
51
46
|
export const OrgUnitsDetailsLayout = ({
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
orgUnitId,
|
|
48
|
+
userId,
|
|
49
|
+
loading = true,
|
|
54
50
|
}: OrgUnitsDetailsLayoutProps) => {
|
|
51
|
+
const { orgUnit, isOrgUnitLoading } = useOrgUnitBasicData(orgUnitId);
|
|
52
|
+
|
|
53
|
+
const { contracts, isContractsLoading } = useContractsByOrgUnitId(orgUnitId);
|
|
54
|
+
|
|
55
|
+
const { user, isUserLoading } = useGetUserById({ orgUnitId, userId });
|
|
56
|
+
|
|
57
|
+
loading = isOrgUnitLoading || isContractsLoading || isUserLoading;
|
|
55
58
|
const isMobile = useMediaQuery(QUERY_TABLET);
|
|
56
59
|
|
|
57
60
|
const isSingleContract = contracts.length <= 1;
|
|
58
61
|
|
|
59
|
-
const { orgUnit: userUnit } = useOrgUnitByUser(
|
|
62
|
+
const { orgUnit: userUnit } = useOrgUnitByUser(userId);
|
|
60
63
|
|
|
61
64
|
const orgUnitList = orgUnit?.path.ids.split("/").slice(1) ?? [];
|
|
62
65
|
|
|
@@ -67,7 +70,7 @@ export const OrgUnitsDetailsLayout = ({
|
|
|
67
70
|
const breadcrumbList = orgUnitList.map((orgUnitId, index) => ({
|
|
68
71
|
unitId: orgUnitId,
|
|
69
72
|
item: buyerPortalRoutes.orgUnitDetails({ orgUnitId }),
|
|
70
|
-
name: orgUnit
|
|
73
|
+
name: orgUnit?.path.names.split("/")[index] ?? "",
|
|
71
74
|
position: index + 1,
|
|
72
75
|
enabled: index >= userUnitIndex,
|
|
73
76
|
}));
|
|
@@ -76,7 +79,7 @@ export const OrgUnitsDetailsLayout = ({
|
|
|
76
79
|
<GlobalLayout>
|
|
77
80
|
{/* TODO: Add person here */}
|
|
78
81
|
<OrgUnitDetailsNavbar
|
|
79
|
-
orgName={orgUnit
|
|
82
|
+
orgName={orgUnit?.name ?? ""}
|
|
80
83
|
person={{
|
|
81
84
|
name: user?.name ?? "",
|
|
82
85
|
role: user?.roles?.[0] ?? "",
|
|
@@ -107,8 +110,8 @@ export const OrgUnitsDetailsLayout = ({
|
|
|
107
110
|
<BasicDropdownMenu.Trigger />
|
|
108
111
|
<OrgUnitsDropdownMenu
|
|
109
112
|
isComplete={false}
|
|
110
|
-
id={
|
|
111
|
-
name={orgUnit
|
|
113
|
+
id={orgUnitId}
|
|
114
|
+
name={orgUnit?.name ?? ""}
|
|
112
115
|
/>
|
|
113
116
|
</Dropdown>
|
|
114
117
|
<Dropdown>
|
|
@@ -118,8 +121,8 @@ export const OrgUnitsDetailsLayout = ({
|
|
|
118
121
|
<AddAllToOrgUnitDropdown
|
|
119
122
|
isSingleContract={isSingleContract}
|
|
120
123
|
contractId={contracts[0]?.id}
|
|
121
|
-
unitId={
|
|
122
|
-
unitName={orgUnit?.name}
|
|
124
|
+
unitId={orgUnitId}
|
|
125
|
+
unitName={orgUnit?.name ?? ""}
|
|
123
126
|
/>
|
|
124
127
|
</Dropdown>
|
|
125
128
|
</HeaderInside>
|
|
@@ -129,13 +132,13 @@ export const OrgUnitsDetailsLayout = ({
|
|
|
129
132
|
data-fs-bp-contracts-settings-card
|
|
130
133
|
footerMessage="Manage contract settings"
|
|
131
134
|
footerLink={buyerPortalRoutes.profileDetails({
|
|
132
|
-
orgUnitId:
|
|
135
|
+
orgUnitId: orgUnitId,
|
|
133
136
|
contractId: contracts[0]?.id ?? "",
|
|
134
137
|
})}
|
|
135
138
|
enableFooter
|
|
136
139
|
>
|
|
137
|
-
<LetterHighlight letter={orgUnit
|
|
138
|
-
<VerticalNav.Menu title={orgUnit
|
|
140
|
+
<LetterHighlight letter={orgUnit?.name?.[0] ?? ""} />
|
|
141
|
+
<VerticalNav.Menu title={orgUnit?.name ?? ""} loading={loading}>
|
|
139
142
|
{loading
|
|
140
143
|
? Array(8)
|
|
141
144
|
.fill(null)
|
|
@@ -150,7 +153,7 @@ export const OrgUnitsDetailsLayout = ({
|
|
|
150
153
|
</li>
|
|
151
154
|
))
|
|
152
155
|
: getContractSettingsLinks({
|
|
153
|
-
orgUnitId:
|
|
156
|
+
orgUnitId: orgUnitId,
|
|
154
157
|
contractId: contracts[0]?.id ?? "",
|
|
155
158
|
}).map(({ name, link }) => (
|
|
156
159
|
<VerticalNav.Link key={name} link={link}>
|
|
@@ -177,7 +180,7 @@ export const OrgUnitsDetailsLayout = ({
|
|
|
177
180
|
/>
|
|
178
181
|
}
|
|
179
182
|
href={buyerPortalRoutes.profileDetails({
|
|
180
|
-
orgUnitId:
|
|
183
|
+
orgUnitId: orgUnitId,
|
|
181
184
|
contractId: contract.id,
|
|
182
185
|
})}
|
|
183
186
|
menu={
|
|
@@ -196,12 +199,12 @@ export const OrgUnitsDetailsLayout = ({
|
|
|
196
199
|
data-fs-bp-organizations-settings-card
|
|
197
200
|
footerMessage="Manage organization settings"
|
|
198
201
|
footerLink={buyerPortalRoutes.users({
|
|
199
|
-
orgUnitId:
|
|
202
|
+
orgUnitId: orgUnitId,
|
|
200
203
|
})}
|
|
201
204
|
enableFooter
|
|
202
205
|
>
|
|
203
206
|
<VerticalNav.Menu title="Organization">
|
|
204
|
-
{getOrganizationSettingsLinks(
|
|
207
|
+
{getOrganizationSettingsLinks(orgUnitId).map((option) => (
|
|
205
208
|
<VerticalNav.Link key={option.name} link={option.link}>
|
|
206
209
|
{option.name}
|
|
207
210
|
</VerticalNav.Link>
|
|
@@ -212,14 +215,14 @@ export const OrgUnitsDetailsLayout = ({
|
|
|
212
215
|
data-fs-bp-compliance-settings-card
|
|
213
216
|
footerMessage="Manage finance and compliance settings"
|
|
214
217
|
footerLink={buyerPortalRoutes.buyingPolicies({
|
|
215
|
-
orgUnitId:
|
|
218
|
+
orgUnitId: orgUnitId,
|
|
216
219
|
contractId: contracts[0]?.id,
|
|
217
220
|
})}
|
|
218
221
|
enableFooter
|
|
219
222
|
>
|
|
220
223
|
<VerticalNav.Menu title="Finance and Compliance">
|
|
221
224
|
{getFinanceSettingsLinks({
|
|
222
|
-
orgUnitId:
|
|
225
|
+
orgUnitId: orgUnitId,
|
|
223
226
|
contractId: contracts[0]?.id ?? "",
|
|
224
227
|
}).map((option) => (
|
|
225
228
|
<VerticalNav.Link key={option.name} link={option.link}>
|
|
@@ -1,18 +1,33 @@
|
|
|
1
|
+
import { useContractDetails } from "../../../contracts/hooks";
|
|
2
|
+
import { useOrgUnitBasicData } from "../../../org-units/hooks";
|
|
1
3
|
import { HeaderInside } from "../../../shared/components";
|
|
2
|
-
import { useBuyerPortal } from "../../../shared/hooks";
|
|
3
4
|
import { GlobalLayout, ContractTabsLayout } from "../../../shared/layouts";
|
|
4
|
-
|
|
5
|
-
import type { ContractData } from "../../../contracts/types";
|
|
5
|
+
import { useGetUserById } from "../../../users/hooks";
|
|
6
6
|
|
|
7
7
|
export type ProfileLayoutProps = {
|
|
8
|
-
|
|
8
|
+
orgUnitId: string;
|
|
9
|
+
contractId: string;
|
|
10
|
+
userId: string;
|
|
9
11
|
};
|
|
10
12
|
|
|
11
|
-
export const ProfileLayout = ({
|
|
12
|
-
|
|
13
|
+
export const ProfileLayout = ({
|
|
14
|
+
orgUnitId,
|
|
15
|
+
contractId,
|
|
16
|
+
userId,
|
|
17
|
+
}: ProfileLayoutProps) => {
|
|
18
|
+
const { orgUnit, isOrgUnitLoading } = useOrgUnitBasicData(orgUnitId);
|
|
19
|
+
|
|
20
|
+
const { contract, isContractLoading } = useContractDetails(
|
|
21
|
+
contractId,
|
|
22
|
+
orgUnitId
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const { user, isUserLoading } = useGetUserById({ orgUnitId, userId });
|
|
26
|
+
|
|
27
|
+
const loading = isContractLoading || isOrgUnitLoading || isUserLoading;
|
|
13
28
|
|
|
14
|
-
const creationDate =
|
|
15
|
-
? new Date(
|
|
29
|
+
const creationDate = contract
|
|
30
|
+
? new Date(contract.creationDate).toLocaleDateString("en-US", {
|
|
16
31
|
year: "numeric",
|
|
17
32
|
month: "long",
|
|
18
33
|
day: "numeric",
|
|
@@ -23,30 +38,32 @@ export const ProfileLayout = ({ data }: ProfileLayoutProps) => {
|
|
|
23
38
|
<GlobalLayout>
|
|
24
39
|
<ContractTabsLayout
|
|
25
40
|
orgUnitName={orgUnit?.name ?? ""}
|
|
26
|
-
orgUnitId={
|
|
27
|
-
contractName={
|
|
28
|
-
contractId={
|
|
41
|
+
orgUnitId={orgUnitId}
|
|
42
|
+
contractName={contract?.name ?? ""}
|
|
43
|
+
contractId={contract?.id ?? ""}
|
|
29
44
|
pageName="Contract"
|
|
30
45
|
person={{
|
|
31
46
|
image: undefined,
|
|
32
47
|
name: user?.name ?? "",
|
|
33
|
-
role: user?.
|
|
48
|
+
role: user?.roles?.[0] ?? "",
|
|
49
|
+
id: userId,
|
|
34
50
|
}}
|
|
51
|
+
loading={loading}
|
|
35
52
|
>
|
|
36
53
|
<section data-fs-bp-profile>
|
|
37
54
|
<HeaderInside title="Profile" />
|
|
38
55
|
|
|
39
|
-
{
|
|
56
|
+
{contract && (
|
|
40
57
|
<div data-fs-bp-profile-details>
|
|
41
58
|
<span data-fs-bp-profile-details-title>Details</span>
|
|
42
59
|
|
|
43
|
-
{!!
|
|
60
|
+
{!!contract.name && (
|
|
44
61
|
<>
|
|
45
62
|
<hr data-fs-bp-profile-divider />
|
|
46
63
|
<div data-fs-bp-profile-details-row>
|
|
47
64
|
<span data-fs-bp-profile-details-row-label>Name</span>
|
|
48
65
|
<span data-fs-bp-profile-details-row-value>
|
|
49
|
-
{
|
|
66
|
+
{contract.name}
|
|
50
67
|
</span>
|
|
51
68
|
</div>
|
|
52
69
|
</>
|
|
@@ -57,7 +74,7 @@ export const ProfileLayout = ({ data }: ProfileLayoutProps) => {
|
|
|
57
74
|
<div data-fs-bp-profile-details-row>
|
|
58
75
|
<span data-fs-bp-profile-details-row-label>Email</span>
|
|
59
76
|
<span data-fs-bp-profile-details-row-value>
|
|
60
|
-
<a href={`mailto:${
|
|
77
|
+
<a href={`mailto:${contract.email}`}>{contract.email}</a>
|
|
61
78
|
</span>
|
|
62
79
|
</div>
|
|
63
80
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import React from "react";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
import { ErrorBoundary } from "../ErrorBoundary/ErrorBoundary";
|
|
6
6
|
|
|
7
7
|
type WithErrorBoundaryOptions = {
|
|
8
8
|
fallback?: React.ReactNode;
|
|
@@ -15,16 +15,15 @@ type WithErrorBoundaryOptions = {
|
|
|
15
15
|
|
|
16
16
|
export function withErrorBoundary<P extends Record<string, unknown>>(
|
|
17
17
|
WrappedComponent: React.ComponentType<P>,
|
|
18
|
-
|
|
19
|
-
_options: WithErrorBoundaryOptions = {}
|
|
18
|
+
options: WithErrorBoundaryOptions = {}
|
|
20
19
|
) {
|
|
21
|
-
|
|
20
|
+
const { onError, tags } = options;
|
|
22
21
|
|
|
23
22
|
const ComponentWithErrorBoundary = (props: P) => {
|
|
24
23
|
return (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
<ErrorBoundary onError={onError} tags={tags}>
|
|
25
|
+
<WrappedComponent {...props} />
|
|
26
|
+
</ErrorBoundary>
|
|
28
27
|
);
|
|
29
28
|
};
|
|
30
29
|
|
|
@@ -12,7 +12,6 @@ import { AUT_COOKIE_KEY } from "../utils/constants";
|
|
|
12
12
|
*/
|
|
13
13
|
export const useCookieMonitor = () => {
|
|
14
14
|
const [hasCookie, setHasCookie] = useState(false);
|
|
15
|
-
const [timedOut, setTimedOut] = useState(false);
|
|
16
15
|
|
|
17
16
|
useEffect(() => {
|
|
18
17
|
const checkCookie = () => {
|
|
@@ -59,10 +58,7 @@ export const useCookieMonitor = () => {
|
|
|
59
58
|
|
|
60
59
|
// Cleanup after 5 seconds max
|
|
61
60
|
const timeout = setTimeout(() => {
|
|
62
|
-
console.log(
|
|
63
|
-
"[useCookieMonitor] Polling timeout reached (5s) - cookie never appeared"
|
|
64
|
-
);
|
|
65
|
-
setTimedOut(true);
|
|
61
|
+
console.log("[useCookieMonitor] Polling timeout reached (5s)");
|
|
66
62
|
clearInterval(interval);
|
|
67
63
|
}, 5000);
|
|
68
64
|
|
|
@@ -73,5 +69,5 @@ export const useCookieMonitor = () => {
|
|
|
73
69
|
}
|
|
74
70
|
}, []);
|
|
75
71
|
|
|
76
|
-
return
|
|
72
|
+
return hasCookie;
|
|
77
73
|
};
|
|
@@ -18,6 +18,7 @@ export type ContractTabsLayoutProps = {
|
|
|
18
18
|
image?: ReactNode;
|
|
19
19
|
name: string;
|
|
20
20
|
role?: string;
|
|
21
|
+
id: string;
|
|
21
22
|
};
|
|
22
23
|
loading?: boolean;
|
|
23
24
|
children?: ReactNode;
|
|
@@ -29,8 +30,9 @@ export const ContractTabsLayout = ({
|
|
|
29
30
|
children,
|
|
30
31
|
orgUnitId,
|
|
31
32
|
contractId,
|
|
33
|
+
person,
|
|
32
34
|
}: ContractTabsLayoutProps) => {
|
|
33
|
-
const { currentOrgUnit,
|
|
35
|
+
const { currentOrgUnit, currentContract } = useBuyerPortal();
|
|
34
36
|
|
|
35
37
|
const verticalLinks = getContractSettingsLinks({
|
|
36
38
|
contractId: currentContract?.id ?? contractId ?? "",
|
|
@@ -43,9 +45,9 @@ export const ContractTabsLayout = ({
|
|
|
43
45
|
orgUnit={currentOrgUnit}
|
|
44
46
|
pageName={pageName}
|
|
45
47
|
person={{
|
|
46
|
-
name:
|
|
47
|
-
role:
|
|
48
|
-
id:
|
|
48
|
+
name: person.name,
|
|
49
|
+
role: person.role,
|
|
50
|
+
id: person.id,
|
|
49
51
|
}}
|
|
50
52
|
loading={loading}
|
|
51
53
|
/>
|
|
@@ -78,6 +78,7 @@ export const LoadingTabsLayout = ({ children }: LoadingTabsLayoutProps) => {
|
|
|
78
78
|
image: undefined,
|
|
79
79
|
name: "",
|
|
80
80
|
role: "",
|
|
81
|
+
id: "",
|
|
81
82
|
}}
|
|
82
83
|
loading={true}
|
|
83
84
|
>
|
|
@@ -100,33 +101,7 @@ export const LoadingTabsLayout = ({ children }: LoadingTabsLayoutProps) => {
|
|
|
100
101
|
);
|
|
101
102
|
|
|
102
103
|
case "OrgUnitDetailsLayout":
|
|
103
|
-
return
|
|
104
|
-
<OrgUnitsDetailsLayout
|
|
105
|
-
loading={true}
|
|
106
|
-
data={{
|
|
107
|
-
contracts: [],
|
|
108
|
-
orgUnit: {
|
|
109
|
-
contractMode: "Single",
|
|
110
|
-
customerGroup: { customerIds: [] },
|
|
111
|
-
id: routeParams.orgUnitId,
|
|
112
|
-
name: "",
|
|
113
|
-
path: {
|
|
114
|
-
ids: "",
|
|
115
|
-
names: "",
|
|
116
|
-
},
|
|
117
|
-
},
|
|
118
|
-
user: {
|
|
119
|
-
name: "",
|
|
120
|
-
roles: [],
|
|
121
|
-
id: "",
|
|
122
|
-
orgUnit: {
|
|
123
|
-
id: routeParams.orgUnitId,
|
|
124
|
-
name: "",
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
}}
|
|
128
|
-
/>
|
|
129
|
-
);
|
|
104
|
+
return <OrgUnitsDetailsLayout loading={true} orgUnitId="" userId="" />;
|
|
130
105
|
|
|
131
106
|
default:
|
|
132
107
|
return <LoadingTabsLayoutContent />;
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import { ClientContext } from "../utils";
|
|
2
2
|
|
|
3
3
|
export type AuthRouteProps<T> =
|
|
4
|
-
| { authorized: true; data: T; clientContext: ClientContext
|
|
5
|
-
| { authorized: false
|
|
6
|
-
| {
|
|
7
|
-
authorized: false;
|
|
8
|
-
loading: true;
|
|
9
|
-
data?: Partial<T>;
|
|
10
|
-
clientContext?: ClientContext;
|
|
11
|
-
};
|
|
4
|
+
| { authorized: true; data: T; clientContext: ClientContext }
|
|
5
|
+
| { authorized: false };
|
|
@@ -1,83 +1,31 @@
|
|
|
1
|
-
import { useEffect,
|
|
1
|
+
import { useEffect, type ComponentType } from "react";
|
|
2
2
|
|
|
3
3
|
import { useRouter } from "next/router";
|
|
4
4
|
|
|
5
|
-
import { useCookieMonitor } from "../hooks/useCookieMonitor";
|
|
6
|
-
|
|
7
5
|
import type { AuthRouteProps } from "../types";
|
|
8
6
|
|
|
9
7
|
/**
|
|
10
|
-
* HOC that checks only for authorization
|
|
11
|
-
* Now handles loading state for pre-fetch scenarios.
|
|
8
|
+
* HOC that checks only for authorization
|
|
12
9
|
*/
|
|
13
10
|
export const withAuth = <T extends Record<string, unknown>>(
|
|
14
11
|
Component: ComponentType<T>
|
|
15
12
|
) => {
|
|
16
13
|
return function AuthenticatedComponent(props: AuthRouteProps<T>) {
|
|
17
14
|
const router = useRouter();
|
|
18
|
-
const { hasCookie, timedOut } = useCookieMonitor();
|
|
19
|
-
const reloadAttemptedRef = useRef(false);
|
|
20
|
-
|
|
21
|
-
// Debug logging
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
console.log("[withAuth] Props state:", {
|
|
24
|
-
authorized: props?.authorized,
|
|
25
|
-
loading: props?.loading,
|
|
26
|
-
hasCookie,
|
|
27
|
-
timedOut,
|
|
28
|
-
reloadAttempted: reloadAttemptedRef.current,
|
|
29
|
-
});
|
|
30
|
-
}, [props?.authorized, props?.loading, hasCookie, timedOut]);
|
|
31
|
-
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
// If not authorized and not loading, reload the page
|
|
34
|
-
if (
|
|
35
|
-
!props?.authorized &&
|
|
36
|
-
!props?.loading &&
|
|
37
|
-
!reloadAttemptedRef.current
|
|
38
|
-
) {
|
|
39
|
-
console.log("[withAuth] Reloading: not authorized and not loading");
|
|
40
|
-
reloadAttemptedRef.current = true;
|
|
41
|
-
// Use replace to bypass Next.js data cache
|
|
42
|
-
router.replace(router.asPath);
|
|
43
|
-
}
|
|
44
|
-
}, [props?.authorized, props?.loading, router]);
|
|
45
15
|
|
|
46
16
|
useEffect(() => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
);
|
|
51
|
-
reloadAttemptedRef.current = true;
|
|
52
|
-
// Hard reload to completely bypass Next.js cache
|
|
53
|
-
if (typeof window !== "undefined") {
|
|
54
|
-
window.location.href = router.asPath;
|
|
55
|
-
}
|
|
17
|
+
// If not authorized, reload the page
|
|
18
|
+
if (!props?.authorized) {
|
|
19
|
+
router.reload();
|
|
56
20
|
}
|
|
57
|
-
}, [props?.
|
|
21
|
+
}, [props?.authorized, router]);
|
|
58
22
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (props?.loading && timedOut && !reloadAttemptedRef.current) {
|
|
62
|
-
console.log("[withAuth] Cookie timeout - redirecting to home page");
|
|
63
|
-
reloadAttemptedRef.current = true;
|
|
64
|
-
router.push("/");
|
|
65
|
-
}
|
|
66
|
-
}, [props?.loading, timedOut, router]);
|
|
67
|
-
|
|
68
|
-
// Always render the component, but pass loading state
|
|
69
|
-
// This allows components to handle their own loading states
|
|
70
|
-
if (!props?.authorized && !props?.loading) {
|
|
71
|
-
// Not authorized and not loading = permanently denied
|
|
23
|
+
// If not authorized, render nothing
|
|
24
|
+
if (!props?.authorized) {
|
|
72
25
|
return null;
|
|
73
26
|
}
|
|
74
27
|
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
...(props?.data || ({} as T)),
|
|
78
|
-
loading: props?.loading || false,
|
|
79
|
-
} as T & { loading: boolean };
|
|
80
|
-
|
|
81
|
-
return <Component {...componentProps} />;
|
|
28
|
+
// If authorized, render the component with the data
|
|
29
|
+
return <Component {...(props.data as T)} />;
|
|
82
30
|
};
|
|
83
31
|
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { validateAccessService } from "../services";
|
|
2
2
|
|
|
3
|
-
import { getAuthCookie } from "./cookie";
|
|
4
3
|
import { ClientContext, getClientContext } from "./getClientContext";
|
|
5
4
|
|
|
6
5
|
import type { AuthRouteProps } from "../types";
|
|
@@ -9,57 +8,31 @@ import type { LoaderData } from "../types";
|
|
|
9
8
|
/**
|
|
10
9
|
* Utility function to encapsulate access validation in loaders.
|
|
11
10
|
* Similar to withAuthProvider but for server-side usage.
|
|
12
|
-
*
|
|
13
|
-
* Now supports a loading state for when cookies are not yet available during pre-fetch.
|
|
14
11
|
*/
|
|
15
12
|
export const withAuthLoader = async <T>(
|
|
16
13
|
data: LoaderData,
|
|
17
14
|
dataLoader: (clientContext: ClientContext) => Promise<T>
|
|
18
15
|
): Promise<AuthRouteProps<T>> => {
|
|
19
16
|
try {
|
|
20
|
-
// Check if auth cookie exists before proceeding
|
|
21
|
-
const authCookie = getAuthCookie(data);
|
|
22
|
-
|
|
23
|
-
console.log("[withAuthLoader] Cookie check:", {
|
|
24
|
-
hasCookie: !!authCookie,
|
|
25
|
-
cookieLength: authCookie?.length,
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
if (!authCookie || authCookie === "") {
|
|
29
|
-
console.log("[withAuthLoader] Returning loading state (no cookie)");
|
|
30
|
-
return {
|
|
31
|
-
authorized: false,
|
|
32
|
-
loading: true,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
17
|
const { cookie, userId, ...clientContext } = await getClientContext(data);
|
|
37
18
|
|
|
38
19
|
const hasAccess = await validateAccessService({ cookie });
|
|
39
20
|
|
|
40
|
-
console.log("[withAuthLoader] Access validation result:", hasAccess);
|
|
41
|
-
|
|
42
21
|
if (!hasAccess) {
|
|
43
|
-
console.log("[withAuthLoader] Access denied, redirecting to /");
|
|
44
22
|
data.res?.writeHead(302, { Location: "/" });
|
|
45
23
|
data.res?.end();
|
|
46
24
|
|
|
47
25
|
return {
|
|
48
26
|
authorized: false,
|
|
49
|
-
loading: false,
|
|
50
27
|
};
|
|
51
28
|
}
|
|
52
29
|
|
|
53
30
|
const pageData = await dataLoader({ cookie, userId, ...clientContext });
|
|
54
31
|
|
|
55
|
-
console.log(
|
|
56
|
-
"[withAuthLoader] Successfully loaded data, returning authorized"
|
|
57
|
-
);
|
|
58
32
|
return {
|
|
59
33
|
authorized: true,
|
|
60
34
|
data: pageData,
|
|
61
35
|
clientContext: { cookie, userId, ...clientContext },
|
|
62
|
-
loading: false,
|
|
63
36
|
};
|
|
64
37
|
} catch (error) {
|
|
65
38
|
console.error("[withAuthLoader] Auth validation failed:", error);
|
|
@@ -69,7 +42,6 @@ export const withAuthLoader = async <T>(
|
|
|
69
42
|
|
|
70
43
|
return {
|
|
71
44
|
authorized: false,
|
|
72
|
-
loading: false,
|
|
73
45
|
};
|
|
74
46
|
}
|
|
75
47
|
};
|
|
@@ -1,107 +1,37 @@
|
|
|
1
|
-
import { useEffect,
|
|
1
|
+
import { useEffect, type ComponentType } from "react";
|
|
2
2
|
|
|
3
3
|
import { useRouter } from "next/router";
|
|
4
4
|
|
|
5
5
|
import { BuyerPortalProvider } from "../components";
|
|
6
|
-
import { useCookieMonitor } from "../hooks/useCookieMonitor";
|
|
7
6
|
|
|
8
7
|
import type { AuthRouteProps } from "../types";
|
|
9
8
|
import type { ClientContext } from "./getClientContext";
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
|
-
* HOC que encapsula lógica de autenticação e provider
|
|
13
|
-
* Now handles loading state for pre-fetch scenarios.
|
|
14
|
-
* Monitors cookie availability and reloads when cookie becomes available.
|
|
11
|
+
* HOC que encapsula lógica de autenticação e provider
|
|
15
12
|
*/
|
|
16
13
|
export const withAuthProvider = <T,>(
|
|
17
14
|
Component: ComponentType<T & { clientContext: ClientContext }>
|
|
18
15
|
) => {
|
|
19
16
|
return function WrappedPage(props: AuthRouteProps<T>) {
|
|
20
17
|
const router = useRouter();
|
|
21
|
-
const { hasCookie, timedOut } = useCookieMonitor();
|
|
22
|
-
const reloadAttemptedRef = useRef(false);
|
|
23
|
-
const isProduction = process.env.NODE_ENV === "production";
|
|
24
18
|
|
|
25
|
-
// Debug logging (only in development or when needed)
|
|
26
19
|
useEffect(() => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
loading: props?.loading,
|
|
31
|
-
hasCookie,
|
|
32
|
-
timedOut,
|
|
33
|
-
reloadAttempted: reloadAttemptedRef.current,
|
|
34
|
-
routerPath: router.asPath,
|
|
35
|
-
});
|
|
20
|
+
// Se não está autorizado, recarrega a página
|
|
21
|
+
if (!props?.authorized) {
|
|
22
|
+
router.reload();
|
|
36
23
|
}
|
|
37
|
-
}, [
|
|
38
|
-
props?.authorized,
|
|
39
|
-
props?.loading,
|
|
40
|
-
hasCookie,
|
|
41
|
-
timedOut,
|
|
42
|
-
router.asPath,
|
|
43
|
-
isProduction,
|
|
44
|
-
]);
|
|
24
|
+
}, [props?.authorized, router]);
|
|
45
25
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (
|
|
49
|
-
!props?.authorized &&
|
|
50
|
-
!props?.loading &&
|
|
51
|
-
!reloadAttemptedRef.current
|
|
52
|
-
) {
|
|
53
|
-
console.log(
|
|
54
|
-
"[withAuthProvider] Reloading: not authorized and not loading"
|
|
55
|
-
);
|
|
56
|
-
reloadAttemptedRef.current = true;
|
|
57
|
-
// Use replace to bypass Next.js data cache
|
|
58
|
-
router.replace(router.asPath);
|
|
59
|
-
}
|
|
60
|
-
}, [props?.authorized, props?.loading, router]);
|
|
61
|
-
|
|
62
|
-
useEffect(() => {
|
|
63
|
-
// If we're in loading state and cookie becomes available, do hard reload
|
|
64
|
-
if (props?.loading && hasCookie && !reloadAttemptedRef.current) {
|
|
65
|
-
console.log(
|
|
66
|
-
"[withAuthProvider] Cookie available, performing hard reload to bypass cache"
|
|
67
|
-
);
|
|
68
|
-
reloadAttemptedRef.current = true;
|
|
69
|
-
// Hard reload to completely bypass Next.js cache
|
|
70
|
-
if (typeof window !== "undefined") {
|
|
71
|
-
window.location.href = router.asPath;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}, [props?.loading, hasCookie, router]);
|
|
75
|
-
|
|
76
|
-
useEffect(() => {
|
|
77
|
-
// If we're in loading state and timeout reached, redirect to home
|
|
78
|
-
if (props?.loading && timedOut && !reloadAttemptedRef.current) {
|
|
79
|
-
console.log(
|
|
80
|
-
"[withAuthProvider] Cookie timeout - redirecting to home page"
|
|
81
|
-
);
|
|
82
|
-
reloadAttemptedRef.current = true;
|
|
83
|
-
router.push("/");
|
|
84
|
-
}
|
|
85
|
-
}, [props?.loading, timedOut, router]);
|
|
86
|
-
|
|
87
|
-
// Always render the component, but pass loading state
|
|
88
|
-
// This allows components to handle their own loading states
|
|
89
|
-
if (!props?.authorized && !props?.loading) {
|
|
90
|
-
// Not authorized and not loading = permanently denied
|
|
26
|
+
// Se não está autorizado, não renderiza nada
|
|
27
|
+
if (!props?.authorized) {
|
|
91
28
|
return null;
|
|
92
29
|
}
|
|
93
30
|
|
|
94
|
-
//
|
|
95
|
-
const componentProps = {
|
|
96
|
-
...(props?.data || ({} as T)),
|
|
97
|
-
loading: props?.loading || false,
|
|
98
|
-
} as T & { loading: boolean };
|
|
99
|
-
|
|
100
|
-
const clientContext = props?.clientContext || ({} as ClientContext);
|
|
101
|
-
|
|
31
|
+
// Se autorizado, renderiza o componente envolvido no provider
|
|
102
32
|
return (
|
|
103
|
-
<BuyerPortalProvider clientContext={clientContext}>
|
|
104
|
-
<Component {...
|
|
33
|
+
<BuyerPortalProvider clientContext={props?.clientContext}>
|
|
34
|
+
<Component {...props.data} clientContext={props?.clientContext} />
|
|
105
35
|
</BuyerPortalProvider>
|
|
106
36
|
);
|
|
107
37
|
};
|
|
@@ -1,49 +1,25 @@
|
|
|
1
|
-
import { getContractsByOrgUnitIdService } from "../features/contracts/services";
|
|
2
1
|
import { OrgUnitsDetailsLayout } from "../features/org-units/layouts";
|
|
3
|
-
import { getOrgUnitBasicDataService } from "../features/org-units/services";
|
|
4
2
|
import { withErrorBoundary } from "../features/shared/components";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
type ClientContext,
|
|
8
|
-
withLoaderErrorBoundary,
|
|
9
|
-
withAuthLoader,
|
|
10
|
-
withProviders,
|
|
11
|
-
} from "../features/shared/utils";
|
|
12
|
-
import { getUserByIdService } from "../features/users/services";
|
|
3
|
+
import { withAuthLoader, withProviders } from "../features/shared/utils";
|
|
4
|
+
import { ClientContext } from "../features/shared/utils/getClientContext";
|
|
13
5
|
|
|
14
|
-
import type { ContractData } from "../features/contracts/types";
|
|
15
|
-
import type { OrgUnitBasicData } from "../features/org-units/types";
|
|
16
6
|
import type { AuthRouteProps, LoaderData } from "../features/shared/types";
|
|
17
|
-
import type { UserData } from "../features/users/types";
|
|
18
7
|
|
|
19
8
|
export type OrgUnitDetailsPageData = {
|
|
20
9
|
data: {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
user: UserData | null;
|
|
10
|
+
orgUnitId: string;
|
|
11
|
+
userId: string;
|
|
24
12
|
};
|
|
25
13
|
context: {
|
|
26
14
|
clientContext: ClientContext;
|
|
27
15
|
};
|
|
28
|
-
hasError?: boolean;
|
|
29
|
-
error?: {
|
|
30
|
-
error: {
|
|
31
|
-
message: string;
|
|
32
|
-
name: string;
|
|
33
|
-
stack?: string;
|
|
34
|
-
};
|
|
35
|
-
tags: {
|
|
36
|
-
component: string;
|
|
37
|
-
errorType: string;
|
|
38
|
-
};
|
|
39
|
-
};
|
|
40
16
|
};
|
|
41
17
|
|
|
42
18
|
type OrgUnitDetailsPageQuery = {
|
|
43
19
|
orgUnitId: string;
|
|
44
20
|
};
|
|
45
21
|
|
|
46
|
-
const
|
|
22
|
+
export const loader = async (
|
|
47
23
|
data: LoaderData<OrgUnitDetailsPageQuery>
|
|
48
24
|
): Promise<AuthRouteProps<OrgUnitDetailsPageData>> => {
|
|
49
25
|
const { orgUnitId } = data.query;
|
|
@@ -53,23 +29,10 @@ const loaderFunction = async (
|
|
|
53
29
|
}
|
|
54
30
|
|
|
55
31
|
return withAuthLoader(data, async ({ cookie, userId, ...clientContext }) => {
|
|
56
|
-
const orgUnit = await getOrgUnitBasicDataService({
|
|
57
|
-
id: orgUnitId,
|
|
58
|
-
cookie,
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
const user = await getUserByIdService({ orgUnitId, userId, cookie });
|
|
62
|
-
|
|
63
|
-
const contracts = await getContractsByOrgUnitIdService({
|
|
64
|
-
orgUnitId,
|
|
65
|
-
cookie,
|
|
66
|
-
});
|
|
67
|
-
|
|
68
32
|
return {
|
|
69
33
|
data: {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
user,
|
|
34
|
+
orgUnitId,
|
|
35
|
+
userId,
|
|
73
36
|
},
|
|
74
37
|
context: {
|
|
75
38
|
clientContext: { cookie, userId, ...clientContext },
|
|
@@ -78,24 +41,9 @@ const loaderFunction = async (
|
|
|
78
41
|
});
|
|
79
42
|
};
|
|
80
43
|
|
|
81
|
-
|
|
82
|
-
componentName: "OrgUnitDetailsPage",
|
|
83
|
-
redirectToError: true,
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
const OrgUnitDetailsPage = ({
|
|
87
|
-
data,
|
|
88
|
-
hasError,
|
|
89
|
-
error,
|
|
90
|
-
}: OrgUnitDetailsPageData) => {
|
|
44
|
+
const OrgUnitDetailsPage = ({ data }: OrgUnitDetailsPageData) => {
|
|
91
45
|
return (
|
|
92
|
-
|
|
93
|
-
{hasError ? (
|
|
94
|
-
<ErrorTabsLayout error={error} />
|
|
95
|
-
) : (
|
|
96
|
-
<OrgUnitsDetailsLayout data={data} />
|
|
97
|
-
)}
|
|
98
|
-
</>
|
|
46
|
+
<OrgUnitsDetailsLayout orgUnitId={data.orgUnitId} userId={data.userId} />
|
|
99
47
|
);
|
|
100
48
|
};
|
|
101
49
|
|
package/src/pages/profile.tsx
CHANGED
|
@@ -1,98 +1,55 @@
|
|
|
1
|
-
import { getContractDetailsService } from "../features/contracts/services";
|
|
2
|
-
import { getOrgUnitBasicDataService } from "../features/org-units/services";
|
|
3
1
|
import { ProfileLayout } from "../features/profile/layouts";
|
|
4
2
|
import { withErrorBoundary } from "../features/shared/components";
|
|
5
|
-
import { ErrorBoundaryProps } from "../features/shared/components/ErrorBoundary/types";
|
|
6
|
-
import { ErrorTabsLayout } from "../features/shared/layouts/ErrorTabsLayout/ErrorTabsLayout";
|
|
7
3
|
import {
|
|
8
4
|
type ClientContext,
|
|
9
|
-
withLoaderErrorBoundary,
|
|
10
|
-
withAuthLoader,
|
|
11
5
|
withProviders,
|
|
6
|
+
withAuthLoader,
|
|
12
7
|
} from "../features/shared/utils";
|
|
13
|
-
import { getUserByIdService } from "../features/users/services";
|
|
14
8
|
|
|
15
|
-
import type { ContractData } from "../features/contracts/types";
|
|
16
|
-
import type { OrgUnitBasicData } from "../features/org-units/types";
|
|
17
9
|
import type { AuthRouteProps, LoaderData } from "../features/shared/types";
|
|
18
|
-
import type { UserData } from "../features/users/types";
|
|
19
10
|
|
|
20
11
|
export type ProfilePageData = {
|
|
21
|
-
data:
|
|
12
|
+
data: {
|
|
13
|
+
contractId: string;
|
|
14
|
+
orgUnitId: string;
|
|
15
|
+
userId: string;
|
|
16
|
+
};
|
|
22
17
|
context: {
|
|
23
18
|
clientContext: ClientContext;
|
|
24
|
-
currentOrgUnit: OrgUnitBasicData | null;
|
|
25
|
-
currentContract: ContractData | null;
|
|
26
|
-
currentUser: UserData | null;
|
|
27
19
|
};
|
|
28
|
-
hasError?: boolean;
|
|
29
|
-
error?: ErrorBoundaryProps;
|
|
30
20
|
};
|
|
31
21
|
|
|
32
22
|
export type ProfilePageQuery = {
|
|
33
23
|
contractId: string;
|
|
34
24
|
orgUnitId: string;
|
|
25
|
+
userId: string;
|
|
35
26
|
};
|
|
36
27
|
|
|
37
|
-
export async
|
|
28
|
+
export const loader = async (
|
|
38
29
|
data: LoaderData<ProfilePageQuery>
|
|
39
|
-
): Promise<AuthRouteProps<ProfilePageData>> {
|
|
30
|
+
): Promise<AuthRouteProps<ProfilePageData>> => {
|
|
40
31
|
const { contractId, orgUnitId } = data.query;
|
|
41
32
|
|
|
42
|
-
return withAuthLoader(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const [orgUnit, contract, user] = await Promise.all([
|
|
58
|
-
getOrgUnitBasicDataService({
|
|
59
|
-
cookie,
|
|
60
|
-
id: orgUnitId,
|
|
61
|
-
}),
|
|
62
|
-
getContractDetailsService({
|
|
63
|
-
contractId,
|
|
64
|
-
cookie,
|
|
65
|
-
unitId: orgUnitId,
|
|
66
|
-
}),
|
|
67
|
-
getUserByIdService({ orgUnitId, userId, cookie }),
|
|
68
|
-
]);
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
data: contract,
|
|
72
|
-
context: {
|
|
73
|
-
clientContext: { customerId, cookie, userId, ...clientContext },
|
|
74
|
-
currentOrgUnit: orgUnit,
|
|
75
|
-
currentContract: contract,
|
|
76
|
-
currentUser: user,
|
|
77
|
-
},
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export const loader = withLoaderErrorBoundary(loaderFunction, {
|
|
84
|
-
componentName: "ProfilePage",
|
|
85
|
-
redirectToError: true,
|
|
86
|
-
});
|
|
33
|
+
return withAuthLoader(data, async ({ cookie, userId, ...clientContext }) => {
|
|
34
|
+
return {
|
|
35
|
+
data: {
|
|
36
|
+
contractId,
|
|
37
|
+
orgUnitId,
|
|
38
|
+
userId,
|
|
39
|
+
},
|
|
40
|
+
context: {
|
|
41
|
+
clientContext: { cookie, userId, ...clientContext },
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
};
|
|
87
46
|
|
|
88
|
-
const ProfilePage = ({ data
|
|
89
|
-
|
|
90
|
-
{
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
)}
|
|
95
|
-
</>
|
|
47
|
+
const ProfilePage = ({ data }: ProfilePageData) => (
|
|
48
|
+
<ProfileLayout
|
|
49
|
+
orgUnitId={data.orgUnitId}
|
|
50
|
+
contractId={data.contractId}
|
|
51
|
+
userId={data.userId}
|
|
52
|
+
/>
|
|
96
53
|
);
|
|
97
54
|
|
|
98
55
|
export default withProviders(
|