Skip to content

Commit 154f12f

Browse files
committed
✨ - feat: implemented comments
1 parent b8b70c2 commit 154f12f

File tree

4 files changed

+132
-39
lines changed

4 files changed

+132
-39
lines changed

frontend/src/components/DestructionList/DestructionList.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import { DataGridProps, ListTemplate } from "@maykin-ui/admin-ui";
22
import { useActionData } from "react-router-dom";
33

44
import { PaginatedZaken } from "../../lib/api/zaken";
5-
import { useDataGridProps } from "../../pages/destructionlist/hooks";
5+
import {
6+
DataGridAction,
7+
useDataGridProps,
8+
} from "../../pages/destructionlist/hooks";
69
import { Zaak } from "../../types";
710

811
export type DestructionList = {
@@ -13,6 +16,7 @@ export type DestructionList = {
1316
storageKey: string;
1417
title: string;
1518
labelAction?: string;
19+
actions?: DataGridAction[];
1620
} & Omit<DataGridProps, "objectList">;
1721

1822
/**
@@ -25,13 +29,15 @@ export function DestructionList({
2529
title,
2630
labelAction = title,
2731
onSubmitSelection,
32+
actions,
2833
...props
2934
}: DestructionList) {
3035
const errors = useActionData() || {};
3136
const { props: dataGridProps, error } = useDataGridProps(
3237
storageKey,
3338
zaken,
3439
selectedZaken,
40+
actions,
3541
);
3642
const _errors = [...Object.values(errors), error].filter((v) => v);
3743

frontend/src/lib/zaakSelection/zaakSelection.ts

+29-17
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,22 @@ import { isPrimitive } from "@maykin-ui/admin-ui";
22

33
import { Zaak } from "../../types";
44

5-
export type ZaakSelection<DetailType = unknown> = {
5+
export type ZaakSelectionMandatoryFields = {
6+
url: string;
7+
};
8+
9+
export type ZaakSelection<
10+
DetailType extends
11+
ZaakSelectionMandatoryFields = ZaakSelectionMandatoryFields,
12+
> = {
613
/**
714
* A `Zaak.url` mapped to a `boolean`.
815
* - `true`: The zaak is added to the selection.
916
* - `false`: The zaak is removed from the selection.
1017
*/
1118
[index: string]: {
1219
selected: boolean;
13-
detail?: DetailType; // todo generic?
20+
detail?: DetailType;
1421
};
1522
};
1623

