Skip to content

Commit

Permalink
MIJN-9682-Feature/blokkeren-stadspas (#1699)
Browse files Browse the repository at this point in the history
* added mock route

* Added block URL to data

* Added conditional button to block stadspassen

* Moved logic

* fixed tests

* TODO comments

* remove imports

* Refactored out function for use in block pass

* Made modal width resemble figma design

* semi working version

* small refactor

* shows geblokkeerd after pas

* Fix all stadspassen having the same ID

* fix test

* Add error alert

* Put list of stadspas owners into a table for the 'actief' status

* stopped updating whole appstate. Using atom instead

* replaced with SWR functionality

* Moved hook to hooks file

* added mock route

* Added block URL to data

* Added conditional button to block stadspassen

* Moved logic

* fixed tests

* TODO comments

* remove imports

* Refactored out function for use in block pass

* Made modal width resemble figma design

* semi working version

* small refactor

* shows geblokkeerd after pas

* Fix all stadspassen having the same ID

* fix test

* Add error alert

* Put list of stadspas owners into a table for the 'actief' status

* stopped updating whole appstate. Using atom instead

* replaced with SWR functionality

* Moved hook to hooks file

* use cache instead of atom, but does not rerender when updating cache

* Corrected a type that got changed after a rebase with main

* Moved routers next to eachother to make it more readable when you want to see which routers are in use

* Refactor some types

* Added route to the private stadspas handlers

* Added route to openapi docs

* Added tests for backend

* updated snapshot

* Added to test, but broken. Blocked pass won't show up yett

* Mijn-9682-Feature - blokkeren stadspas with proper swr (#1708)

* Fix types

* Fix implementation

* Refine types

* Refine type

* Juggle around references, change name

* Change mock server responses (add dynamic props)

* Change name

* Change http verb

* Rename hook

* Enable delay

* Change markup

* FIx type

* Add deprecation (boyscout)

* Rename

* Styling

* ADd hack

* Fix test

* Fix gpass tests

* Fix

* Addes tests, made helper to create components

* Add test for blocked pas

---------

Co-authored-by: Tim van Oostrom <[email protected]>
  • Loading branch information
RoanPaulus and timvanoostrom authored Jan 17, 2025
1 parent 1ab9a1c commit d1a504d
Show file tree
Hide file tree
Showing 66 changed files with 1,224 additions and 349 deletions.
1 change: 1 addition & 0 deletions mocks/collections.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"get-gpass-stadspas:standard",
"get-gpass-transacties:standard",
"get-gpass-aanbiedingen-transacties:standard",
"post-toggle-stadspas:standard",
"get-krefia:standard",
"get-kvk:standard",
"post-loodmetingen-auth:standard",
Expand Down
2 changes: 1 addition & 1 deletion mocks/fixtures/gpass-pashouders.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"categorie": "Minima stadspas",
"categorie_code": "M",
"actief": true,
"expiry_date": "2024-07-31T21:59:59.000Z",
"expiry_date": "2090-07-31T21:59:59.000Z",
"heeft_budget": false,
"vervangen": false,
"securitycode": "012346",
Expand Down
40 changes: 34 additions & 6 deletions mocks/routes/gpass.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
const UID = require('uid-safe');

const settings = require('../settings');
const RESPONSES = {
PASHOUDER: require('../fixtures/gpass-pashouders.json'),
Expand All @@ -25,15 +23,21 @@ module.exports = [
},
{
id: 'get-gpass-stadspas',
url: `${settings.MOCK_BASE_PATH}/gpass/rest/sales/v1/pas/*`,
url: `${settings.MOCK_BASE_PATH}/gpass/rest/sales/v1/pas/:pasnummer`,
method: 'GET',
variants: [
{
id: 'standard',
type: 'json',
type: 'middleware',
options: {
status: 200,
body: RESPONSES.STADSPAS,
middleware: (req, res) => {
res.send({
...RESPONSES.STADSPAS,
pasnummer: req.params.pasnummer,
pasnummer_volledig: `volledig.${req.params.pasnummer}`,
id: req.params.pasnummer,
});
},
},
},
],
Expand Down Expand Up @@ -68,4 +72,28 @@ module.exports = [
},
],
},
{
id: 'post-toggle-stadspas',
url: `${settings.MOCK_BASE_PATH}/gpass/rest/sales/v1/togglepas/:pasnummer`,
method: 'POST',
// Add delay to make loading icon visibile in the front end when pressing the block button.
delay: 2500,
variants: [
{
id: 'standard',
type: 'middleware',
options: {
middleware: (req, res) => {
// return res.status(500).end();
res.send({
// NOT sure if this is the same response as the real API
...RESPONSES.STADSPAS,
pasnummer: req.params.pasnummer,
actief: false,
});
},
},
},
],
},
];
23 changes: 23 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@
"sass": "^1.83.0",
"slugme": "^1.1.1",
"supercluster": "^7.1.5",
"swr": "^2.3.0",
"thenby": "^1.3.4",
"throttle-debounce": "^5.0.2",
"ts-node": "^10.9.2",
Expand Down
8 changes: 3 additions & 5 deletions src/client/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ export function Modal({
return isOpen
? ReactDOM.createPortal(
<div className={styles.ModalContainer}>
<div
className={classnames(styles.Modal, className)}
onClick={onClose}
/>
<div className={styles.Modal} onClick={onClose} />

<Dialog
ref={dialogEl}
Expand All @@ -51,7 +48,8 @@ export function Modal({
style={{ transform: `translateY(${marginTop}px)` }}
className={classnames(
styles.Dialog,
!showCloseButton && styles.DialogWithoutCloseButton
!showCloseButton && styles.DialogWithoutCloseButton,
className
)}
>
{children}
Expand Down
7 changes: 5 additions & 2 deletions src/client/components/Search/useSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ import {
displayPath,
} from './search-config';
import { AppRoutes } from '../../../universal/config/routes';
import { ApiResponse, isError } from '../../../universal/helpers/api';
import {
ApiResponse_DEPRECATED,
isError,
} from '../../../universal/helpers/api';
import { pick, uniqueArray } from '../../../universal/helpers/utils';
import { AppState, AppStateKey } from '../../../universal/types/App.types';
import { IconMarker } from '../../assets/icons';
Expand Down Expand Up @@ -373,7 +376,7 @@ export const searchConfigRemote = selector<SearchConfigRemote | null>({
get: async ({ get }) => {
// Subscribe to updates from requestID to re-evaluate selector to reload the SEARCH_CONFIG
get(requestID);
const response: AxiosResponse<ApiResponse<SearchConfigRemote>> =
const response: AxiosResponse<ApiResponse_DEPRECATED<SearchConfigRemote>> =
await axios.get(BFFApiUrls.SEARCH_CONFIGURATION, {
responseType: 'json',
withCredentials: true,
Expand Down
11 changes: 7 additions & 4 deletions src/client/config/api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { IS_PRODUCTION } from '../../universal/config/env';
import { ApiResponse, FailedDependencies } from '../../universal/helpers/api';
import {
ApiResponse_DEPRECATED,
FailedDependencies,
} from '../../universal/helpers/api';
import { ApiError, AppState } from '../../universal/types';

export const BFF_API_BASE_URL = import.meta.env.REACT_APP_BFF_API_URL;
Expand Down Expand Up @@ -89,7 +92,7 @@ export const ErrorNames: Record<string /* ApiStateKey */, string> = {

export function createErrorDisplayData(
stateKey: string,
apiResponseData: ApiResponse<unknown> | null | string
apiResponseData: ApiResponse_DEPRECATED<unknown> | null | string
): ApiError {
const name = ErrorNames[stateKey] || stateKey;
const errorMessage =
Expand All @@ -116,7 +119,7 @@ export function createFailedDependenciesError(
apiErrors.push(
createErrorDisplayData(
`${stateKey}_${stateDependencyKey}`,
apiDependencyResponseData as ApiResponse<unknown>
apiDependencyResponseData as ApiResponse_DEPRECATED<unknown>
)
);
}
Expand Down Expand Up @@ -158,7 +161,7 @@ export function getApiErrors(appState: AppState): ApiError[] {
apiErrors.push(
createErrorDisplayData(
stateKey,
apiResponseData as ApiResponse<unknown>
apiResponseData as ApiResponse_DEPRECATED<unknown>
)
);
}
Expand Down
Empty file.
9 changes: 7 additions & 2 deletions src/client/hooks/api/useCmsMaintenanceNotifications.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import type { CMSMaintenanceNotification } from '../../../server/services/cms-maintenance-notifications';
import { ApiResponse, apiPristineResult } from '../../../universal/helpers/api';
import {
ApiResponse_DEPRECATED,
apiPristineResult,
} from '../../../universal/helpers/api';
import { BFFApiUrls } from '../../config/api';
import { useAppStateGetter } from '../useAppState';
import { useDataApi } from './useDataApi';
Expand All @@ -9,7 +12,9 @@ export function useCmsMaintenanceNotifications(
fromApiDirectly: boolean = false
) {
const { CMS_MAINTENANCE_NOTIFICATIONS } = useAppStateGetter();
const [api] = useDataApi<ApiResponse<CMSMaintenanceNotification[]>>(
const [api] = useDataApi<
ApiResponse_DEPRECATED<CMSMaintenanceNotification[]>
>(
{
url:
BFFApiUrls.SERVICES_CMS_MAINTENANCE_NOTIFICATIONS_URL +
Expand Down
14 changes: 9 additions & 5 deletions src/client/hooks/useAppState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { SetterOrUpdater, atom, useRecoilState, useRecoilValue } from 'recoil';

import { streamEndpointQueryParamKeys } from '../../universal/config/app';
import { FeatureToggle } from '../../universal/config/feature-toggles';
import { ApiResponse, apiPristineResult } from '../../universal/helpers/api';
import {
ApiResponse_DEPRECATED,
apiPristineResult,
} from '../../universal/helpers/api';
import { AppState, BagThema } from '../../universal/types/App.types';
import { PRISTINE_APPSTATE, createAllErrorState } from '../AppState';
import { BFFApiUrls } from '../config/api';
Expand Down Expand Up @@ -214,7 +217,7 @@ export function useAppStateBagApi<T>({
typeof appState[bagThema] !== 'undefined' &&
key in appState[bagThema]!;

const [api, fetch] = useDataApi<ApiResponse<T | null>>(
const [api, fetch] = useDataApi<ApiResponse_DEPRECATED<T | null>>(
{
url,
postpone: isApiDataCached || !url,
Expand All @@ -240,7 +243,7 @@ export function useAppStateBagApi<T>({

localState = {
...localState,
[key]: api.data as ApiResponse<T | null>,
[key]: api.data as ApiResponse_DEPRECATED<T | null>,
};

return {
Expand All @@ -252,7 +255,8 @@ export function useAppStateBagApi<T>({
}, [isApiDataCached, api, key, url]);

return [
(appState?.[bagThema]?.[key] as ApiResponse<T | null>) || api.data, // Return the response data from remote system or the pristine data provided to useApiData.
(appState?.[bagThema]?.[key] as ApiResponse_DEPRECATED<T | null>) ||
api.data, // Return the response data from remote system or the pristine data provided to useApiData.
fetch,
isApiDataCached,
] as const;
Expand All @@ -261,7 +265,7 @@ export function useAppStateBagApi<T>({
export function useGetAppStateBagDataByKey<T>({
bagThema,
key,
}: Omit<AppStateBagApiParams, 'url'>): ApiResponse<T | null> | null {
}: Omit<AppStateBagApiParams, 'url'>): ApiResponse_DEPRECATED<T | null> | null {
const appState = useRecoilValue(appStateAtom);
return appState?.[bagThema]?.[key] ?? null;
}
Expand Down
57 changes: 57 additions & 0 deletions src/client/pages/HLI/HLI.hooks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { atom, useRecoilState } from 'recoil';
import useSWRMutation from 'swr/mutation';

import { StadspasFrontend } from '../../../server/services/hli/stadspas-types';
import { useAppStateGetter } from '../../hooks/useAppState';

type StadspasActiefByID = {
[id: string]: boolean;
};

const stadspasActiefAtom = atom<StadspasActiefByID>({
key: 'stadspasActief',
default: {},
});

export function useStadspassen() {
const { HLI } = useAppStateGetter();
const [stadspasActief, setStadspassenActiefStatus] =
useRecoilState(stadspasActiefAtom);

const stadspassen: StadspasFrontend[] = (HLI.content?.stadspas || []).map(
(pas) => {
const stadspas = {
...pas,
actief: stadspasActief[pas.id] ?? true,
};
return stadspas;
}
);

return [stadspassen, setStadspassenActiefStatus] as const;
}

export function useBlockStadspas(url: string | null, stadspasId: string) {
const setStadspassenActiefStatus = useStadspassen()[1];

return useSWRMutation(
url,
async (url) => {
const response = await fetch(url, {
method: 'POST',
credentials: 'include',
});

if (!response.ok) {
throw new Error('Request returned with an error');
}

setStadspassenActiefStatus((stadspasActiefState) => {
return { ...stadspasActiefState, [stadspasId]: false };
});

return response;
},
{ revalidate: false, populateCache: false }
);
}
17 changes: 17 additions & 0 deletions src/client/pages/HLI/HLI.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,25 @@
--ams-paragraph-color: #{$color-neutral-grey4};
}

.Stadspassen {
height: fit-content;
tr {
height: 100%;
}
}

.StatusValue {
// Hack to align table cell content with other cells content
&:before {
content: '';
line-height: var(--ams-link-standalone-line-height);
font-size: var(--ams-text-level-2-font-size);
}
}

@media screen and (min-width: $ams-breakpoint-medium) {
.EerdereRegelingen,
.Stadspassen,
.HuidigeRegelingen {
tr {
> th,
Expand Down
Loading

0 comments on commit d1a504d

Please sign in to comment.