Skip to content

Commit ba9e24e

Browse files
authored
Merge pull request #134 from maykinmedia/issue/#120-comments
#120 - feat: implemented comments
2 parents abb0a50 + 7012eb0 commit ba9e24e

File tree

4 files changed

+128
-20
lines changed

4 files changed

+128
-20
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

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export type ZaakSelection<DetailType = unknown> = {
1010
*/
1111
[index: string]: {
1212
selected: boolean;
13-
detail?: DetailType; // todo generic?
13+
detail?: DetailType;
1414
};
1515
};
1616

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

+82-13
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";
@@ -17,20 +20,29 @@ import {
1720
} from "../../lib/fieldSelection/fieldSelection";
1821
import {
1922
addToZaakSelection,
23+
getZaakSelection,
2024
removeFromZaakSelection,
2125
} from "../../lib/zaakSelection/zaakSelection";
2226
import { ExpandZaak, Zaak } from "../../types";
2327

2428
/** The template used to format urls to an external application providing zaak details. */
2529
const REACT_APP_ZAAK_URL_TEMPLATE = process.env.REACT_APP_ZAAK_URL_TEMPLATE;
2630

31+
export interface DataGridAction
32+
extends Omit<ButtonProps, "onClick" | "onMouseEnter"> {
33+
onMouseEnter?: (zaak: Zaak, detail?: unknown) => void;
34+
onClick?: (zaak: Zaak, detail?: unknown) => void;
35+
tooltip?: ReactNode;
36+
}
37+
2738
/**
2839
* Hook that returns base props for most Zaak related DataGrid components.
2940
*/
3041
export function useDataGridProps(
3142
storageKey: string,
3243
paginatedResults: PaginatedZaken,
3344
selectedResults: (Zaak | { url: string })[],
45+
actions?: DataGridAction[],
3446
): { props: DataGridProps; error: unknown } {
3547
const { state } = useNavigation();
3648
const [searchParams, setSearchParams] = useSearchParams();
@@ -78,22 +90,75 @@ export function useDataGridProps(
7890
);
7991
}, []);
8092

81-
const fields = getFields(searchParams, zaaktypeChoicesState).map((field) => {
82-
const isActiveFromStorage = fieldSelectionState?.[field.name];
83-
const isActive =
84-
typeof isActiveFromStorage === "undefined"
85-
? field.active !== false
86-
: isActiveFromStorage;
87-
return { ...field, active: isActive } as TypedField;
88-
});
93+
//
94+
// Gets a specific zaak selection based on the url.
95+
//
96+
const getSpecificZaakSelection = async (url: string) => {
97+
const zaakSelection = await getZaakSelection(storageKey);
98+
if (!zaakSelection[url]?.selected) return;
99+
return zaakSelection[url].detail;
100+
};
101+
102+
const hasActions = Boolean(actions?.length);
103+
const fields = getFields(searchParams, zaaktypeChoicesState, hasActions).map(
104+
(field) => {
105+
const isActiveFromStorage = fieldSelectionState?.[field.name];
106+
const isActive =
107+
typeof isActiveFromStorage === "undefined"
108+
? field.active !== false
109+
: isActiveFromStorage;
110+
return { ...field, active: isActive } as TypedField;
111+
},
112+
);
113+
114+
//
115+
// Render action buttons.
116+
//
117+
const renderActionButtons = (zaak: Zaak, actions?: DataGridAction[]) => {
118+
return actions?.map(
119+
({ onClick, onMouseEnter, tooltip, ...action }, index) => {
120+
const handleAction = async (
121+
zaak: Zaak,
122+
actionFn?: (zaak: Zaak, detail?: unknown) => void,
123+
) => {
124+
const foundZaak = await getSpecificZaakSelection(zaak.url!);
125+
actionFn?.(zaak, foundZaak);
126+
};
127+
128+
const ButtonComponent = (
129+
<Button
130+
pad={false}
131+
variant={"transparent"}
132+
key={index}
133+
onClick={() => handleAction(zaak, onClick)}
134+
onMouseEnter={() => handleAction(zaak, onMouseEnter)}
135+
{...action}
136+
/>
137+
);
138+
139+
if (tooltip) {
140+
return (
141+
<Tooltip key={index} content={tooltip} placement={"bottom-start"}>
142+
{ButtonComponent}
143+
</Tooltip>
144+
);
145+
}
146+
147+
return ButtonComponent;
148+
},
149+
);
150+
};
89151

