Skip to content

Commit 3d68e3b

Browse files
authored
Vis samtykkeforespørsler på forespørsel-siden (#1808)
* show consent requests in requests page * refactor * fixes * nitpick * nitpick * sort pending consents by date * use common type for request * fix party * error handling
1 parent d856fd7 commit 3d68e3b

9 files changed

Lines changed: 243 additions & 6 deletions

File tree

src/features/amUI/common/PageLayoutWrapper/useSidebarItems.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useRequests } from '@/resources/hooks/useRequests';
12
import {
23
hasConsentPermission,
34
hasCreateSystemUserPermission,
@@ -21,7 +22,7 @@ import {
2122
useGetIsCompanyProfileAdminQuery,
2223
useGetReporteeQuery,
2324
} from '@/rtk/features/userInfoApi';
24-
import { MenuItemProps } from '@altinn/altinn-components';
25+
import { BadgeVariant, Color, MenuItemProps } from '@altinn/altinn-components';
2526
import { useLocation } from 'react-router';
2627

2728
export const useSidebarItems = ({ isSmall }: { isSmall?: boolean }) => {
@@ -39,6 +40,7 @@ export const useSidebarItems = ({ isSmall }: { isSmall?: boolean }) => {
3940
const { data: isClientAdmin, isLoading: isLoadingIsClientAdmin } = useGetIsClientAdminQuery();
4041
const { data: canAccessSettings, isLoading: isLoadingCompanyProfileAdmin } =
4142
useGetIsCompanyProfileAdminQuery();
43+
const { pendingRequests } = useRequests();
4244

4345
const isLoading =
4446
isLoadingReportee || isLoadingIsAdmin || isLoadingIsClientAdmin || isLoadingCompanyProfileAdmin;
@@ -49,7 +51,18 @@ export const useSidebarItems = ({ isSmall }: { isSmall?: boolean }) => {
4951
items.push(getHeadingMenuItem(pathname, isLoading));
5052
}
5153
if (displayRequestsPage) {
52-
items.push(getRequestsMenuItem(pathname, isLoading, isSmall));
54+
const requestsBadge =
55+
pendingRequests && pendingRequests.length > 0
56+
? {
57+
label: pendingRequests.length,
58+
color: 'warning' as Color,
59+
variant: 'base' as BadgeVariant,
60+
}
61+
: undefined;
62+
items.push({
63+
...getRequestsMenuItem(pathname, isLoading, isSmall),
64+
badge: requestsBadge,
65+
});
5366
}
5467

5568
if (displayConfettiPackage) {

src/features/amUI/landingPage/LandingPage.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import {
4141
import { useGetPartyFromLoggedInUserQuery } from '@/rtk/features/lookupApi';
4242
import { formatOrgNr, isOrganization, isSubUnit } from '@/resources/utils/reporteeUtils';
4343
import { getHostUrl } from '@/resources/utils/pathUtils';
44+
import { useRequests } from '@/resources/hooks/useRequests';
4445

4546
export const LandingPage = () => {
4647
const { t } = useTranslation();
@@ -52,6 +53,7 @@ export const LandingPage = () => {
5253
const { data: canAccessSettings, isLoading: isLoadingCanAccessSettings } =
5354
useGetIsCompanyProfileAdminQuery();
5455
const { data: currentUser, isLoading: currentUserIsLoading } = useGetPartyFromLoggedInUserQuery();
56+
const { pendingRequests, isLoadingRequests } = useRequests();
5557

5658
const reporteeName = formatDisplayName({
5759
fullName: reportee?.name || '',
@@ -73,7 +75,8 @@ export const LandingPage = () => {
7375
isLoadingIsAdmin ||
7476
isLoadingIsClientAdmin ||
7577
isLoadingCanAccessSettings ||
76-
currentUserIsLoading;
78+
currentUserIsLoading ||
79+
isLoadingRequests;
7780

7881
const getMenuItems = (): MenuItemProps[] => {
7982
const displayConfettiPackage = window.featureFlags?.displayConfettiPackage;
@@ -163,7 +166,7 @@ export const LandingPage = () => {
163166
const getOtherItems = (): MenuItemProps[] => {
164167
const displaySettingsPage = window.featureFlags?.displaySettingsPage;
165168
const displayRequestsPage = window.featureFlags?.displayRequestsPage;
166-
const requestCount = 0;
169+
const requestCount = pendingRequests ? pendingRequests.length : 0;
167170
const items: MenuItemProps[] = [];
168171

169172
if (displayRequestsPage) {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.requestPageTabs {
2+
margin-top: var(--ds-size-4);
3+
margin-bottom: var(--ds-size-6);
4+
}
5+
6+
.requestTab {
7+
display: flex;
8+
gap: var(--ds-size-2);
9+
}
Lines changed: 125 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,141 @@
1-
import { PageWrapper } from '@/components';
21
import React from 'react';
2+
import { Link } from 'react-router';
3+
import { useTranslation } from 'react-i18next';
4+
import {
5+
Badge,
6+
DsAlert,
7+
DsTabs,
8+
formatDisplayName,
9+
List,
10+
UserListItem,
11+
} from '@altinn/altinn-components';
12+
import { PageWrapper } from '@/components';
313
import { PageLayoutWrapper } from '../common/PageLayoutWrapper';
414
import { useRerouteIfRequestPageDisabled } from '@/resources/utils/featureFlagUtils';
515
import { Breadcrumbs } from '../common/Breadcrumbs/Breadcrumbs';
16+
import ReporteePageHeading from '../common/ReporteePageHeading';
17+
import { useGetReporteeQuery } from '@/rtk/features/userInfoApi';
18+
import { useDocumentTitle } from '@/resources/hooks/useDocumentTitle';
19+
import { formatDateToNorwegian } from '@/resources/utils';
20+
import { useRequests } from '@/resources/hooks/useRequests';
21+
import classes from './RequestPage.module.css';
22+
import { Request } from './types';
623

724
export const RequestPage = () => {
25+
const { t } = useTranslation();
26+
827
useRerouteIfRequestPageDisabled();
928

29+
useDocumentTitle(t('request_page.page_title'));
30+
31+
const { data: reportee, isLoading: isLoadingReportee } = useGetReporteeQuery();
32+
const { pendingRequests, isLoadingRequests, isError } = useRequests();
33+
34+
const name = formatDisplayName({
35+
fullName: reportee?.name || '',
36+
type: reportee?.type === 'Person' ? 'person' : 'company',
37+
});
38+
39+
const totalRequests = pendingRequests ? pendingRequests.length : 0;
40+
1041
return (
1142
<PageWrapper>
1243
<PageLayoutWrapper>
1344
<Breadcrumbs items={['root', 'requests']} />
14-
<div>Forespørsel-siden er under arbeid</div>
45+
<ReporteePageHeading
46+
title={t('request_page.heading', { name })}
47+
reportee={reportee}
48+
isLoading={isLoadingReportee}
49+
/>
50+
<DsTabs
51+
defaultValue='incomingRequests'
52+
data-size='sm'
53+
>
54+
<DsTabs.List className={classes.requestPageTabs}>
55+
<DsTabs.Tab
56+
value='incomingRequests'
57+
className={classes.requestTab}
58+
>
59+
{!!totalRequests && (
60+
<Badge
61+
data-size='sm'
62+
variant='base'
63+
label={totalRequests}
64+
/>
65+
)}
66+
{t('request_page.incoming_requests')}
67+
</DsTabs.Tab>
68+
<DsTabs.Tab value='sentRequests'>{t('request_page.sent_requests')}</DsTabs.Tab>
69+
</DsTabs.List>
70+
<DsTabs.Panel value='incomingRequests'>
71+
<List>
72+
{isLoadingRequests ? (
73+
<>
74+
<LoadingRequestListItem />
75+
<LoadingRequestListItem />
76+
<LoadingRequestListItem />
77+
<LoadingRequestListItem />
78+
</>
79+
) : (
80+
<PendingRequests pendingRequests={pendingRequests} />
81+
)}
82+
{!isLoadingRequests && totalRequests === 0 && (
83+
<div>{t('request_page.no_received_requests')}</div>
84+
)}
85+
</List>
86+
{isError && (
87+
<DsAlert data-color='danger'>{t('request_page.error_loading_requests')}</DsAlert>
88+
)}
89+
</DsTabs.Panel>
90+
<DsTabs.Panel value='sentRequests'>
91+
<div>{t('request_page.no_sent_requests')}</div>
92+
</DsTabs.Panel>
93+
</DsTabs>
1594
</PageLayoutWrapper>
1695
</PageWrapper>
1796
);
1897
};
98+
99+
interface PendingRequestsProps {
100+
pendingRequests: Request[] | undefined;
101+
}
102+
103+
const PendingRequests = ({ pendingRequests }: PendingRequestsProps) => {
104+
const { t } = useTranslation();
105+
return (
106+
<>
107+
{pendingRequests?.map((request) => {
108+
return (
109+
<UserListItem
110+
key={request.id}
111+
id={request.id}
112+
name={request.fromPartyName}
113+
type={request.fromPartyType}
114+
linkIcon
115+
description={`${t(request.description)} (${formatDateToNorwegian(request.createdDate)})`}
116+
as={(props) => (
117+
<Link
118+
to={`/consent/request?id=${request.id}`}
119+
{...props}
120+
/>
121+
)}
122+
controls={t('request_page.process_request')}
123+
/>
124+
);
125+
})}
126+
</>
127+
);
128+
};
129+
130+
const LoadingRequestListItem = () => {
131+
return (
132+
<UserListItem
133+
id={''}
134+
name={'xxxxxxxxxxxx'}
135+
description='xxxxxxxxxxxxxxxxxxxxxxxxxxxx'
136+
type={'person'}
137+
interactive={false}
138+
loading
139+
/>
140+
);
141+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export interface Request {
2+
id: string;
3+
type: 'consent' | 'systemuser' | 'accessrequest';
4+
createdDate: string;
5+
fromPartyName: string;
6+
fromPartyType: 'person' | 'company';
7+
description: string;
8+
}

src/localizations/en.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,5 +855,17 @@
855855
"client_admin_item_description": "Delegate power of attorney from clients to users in your organization.",
856856
"new_requests_single": "{{reportee}} has {{requestCount}} new request",
857857
"new_requests_plural": "{{reportee}} has {{requestCount}} new requests"
858+
},
859+
"request_page": {
860+
"page_title": "Requests - Altinn",
861+
"heading": "Requests for {{name}}",
862+
"incoming_requests": "Received requests",
863+
"sent_requests": "Sent requests",
864+
"no_received_requests": "No received requests",
865+
"no_sent_requests": "No sent requests",
866+
"process_request": "Process request",
867+
"request_consent": "Requests consent",
868+
"request_poa": "Requests power of attorney",
869+
"error_loading_requests": "Could not load received requests"
858870
}
859871
}

src/localizations/no_nb.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,5 +852,17 @@
852852
"client_admin_item_description": "Deleger fullmakter fra klienter til brukere i virksomheten.",
853853
"new_requests_single": "{{reportee}} har {{requestCount}} ny forespørsel",
854854
"new_requests_plural": "{{reportee}} har {{requestCount}} nye forespørsler"
855+
},
856+
"request_page": {
857+
"page_title": "Forespørsler - Altinn",
858+
"heading": "Forespørsler for {{name}}",
859+
"incoming_requests": "Mottatte forespørsler",
860+
"sent_requests": "Sendte forespørsler",
861+
"no_received_requests": "Ingen mottatte forespørsler",
862+
"no_sent_requests": "Ingen sendte forespørsler",
863+
"process_request": "Behandle forespørsel",
864+
"request_consent": "Ber om samtykke",
865+
"request_poa": "Ber om fullmakt",
866+
"error_loading_requests": "Kunne ikke laste mottatte forespørsler"
855867
}
856868
}

src/localizations/no_nn.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,5 +852,17 @@
852852
"client_admin_item_description": "Deleger fullmakter frå klientar til brukarar i verksemda.",
853853
"new_requests_single": "{{reportee}} har {{requestCount}} ny førespurnad",
854854
"new_requests_plural": "{{reportee}} har {{requestCount}} nye førespurnader"
855+
},
856+
"request_page": {
857+
"page_title": "Førespurnader - Altinn",
858+
"heading": "Førespurnader for {{name}}",
859+
"incoming_requests": "Mottatte førespurnader",
860+
"sent_requests": "Sendte førespurnader",
861+
"no_received_requests": "Ingen mottatte førespurnader",
862+
"no_sent_requests": "Ingen sendte førespurnader",
863+
"process_request": "Behandle førespurnad",
864+
"request_consent": "Ber om samtykke",
865+
"request_poa": "Ber om fullmakt",
866+
"error_loading_requests": "Kunne ikkje laste mottatte førespurnader"
855867
}
856868
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import React, { useMemo } from 'react';
2+
import { getCookie } from '../Cookie/CookieMethods';
3+
import { useGetIsAdminQuery } from '@/rtk/features/userInfoApi';
4+
import { hasConsentPermission } from '../utils/permissionUtils';
5+
import { useGetActiveConsentsQuery } from '@/rtk/features/consentApi';
6+
import { Request } from '@/features/amUI/requestPage/types';
7+
8+
export const useRequests = () => {
9+
const partyUuid = getCookie('AltinnPartyUuid');
10+
11+
const {
12+
data: isAdmin,
13+
isLoading: isLoadingIsAdmin,
14+
isError: isAdminError,
15+
} = useGetIsAdminQuery();
16+
17+
const hasPermission = hasConsentPermission(isAdmin);
18+
const {
19+
data: activeConsents,
20+
isLoading: isLoadingActiveConsents,
21+
isError: isLoadingConsentsError,
22+
} = useGetActiveConsentsQuery({ partyId: partyUuid }, { skip: !partyUuid || !hasPermission });
23+
24+
const pendingRequests: Request[] = useMemo(() => {
25+
const consents = (activeConsents || [])
26+
.filter((x) => x.isPendingConsent)
27+
.map<Request>((consent) => ({
28+
id: consent.id,
29+
type: 'consent',
30+
createdDate: consent.createdDate,
31+
fromPartyName: consent.toParty.name,
32+
fromPartyType: consent.toParty.type === 'Person' ? 'person' : 'company',
33+
description: consent.isPoa ? 'request_page.request_poa' : 'request_page.request_consent',
34+
}));
35+
return consents.sort(
36+
(a, b) => new Date(b.createdDate).getTime() - new Date(a.createdDate).getTime(),
37+
);
38+
}, [activeConsents]);
39+
40+
return {
41+
pendingRequests,
42+
isError: isAdminError || isLoadingConsentsError,
43+
isLoadingRequests: isLoadingIsAdmin || isLoadingActiveConsents,
44+
};
45+
};

0 commit comments

Comments
 (0)