diff --git a/azure-pipeline-bff.yaml b/azure-pipeline-bff.yaml
index a3d50b74f3..26e6afd1a9 100644
--- a/azure-pipeline-bff.yaml
+++ b/azure-pipeline-bff.yaml
@@ -2,8 +2,9 @@ trigger:
batch: true
branches:
include:
+ - ontwikkelen
- testen
- - az-acceptance
+ - main
paths:
include:
- src/server
@@ -50,6 +51,9 @@ parameters:
default: false
variables:
+ - ${{ if eq(variables['Build.SourceBranchName'], 'ontwikkelen') }}:
+ - name: dtapName
+ value: o
- ${{ if or(eq(variables['Build.SourceBranchName'], 'testen'), eq(variables['Build.Reason'], 'PullRequest')) }}:
- name: dtapName
value: t
@@ -76,4 +80,3 @@ jobs:
btdAppBFF: true
btdAppUI: false
updateAppSettings: ${{ parameters.updateAppSettings }}
- aquaScan: ${{ eq(variables['Build.Reason'], 'PullRequest') }}
diff --git a/azure-pipeline-ui.yaml b/azure-pipeline-ui.yaml
index b59e6845e1..5316f0197b 100644
--- a/azure-pipeline-ui.yaml
+++ b/azure-pipeline-ui.yaml
@@ -2,8 +2,9 @@ trigger:
batch: true
branches:
include:
+ - ontwikkelen
- testen
- - az-acceptance
+ - main
paths:
include:
- src/client
@@ -80,4 +81,3 @@ jobs:
btdAppBFF: false
btdAppUI: true
updateAppSettings: ${{ parameters.updateAppSettings }}
- aquaScan: ${{ eq(variables['Build.Reason'], 'PullRequest') }}
diff --git a/src/client/AppState.ts b/src/client/AppState.ts
index 0b6e8afc47..aff0c0d9f4 100644
--- a/src/client/AppState.ts
+++ b/src/client/AppState.ts
@@ -60,6 +60,7 @@ export const PRISTINE_APPSTATE: AppState = {
profileTypes: ['private'],
}),
MILIEUZONE: apiPristineResult({ isKnown: false }),
+ OVERTREDINGEN: apiPristineResult({ isKnown: false }),
TOERISTISCHE_VERHUUR: apiPristineResult({
vergunningen: [],
registraties: [],
diff --git a/src/client/assets/icons/Overtredingen.svg b/src/client/assets/icons/Overtredingen.svg
new file mode 100644
index 0000000000..aae1c9ca49
--- /dev/null
+++ b/src/client/assets/icons/Overtredingen.svg
@@ -0,0 +1,20 @@
+
+
\ No newline at end of file
diff --git a/src/client/assets/icons/index.tsx b/src/client/assets/icons/index.tsx
index ce7b3c31af..73864f9342 100644
--- a/src/client/assets/icons/index.tsx
+++ b/src/client/assets/icons/index.tsx
@@ -30,11 +30,11 @@ export { default as IconInkomenSVWI } from './inkomen-svwi.svg?react';
export { default as IconKlachten } from './IconKlachten.svg?react';
export { default as IconKrefia } from './krefia.svg?react';
export { default as IconLogout } from './Logout.svg?react';
-// Map icons
export { default as MapIconHomeCommercial } from './map/homeCommercial__primary-red.svg?react';
export { default as IconMarker } from './Marker.svg?react';
export { default as IconMijnGegevens } from './MijnGegevens.svg?react';
export { default as IconMilieuzone } from './milieuzone.svg?react';
+export { default as IconOvertredingen } from './Overtredingen.svg?react';
export {
default as IconIndeterminate,
default as IconMin,
diff --git a/src/client/components/MainNavSubmenu/MainNavSubmenu.module.scss b/src/client/components/MainNavSubmenu/MainNavSubmenu.module.scss
index 4a762a4abe..9d70a78dc5 100644
--- a/src/client/components/MainNavSubmenu/MainNavSubmenu.module.scss
+++ b/src/client/components/MainNavSubmenu/MainNavSubmenu.module.scss
@@ -117,7 +117,7 @@
border-bottom: solid 0.2rem transparent;
@include mq-tablet() {
- line-height: 2.5rem;
+ line-height: 1;
}
}
diff --git a/src/client/components/MyChaptersPanel/MyChaptersPanel.tsx b/src/client/components/MyChaptersPanel/MyChaptersPanel.tsx
index 467c5d3251..eafa4adaa5 100644
--- a/src/client/components/MyChaptersPanel/MyChaptersPanel.tsx
+++ b/src/client/components/MyChaptersPanel/MyChaptersPanel.tsx
@@ -1,6 +1,5 @@
-import { AppRoutes } from '../../../universal/config';
+import { AppRoutes, ChapterMenuItem } from '../../../universal/config';
import { ChapterIcons } from '../../config/chapterIcons';
-import { ChapterMenuItem } from '../../config/menuItems';
import { Heading } from '@amsterdam/design-system-react';
import { IconInfo } from '../../assets/icons';
import Linkd from '../Button/Button';
diff --git a/src/client/config/api.ts b/src/client/config/api.ts
index 1cdd1140dc..115cf8288b 100644
--- a/src/client/config/api.ts
+++ b/src/client/config/api.ts
@@ -56,6 +56,7 @@ export const ErrorNames: Record = {
BUURT: 'Mijn buurt / Mijn bedrijfsomgeving',
BELASTINGEN: 'Actuele updates over uw belastingen',
MILIEUZONE: 'Milieuzone',
+ OVERTREDINGEN: 'Overtredingen voertuigen',
MY_LOCATION: 'Uw locatie op de kaart',
VERGUNNINGEN: 'Vergunningen',
ALL: 'Alle gegevens', // indien data helemaal niet opgehaald kan worden
diff --git a/src/client/config/chapterIcons.tsx b/src/client/config/chapterIcons.tsx
index d361e03ba0..07574850c8 100644
--- a/src/client/config/chapterIcons.tsx
+++ b/src/client/config/chapterIcons.tsx
@@ -5,29 +5,29 @@ import {
IconAVG,
IconBelastingen,
IconBezwaren,
+ IconBodem,
IconBurgerZaken,
IconErfpacht,
IconGarbage,
IconHomeCommercial,
+ IconHoreca,
IconInkomen,
IconInkomenSVWI,
+ IconKlachten,
+ IconKrefia,
IconMijnGegevens,
IconMilieuzone,
IconMyNotifications,
+ IconOvertredingen,
+ IconParkeren,
+ IconSearch,
IconSiaMeldingen,
IconStadspas,
- IconTips,
- IconVergunningen,
- IconZorg,
- IconToeristischeVerhuur,
- IconKrefia,
IconSubsidie,
- IconSearch,
+ IconToeristischeVerhuur,
+ IconVergunningen,
IconWior,
- IconParkeren,
- IconKlachten,
- IconHoreca,
- IconBodem,
+ IconZorg,
} from '../assets/icons';
export const ChapterIcons: Record = {
@@ -42,6 +42,7 @@ export const ChapterIcons: Record = {
[Chapters.STADSPAS]: IconStadspas,
[Chapters.BRP]: IconMijnGegevens,
[Chapters.MILIEUZONE]: IconMilieuzone,
+ [Chapters.OVERTREDINGEN]: IconOvertredingen,
[Chapters.SIA]: IconSiaMeldingen,
[Chapters.NOTIFICATIONS]: IconMyNotifications,
[Chapters.ROOT]: IconBurgerZaken,
diff --git a/src/server/config.ts b/src/server/config.ts
index beeae40541..5080d9cb68 100644
--- a/src/server/config.ts
+++ b/src/server/config.ts
@@ -177,7 +177,7 @@ export const ApiConfig: ApiDataRequestConfig = {
},
CLEOPATRA: {
url: `${process.env.BFF_CLEOPATRA_API_ENDPOINT}`,
- postponeFetch: !FeatureToggle.milieuzoneApiActive,
+ postponeFetch: !FeatureToggle.cleopatraApiActive,
method: 'POST',
httpsAgent: new https.Agent({
cert: getCert('BFF_SERVER_CLIENT_CERT'),
diff --git a/src/server/mock-data/index.ts b/src/server/mock-data/index.ts
index 720e3fd05c..4a40f5a10c 100644
--- a/src/server/mock-data/index.ts
+++ b/src/server/mock-data/index.ts
@@ -18,7 +18,7 @@ import KVK1 from './json/kvk-handelsregister.json';
import KVK2 from './json/kvk-handelsregister2.json';
import LOODMETING_RAPPORT from './json/loodmeting_rapport.json';
import LOODMETINGEN from './json/loodmetingen.json';
-import MILIEUZONE from './json/milieuzone.json';
+import CLEOPATRA from './json/cleopatra.json';
import TOERISTISCHE_VERHUUR_REGISTRATIES_BSN from './json/registraties-toeristische-verhuur-bsn.json';
import TOERISTISCHE_VERHUUR_REGISTRATIE from './json/registraties-toeristische-verhuur.json';
import SIA_HISTORY from './json/sia-history.json';
@@ -226,7 +226,7 @@ export const mockDataConfig: MockDataConfig = {
method: 'post',
status: (config: any) => (isCommercialUser(config) ? 200 : 200),
responseData: async (config: any) => {
- return await loadMockApiResponseJson(MILIEUZONE);
+ return await loadMockApiResponseJson(CLEOPATRA);
},
},
[String(ApiUrls.VERGUNNINGEN)]: {
diff --git a/src/server/mock-data/json/cleopatra.json b/src/server/mock-data/json/cleopatra.json
new file mode 100644
index 0000000000..77005aabfb
--- /dev/null
+++ b/src/server/mock-data/json/cleopatra.json
@@ -0,0 +1,102 @@
+[
+ {
+ "thema": "Milieuzone",
+ "categorie": "M1",
+ "prioriteit": 0,
+ "datum": "2019-12-13",
+ "titel": "Uw aanvraag ontheffing milieuzone Brom- en snorfietsen",
+ "omschrijving": "Uw moet uw aanvraag voor ontheffing milieuzone Brom- en snorfietsen nog betalen",
+ "url": "https://ontheffingen-acc.amsterdam.nl/publiek/aanvraag/56B31535-1404-4AC0-8658-CD77C32C12EE",
+ "urlNaam": "Betaal direct"
+ },
+ {
+ "thema": "Milieuzone",
+ "categorie": "F3",
+ "prioriteit": 0,
+ "datum": "2020-12-21",
+ "titel": "Uw aanvraag ontheffing milieuzone Vracht",
+ "omschrijving": "Uw aanvraag voor ontheffing milieuzone Vracht is toegekend",
+ "url": "https://ontheffingen-acc.amsterdam.nl/publiek/aanvraag/2a5d9103-42bb-4a88-9bf9-5cd58580e209",
+ "urlNaam": "Meer informatie"
+ },
+ {
+ "thema": "Milieuzone",
+ "categorie": "F3",
+ "prioriteit": 0,
+ "datum": "2019-12-13",
+ "titel": "Uw aanvraag ontheffing milieuzone Brom- en snorfietsen",
+ "omschrijving": "Uw aanvraag voor ontheffing milieuzone Brom- en snorfietsen is toegekend",
+ "url": "https://ontheffingen-acc.amsterdam.nl/publiek/aanvraag/7B46A24E-BC21-44F9-ADB8-B85A75FAFB90",
+ "urlNaam": "Meer informatie"
+ },
+ {
+ "thema": "Milieuzone",
+ "categorie": "F2",
+ "prioriteit": 50,
+ "datum": "2023-10-12",
+ "titel": "Ontheffing milieuzone",
+ "omschrijving": "",
+ "url": "https://ontheffingen-acc.amsterdam.nl/publiek/aanvragen",
+ "urlNaam": "Milieuzone"
+ },
+ {
+ "thema": "Milieuzone",
+ "categorie": "M1",
+ "prioriteit": 0,
+ "datum": "2019-12-13",
+ "titel": "Uw aanvraag ontheffing milieuzone Brom- en snorfietsen",
+ "omschrijving": "Uw moet uw aanvraag voor ontheffing milieuzone Brom- en snorfietsen nog betalen",
+ "url": "https://ontheffingen-acc.amsterdam.nl/publiek/aanvraag/88D12139-6BFF-45BF-9FA5-4BFCC01F284F",
+ "urlNaam": "Betaal direct"
+ },
+ {
+ "thema": "Milieuzone",
+ "categorie": "F3",
+ "prioriteit": 0,
+ "datum": "2019-12-13",
+ "titel": "Uw aanvraag ontheffing milieuzone Brom- en snorfietsen",
+ "omschrijving": "Uw aanvraag voor ontheffing milieuzone Brom- en snorfietsen is toegekend",
+ "url": "https://ontheffingen-acc.amsterdam.nl/publiek/aanvraag/3A36D276-244D-4B12-8A43-97573502728E",
+ "urlNaam": "Meer informatie"
+ },
+ {
+ "thema": "Overtredingen",
+ "categorie": "F2",
+ "prioriteit": 50,
+ "datum": "2023-10-12",
+ "titel": "Overtredingen",
+ "omschrijving": "",
+ "url": "https://ontheffingen-acc.amsterdam.nl/publiek/aanvragen",
+ "urlNaam": "Overtredingen"
+ },
+ {
+ "thema": "Milieuzone",
+ "categorie": "F3",
+ "prioriteit": 0,
+ "datum": "2019-12-13",
+ "titel": "Uw aanvraag ontheffing milieuzone Brom- en snorfietsen",
+ "omschrijving": "Uw aanvraag voor ontheffing milieuzone Brom- en snorfietsen is afgewezen",
+ "url": "https://ontheffingen-acc.amsterdam.nl/publiek/aanvraag/5A158FD9-B07D-4A4C-B780-8359A9A14906",
+ "urlNaam": "Meer informatie"
+ },
+ {
+ "thema": "Milieuzone",
+ "categorie": "F3",
+ "prioriteit": 0,
+ "datum": "2019-12-13",
+ "titel": "Uw aanvraag ontheffing milieuzone Brom- en snorfietsen",
+ "omschrijving": "Uw aanvraag voor ontheffing milieuzone Brom- en snorfietsen is afgewezen",
+ "url": "https://ontheffingen-acc.amsterdam.nl/publiek/aanvraag/2A3B4C05-700C-4C1E-A399-4E171F5B5420",
+ "urlNaam": "Meer informatie"
+ },
+ {
+ "thema": "Milieuzone",
+ "categorie": "M1",
+ "prioriteit": 0,
+ "datum": "2021-10-18",
+ "titel": "Uw aanvraag ontheffing milieuzone Vracht",
+ "omschrijving": "Uw moet uw aanvraag voor ontheffing milieuzone Vracht nog betalen",
+ "url": "https://ontheffingen-acc.amsterdam.nl/publiek/aanvraag/e9d0d30b-2de4-4c7a-9340-4e784d51f1d6",
+ "urlNaam": "Betaal direct"
+ }
+]
\ No newline at end of file
diff --git a/src/server/mock-data/json/milieuzone.json b/src/server/mock-data/json/milieuzone.json
deleted file mode 100644
index 68d43e32a5..0000000000
--- a/src/server/mock-data/json/milieuzone.json
+++ /dev/null
@@ -1,32 +0,0 @@
-[
- {
- "thema": "Milieuzone",
- "categorie": "M1",
- "prioriteit": 0,
- "datum": "2019-03-13",
- "titel": "Uw aanvraag ontheffing milieuzone Brom- en snorfietsen",
- "omschrijving": "Uw moet uw aanvraag voor ontheffing milieuzone Brom- en snorfietsen nog betalen",
- "url": "https://ontheffingen-acc.amsterdam.nl/publiek/aanvraag/1",
- "urlNaam": "Betaal direct"
- },
- {
- "thema": "Milieuzone",
- "categorie": "M1",
- "prioriteit": 0,
- "datum": "2019-03-13",
- "titel": "Uw aanvraag ontheffing milieuzone Brom- en snorfietsen",
- "omschrijving": "Uw moet uw aanvraag voor ontheffing milieuzone Brom- en snorfietsen nog betalen",
- "url": "https://ontheffingen-acc.amsterdam.nl/publiek/aanvraag/2",
- "urlNaam": "Betaal direct"
- },
- {
- "thema": "Milieuzone",
- "categorie": "F2",
- "prioriteit": 50,
- "datum": "2022-06-07",
- "titel": "milieuzone.f2.aanvragen_en_ontheffingen.titel",
- "omschrijving": "milieuzone.f2.aanvragen_en_ontheffingen.omschrijving",
- "url": "https://ontheffingen-acc.amsterdam.nl/publiek/aanvragen",
- "urlNaam": "milieuzone.f2.aanvragen_en_ontheffingen.button"
- }
-]
\ No newline at end of file
diff --git a/src/server/openapi.yml b/src/server/openapi.yml
index 107a96f85a..5bf25855a9 100644
--- a/src/server/openapi.yml
+++ b/src/server/openapi.yml
@@ -265,6 +265,8 @@ components:
$ref: '#/components/schemas/ApiSearchConfigResult'
MILIEUZONE:
$ref: '#/components/schemas/ApiSearchConfigResult'
+ OVERTREDINGEN:
+ $ref: '#/components/schemas/ApiSearchConfigResult'
TOERISTISCHE_VERHUUR:
$ref: '#/components/schemas/ApiSearchConfigResult'
ERFPACHT:
@@ -325,6 +327,8 @@ components:
type: object
MILIEUZONE:
type: object
+ OVERTREDINGEN:
+ type: object
TOERISTISCHE_VERHUUR:
type: object
SUBSIDIE:
diff --git a/src/server/services/afval/afvalpunten.ts b/src/server/services/afval/afvalpunten.ts
index 5dbd034786..933e249ba2 100644
--- a/src/server/services/afval/afvalpunten.ts
+++ b/src/server/services/afval/afvalpunten.ts
@@ -2,7 +2,7 @@ import { LatLngLiteral } from 'leaflet';
import {
apiSuccessResult,
getApproximateDistance,
- sortAlpha,
+ sortByNumber,
} from '../../../universal/helpers';
import type {
AfvalPuntenData,
@@ -22,7 +22,7 @@ function addApproximateDistance(
: 0,
});
})
- .sort(sortAlpha('distance'));
+ .sort(sortByNumber('distance', 'asc'));
}
export function fetchAfvalpunten(latlng: LatLngLiteral | null) {
diff --git a/src/server/services/controller.ts b/src/server/services/controller.ts
index 97ca4169db..92ef64d917 100644
--- a/src/server/services/controller.ts
+++ b/src/server/services/controller.ts
@@ -31,8 +31,10 @@ import { fetchSignals } from './sia';
import {
fetchBelasting,
fetchMilieuzone,
+ fetchOvertredingen,
fetchSubsidie,
} from './simple-connect';
+import { fetchErfpacht, fetchErfpachtV2 } from './simple-connect/erfpacht';
import {
fetchTipsAndNotifications,
sortNotifications,
@@ -52,7 +54,6 @@ import {
fetchTonk,
fetchTozo,
} from './wpi';
-import { fetchErfpacht, fetchErfpachtV2 } from './simple-connect/erfpacht';
// Default service call just passing requestID and request headers as arguments
function callService(fetchService: (...args: any) => Promise) {
@@ -125,6 +126,7 @@ const AFVALPUNTEN = async (requestID: requestID, req: Request) =>
// Architectural pattern C. TODO: Make generic services for pattern C.
const BELASTINGEN = callService(fetchBelasting);
const MILIEUZONE = callService(fetchMilieuzone);
+const OVERTREDINGEN = callService(fetchOvertredingen);
const ERFPACHT = callService(fetchErfpacht);
const ERFPACHTv2 = callService(fetchErfpachtV2);
const SUBSIDIE = callService(fetchSubsidie);
@@ -177,6 +179,7 @@ const SERVICES_INDEX = {
AFVALPUNTEN,
BELASTINGEN,
MILIEUZONE,
+ OVERTREDINGEN,
TOERISTISCHE_VERHUUR,
ERFPACHT,
ERFPACHTv2,
@@ -219,6 +222,7 @@ type CommercialServices = Pick<
| 'MY_LOCATION'
| 'KVK'
| 'MILIEUZONE'
+ | 'OVERTREDINGEN'
| 'VERGUNNINGEN'
| 'TOERISTISCHE_VERHUUR'
| 'HORECA'
@@ -252,6 +256,7 @@ export const servicesByProfileType: ServicesByProfileType = {
MY_LOCATION,
KVK,
MILIEUZONE,
+ OVERTREDINGEN,
TOERISTISCHE_VERHUUR,
SUBSIDIE,
VERGUNNINGEN,
@@ -281,6 +286,7 @@ export const servicesByProfileType: ServicesByProfileType = {
MY_LOCATION,
KVK,
MILIEUZONE,
+ OVERTREDINGEN,
TOERISTISCHE_VERHUUR,
SUBSIDIE,
VERGUNNINGEN,
diff --git a/src/server/services/simple-connect/cleopatra.test.ts b/src/server/services/simple-connect/cleopatra.test.ts
index 7d96eb873d..83eb9edb8e 100644
--- a/src/server/services/simple-connect/cleopatra.test.ts
+++ b/src/server/services/simple-connect/cleopatra.test.ts
@@ -1,9 +1,10 @@
import { describe, expect, test } from 'vitest';
-import { ApiConfig } from '../../config';
import { AuthProfileAndToken } from '../../helpers/app';
import {
fetchMilieuzone,
fetchMilieuzoneNotifications,
+ fetchOvertredingen,
+ fetchOvertredingenNotifications,
getJSONRequestPayload,
} from './cleopatra';
import { remoteApi } from '../../../test-utils';
@@ -59,6 +60,7 @@ describe('simple-connect/cleopatra', () => {
content: [
{
categorie: 'M1',
+ thema: 'Milieuzone',
datum: '2019-03-13',
titel: 'Uw aanvraag ontheffing milieuzone Brom- en snorfietsen',
omschrijving:
@@ -68,6 +70,7 @@ describe('simple-connect/cleopatra', () => {
},
{
categorie: 'M1',
+ thema: 'Milieuzone',
datum: '2019-03-13',
titel: 'Uw aanvraag ontheffing milieuzone Brom- en snorfietsen',
omschrijving:
@@ -77,6 +80,7 @@ describe('simple-connect/cleopatra', () => {
},
{
categorie: 'F2',
+ thema: 'Milieuzone',
},
],
status: 'OK',
@@ -109,7 +113,7 @@ describe('simple-connect/cleopatra', () => {
"chapter": "MILIEUZONE",
"datePublished": "2019-03-13",
"description": "Uw moet uw aanvraag voor ontheffing milieuzone Brom- en snorfietsen nog betalen",
- "id": "milieuzone-M1",
+ "id": "MILIEUZONE-M1",
"link": {
"title": "Betaal direct",
"to": "https://ontheffingen-acc.amsterdam.nl/publiek/aanvraag/1",
@@ -120,7 +124,7 @@ describe('simple-connect/cleopatra', () => {
"chapter": "MILIEUZONE",
"datePublished": "2019-03-13",
"description": "Uw moet uw aanvraag voor ontheffing milieuzone Brom- en snorfietsen nog betalen",
- "id": "milieuzone-M1",
+ "id": "MILIEUZONE-M1",
"link": {
"title": "Betaal direct",
"to": "https://ontheffingen-acc.amsterdam.nl/publiek/aanvraag/2",
@@ -133,4 +137,68 @@ describe('simple-connect/cleopatra', () => {
}
`);
});
+
+ test('fetchOvertredingen content', async () => {
+ remoteApi
+ .post('/cleopatra')
+ .times(2)
+ .reply(200, {
+ content: [
+ {
+ categorie: 'M1',
+ thema: 'Overtredingen',
+ datum: '2019-03-13',
+ titel: 'Overtreding betalen',
+ omschrijving: 'Uw moet uw overtreding nog betalen',
+ url: 'https://ontheffingen-acc.amsterdam.nl/publiek/aanvraag/1',
+ urlNaam: 'Betaal direct',
+ },
+ {
+ categorie: 'F2',
+ thema: 'Overtredingen',
+ },
+ ],
+ status: 'OK',
+ });
+
+ const responseContent = await fetchOvertredingen(
+ REQUEST_ID,
+ authProfileAndToken
+ );
+
+ expect(responseContent).toMatchInlineSnapshot(`
+ {
+ "content": {
+ "isKnown": true,
+ },
+ "status": "OK",
+ }
+ `);
+
+ const notificationsResponse = await fetchOvertredingenNotifications(
+ REQUEST_ID,
+ authProfileAndToken
+ );
+
+ expect(notificationsResponse).toMatchInlineSnapshot(`
+ {
+ "content": {
+ "notifications": [
+ {
+ "chapter": "OVERTREDINGEN",
+ "datePublished": "2019-03-13",
+ "description": "Uw moet uw overtreding nog betalen",
+ "id": "OVERTREDINGEN-M1",
+ "link": {
+ "title": "Betaal direct",
+ "to": "https://ontheffingen-acc.amsterdam.nl/publiek/aanvraag/1",
+ },
+ "title": "Overtreding betalen",
+ },
+ ],
+ },
+ "status": "OK",
+ }
+ `);
+ });
});
diff --git a/src/server/services/simple-connect/cleopatra.ts b/src/server/services/simple-connect/cleopatra.ts
index 111ba77e28..9e5f37ad80 100644
--- a/src/server/services/simple-connect/cleopatra.ts
+++ b/src/server/services/simple-connect/cleopatra.ts
@@ -4,7 +4,12 @@ import { Chapters, IS_TAP } from '../../../universal/config';
import { MyNotification } from '../../../universal/types';
import { DataRequestConfig, getApiConfig } from '../../config';
import { AuthProfileAndToken } from '../../helpers/app';
-import { fetchService, fetchTipsAndNotifications } from './api-service';
+import {
+ ApiPatternResponseA,
+ fetchService,
+ fetchTipsAndNotifications,
+} from './api-service';
+import { apiSuccessResult } from '../../../universal/helpers';
const DEV_KEY = {
kty: 'RSA',
@@ -35,7 +40,7 @@ const pemPubKey =
export function getJSONRequestPayload(
profile: AuthProfileAndToken['profile']
): string {
- const payload: MilieuzoneRequestPayload =
+ const payload: CleopatraRequestPayload =
profile.profileType === 'commercial'
? {
kvk: profile.id!,
@@ -46,7 +51,7 @@ export function getJSONRequestPayload(
return JSON.stringify(payload);
}
-export async function encryptPayload(payload: MilieuzoneRequestPayloadString) {
+export async function encryptPayload(payload: CleopatraRequestPayloadString) {
const key = await pemPubKey;
return jose.JWE.createEncrypt(
@@ -65,8 +70,8 @@ export async function encryptPayload(payload: MilieuzoneRequestPayloadString) {
.final();
}
-interface MilieuzoneMessage {
- thema: 'Milieuzone';
+interface CleopatraMessage {
+ thema: 'Milieuzone' | 'Overtredingen';
categorie: 'F2' | 'M1' | 'F3';
nummer: number;
prioriteit: number;
@@ -78,40 +83,56 @@ interface MilieuzoneMessage {
informatie: string;
}
-type MilieuzoneRequestPayload = { kvk: string } | { bsn: string };
-type MilieuzoneRequestPayloadString = string;
+type CleopatraRequestPayload = { kvk: string } | { bsn: string };
+type CleopatraRequestPayloadString = string;
-function transformMilieuzoneResponse(response: MilieuzoneMessage[]) {
+type CleoPatraPatternResponse = ApiPatternResponseA & {
+ isKnownMilieuzone: boolean;
+ isKnownOvertredingen: boolean;
+};
+
+function transformCleopatraResponse(response: CleopatraMessage[]) {
const notifications: MyNotification[] = [];
- let isKnown: boolean = false;
+ let isKnownMilieuzone: boolean = false;
+ let isKnownOvertredingen: boolean = false;
if (Array.isArray(response)) {
for (const message of response) {
- switch (message.categorie) {
- case 'F2':
- isKnown = true;
+ switch (true) {
+ case message.categorie === 'F2' && message.thema === 'Overtredingen':
+ isKnownOvertredingen = true;
+ break;
+ case message.categorie === 'F2' && message.thema === 'Milieuzone':
+ isKnownMilieuzone = true;
break;
// Melding / Notification
- case 'M1':
- case 'F3':
- notifications.push({
- id: `milieuzone-${message.categorie}`,
- chapter: Chapters.MILIEUZONE,
- title: message.titel,
- datePublished: message.datum,
- description: message.omschrijving,
- link: {
- title: message.urlNaam,
- to: message.url,
- },
- });
+ case message.categorie === 'M1' || message.categorie === 'F3':
+ {
+ const chapter =
+ message.thema === 'Milieuzone'
+ ? Chapters.MILIEUZONE
+ : Chapters.OVERTREDINGEN;
+
+ notifications.push({
+ id: `${chapter}-${message.categorie}`,
+ chapter,
+ title: message.titel,
+ datePublished: message.datum,
+ description: message.omschrijving,
+ link: {
+ title: message.urlNaam,
+ to: message.url,
+ },
+ });
+ }
break;
}
}
}
return {
- isKnown,
+ isKnownOvertredingen,
+ isKnownMilieuzone,
notifications,
};
}
@@ -125,32 +146,86 @@ async function getConfig(
);
return getApiConfig('CLEOPATRA', {
- transformResponse: transformMilieuzoneResponse,
+ transformResponse: transformCleopatraResponse,
cacheKey: `cleopatra-${requestID}`,
data: postData,
});
}
-export async function fetchMilieuzone(
+async function fetchCleopatra(
requestID: requestID,
authProfileAndToken: AuthProfileAndToken
) {
- return fetchService(
+ const INCLUDE_TIPS_AND_NOTIFICATIONS = true;
+ return fetchService(
requestID,
await getConfig(authProfileAndToken, requestID),
- false
+ INCLUDE_TIPS_AND_NOTIFICATIONS
);
}
+export async function fetchMilieuzone(
+ requestID: requestID,
+ authProfileAndToken: AuthProfileAndToken
+) {
+ const response = await fetchCleopatra(requestID, authProfileAndToken);
+
+ if (response.status === 'OK') {
+ return apiSuccessResult({
+ isKnown: response.content?.isKnownMilieuzone ?? false,
+ });
+ }
+
+ return response;
+}
+
+export async function fetchOvertredingen(
+ requestID: requestID,
+ authProfileAndToken: AuthProfileAndToken
+) {
+ const response = await fetchCleopatra(requestID, authProfileAndToken);
+
+ if (response.status === 'OK') {
+ return apiSuccessResult({
+ isKnown: response.content?.isKnownOvertredingen ?? false,
+ });
+ }
+
+ return response;
+}
+
export async function fetchMilieuzoneNotifications(
requestID: requestID,
authProfileAndToken: AuthProfileAndToken
) {
- const response = await fetchTipsAndNotifications(
- requestID,
- await getConfig(authProfileAndToken, requestID),
- Chapters.MILIEUZONE
- );
+ const response = await fetchCleopatra(requestID, authProfileAndToken);
+
+ if (response.status === 'OK') {
+ return apiSuccessResult({
+ notifications:
+ response.content?.notifications?.filter(
+ (notifiction) => notifiction.chapter === Chapters.MILIEUZONE
+ ) ?? [],
+ });
+ }
+
+ return response;
+}
+
+export async function fetchOvertredingenNotifications(
+ requestID: requestID,
+ authProfileAndToken: AuthProfileAndToken
+) {
+ const response = await fetchCleopatra(requestID, authProfileAndToken);
+
+ if (response.status === 'OK') {
+ return apiSuccessResult({
+ notifications:
+ response.content?.notifications?.filter(
+ (notifiction) => notifiction.chapter === Chapters.OVERTREDINGEN
+ ) ?? [],
+ });
+ }
return response;
}
diff --git a/src/server/services/simple-connect/index.ts b/src/server/services/simple-connect/index.ts
index 71281d6cee..afe05f3ab1 100644
--- a/src/server/services/simple-connect/index.ts
+++ b/src/server/services/simple-connect/index.ts
@@ -1,4 +1,9 @@
export { fetchBelasting, fetchBelastingNotifications } from './belasting';
export { fetchSubsidie, fetchSubsidieNotifications } from './subsidie';
-export { fetchMilieuzone, fetchMilieuzoneNotifications } from './cleopatra';
+export {
+ fetchOvertredingen,
+ fetchOvertredingenNotifications,
+ fetchMilieuzone,
+ fetchMilieuzoneNotifications,
+} from './cleopatra';
export { fetchErfpacht, fetchErfpachtNotifications } from './erfpacht';
diff --git a/src/server/services/tips-and-notifications.ts b/src/server/services/tips-and-notifications.ts
index cc0c841551..9330699068 100644
--- a/src/server/services/tips-and-notifications.ts
+++ b/src/server/services/tips-and-notifications.ts
@@ -18,6 +18,7 @@ import {
fetchBelastingNotifications,
fetchErfpachtNotifications,
fetchMilieuzoneNotifications,
+ fetchOvertredingenNotifications,
fetchSubsidieNotifications,
} from './simple-connect';
import { convertTipToNotication } from './tips/tips-service';
@@ -104,6 +105,7 @@ type NotificationServices = Record<
const notificationServices: NotificationServices = {
commercial: {
milieuzone: fetchMilieuzoneNotifications,
+ overtredingen: fetchOvertredingenNotifications,
vergunningen: fetchVergunningenNotifications,
horeca: fetchHorecaNotifications,
erfpacht: fetchErfpachtNotifications,
@@ -128,6 +130,7 @@ const notificationServices: NotificationServices = {
brp: fetchBrpNotifications,
belasting: fetchBelastingNotifications,
milieuzone: fetchMilieuzoneNotifications,
+ overtredingen: fetchOvertredingenNotifications,
vergunningen: fetchVergunningenNotifications,
erfpacht: fetchErfpachtNotifications,
subsidie: fetchSubsidieNotifications,
diff --git a/src/universal/config/app.ts b/src/universal/config/app.ts
index 7693ffd7eb..ec8309232d 100644
--- a/src/universal/config/app.ts
+++ b/src/universal/config/app.ts
@@ -4,7 +4,7 @@ import { IS_PRODUCTION } from './env';
export const FeatureToggle = {
garbageInformationPage: true,
belastingApiActive: true,
- milieuzoneApiActive: true,
+ cleopatraApiActive: true,
identiteitsbewijzenActive: true,
eherkenningActive: true,
vergunningenActive: true,
diff --git a/src/universal/config/chapter.ts b/src/universal/config/chapter.ts
index afebae9e90..297ec352bf 100644
--- a/src/universal/config/chapter.ts
+++ b/src/universal/config/chapter.ts
@@ -15,6 +15,7 @@ export type Chapter =
| 'STADSPAS'
| 'BRP'
| 'MILIEUZONE'
+ | 'OVERTREDINGEN'
| 'NOTIFICATIONS'
| 'ROOT'
| 'ERFPACHT'
@@ -44,6 +45,7 @@ export const Chapters: Record = {
STADSPAS: 'STADSPAS',
BRP: 'BRP',
MILIEUZONE: 'MILIEUZONE',
+ OVERTREDINGEN: 'OVERTREDINGEN',
NOTIFICATIONS: 'NOTIFICATIONS',
ROOT: 'ROOT',
ERFPACHT: 'ERFPACHT',
@@ -74,6 +76,7 @@ export const ChapterTitles: { [chapter in Chapter]: string } = {
STADSPAS: 'Stadspas',
BRP: 'Mijn gegevens',
MILIEUZONE: 'Milieuzone',
+ OVERTREDINGEN: 'Overtredingen voertuigen',
NOTIFICATIONS: 'Actueel',
ROOT: 'Home',
ERFPACHT: 'Erfpacht',
@@ -302,6 +305,13 @@ export const myChaptersMenuItems: ChapterMenuItem[] = [
rel: 'external',
profileTypes: ['private', 'commercial'],
},
+ {
+ title: ChapterTitles.OVERTREDINGEN,
+ id: Chapters.OVERTREDINGEN,
+ to: ExternalUrls.SSO_MILIEUZONE || '', // TODO: In de toekomst wordt dit een andere link
+ rel: 'external',
+ profileTypes: ['private', 'commercial'],
+ },
{
title: ChapterTitles.SIA,
id: Chapters.SIA,
diff --git a/src/universal/helpers/chapters.ts b/src/universal/helpers/chapters.ts
index 8ae8827efb..3a7cf959cf 100644
--- a/src/universal/helpers/chapters.ts
+++ b/src/universal/helpers/chapters.ts
@@ -16,6 +16,7 @@ export function isChapterActive(item: ChapterMenuItem, appState: AppState) {
BRP,
BELASTINGEN,
MILIEUZONE,
+ OVERTREDINGEN,
VERGUNNINGEN,
SIA,
TOERISTISCHE_VERHUUR,
@@ -83,8 +84,14 @@ export function isChapterActive(item: ChapterMenuItem, appState: AppState) {
case Chapters.MILIEUZONE:
return (
!isLoading(MILIEUZONE) &&
- (FeatureToggle.milieuzoneApiActive
- ? MILIEUZONE.content?.isKnown
+ (FeatureToggle.cleopatraApiActive ? MILIEUZONE.content?.isKnown : false)
+ );
+
+ case Chapters.OVERTREDINGEN:
+ return (
+ !isLoading(OVERTREDINGEN) &&
+ (FeatureToggle.cleopatraApiActive
+ ? OVERTREDINGEN.content?.isKnown
: false)
);
diff --git a/src/universal/helpers/utils.ts b/src/universal/helpers/utils.ts
index 41934e01f6..1fcd375140 100644
--- a/src/universal/helpers/utils.ts
+++ b/src/universal/helpers/utils.ts
@@ -106,6 +106,16 @@ export function sortAlpha(
};
}
+export function sortByNumber(key: string, direction: 'asc' | 'desc' = 'asc') {
+ return (a: Record, b: Record) => {
+ const sortASC = direction === 'asc';
+ let aValue = a[key];
+ let bValue = b[key];
+
+ return sortASC ? aValue - bValue : bValue - aValue;
+ };
+}
+
// https://github.com/darkskyapp/string-hash
export function hash(str: string) {
var hash = 5381,