90152
//
91153
// Get object list.
92154
//
93-
const objectList = paginatedResults.results.map((zaak) => ({
94-
...zaak,
95-
href: formatMessage(REACT_APP_ZAAK_URL_TEMPLATE || "", zaak),
96-
})) as unknown as AttributeData[];
155+
const objectList = paginatedResults.results.map((zaak) => {
156+
return {
157+
...zaak,
158+
href: formatMessage(REACT_APP_ZAAK_URL_TEMPLATE || "", zaak),
159+
acties: <>{renderActionButtons(zaak, actions)}</>,
160+
};
161+
}) as unknown as AttributeData[];
97162

98163
/**
99164
* Gets called when the fields selection is changed.
@@ -223,6 +288,7 @@ export function useDataGridProps(
223288
export function getFields(
224289
searchParams: URLSearchParams,
225290
zaaktypeChoices: ZaaktypeChoice[],
291+
hasActions: boolean,
226292
): TypedField[] {
227293
return [
228294
{
@@ -341,5 +407,8 @@ export function getFields(
341407
{ value: "false", label: "Nee" },
342408
],
343409
},
410+
...([hasActions && { name: "acties", type: "string" }].filter(
411+
Boolean,
412+
) as TypedField[]),
344413
];
345414
}

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

+38-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import {
33
Body,
44
Form,
55
FormField,
6+
H2,
67
Modal,
8+
Outline,
9+
P,
710
} from "@maykin-ui/admin-ui";
811
import { FormEvent, useState } from "react";
912
import {
@@ -75,8 +78,11 @@ export function DestructionListReviewPage() {
7578
const submit = useSubmit();
7679
const destructionListReviewKey = getDestructionListReviewKey(uuid);
7780

81+
/* Tooltip Motivation */
82+
const [tooltipMotivation, setTooltipMotivation] = useState<string>("");
83+
7884
/* State to manage the count of selected zaken */
79-
const [zaakSelectionCount, setZaakSelectionCount] = useState<number>(0);
85+
const [zaakSelection, setZaakSelection] = useState<FormDataState[]>([]);
8086

8187
/* State to manage the state of the zaak modal (when clicking a checkbox) */
8288
const [zaakModalDataState, setZaakModalDataState] =
@@ -186,7 +192,7 @@ export function DestructionListReviewPage() {
186192
const zaakSelectionSelected = Object.values(zaakSelection).filter(
187193
(f) => f.selected,
188194
);
189-
setZaakSelectionCount(zaakSelectionSelected.length);
195+
setZaakSelection(zaakSelectionSelected.map((f) => f.detail!));
190196
};
191197

192198
return (
@@ -207,7 +213,7 @@ export function DestructionListReviewPage() {
207213
</Body>
208214
</Modal>
209215
<Modal
210-
title={zaakSelectionCount > 0 ? "Beoordelen" : "Accoderen"}
216+
title={zaakSelection.length > 0 ? "Beoordelen" : "Accoderen"}
211217
open={listModalDataState.open}
212218
size="m"
213219
onClose={() => setListModalDataState({ open: false })}
@@ -217,19 +223,46 @@ export function DestructionListReviewPage() {
217223
fields={listModalFormFields}
218224
onSubmit={onSubmitDestructionListForm}
219225
validateOnChange
220-
labelSubmit={zaakSelectionCount > 0 ? "Beoordelen" : "Accoderen"}
226+
labelSubmit={zaakSelection.length > 0 ? "Beoordelen" : "Accoderen"}
221227
/>
222228
</Body>
223229
</Modal>
230+
224231
<DestructionListComponent
225232
storageKey={destructionListReviewKey}
226233
zaken={zaken}
227234
selectedZaken={selectedZaken}
228-
labelAction={zaakSelectionCount > 0 ? "Beoordelen" : "Accoderen"}
235+
labelAction={zaakSelection.length > 0 ? "Beoordelen" : "Accoderen"}
229236
title={`${list.name} beoordelen`}
230237
onSubmitSelection={() => setListModalDataState({ open: true })}
231238
onSelect={onSelect}
232239
allowSelectAll={false}
240+
actions={[
241+
{
242+
children: <Outline.ChatBubbleBottomCenterIcon />,
243+
tooltip: tooltipMotivation && (
244+
<>
245+
<H2>Opmerking</H2>
246+
<P>{tooltipMotivation}</P>
247+
</>
248+
),
249+
onMouseEnter: (_, detail) => {
250+
const _detail = detail as FormDataState | undefined;
251+
if (_detail) {
252+
setTooltipMotivation(_detail.motivation);
253+
} else {
254+
setTooltipMotivation("");
255+
}
256+
},
257+
onClick: (zaak: Zaak) => {
258+
setZaakModalDataState({
259+
open: true,
260+
uuid: zaak.uuid,
261+
title: `${zaak.identificatie} uitzonderen`,
262+
});
263+
},
264+
},
265+
]}
233266
/>
234267
</>
235268
);

0 commit comments

Comments
 (0)