@@ -22,11 +29,10 @@ export type ZaakSelection<DetailType = unknown> = {
2229
* @param zaken An array containing either `Zaak.url` or `Zaak` objects
2330
* @param detail An optional detail object of generic type
2431
*/
25-
export async function addToZaakSelection<DetailType = unknown>(
26-
key: string,
27-
zaken: string[] | Zaak[],
28-
detail?: DetailType,
29-
) {
32+
export async function addToZaakSelection<
33+
DetailType extends
34+
ZaakSelectionMandatoryFields = ZaakSelectionMandatoryFields,
35+
>(key: string, zaken: string[] | Zaak[], detail?: DetailType) {
3036
await _mutateZaakSelection(key, zaken, true, detail);
3137
}
3238

@@ -50,7 +56,10 @@ export async function removeFromZaakSelection(
5056
* Note: This function is async to accommodate possible future refactors.
5157
* @param key A key identifying the selection
5258
*/
53-
export async function getZaakSelection<DetailType = unknown>(key: string) {
59+
export async function getZaakSelection<
60+
DetailType extends
61+
ZaakSelectionMandatoryFields = ZaakSelectionMandatoryFields,
62+
>(key: string) {
5463
const computedKey = _getComputedKey(key);
5564
const json = sessionStorage.getItem(computedKey) || "{}";
5665
return JSON.parse(json) as ZaakSelection<DetailType>;
@@ -63,10 +72,10 @@ export async function getZaakSelection<DetailType = unknown>(key: string) {
6372
* @param key A key identifying the selection
6473
* @param zaakSelection
6574
*/
66-
export async function setZaakSelection<DetailType = unknown>(
67-
key: string,
68-
zaakSelection: ZaakSelection<DetailType>,
69-
) {
75+
export async function setZaakSelection<
76+
DetailType extends
77+
ZaakSelectionMandatoryFields = ZaakSelectionMandatoryFields,
78+
>(key: string, zaakSelection: ZaakSelection<DetailType>) {
7079
const computedKey = _getComputedKey(key);
7180
const json = JSON.stringify(zaakSelection);
7281
sessionStorage.setItem(computedKey, json);
@@ -89,10 +98,10 @@ export async function clearZaakSelection(key: string) {
8998
* @param key A key identifying the selection
9099
* @param zaak Either a `Zaak.url` or `Zaak` object.
91100
*/
92-
export async function isZaakSelected<DetailType = unknown>(
93-
key: string,
94-
zaak: string | Zaak,
95-
) {
101+
export async function isZaakSelected<
102+
DetailType extends
103+
ZaakSelectionMandatoryFields = ZaakSelectionMandatoryFields,
104+
>(key: string, zaak: string | Zaak) {
96105
const zaakSelection = await getZaakSelection<DetailType>(key);
97106
const url = _getZaakUrl(zaak);
98107
return zaakSelection[url]?.selected;
@@ -107,7 +116,10 @@ export async function isZaakSelected<DetailType = unknown>(
107116
* @param selected Indicating whether the selection should be added (`true) or removed (`false).
108117
* @param detail An optional detail object of generic type
109118
*/
110-
export async function _mutateZaakSelection<DetailType = unknown>(
119+
export async function _mutateZaakSelection<
120+
DetailType extends
121+
ZaakSelectionMandatoryFields = ZaakSelectionMandatoryFields,
122+
>(
111123
key: string,
112124
zaken: string[] | Zaak[],
113125
selected: boolean,

frontend/src/pages/destructionlist/hooks.ts frontend/src/pages/destructionlist/hooks.tsx

+67-21
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import {
22
AttributeData,
3+
Button,
4+
ButtonProps,
35
DataGridProps,
6+
Tooltip,
47
TypedField,
58
formatMessage,
69
} from "@maykin-ui/admin-ui";
7-
import { useEffect, useRef, useState } from "react";
10+
import { ReactNode, useEffect, useRef, useState } from "react";
811
import { useNavigation, useSearchParams } from "react-router-dom";
912

1013
import { ZaaktypeChoice, listZaaktypeChoices } from "../../lib/api/private";
@@ -16,25 +19,31 @@ import {
1619
removeFromFieldSelection,
1720
} from "../../lib/fieldSelection/fieldSelection";
1821
import {
22+
ZaakSelectionMandatoryFields,
1923
addToZaakSelection,
24+
getZaakSelection,
2025
removeFromZaakSelection,
2126
} from "../../lib/zaakSelection/zaakSelection";
2227
import { ExpandZaak, Zaak } from "../../types";
2328

2429
/** The template used to format urls to an external application providing zaak details. */
2530
const REACT_APP_ZAAK_URL_TEMPLATE = process.env.REACT_APP_ZAAK_URL_TEMPLATE;
2631

27-
interface PaginatedZakenResultsWithAction extends PaginatedZaken {
28-
results: (Zaak & { action?: string })[];
32+
export interface DataGridAction
33+
extends Omit<ButtonProps, "onClick" | "onMouseEnter"> {
34+
onMouseEnter?: (zaak: Zaak, detail?: ZaakSelectionMandatoryFields) => void;
35+
onClick?: (zaak: Zaak, detail?: ZaakSelectionMandatoryFields) => void;
36+
tooltip?: ReactNode;
2937
}
3038

3139
/**
3240
* Hook that returns base props for most Zaak related DataGrid components.
3341
*/
3442
export function useDataGridProps(
3543
storageKey: string,
36-
paginatedResults: PaginatedZakenResultsWithAction,
44+
paginatedResults: PaginatedZaken,
3745
selectedResults: (Zaak | { url: string })[],
46+
actions?: DataGridAction[],
3847
): { props: DataGridProps; error: unknown } {
3948
const { state } = useNavigation();
4049
const [searchParams, setSearchParams] = useSearchParams();
@@ -82,8 +91,14 @@ export function useDataGridProps(
8291
);
8392
}, []);
8493

85-
const hasAction = paginatedResults.results.some((zaak) => zaak.action);
86-
const fields = getFields(searchParams, zaaktypeChoicesState, hasAction).map(
94+
const getSpecificZaakSelection = async (url: string) => {
95+
const zaakSelection = await getZaakSelection(storageKey);
96+
if (!zaakSelection[url].selected) return;
97+
return zaakSelection[url].detail;
98+
};
99+
100+
const hasActions = Boolean(actions?.length);
101+
const fields = getFields(searchParams, zaaktypeChoicesState, hasActions).map(
87102
(field) => {
88103
const isActiveFromStorage = fieldSelectionState?.[field.name];
89104
const isActive =
@@ -97,10 +112,48 @@ export function useDataGridProps(
97112
//
98113
// Get object list.
99114
//
100-
const objectList = paginatedResults.results.map((zaak) => ({
101-
...zaak,
102-
href: formatMessage(REACT_APP_ZAAK_URL_TEMPLATE || "", zaak),
103-
})) as unknown as AttributeData[];
115+
const objectList = paginatedResults.results.map((zaak) => {
116+
return {
117+
...zaak,
118+
href: formatMessage(REACT_APP_ZAAK_URL_TEMPLATE || "", zaak),
119+
acties: (
120+
<>
121+
{actions?.map(
122+
({ onClick, onMouseEnter, tooltip, ...action }, index) => {
123+
const ButtonComponent = (
124+
<Button
125+
pad={false}
126+
variant={"transparent"}
127+
key={index}
128+
onClick={async () => {
129+
const foundZaak = await getSpecificZaakSelection(zaak.url!);
130+
onClick?.(zaak, foundZaak);
131+
}}
132+
onMouseEnter={async () => {
133+
const foundZaak = await getSpecificZaakSelection(zaak.url!);
134+
onMouseEnter?.(zaak, foundZaak);
135+
}}
136+
{...action}
137+
/>
138+
);
139+
if (tooltip) {
140+
return (
141+
<Tooltip
142+
key={index}
143+
content={tooltip}
144+
placement={"bottom-start"}
145+
>
146+
{ButtonComponent}
147+
</Tooltip>
148+
);
149+
}
150+
return ButtonComponent;
151+
},
152+
)}
153+
</>
154+
),
155+
};
156+
}) as unknown as AttributeData[];
104157

105158
/**
106159
* Gets called when the fields selection is changed.
@@ -230,7 +283,7 @@ export function useDataGridProps(
230283
export function getFields(
231284
searchParams: URLSearchParams,
232285
zaaktypeChoices: ZaaktypeChoice[],
233-
hasAction: boolean,
286+
hasActions: boolean,
234287
): TypedField[] {
235288
return [
236289
{
@@ -349,15 +402,8 @@ export function getFields(
349402
{ value: "false", label: "Nee" },
350403
],
351404
},
352-
// Only show action column if there are actions to show
353-
...(hasAction
354-
? [
355-
{
356-
name: "action",
357-
type: "action",
358-
filterable: false,
359-
},
360-
]
361-
: []),
405+
...([hasActions && { name: "acties", type: "string" }].filter(
406+
Boolean,
407+
) as TypedField[]),
362408
];
363409
}

frontend/src/pages/destructionlist/review/DestructionListReview.tsx

+29
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ export function DestructionListReviewPage() {
8080
const submit = useSubmit();
8181
const destructionListReviewKey = getDestructionListReviewKey(uuid);
8282

83+
/* Tooltip Motivation */
84+
const [tooltipMotivation, setTooltipMotivation] = useState<string>("");
85+
8386
/* State to manage the count of selected zaken */
8487
const [zaakSelection, setZaakSelection] = useState<FormDataState[]>([]);
8588

@@ -268,6 +271,32 @@ export function DestructionListReviewPage() {
268271
onSubmitSelection={() => setListModalDataState({ open: true })}
269272
onSelect={onSelect}
270273
allowSelectAll={false}
274+
actions={[
275+
{
276+
children: <Outline.ChatBubbleBottomCenterIcon />,
277+
tooltip: tooltipMotivation && (
278+
<>
279+
<H2>Opmerking</H2>
280+
<P>{tooltipMotivation}</P>
281+
</>
282+
),
283+
onMouseEnter: (_, detail) => {
284+
const _detail = detail as FormDataState | undefined;
285+
if (_detail) {
286+
setTooltipMotivation(_detail.motivation);
287+
} else {
288+
setTooltipMotivation("");
289+
}
290+
},
291+
onClick: (zaak: Zaak) => {
292+
setZaakModalDataState({
293+
open: true,
294+
uuid: zaak.uuid,
295+
title: `${zaak.identificatie} uitzonderen`,
296+
});
297+
},
298+
},
299+
]}
271300
/>
272301
</>
273302
);

0 commit comments

Comments
 (0)