Skip to content

Commit c714552

Browse files
✨ [#37] feat: implement detail routing
1 parent e0e7574 commit c714552

File tree

5 files changed

+55
-18
lines changed

5 files changed

+55
-18
lines changed

frontend/src/pages/zaaktype/zaaktype.loader.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,10 @@ export const zaaktypeLoader = loginRequired(
1818
async (
1919
loaderFunctionArgs: LoaderFunctionArgs,
2020
): Promise<ZaaktypeLoaderData> => {
21-
const url = new URL(loaderFunctionArgs.request.url);
22-
const uuid = loaderFunctionArgs.params.zaaktypeId;
23-
const params = url.searchParams;
21+
const { params } = loaderFunctionArgs;
2422
const response = await request<DetailResponse<ZaakType>>(
2523
"GET",
26-
`/catalogi/zaaktypen/${uuid}`,
27-
params,
24+
`/service/${params.serviceSlug}/zaaktypen/${params.zaaktypeUUID}`,
2825
);
2926
return { ...response, fieldsets: ZAAKTYPE_FIELDSETS };
3027
},
Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { useLoaderData } from "react-router";
1+
import { useCallback } from "react";
2+
import { useLoaderData, useLocation } from "react-router";
23
import { ZaaktypenLoaderData } from "~/pages";
34
import { ListView } from "~/views";
45

@@ -7,5 +8,16 @@ import { ListView } from "~/views";
78
*/
89
export function ZaaktypenPage() {
910
const loaderData = useLoaderData<ZaaktypenLoaderData>();
10-
return <ListView {...loaderData} />;
11+
const { pathname } = useLocation();
12+
13+
/**
14+
* Splits `obj.url` into parts, using the last part as UUID.
15+
* @param obj - An object which implements a `url` key.
16+
*/
17+
const getUUID = useCallback(
18+
(obj: { url: string }) => `${pathname}/${obj.url.split("/").reverse()[0]}`,
19+
[pathname],
20+
);
21+
22+
return <ListView {...loaderData} getHref={getUUID} />;
1123
}

frontend/src/pages/zaaktypen/zaaktypen.loader.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,17 @@ export const zaaktypenLoader = loginRequired(
1919
loaderFunctionArgs: LoaderFunctionArgs,
2020
): Promise<ZaaktypenLoaderData> => {
2121
const { params } = loaderFunctionArgs;
22+
23+
// Skip fetching if detail view is active.
24+
if (params.zaaktypeUUID) {
25+
return {
26+
fields: [],
27+
fieldsets: [],
28+
pagination: { count: 0, page: 1, pageSize: 0 },
29+
results: [],
30+
};
31+
}
32+
2233
const response = await request<ListResponse<ZaakType>>(
2334
"GET",
2435
`/service/${params.serviceSlug}/zaaktypen`,

frontend/src/routes.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const routes: RouteObject[] = [
4646
children: [
4747
{
4848
id: "zaaktype",
49-
path: ":zaaktypeId",
49+
path: ":zaaktypeUUID",
5050
element: <ZaaktypePage />,
5151
loader: zaaktypeLoader,
5252
},

frontend/src/views/ListView/ListView.tsx

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { FieldSet, ListTemplate } from "@maykin-ui/admin-ui";
2-
import { useCallback } from "react";
1+
import { ListTemplate } from "@maykin-ui/admin-ui";
2+
import React, { useCallback } from "react";
33
import {
4-
useLocation,
4+
useNavigate,
55
useNavigation,
66
useOutlet,
77
useSearchParams,
@@ -10,7 +10,7 @@ import { ListResponse } from "~/api/types";
1010
import { useBreadcrumbItems } from "~/hooks";
1111

1212
export type ListViewProps<T extends object> = ListResponse<T> & {
13-
fieldsets: FieldSet<T>[];
13+
getHref?: (obj: T) => string;
1414
};
1515

1616
/**
@@ -19,20 +19,22 @@ export type ListViewProps<T extends object> = ListResponse<T> & {
1919
* The primary action (click) shows item details in a side pane.
2020
* Ctrl+click or Cmd+click navigates to the item's detail route in fullscreen.
2121
*
22-
* @typeParam T - The type of items in the list. Must include at least `uuid` and `identificatie` fields.
22+
* @typeParam T - The type of items in the list. Must include at least `uuid` and
23+
* `identificatie` fields.
2324
*
2425
* @param fields - The field's configuration.
2526
* @param pagination - The paginator configuration.
2627
* @param results - The list of items to render in the data grid.
27-
* @param fieldsets - Optional custom fieldsets used for rendering item details.
28-
* @param fieldsets - Optional custom fieldsets used for rendering item details.
28+
* @param getHref - A function that if set, receives the row and should return a
29+
* URL to navigate to.
2930
*/
3031
export function ListView<T extends object>({
3132
fields,
3233
pagination,
3334
results,
35+
getHref,
3436
}: ListViewProps<T>) {
35-
const { pathname } = useLocation();
37+
const navigate = useNavigate();
3638
const { state } = useNavigation();
3739
const outlet = useOutlet();
3840
const [urlSearchParams, setURLSearchParams] = useSearchParams();
@@ -69,22 +71,37 @@ export function ListView<T extends object>({
6971
[urlSearchParams],
7072
);
7173

74+
/**
75+
* Gets called when a row's identifier is clicked.
76+
* @param event - The mouse event.
77+
* @param data - The row data.
78+
*/
79+
const handleClick = useCallback(
80+
(event: React.MouseEvent<HTMLAnchorElement>, data: T) => {
81+
event.preventDefault();
82+
if (getHref) {
83+
navigate(getHref(data));
84+
}
85+
},
86+
[getHref],
87+
);
88+
7289
return (
7390
outlet || (
7491
<ListTemplate
7592
breadcrumbItems={breadcrumbItems}
7693
dataGridProps={{
7794
objectList: results.map((row) => ({
7895
...row,
79-
// @ts-expect-error - Assume uuid.
80-
href: row.uuid ? `${pathname}/${row.uuid}` : undefined,
96+
href: getHref && getHref(row),
8197
})),
8298
decorate: true,
8399
fields: fields,
84100
height: "fill-available-space",
85101
showPaginator: Boolean(pagination),
86102
loading: state !== "idle",
87103
paginatorProps: pagination,
104+
onClick: handleClick,
88105
onPageChange: handlePageChange,
89106
}}
90107
/>

0 commit comments

Comments
 (0)