From d413fc14d3a616b9d3f208746b6e6001ab3f0505 Mon Sep 17 00:00:00 2001 From: Mike van den Hoek Date: Thu, 6 Aug 2026 08:55:38 +0200 Subject: [PATCH 1/4] feat: filter zaken on configured Zaaktypen --- build/mijn-zaken/block.json | 4 + build/mijn-zaken/index-rtl.css | 2 +- build/mijn-zaken/index.asset.php | 2 +- build/mijn-zaken/index.css | 2 +- build/mijn-zaken/index.js | 2 +- config/php-di.php | 11 + languages/owc-mijn-services.pot | 232 ++++++++-------- resources/blocks/mijn-zaken/block.json | 1 + resources/blocks/mijn-zaken/edit.js | 109 ++++++++ resources/blocks/mijn-zaken/editor.css | 6 + src/Blocks/Block.php | 118 +++++++- src/Controllers/ZaaktypenCacheController.php | 89 +++++++ src/Providers/BlockServiceProvider.php | 113 ++++++-- src/Providers/SettingsServiceProvider.php | 7 + src/Providers/WPCronServiceProvider.php | 8 + src/Settings/Adapters/ZaaktypeAdapter.php | 267 +++++++++++++++++++ src/Settings/OptionsPageRegistrar.php | 52 ++++ src/Traits/Supplier.php | 17 ++ src/WPCron/Events/PopulateZaaktypen.php | 62 +++++ 19 files changed, 962 insertions(+), 142 deletions(-) create mode 100644 src/Controllers/ZaaktypenCacheController.php create mode 100644 src/Settings/Adapters/ZaaktypeAdapter.php create mode 100644 src/WPCron/Events/PopulateZaaktypen.php diff --git a/build/mijn-zaken/block.json b/build/mijn-zaken/block.json index 3ae35e1..c923b8f 100644 --- a/build/mijn-zaken/block.json +++ b/build/mijn-zaken/block.json @@ -14,6 +14,10 @@ "type": "array", "default": [] }, + "zaaktypen": { + "type": "object", + "default": {} + }, "byBSN": { "type": "boolean", "default": true diff --git a/build/mijn-zaken/index-rtl.css b/build/mijn-zaken/index-rtl.css index 8b13789..ac6b413 100644 --- a/build/mijn-zaken/index-rtl.css +++ b/build/mijn-zaken/index-rtl.css @@ -1 +1 @@ - +.owc-my-services-zaaktypen-supplier-panel.components-panel__body{border:1px solid #ddd;margin:0 0 8px} diff --git a/build/mijn-zaken/index.asset.php b/build/mijn-zaken/index.asset.php index af1c793..44750a9 100644 --- a/build/mijn-zaken/index.asset.php +++ b/build/mijn-zaken/index.asset.php @@ -1 +1 @@ - array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => '8c486808bb89d10fc60f'); + array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => 'c643d1ab2f1e94445f44'); diff --git a/build/mijn-zaken/index.css b/build/mijn-zaken/index.css index 8b13789..ac6b413 100644 --- a/build/mijn-zaken/index.css +++ b/build/mijn-zaken/index.css @@ -1 +1 @@ - +.owc-my-services-zaaktypen-supplier-panel.components-panel__body{border:1px solid #ddd;margin:0 0 8px} diff --git a/build/mijn-zaken/index.js b/build/mijn-zaken/index.js index fb683ee..16e85af 100644 --- a/build/mijn-zaken/index.js +++ b/build/mijn-zaken/index.js @@ -1 +1 @@ -(()=>{"use strict";var e,i={507:()=>{const e=window.wp.blocks,i=window.wp.element,n=window.wp.blockEditor,s=window.wp.components,a=window.wp.i18n,t=window.ReactJSXRuntime,r=[{label:(0,a.__)("Standaard volgorde","owc-mijn-services"),value:""},{label:(0,a.__)("Startdatum","owc-mijn-services"),value:"startdatum"},{label:(0,a.__)("Einddatum","owc-mijn-services"),value:"einddatum"},{label:(0,a.__)("Publicatiedatum","owc-mijn-services"),value:"publicatiedatum"},{label:(0,a.__)("Archiefactiedatum","owc-mijn-services"),value:"archiefactiedatum"},{label:(0,a.__)("Registratiedatum","owc-mijn-services"),value:"registratiedatum"},{label:(0,a.__)("Zaaknummer","owc-mijn-services"),value:"identificatie"}],l=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"owc-my-services/mijn-zaken","version":"1.0.0","title":"OWC Mijn Zaken","description":"Toont Mijn Zaken blok.","attributes":{"zaakClient":{"type":"string","default":""},"zaakClients":{"type":"array","default":[]},"byBSN":{"type":"boolean","default":true},"byKVK":{"type":"boolean","default":false},"showTabs":{"type":"boolean","default":true},"perPage":{"type":"number","default":10},"orderBy":{"type":"string","default":"startdatum"},"orderByDirection":{"type":"string","default":"-"}},"supports":{"html":false},"textdomain":"owc-my-services","editorScript":"file:./index.js","editorStyle":"file:./editor.css","style":"file:./style-index.css","viewScript":"file:./view.js"}');(0,e.registerBlockType)(l,{edit:({attributes:e,setAttributes:l})=>{const{zaakClient:o,zaakClients:c,byBSN:d,byKVK:u,showTabs:v,perPage:m,orderBy:w,orderByDirection:g}=e,j=(window?.owcMyServices?.zaakClientOptions??[]).filter((e=>""!==e.value)),p=window?.owcMyServices?.productionChecksEnabled??!0,_=window?.owcMyServices?.disableKVKFiltering??!1,k=p&&!d&&!(u&&!_);return(0,i.useEffect)((()=>{o&&0===c.length&&l({zaakClients:[o],zaakClient:""})}),[]),(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)(n.InspectorControls,{children:[(0,t.jsx)(s.PanelBody,{title:(0,a.__)("Zaaksystemen","owc-mijn-services"),initialOpen:!0,children:(0,t.jsx)(s.__experimentalVStack,{children:0===j.length?(0,t.jsx)(s.Notice,{status:"warning",isDismissible:!1,children:(0,a.__)("Er zijn nog geen zaaksystemen geconfigureerd in de ZGW API-instellingen.","owc-mijn-services")}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("p",{children:(0,a.__)("Uit welke zaaksystemen worden zaken opgehaald?","owc-mijn-services")}),(0,t.jsx)(s.__experimentalVStack,{spacing:2,children:j.map((e=>(0,t.jsx)(s.CheckboxControl,{label:e.label,checked:c.includes(e.value),onChange:i=>((e,i)=>l({zaakClients:i?[...c,e]:c.filter((i=>i!==e))}))(e.value,i)},e.value)))}),0===c.length&&(0,t.jsx)(s.Notice,{status:"warning",isDismissible:!1,children:(0,a.__)("Selecteer minimaal één zaaksysteem. Zonder selectie worden er geen zaken getoond.","owc-mijn-services")})]})})}),(0,t.jsx)(s.PanelBody,{title:(0,a.__)("Zichtbare zaken","owc-mijn-services"),initialOpen:!0,children:(0,t.jsxs)(s.__experimentalVStack,{children:[(0,t.jsx)(s.ToggleControl,{label:(0,a.__)("Persoonlijke zaken (DigiD)","owc-mijn-services"),help:(0,a.__)("Zaken gekoppeld aan het BSN van de ingelogde gebruiker.","owc-mijn-services"),checked:d,onChange:e=>l({byBSN:e})}),k&&(0,t.jsx)(s.Notice,{status:"warning",isDismissible:!1,children:_?(0,a.__)('Zet "Persoonlijke zaken" aan, anders worden er geen zaken getoond.',"owc-mijn-services"):(0,a.__)("Zet minimaal één van beide opties aan, anders worden er geen zaken getoond.","owc-mijn-services")}),_?(0,t.jsx)(s.Notice,{status:"info",isDismissible:!1,children:(0,a.__)("Zakelijke zaken (eHerkenning) zijn uitgeschakeld in de plugin-instellingen.","owc-mijn-services")}):(0,t.jsx)(s.ToggleControl,{label:(0,a.__)("Zakelijke zaken (eHerkenning)","owc-mijn-services"),help:(0,a.__)("Zaken gekoppeld aan het KVK-nummer van de ingelogde gebruiker.","owc-mijn-services"),checked:u,onChange:e=>l({byKVK:e})})]})}),(0,t.jsx)(s.PanelBody,{title:(0,a.__)("Weergave","owc-mijn-services"),initialOpen:!0,children:(0,t.jsxs)(s.__experimentalVStack,{children:[(0,t.jsx)(s.ToggleControl,{label:(0,a.__)("Tabbladen tonen","owc-mijn-services"),checked:v,onChange:e=>l({showTabs:e})}),(0,t.jsx)(s.RangeControl,{label:(0,a.__)("Aantal zaken","owc-mijn-services"),value:m,min:1,max:25,onChange:e=>l({perPage:e})}),(0,t.jsx)(s.SelectControl,{label:(0,a.__)("Sorteren op","owc-mijn-services"),value:w,options:r,onChange:e=>l({orderBy:e})}),w&&(0,t.jsx)(s.SelectControl,{label:(0,a.__)("Volgorde","owc-mijn-services"),value:g,options:[{label:(0,a.__)("Nieuwste eerst","owc-mijn-services"),value:"-"},{label:(0,a.__)("Oudste eerst","owc-mijn-services"),value:"+"}],onChange:e=>l({orderByDirection:e})})]})})]}),(0,t.jsx)("div",{...(0,n.useBlockProps)(),children:(0,t.jsx)(s.Placeholder,{icon:"list-view",label:(0,a.__)("Het persoonlijke zakenoverzicht","owc-mijn-services"),instructions:(0,a.__)("Toont een overzicht van de zaken voor de ingelogde gebruiker.","owc-mijn-services")})})]})},save:function(){return null}})}},n={};function s(e){var a=n[e];if(void 0!==a)return a.exports;var t=n[e]={exports:{}};return i[e](t,t.exports,s),t.exports}s.m=i,e=[],s.O=(i,n,a,t)=>{if(!n){var r=1/0;for(d=0;d=t)&&Object.keys(s.O).every((e=>s.O[e](n[o])))?n.splice(o--,1):(l=!1,t0&&e[d-1][2]>t;d--)e[d]=e[d-1];e[d]=[n,a,t]},s.o=(e,i)=>Object.prototype.hasOwnProperty.call(e,i),(()=>{var e={500:0,860:0};s.O.j=i=>0===e[i];var i=(i,n)=>{var a,t,[r,l,o]=n,c=0;if(r.some((i=>0!==e[i]))){for(a in l)s.o(l,a)&&(s.m[a]=l[a]);if(o)var d=o(s)}for(i&&i(n);cs(507)));a=s.O(a)})(); \ No newline at end of file +(()=>{"use strict";var e,n={507:()=>{const e=window.wp.blocks,n=window.wp.element,i=window.wp.blockEditor,a=window.wp.components,t=window.wp.i18n,s=window.ReactJSXRuntime,l=[{label:(0,t.__)("Standaard volgorde","owc-mijn-services"),value:""},{label:(0,t.__)("Startdatum","owc-mijn-services"),value:"startdatum"},{label:(0,t.__)("Einddatum","owc-mijn-services"),value:"einddatum"},{label:(0,t.__)("Publicatiedatum","owc-mijn-services"),value:"publicatiedatum"},{label:(0,t.__)("Archiefactiedatum","owc-mijn-services"),value:"archiefactiedatum"},{label:(0,t.__)("Registratiedatum","owc-mijn-services"),value:"registratiedatum"},{label:(0,t.__)("Zaaknummer","owc-mijn-services"),value:"identificatie"}],r=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"owc-my-services/mijn-zaken","version":"1.0.0","title":"OWC Mijn Zaken","description":"Toont Mijn Zaken blok.","attributes":{"zaakClient":{"type":"string","default":""},"zaakClients":{"type":"array","default":[]},"zaaktypen":{"type":"object","default":{}},"byBSN":{"type":"boolean","default":true},"byKVK":{"type":"boolean","default":false},"showTabs":{"type":"boolean","default":true},"perPage":{"type":"number","default":10},"orderBy":{"type":"string","default":"startdatum"},"orderByDirection":{"type":"string","default":"-"}},"supports":{"html":false},"textdomain":"owc-my-services","editorScript":"file:./index.js","editorStyle":"file:./editor.css","style":"file:./style-index.css","viewScript":"file:./view.js"}');(0,e.registerBlockType)(r,{edit:({attributes:e,setAttributes:r})=>{const{zaakClient:o,zaakClients:c,zaaktypen:d,byBSN:p,byKVK:m,showTabs:u,perPage:v,orderBy:k,orderByDirection:w}=e,g=(window?.owcMyServices?.zaakClientOptions??[]).filter((e=>""!==e.value)),j=window?.owcMyServices?.productionChecksEnabled??!0,h=window?.owcMyServices?.disableKVKFiltering??!1,_=j&&!p&&!(m&&!h),b=window?.owcMyServices?.zaaktypeOptions??{},y=c.filter((e=>(b[e]??[]).length>0));return(0,n.useEffect)((()=>{o&&0===c.length&&r({zaakClients:[o],zaakClient:""})}),[]),(0,n.useEffect)((()=>{const e=window?.owcMyServices?.zaaktypeUrlMigrations??{};if(0===Object.keys(e).length)return;let n=!1;const i={};Object.keys(d).forEach((a=>{const t=e[a]??{},s=(d[a]??[]).map((e=>t[e]?(n=!0,t[e]):e));i[a]=[...new Set(s)]})),n&&r({zaaktypen:i})}),[]),(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(i.InspectorControls,{children:[(0,s.jsx)(a.PanelBody,{title:(0,t.__)("Zaaksystemen","owc-mijn-services"),initialOpen:!0,children:(0,s.jsx)(a.__experimentalVStack,{children:0===g.length?(0,s.jsx)(a.Notice,{status:"warning",isDismissible:!1,children:(0,t.__)("Er zijn nog geen zaaksystemen geconfigureerd in de ZGW API-instellingen.","owc-mijn-services")}):(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("p",{children:(0,t.__)("Uit welke zaaksystemen worden zaken opgehaald?","owc-mijn-services")}),(0,s.jsx)(a.__experimentalVStack,{spacing:2,children:g.map((e=>(0,s.jsx)(a.CheckboxControl,{label:e.label,checked:c.includes(e.value),onChange:n=>((e,n)=>r({zaakClients:n?[...c,e]:c.filter((n=>n!==e))}))(e.value,n)},e.value)))}),0===c.length&&(0,s.jsx)(a.Notice,{status:"warning",isDismissible:!1,children:(0,t.__)("Selecteer minimaal één zaaksysteem. Zonder selectie worden er geen zaken getoond.","owc-mijn-services")})]})})}),c.length>0&&(0,s.jsx)(a.PanelBody,{title:(0,t.__)("Zaaktypen","owc-mijn-services"),initialOpen:!1,children:(0,s.jsx)(a.__experimentalVStack,{children:0===y.length?(0,s.jsx)(a.Notice,{status:"info",isDismissible:!1,children:(0,t.__)("Zaaktypefiltering is uitgeschakeld voor de geselecteerde zaaksystemen. Schakel dit in bij Instellingen → OWC Mijn Services → 'Zaaktypefiltering ondersteunde leveranciers' om hier zaaktypen te kunnen selecteren.","owc-mijn-services")}):(0,s.jsx)(a.BaseControl,{id:"owc-my-services-zaaktypen-selection",label:(0,t.__)("Zaaktypen","owc-mijn-services"),help:(0,t.__)("Selecteer per zaaksysteem de zaaktypen waarop gefilterd moet worden. Selecteer geen zaaktypen om alle zaaktypen te tonen.","owc-mijn-services"),children:y.map((e=>{const n=b[e]??[];return(0,s.jsx)(a.PanelBody,{title:e,initialOpen:!1,className:"owc-my-services-zaaktypen-supplier-panel",children:n.map((n=>(0,s.jsx)(a.CheckboxControl,{label:n.label,checked:(d[e]??[]).includes(n.value),onChange:i=>((e,n,i)=>{const a=d[e]??[],t=i?[...a,n]:a.filter((e=>e!==n));r({zaaktypen:{...d,[e]:t}})})(e,n.value,i)},n.value)))},e)}))})})}),(0,s.jsx)(a.PanelBody,{title:(0,t.__)("Zichtbare zaken","owc-mijn-services"),initialOpen:!0,children:(0,s.jsxs)(a.__experimentalVStack,{children:[(0,s.jsx)(a.ToggleControl,{label:(0,t.__)("Persoonlijke zaken (DigiD)","owc-mijn-services"),help:(0,t.__)("Zaken gekoppeld aan het BSN van de ingelogde gebruiker.","owc-mijn-services"),checked:p,onChange:e=>r({byBSN:e})}),_&&(0,s.jsx)(a.Notice,{status:"warning",isDismissible:!1,children:h?(0,t.__)('Zet "Persoonlijke zaken" aan, anders worden er geen zaken getoond.',"owc-mijn-services"):(0,t.__)("Zet minimaal één van beide opties aan, anders worden er geen zaken getoond.","owc-mijn-services")}),h?(0,s.jsx)(a.Notice,{status:"info",isDismissible:!1,children:(0,t.__)("Zakelijke zaken (eHerkenning) zijn uitgeschakeld in de plugin-instellingen.","owc-mijn-services")}):(0,s.jsx)(a.ToggleControl,{label:(0,t.__)("Zakelijke zaken (eHerkenning)","owc-mijn-services"),help:(0,t.__)("Zaken gekoppeld aan het KVK-nummer van de ingelogde gebruiker.","owc-mijn-services"),checked:m,onChange:e=>r({byKVK:e})})]})}),(0,s.jsx)(a.PanelBody,{title:(0,t.__)("Weergave","owc-mijn-services"),initialOpen:!0,children:(0,s.jsxs)(a.__experimentalVStack,{children:[(0,s.jsx)(a.ToggleControl,{label:(0,t.__)("Tabbladen tonen","owc-mijn-services"),checked:u,onChange:e=>r({showTabs:e})}),(0,s.jsx)(a.RangeControl,{label:(0,t.__)("Aantal zaken","owc-mijn-services"),value:v,min:1,max:25,onChange:e=>r({perPage:e})}),(0,s.jsx)(a.SelectControl,{label:(0,t.__)("Sorteren op","owc-mijn-services"),value:k,options:l,onChange:e=>r({orderBy:e})}),k&&(0,s.jsx)(a.SelectControl,{label:(0,t.__)("Volgorde","owc-mijn-services"),value:w,options:[{label:(0,t.__)("Nieuwste eerst","owc-mijn-services"),value:"-"},{label:(0,t.__)("Oudste eerst","owc-mijn-services"),value:"+"}],onChange:e=>r({orderByDirection:e})})]})})]}),(0,s.jsx)("div",{...(0,i.useBlockProps)(),children:(0,s.jsx)(a.Placeholder,{icon:"list-view",label:(0,t.__)("Het persoonlijke zakenoverzicht","owc-mijn-services"),instructions:(0,t.__)("Toont een overzicht van de zaken voor de ingelogde gebruiker.","owc-mijn-services")})})]})},save:function(){return null}})}},i={};function a(e){var t=i[e];if(void 0!==t)return t.exports;var s=i[e]={exports:{}};return n[e](s,s.exports,a),s.exports}a.m=n,e=[],a.O=(n,i,t,s)=>{if(!i){var l=1/0;for(d=0;d=s)&&Object.keys(a.O).every((e=>a.O[e](i[o])))?i.splice(o--,1):(r=!1,s0&&e[d-1][2]>s;d--)e[d]=e[d-1];e[d]=[i,t,s]},a.o=(e,n)=>Object.prototype.hasOwnProperty.call(e,n),(()=>{var e={500:0,860:0};a.O.j=n=>0===e[n];var n=(n,i)=>{var t,s,[l,r,o]=i,c=0;if(l.some((n=>0!==e[n]))){for(t in r)a.o(r,t)&&(a.m[t]=r[t]);if(o)var d=o(a)}for(n&&n(i);ca(507)));t=a.O(t)})(); \ No newline at end of file diff --git a/config/php-di.php b/config/php-di.php index 2e0154d..3de1ff9 100644 --- a/config/php-di.php +++ b/config/php-di.php @@ -106,6 +106,17 @@ function ( $client ) use ( $name ) { return ( new InformatieobjecttypeCatalog() )->group_by_supplier( $urls ); }, + /** + * Suppliers for which filtering zaken on zaaktype is supported. Zaaktype filtering is + * disabled by default, so a supplier only has it applied once explicitly selected here. + * + * @return string[] + */ + 'display.zaaktype-filtering-suppliers' => function ( Container $container ) { + $value = $container->make( 'zgw.settings', array( 'owc-mijn-services-zaaktype-filtering-suppliers' ) ); + + return is_array( $value ) ? array_values( array_filter( $value, 'is_string' ) ) : array(); + }, 'display.disable-production-checks' => function ( Container $container ) { return (bool) $container->make( 'zgw.settings', array( 'owc-mijn-services-disable-production-checks' ) ); }, diff --git a/languages/owc-mijn-services.pot b/languages/owc-mijn-services.pot index 7c2fa3b..3ca70ea 100644 --- a/languages/owc-mijn-services.pot +++ b/languages/owc-mijn-services.pot @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-09-22T07:11:01+00:00\n" +"POT-Creation-Date: 2026-09-22T08:29:51+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: owc-mijn-services\n" @@ -39,40 +39,38 @@ msgstr "" msgid "https://www.yard.nl" msgstr "" -#: src/Blocks/Block.php:76 +#: src/Blocks/Block.php:93 msgid "Je moet ingelogd zijn om deze informatie te kunnen zien." msgstr "" -#: src/Blocks/Block.php:83 +#: src/Blocks/Block.php:100 msgid "Configureer minimaal één filteroptie: 'Filter op BSN' of 'Filter op KVK'." msgstr "" -#: src/Blocks/Block.php:91 +#: src/Blocks/Block.php:108 msgid "De filterinstellingen van dit blok zijn niet compatibel met uw inlogmethode. Neem contact op met de beheerder van deze website." msgstr "" -#: src/Blocks/Block.php:98 +#: src/Blocks/Block.php:117 msgid "Geen van de gekozen zaaksysteem leveranciers is geconfigureerd of ondersteunt zaken." msgstr "" -#: src/Blocks/Block.php:105 +#: src/Blocks/Block.php:125 #: src/Blocks/Zaak.php:48 msgid "De gekozen zaaksysteem leverancier client is niet geconfigureerd." msgstr "" -#: src/Blocks/Block.php:109 +#: src/Blocks/Block.php:129 msgid "De gekozen zaaksysteem leverancier ondersteunt geen zaken." msgstr "" #: src/Blocks/MijnZaken.php:24 -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:268 +#: resources/blocks/mijn-zaken/edit.js:369 msgid "Het persoonlijke zakenoverzicht" msgstr "" #: src/Blocks/MijnZaken.php:25 -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:272 +#: resources/blocks/mijn-zaken/edit.js:373 msgid "Toont een overzicht van de zaken voor de ingelogde gebruiker." msgstr "" @@ -106,6 +104,7 @@ msgid "Informatieobjecttypen opnieuw ophalen" msgstr "" #: src/Controllers/InformatieobjecttypenCacheController.php:64 +#: src/Controllers/ZaaktypenCacheController.php:64 msgid "Je hebt geen toestemming om deze actie uit te voeren." msgstr "" @@ -117,71 +116,90 @@ msgstr "" msgid "Het informatieobject kon niet worden gedownload." msgstr "" +#: src/Controllers/ZaaktypenCacheController.php:49 +msgid "Zaaktypen opnieuw ophalen" +msgstr "" + +#: src/Controllers/ZaaktypenCacheController.php:86 +msgid "De zaaktypen zijn opnieuw opgehaald." +msgstr "" + #: src/Macros/ZgwApiMacros.php:221 msgid "Ophalen van het resultaat is mislukt" msgstr "" -#: src/Settings/OptionsPageRegistrar.php:52 +#: src/Settings/OptionsPageRegistrar.php:53 msgid "OWC Mijn Services" msgstr "" -#: src/Settings/OptionsPageRegistrar.php:71 +#: src/Settings/OptionsPageRegistrar.php:72 msgid "Logboekinstellingen" msgstr "" -#: src/Settings/OptionsPageRegistrar.php:72 +#: src/Settings/OptionsPageRegistrar.php:73 msgid "Schakel deze optie in om het loggen van systeemactiviteiten en foutmeldingen te activeren. Dit kan nuttig zijn voor het opsporen en oplossen van problemen binnen de plug-in." msgstr "" -#: src/Settings/OptionsPageRegistrar.php:84 +#: src/Settings/OptionsPageRegistrar.php:85 msgid "DOC- en DOCX-documenten uitsluiten" msgstr "" -#: src/Settings/OptionsPageRegistrar.php:85 +#: src/Settings/OptionsPageRegistrar.php:86 msgid "Schakel deze optie in om DOC- en DOCX-documenten niet op te halen bij het tonen van een zaak." msgstr "" -#: src/Settings/OptionsPageRegistrar.php:97 +#: src/Settings/OptionsPageRegistrar.php:98 msgid "Toegestane informatieobjecttypen" msgstr "" -#: src/Settings/OptionsPageRegistrar.php:98 +#: src/Settings/OptionsPageRegistrar.php:99 msgid "Selecteer de informatieobjecttypen die mogen worden gebruikt voor het ophalen van informatieobjecten bij een zaak. Laat dit veld leeg om alle informatieobjecten te tonen." msgstr "" -#: src/Settings/OptionsPageRegistrar.php:111 +#: src/Settings/OptionsPageRegistrar.php:112 msgid "Zoek en selecteer informatieobjecttypen…" msgstr "" -#: src/Settings/OptionsPageRegistrar.php:119 +#: src/Settings/OptionsPageRegistrar.php:121 +msgid "De zaaktypen die gebruikt worden voor de zaaktypefilter in het 'Mijn zaken'-blok worden dagelijks automatisch ververst. Gebruik onderstaande knop om ze direct opnieuw op te halen." +msgstr "" + +#: src/Settings/OptionsPageRegistrar.php:125 +#: build/mijn-zaken/index.js:1 +#: resources/blocks/mijn-zaken/edit.js:193 +#: resources/blocks/mijn-zaken/edit.js:199 +msgid "Zaaktypen" +msgstr "" + +#: src/Settings/OptionsPageRegistrar.php:136 msgid "Productiecontroles uitschakelen" msgstr "" -#: src/Settings/OptionsPageRegistrar.php:120 +#: src/Settings/OptionsPageRegistrar.php:137 msgid "Schakel deze optie in om de verplichting van het gebruik van de blokattributen 'Filter op BSN' of 'Filter op KVK' uit te zetten. Standaard zijn productiecontroles ingeschakeld en is minimaal één van beide filterattributen vereist." msgstr "" -#: src/Settings/OptionsPageRegistrar.php:132 +#: src/Settings/OptionsPageRegistrar.php:149 msgid "Filtering op KVK uitschakelen" msgstr "" -#: src/Settings/OptionsPageRegistrar.php:133 +#: src/Settings/OptionsPageRegistrar.php:150 msgid "Schakel deze optie in als de leverancier het filteren op KVK (eHerkenning) niet ondersteunt. Gebruikers die via eHerkenning zijn ingelogd kunnen dan geen zaken ophalen." msgstr "" -#: src/Settings/OptionsPageRegistrar.php:145 +#: src/Settings/OptionsPageRegistrar.php:162 msgid "Statusstappen zonder datum verbergen" msgstr "" -#: src/Settings/OptionsPageRegistrar.php:146 +#: src/Settings/OptionsPageRegistrar.php:163 msgid "Schakel deze optie in om statusstappen zonder gezette datum te verbergen in het statusoverzicht van een zaak. Dit verbergt ook nog niet bereikte (toekomstige) stappen. Standaard worden alle statusstappen getoond." msgstr "" -#: src/Settings/OptionsPageRegistrar.php:158 +#: src/Settings/OptionsPageRegistrar.php:175 msgid "Volgnummers verbergen" msgstr "" -#: src/Settings/OptionsPageRegistrar.php:159 +#: src/Settings/OptionsPageRegistrar.php:176 msgid "Schakel deze optie in om de volgnummers van statusstappen te verbergen in het statusoverzicht van een zaak. Standaard worden volgnummers getoond." msgstr "" @@ -283,163 +301,153 @@ msgid "Er is (momenteel) geen status beschikbaar." msgstr "" #: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:24 -msgid "Standaard volgorde" +#: build/zaak/index.js:1 +#: resources/blocks/zaak/edit.js:44 +msgid "Instellingen" msgstr "" #: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:25 -msgid "Startdatum" +#: build/zaak/index.js:1 +#: resources/blocks/mijn-zaken/edit.js:140 +#: resources/blocks/zaak/edit.js:50 +msgid "Zaaksystemen" msgstr "" #: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:26 -msgid "Einddatum" +msgid "Selecteer de zaaksystemen waaruit de zaken opgehaald moeten worden." msgstr "" #: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:28 -msgid "Publicatiedatum" +#: build/zaak/index.js:1 +#: resources/blocks/zaak/edit.js:76 +msgid "Geen leveranciers geconfigureerd." msgstr "" #: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:32 -msgid "Archiefactiedatum" +#: resources/blocks/mijn-zaken/edit.js:200 +msgid "Selecteer per zaaksysteem de zaaktypen waarop gefilterd moet worden. Selecteer geen zaaktypen om alle zaaktypen te tonen." msgstr "" #: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:36 -msgid "Registratiedatum" +#: build/zaak/index.js:1 +#: resources/blocks/zaak/edit.js:85 +msgid "Schakel de filteroptie Filter op BSN in." msgstr "" #: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:40 -msgid "Zaaknummer" +#: build/zaak/index.js:1 +#: resources/blocks/zaak/edit.js:86 +msgid "Selecteer minimaal één filteroptie: Filter op BSN of Filter op KVK." msgstr "" #: build/mijn-zaken/index.js:1 #: build/zaak/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:91 -#: resources/blocks/zaak/edit.js:50 -msgid "Zaaksystemen" +#: resources/blocks/zaak/edit.js:114 +msgid "Filteren op KVK is uitgeschakeld in de instellingen van de plugin." msgstr "" #: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:97 +#: resources/blocks/mijn-zaken/edit.js:317 +msgid "Aantal zaken" +msgstr "" + +#: build/zaak/index.js:1 +#: resources/blocks/zaak/edit.js:51 +msgid "Selecteer de zaaksystemen waarvan zaken op deze pagina getoond kunnen worden." +msgstr "" + +#: resources/blocks/mijn-zaken/edit.js:25 +msgid "Standaard volgorde" +msgstr "" + +#: resources/blocks/mijn-zaken/edit.js:26 +msgid "Startdatum" +msgstr "" + +#: resources/blocks/mijn-zaken/edit.js:27 +msgid "Einddatum" +msgstr "" + +#: resources/blocks/mijn-zaken/edit.js:29 +msgid "Publicatiedatum" +msgstr "" + +#: resources/blocks/mijn-zaken/edit.js:33 +msgid "Archiefactiedatum" +msgstr "" + +#: resources/blocks/mijn-zaken/edit.js:37 +msgid "Registratiedatum" +msgstr "" + +#: resources/blocks/mijn-zaken/edit.js:41 +msgid "Zaaknummer" +msgstr "" + +#: resources/blocks/mijn-zaken/edit.js:146 msgid "Er zijn nog geen zaaksystemen geconfigureerd in de ZGW API-instellingen." msgstr "" -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:105 +#: resources/blocks/mijn-zaken/edit.js:154 msgid "Uit welke zaaksystemen worden zaken opgehaald?" msgstr "" -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:132 +#: resources/blocks/mijn-zaken/edit.js:181 msgid "Selecteer minimaal één zaaksysteem. Zonder selectie worden er geen zaken getoond." msgstr "" -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:143 +#: resources/blocks/mijn-zaken/edit.js:244 msgid "Zichtbare zaken" msgstr "" -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:148 +#: resources/blocks/mijn-zaken/edit.js:249 msgid "Persoonlijke zaken (DigiD)" msgstr "" -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:152 +#: resources/blocks/mijn-zaken/edit.js:253 msgid "Zaken gekoppeld aan het BSN van de ingelogde gebruiker." msgstr "" -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:164 +#: resources/blocks/mijn-zaken/edit.js:265 msgid "Zet \"Persoonlijke zaken\" aan, anders worden er geen zaken getoond." msgstr "" -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:168 +#: resources/blocks/mijn-zaken/edit.js:269 msgid "Zet minimaal één van beide opties aan, anders worden er geen zaken getoond." msgstr "" -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:176 +#: resources/blocks/mijn-zaken/edit.js:277 msgid "Zakelijke zaken (eHerkenning) zijn uitgeschakeld in de plugin-instellingen." msgstr "" -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:183 +#: resources/blocks/mijn-zaken/edit.js:284 msgid "Zakelijke zaken (eHerkenning)" msgstr "" -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:187 +#: resources/blocks/mijn-zaken/edit.js:288 msgid "Zaken gekoppeld aan het KVK-nummer van de ingelogde gebruiker." msgstr "" -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:201 +#: resources/blocks/mijn-zaken/edit.js:302 msgid "Weergave" msgstr "" -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:206 +#: resources/blocks/mijn-zaken/edit.js:307 msgid "Tabbladen tonen" msgstr "" -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:216 -msgid "Aantal zaken" -msgstr "" - -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:228 +#: resources/blocks/mijn-zaken/edit.js:329 msgid "Sorteren op" msgstr "" -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:237 +#: resources/blocks/mijn-zaken/edit.js:338 msgid "Volgorde" msgstr "" -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:241 +#: resources/blocks/mijn-zaken/edit.js:342 msgid "Nieuwste eerst" msgstr "" -#: build/mijn-zaken/index.js:1 -#: resources/blocks/mijn-zaken/edit.js:248 +#: resources/blocks/mijn-zaken/edit.js:349 msgid "Oudste eerst" msgstr "" - -#: build/zaak/index.js:1 -#: resources/blocks/zaak/edit.js:44 -msgid "Instellingen" -msgstr "" - -#: build/zaak/index.js:1 -#: resources/blocks/zaak/edit.js:51 -msgid "Selecteer de zaaksystemen waarvan zaken op deze pagina getoond kunnen worden." -msgstr "" - -#: build/zaak/index.js:1 -#: resources/blocks/zaak/edit.js:76 -msgid "Geen leveranciers geconfigureerd." -msgstr "" - -#: build/zaak/index.js:1 -#: resources/blocks/zaak/edit.js:85 -msgid "Schakel de filteroptie Filter op BSN in." -msgstr "" - -#: build/zaak/index.js:1 -#: resources/blocks/zaak/edit.js:86 -msgid "Selecteer minimaal één filteroptie: Filter op BSN of Filter op KVK." -msgstr "" - -#: build/zaak/index.js:1 -#: resources/blocks/zaak/edit.js:114 -msgid "Filteren op KVK is uitgeschakeld in de instellingen van de plugin." -msgstr "" diff --git a/resources/blocks/mijn-zaken/block.json b/resources/blocks/mijn-zaken/block.json index 107d43c..4e5d5bc 100644 --- a/resources/blocks/mijn-zaken/block.json +++ b/resources/blocks/mijn-zaken/block.json @@ -8,6 +8,7 @@ "attributes": { "zaakClient": { "type": "string", "default": "" }, "zaakClients": { "type": "array", "default": [] }, + "zaaktypen": { "type": "object", "default": {} }, "byBSN": { "type": "boolean", "default": true }, "byKVK": { "type": "boolean", "default": false }, "showTabs": { "type": "boolean", "default": true }, diff --git a/resources/blocks/mijn-zaken/edit.js b/resources/blocks/mijn-zaken/edit.js index fc89382..8eef374 100644 --- a/resources/blocks/mijn-zaken/edit.js +++ b/resources/blocks/mijn-zaken/edit.js @@ -5,6 +5,7 @@ import { useEffect } from '@wordpress/element'; import { InspectorControls, useBlockProps } from '@wordpress/block-editor'; import { PanelBody, + BaseControl, CheckboxControl, Notice, Placeholder, @@ -49,6 +50,7 @@ const Edit = ( { attributes, setAttributes } ) => { const { zaakClient, zaakClients, + zaaktypen, byBSN, byKVK, showTabs, @@ -70,6 +72,22 @@ const Edit = ( { attributes, setAttributes } ) => { ! byBSN && ! ( byKVK && ! disableKVKFiltering ); + const zaaktypeOptionsBySupplier = window?.owcMyServices?.zaaktypeOptions ?? {}; + const suppliersWithZaaktypeOptions = zaakClients.filter( + ( supplier ) => ( zaaktypeOptionsBySupplier[ supplier ] ?? [] ).length > 0 + ); + + const toggleZaaktype = ( supplier, url, checked ) => { + const current = zaaktypen[ supplier ] ?? []; + const next = checked + ? [ ...current, url ] + : current.filter( ( value ) => value !== url ); + + setAttributes( { + zaaktypen: { ...zaaktypen, [ supplier ]: next }, + } ); + }; + // Migrate legacy single zaakClient string to zaakClients array. useEffect( () => { if ( zaakClient && zaakClients.length === 0 ) { @@ -84,6 +102,40 @@ const Edit = ( { attributes, setAttributes } ) => { : zaakClients.filter( ( value ) => value !== supplier ), } ); + // Replace zaaktype selections pointing at a superseded zaaktype version with its current URL. + useEffect( () => { + const migrationsBySupplier = + window?.owcMyServices?.zaaktypeUrlMigrations ?? {}; + + if ( Object.keys( migrationsBySupplier ).length === 0 ) { + return; + } + + let changed = false; + const next = {}; + + Object.keys( zaaktypen ).forEach( ( supplier ) => { + const migrations = migrationsBySupplier[ supplier ] ?? {}; + const urls = zaaktypen[ supplier ] ?? []; + + const migratedUrls = urls.map( ( url ) => { + if ( migrations[ url ] ) { + changed = true; + + return migrations[ url ]; + } + + return url; + } ); + + next[ supplier ] = [ ...new Set( migratedUrls ) ]; + } ); + + if ( changed ) { + setAttributes( { zaaktypen: next } ); + } + }, [] ); + return ( <> @@ -139,6 +191,63 @@ const Edit = ( { attributes, setAttributes } ) => { ) } + { zaakClients.length > 0 && ( + + + { suppliersWithZaaktypeOptions.length === 0 ? ( + + { __( + 'Zaaktypefiltering is uitgeschakeld voor de geselecteerde zaaksystemen. Schakel dit in bij Instellingen → OWC Mijn Services → \'Zaaktypefiltering ondersteunde leveranciers\' om hier zaaktypen te kunnen selecteren.', + 'owc-mijn-services' + ) } + + ) : ( + + { suppliersWithZaaktypeOptions.map( ( supplier ) => { + const options = + zaaktypeOptionsBySupplier[ supplier ] ?? []; + + return ( + + { options.map( ( option ) => ( + + toggleZaaktype( + supplier, + option.value, + checked + ) + } + /> + ) ) } + + ); + } ) } + + ) } + + + ) } + */ + protected array $zaaktypen_by_supplier = array(); + + /** + * Supplier name resolved for the legacy single `zaakClient` attribute. + * + * @since NEXT + */ + protected string $single_client_supplier_name = ''; + public function __construct() { $this->zaken_filter = new ZakenFilter(); @@ -91,6 +108,8 @@ final public function render( array $attributes, string $block_content, WP_Block return owc_mijn_services_render_view( 'owc-error', array( 'message' => __( 'De filterinstellingen van dit blok zijn niet compatibel met uw inlogmethode. Neem contact op met de beheerder van deze website.', 'owc-mijn-services' ) ) ); } + $this->zaaktypen_by_supplier = $this->normalize_zaaktypen_attribute( $attributes['zaaktypen'] ?? array() ); + if (is_array( $attributes['zaakClients'] ?? null ) && 0 < count( $attributes['zaakClients'] )) { $this->setup_clients( $attributes['zaakClients'] ); @@ -99,8 +118,9 @@ final public function render( array $attributes, string $block_content, WP_Block } } else { try { - $supplier = is_string( $attributes['zaakClient'] ?? null ) && '' !== $attributes['zaakClient'] ? $attributes['zaakClient'] : (string) get_query_var( BlockServiceProvider::QUERY_VAR_SUPPLIER ); - $this->client = apiClientManager()->getClient( $supplier ); + $supplier = is_string( $attributes['zaakClient'] ?? null ) && '' !== $attributes['zaakClient'] ? $attributes['zaakClient'] : (string) get_query_var( BlockServiceProvider::QUERY_VAR_SUPPLIER ); + $this->client = apiClientManager()->getClient( $supplier ); + $this->single_client_supplier_name = $supplier; } catch (NotFoundException $e) { return owc_mijn_services_render_view( 'owc-error', array( 'message' => __( 'De gekozen zaaksysteem leverancier client is niet geconfigureerd.', 'owc-mijn-services' ) ) ); } @@ -113,6 +133,28 @@ final public function render( array $attributes, string $block_content, WP_Block return $this->render_block( $attributes, $block_content, $block ); } + /** + * Normalizes the `zaaktypen` block attribute (a supplier name => zaaktype URLs map) + * into a strictly typed array, discarding anything that doesn't match the expected shape. + * + * @since NEXT + * + * @return array + */ + private function normalize_zaaktypen_attribute( $zaaktypen ): array + { + if ( ! is_array( $zaaktypen )) { + return array(); + } + + return array_map( + function ( $urls ) { + return is_array( $urls ) ? array_values( array_filter( $urls, 'is_string' ) ) : array(); + }, + $zaaktypen + ); + } + /** * Returns true when at least one supplier is configured on the block, * checking the multi-supplier array first and falling back to the legacy string. @@ -187,7 +229,11 @@ final protected function get_zaken(): Collection return Collection::collect( array() ); } - return $this->client->zaken()->filter( $this->zaken_filter ); + $zaaktype_urls = $this->supports_zaaktype_filtering( $this->single_client_supplier_name ) + ? $this->resolve_zaaktype_urls( $this->single_client_supplier_name, $this->zaaktypen_by_supplier[ $this->single_client_supplier_name ] ?? array() ) + : array(); + + return Collection::collect( $this->fetch_zaken( $this->client, $zaaktype_urls ) ); } /** @@ -202,9 +248,11 @@ final protected function get_zaken_from_clients(): Collection foreach ($this->clients as $supplier_name => $client) { try { - $zaken = $client->zaken()->filter( clone $this->zaken_filter ); + $zaaktype_urls = $this->supports_zaaktype_filtering( $supplier_name ) + ? $this->resolve_zaaktype_urls( $supplier_name, $this->zaaktypen_by_supplier[ $supplier_name ] ?? array() ) + : array(); - foreach ($zaken->all() as $zaak) { + foreach ($this->fetch_zaken( $client, $zaaktype_urls ) as $zaak) { $zaak->setValue( 'supplier', $supplier_name ); $all_zaken[] = $zaak; } @@ -216,6 +264,66 @@ final protected function get_zaken_from_clients(): Collection return Collection::collect( $all_zaken ); } + /** + * Fetches zaken for a single client. When zaaktype URLs are given, issues one filtered + * request per zaaktype and merges the results, since the ZGW Zaken API filters on a + * single zaaktype per request. Without zaaktype URLs, all zaaktypen are fetched. + * + * @since NEXT + * + * @param string[] $zaaktype_urls + */ + private function fetch_zaken( Client $client, array $zaaktype_urls ): array + { + if (array() === $zaaktype_urls) { + return (array) $client->zaken()->filter( clone $this->zaken_filter )->all(); + } + + $zaken = array(); + + foreach ($zaaktype_urls as $zaaktype_url) { + $filter = ( clone $this->zaken_filter )->add( 'zaaktype', $zaaktype_url ); + $zaken = array_merge( $zaken, (array) $client->zaken()->filter( $filter )->all() ); + } + + return $zaken; + } + + /** + * Resolves any zaaktype URL that has been superseded by a newer version to that version's + * URL, so a block's saved zaaktype selection keeps matching zaken even when it was chosen + * before the zaaktype was re-versioned in the ZTC. Falls back to the URL as-is when no + * migration is known (e.g. the block hasn't triggered a zaaktypen fetch yet). + * + * @since NEXT + * + * @param string[] $urls + * @return string[] + */ + private function resolve_zaaktype_urls( string $supplier_name, array $urls ): array + { + if (array() === $urls) { + return $urls; + } + + $migrations = ZaaktypeAdapter::url_migrations( $supplier_name ); + + if (array() === $migrations) { + return $urls; + } + + return array_values( + array_unique( + array_map( + function ( $url ) use ( $migrations ) { + return $migrations[ $url ] ?? $url; + }, + $urls + ) + ) + ); + } + /** * Resolves a list of supplier names into API clients, skipping any that are not * configured or do not support zaken. diff --git a/src/Controllers/ZaaktypenCacheController.php b/src/Controllers/ZaaktypenCacheController.php new file mode 100644 index 0000000..9e95ea7 --- /dev/null +++ b/src/Controllers/ZaaktypenCacheController.php @@ -0,0 +1,89 @@ +%s

', + esc_url( $url ), + esc_html__( 'Zaaktypen opnieuw ophalen', 'owc-mijn-services' ) + ); + } + + /** + * Handles the request to manually re-fetch the zaaktypen of all configured suppliers. + * + * Fetches live rather than merely clearing the cache, since this is an explicit, + * user-initiated action where waiting for the request to finish is expected. + */ + public function handle_refetch_request(): void + { + $capability = OptionsPageRegistrar::get_allowed_settings_capability(); + + if ( ! current_user_can( 'manage_options' ) && ! current_user_can( $capability )) { + wp_die( esc_html__( 'Je hebt geen toestemming om deze actie uit te voeren.', 'owc-mijn-services' ) ); + } + + check_admin_referer( self::ACTION, self::NONCE_QUERY ); + + ( new PopulateZaaktypen() )->init(); + + wp_safe_redirect( add_query_arg( self::NOTICE_FLAG, '1', wp_get_referer() ?: admin_url() ) ); + exit; + } + + /** + * Shows an admin notice right after the zaaktypen have been re-fetched. + */ + public function render_refetched_notice(): void + { + if ( ! isset( $_GET[ self::NOTICE_FLAG ] )) { + return; + } + + printf( + '

%s

', + esc_html__( 'De zaaktypen zijn opnieuw opgehaald.', 'owc-mijn-services' ) + ); + } +} diff --git a/src/Providers/BlockServiceProvider.php b/src/Providers/BlockServiceProvider.php index aa519db..3ab8d0e 100644 --- a/src/Providers/BlockServiceProvider.php +++ b/src/Providers/BlockServiceProvider.php @@ -19,13 +19,17 @@ exit; } +use DI\NotFoundException; use OWC\My_Services\Blocks\MijnZaken; use OWC\My_Services\Blocks\Zaak; use OWC\My_Services\ContainerResolver; +use OWC\My_Services\Settings\Adapters\ZaaktypeAdapter; use WP_Block_Editor_Context; use WP_Block_Type; use OWC\My_Services\Traits\Supplier; +use function OWC\ZGW\apiClientManager; + /** * Register block service provider. * @@ -130,6 +134,10 @@ private function register_mijn_zaken_block(): void 'type' => 'array', 'default' => array(), ), + 'zaaktypen' => array( + 'type' => 'object', + 'default' => array(), + ), 'byBSN' => array( 'type' => 'boolean', 'default' => true, @@ -163,6 +171,7 @@ private function register_mijn_zaken_block(): void } $this->preprare_and_add_client_options( $block_type ); + $this->add_zaaktype_options( $block_type ); } /** @@ -212,29 +221,16 @@ private function preprare_and_add_client_options( WP_Block_Type $block_type ): v return; } - $clients = $this->get_configured_suppliers(); - - $options = array( - array( - 'value' => '', - 'label' => 'Selecteer een leverancier', - ), + $options = array_map( + function ( $client ) { + return array( + 'value' => $client['name'], + 'label' => $client['name'], + ); + }, + $this->get_configured_suppliers() ); - if (0 < count( $clients )) { - $prepared_client_options = array_map( - function ( $client ) { - return array( - 'value' => $client['name'], - 'label' => $client['name'], - ); - }, - $clients - ); - - $options = array_merge( $options, $prepared_client_options ); - } - $production_checks_enabled = ! ContainerResolver::make()->get( 'display.disable-production-checks' ); $disable_kvk_filtering = ContainerResolver::make()->get( 'display.disable-kvk-filtering' ); @@ -251,6 +247,81 @@ function ( $client ) { $this->zaak_client_options_inline_script_added = true; } + /** + * Localizes the zaaktypen of every configured supplier that supports them, grouped + * per supplier, so the block editor can offer a per-supplier zaaktype filter. + * + * Skips suppliers not selected in the 'Zaaktypefiltering ondersteunde leveranciers' setting, + * and localizes nothing at all when no supplier is selected there, so the block editor never + * receives zaaktype options for a supplier it can't actually filter on. + * + * Only runs in wp-admin: the result is only ever read by the block editor, and the + * underlying zaaktypen are already cached in a transient (kept warm by a daily cron), + * so this stays cheap even though it runs on every editor screen load. + * + * @since NEXT + */ + private function add_zaaktype_options( WP_Block_Type $block_type ): void + { + if ( ! is_admin() ) { + return; + } + + $filtering_suppliers = ContainerResolver::make()->get( 'display.zaaktype-filtering-suppliers' ); + + if (array() === $filtering_suppliers) { + return; + } + + $grouped = array(); + $migrations = array(); + + foreach ($this->get_configured_suppliers() as $supplier) { + if ( ! in_array( $supplier['name'], $filtering_suppliers, true )) { + continue; + } + + try { + $client = apiClientManager()->getClient( $supplier['name'] ); + } catch (NotFoundException $e) { + continue; + } + + if ( ! $client->supports( 'zaaktypen' )) { + continue; + } + + $types = ( new ZaaktypeAdapter( $client, $supplier['name'] ) )->handle(); + + if (array() === $types) { + continue; + } + + $grouped[ $supplier['name'] ] = array_map( + function ( $url, $label ) { + return array( + 'value' => $url, + 'label' => $label, + ); + }, + array_keys( $types ), + $types + ); + + $supplier_migrations = ZaaktypeAdapter::url_migrations( $supplier['name'] ); + + if (array() !== $supplier_migrations) { + $migrations[ $supplier['name'] ] = $supplier_migrations; + } + } + + wp_add_inline_script( + $block_type->editor_script, + 'window.owcMyServices = window.owcMyServices || {}; window.owcMyServices.zaaktypeOptions = ' . wp_json_encode( $grouped ) . '; window.owcMyServices.zaaktypeUrlMigrations = ' . wp_json_encode( $migrations ) . ';', + 'before' + ); + } + public function maybe_handle_information_object_download( string $template ): string { if (get_query_var( 'pagename' ) === 'zaak-download') { diff --git a/src/Providers/SettingsServiceProvider.php b/src/Providers/SettingsServiceProvider.php index 4a2c40f..9e00bb9 100644 --- a/src/Providers/SettingsServiceProvider.php +++ b/src/Providers/SettingsServiceProvider.php @@ -20,6 +20,7 @@ } use OWC\My_Services\Controllers\InformatieobjecttypenCacheController; +use OWC\My_Services\Controllers\ZaaktypenCacheController; use OWC\My_Services\Settings\OptionsPageRegistrar; use OWC\ZGW\ApiClientManager; use OWC\ZGW\WordPress\ClientProvider; @@ -43,9 +44,15 @@ public function register(): void add_action( 'cmb2_admin_init', ( new OptionsPageRegistrar() )->addSettingsFields( ... ) ); + // Informatieobjecttypen cache actions. add_action( 'admin_post_' . InformatieobjecttypenCacheController::ACTION, ( new InformatieobjecttypenCacheController() )->handle_clear_cache_request( ... ) ); add_action( 'admin_notices', ( new InformatieobjecttypenCacheController() )->render_cache_cleared_notice( ... ) ); + // Zaaktypen cache actions. + add_action( 'admin_post_' . ZaaktypenCacheController::ACTION, ( new ZaaktypenCacheController() )->handle_refetch_request( ... ) ); + add_action( 'admin_notices', ( new ZaaktypenCacheController() )->render_refetched_notice( ... ) ); + + // Enqueue scripts for the settings page. add_action( 'admin_enqueue_scripts', $this->enqueue_scripts( ... ) ); } diff --git a/src/Providers/WPCronServiceProvider.php b/src/Providers/WPCronServiceProvider.php index 42170cf..ef59bd8 100644 --- a/src/Providers/WPCronServiceProvider.php +++ b/src/Providers/WPCronServiceProvider.php @@ -22,6 +22,7 @@ use DateTime; use DateTimeZone; use OWC\My_Services\WPCron\Events\PopulateInformatieobjecttypen; +use OWC\My_Services\WPCron\Events\PopulateZaaktypen; /** * Register WP-Cron service provider. @@ -31,6 +32,7 @@ class WPCronServiceProvider extends ServiceProvider { private const POPULATE_INFORMATIEOBJECTTYPEN_HOOK = 'owc-mijn-services-populate-informatieobjecttypen-cron'; + private const POPULATE_ZAAKTYPEN_HOOK = 'owc-mijn-services-populate-zaaktypen-cron'; /** * @inheritDoc @@ -42,6 +44,12 @@ public function register(): void if ( ! wp_next_scheduled( self::POPULATE_INFORMATIEOBJECTTYPEN_HOOK )) { wp_schedule_event( $this->time_to_execute( 'tomorrow 04:00:00' ), 'daily', self::POPULATE_INFORMATIEOBJECTTYPEN_HOOK ); } + + add_action( self::POPULATE_ZAAKTYPEN_HOOK, ( new PopulateZaaktypen() )->init( ... ) ); + + if ( ! wp_next_scheduled( self::POPULATE_ZAAKTYPEN_HOOK )) { + wp_schedule_event( $this->time_to_execute( 'tomorrow 04:00:00' ), 'daily', self::POPULATE_ZAAKTYPEN_HOOK ); + } } /** diff --git a/src/Settings/Adapters/ZaaktypeAdapter.php b/src/Settings/Adapters/ZaaktypeAdapter.php new file mode 100644 index 0000000..81ef82c --- /dev/null +++ b/src/Settings/Adapters/ZaaktypeAdapter.php @@ -0,0 +1,267 @@ +client = $client; + $this->supplier_name = $supplier_name; + $this->is_cron = $is_cron; + } + + /** + * Builds the transient key used to cache the zaaktypen of a supplier. + * + * @since NEXT + */ + public static function transient_key( string $supplier_name ): string + { + return sprintf( 'owcms-zaaktypen-%s', strtolower( $supplier_name ) ); + } + + /** + * Builds the transient key used to cache the zaaktype URL migrations of a supplier. + * + * @since NEXT + */ + public static function migrations_transient_key( string $supplier_name ): string + { + return sprintf( 'owcms-zaaktypen-url-migrations-%s', strtolower( $supplier_name ) ); + } + + /** + * Returns a map of superseded zaaktype URL => current (latest version) zaaktype URL for a + * supplier, built the last time its zaaktypen were freshly fetched by handle(). Only reads + * the cache, never triggers a live fetch itself, so it's safe to call at render time. + * + * @since NEXT + * + * @return array + */ + public static function url_migrations( string $supplier_name ): array + { + $migrations = get_transient( self::migrations_transient_key( $supplier_name ) ); + + return is_array( $migrations ) ? $migrations : array(); + } + + /** + * Returns the zaaktypen of the supplier as a value => label map, + * ready to use as options for a select field. + * + * When called from a cron context, the transient is always refreshed rather than reused, + * so the cache stays warm and no site visitor or editor has to wait for the API request. + * + * @return array + */ + public function handle(): array + { + $transient_key = self::transient_key( $this->supplier_name ); + $types = get_transient( $transient_key ); + + if ( ! $this->is_cron ) { + return is_array( $types ) ? $types : array(); + } + + try { + $raw = $this->fetch_types(); + $filtered = $this->filter_zaaktypen_by_version_date( $raw ); + $types = $this->prepare_types( $filtered ); + } catch (Exception $e) { + LoggerService::log( 'error', $e->getMessage() ); + + return array(); + } + + if (array() === $types) { + return array(); + } + + set_transient( $transient_key, $types, self::TRANSIENT_LIFETIME_IN_SECONDS ); + set_transient( self::migrations_transient_key( $this->supplier_name ), $this->build_url_migrations( $raw, $filtered ), self::TRANSIENT_LIFETIME_IN_SECONDS ); + + return $types; + } + + /** + * Maps every superseded zaaktype URL (any zaaktype sharing an omschrijving with a newer + * version) to the URL of its latest version, so filters that still reference an older + * version (e.g. a block's saved attributes) can be resolved to a currently valid zaaktype. + * + * @since NEXT + * + * @param Zaaktype[] $raw + * @param Zaaktype[] $filtered + * @return array + */ + private function build_url_migrations( array $raw, array $filtered ): array + { + $latest_url_by_description = array(); + + foreach ($filtered as $zaaktype) { + $description = trim( (string) ( $zaaktype->omschrijving ?? '' ) ); + $url = trim( (string) ( $zaaktype->url ?? '' ) ); + + if ('' !== $description && '' !== $url) { + $latest_url_by_description[ $description ] = $url; + } + } + + $migrations = array(); + + foreach ($raw as $zaaktype) { + $description = trim( (string) ( $zaaktype->omschrijving ?? '' ) ); + $url = trim( (string) ( $zaaktype->url ?? '' ) ); + + if ('' === $description || '' === $url) { + continue; + } + + $latest_url = $latest_url_by_description[ $description ] ?? ''; + + if ('' !== $latest_url && $latest_url !== $url) { + $migrations[ $url ] = $latest_url; + } + } + + return $migrations; + } + + /** + * Filters an array of zaaktypen to ensure unique 'omschrijvingen' (description), keeping + * only the one with the latest 'versiedatum' (version date) per description. A zaaktype is + * versioned in the ZTC API by creating a new resource with the same omschrijving, so without + * this the block would offer several selectable entries that all represent the same zaaktype. + * + * @since NEXT + */ + private function filter_zaaktypen_by_version_date( array $zaaktypen ): array + { + $filtered = array(); + + foreach ($zaaktypen as $zaaktype) { + $description = trim( (string) ( $zaaktype->omschrijving ?? '' ) ); + + if ('' === $description) { + continue; + } + + if ( ! isset( $filtered[ $description ] )) { + $filtered[ $description ] = $zaaktype; + + continue; + } + + if ($this->get_zaaktype_timestamp( $zaaktype ) > $this->get_zaaktype_timestamp( $filtered[ $description ] )) { + $filtered[ $description ] = $zaaktype; + } + } + + return array_values( $filtered ); + } + + private function get_zaaktype_timestamp( Zaaktype $zaaktype ): int + { + if ( ! $zaaktype->versiedatum instanceof DateTimeImmutable) { + return 0; + } + + $timestamp = $zaaktype->versiedatum->getTimestamp(); + + return false === $timestamp ? 0 : $timestamp; + } + + private function fetch_types(): array + { + $page = 1; + $types = array(); + + while ($page) { + $result = $this->client->zaaktypen()->all( ( new ZaaktypenFilter() )->page( $page ) ); + $types = array_merge( $types, (array) $result->all() ); + $page = $result->pageMeta()->getNextPageNumber(); + } + + return $types; + } + + /** + * @return array + */ + private function prepare_types( array $types ): array + { + $prepared = (array) Collection::collect( $types )->map( + function ( Zaaktype $zaaktype ) { + $description = (string) ( $zaaktype->omschrijving ?? '' ); + $url = (string) ( $zaaktype->url ?? '' ); + $identificatie = (string) ( $zaaktype->identificatie ?? '' ); + + if ('' === $description || '' === $url) { + return null; + } + + return array( + 'url' => $url, + 'label' => '' !== $identificatie ? sprintf( '%s (%s)', $description, $identificatie ) : $description, + ); + } + )->filter( + function ( $item ) { + return null !== $item; + } + )->all(); + + usort( + $prepared, + function ( $a, $b ) { + return strcmp( $a['label'], $b['label'] ); + } + ); + + $options = array(); + + foreach ($prepared as $item) { + $options[ $item['url'] ] = $item['label']; + } + + return $options; + } +} diff --git a/src/Settings/OptionsPageRegistrar.php b/src/Settings/OptionsPageRegistrar.php index 62d0a66..781e5fa 100644 --- a/src/Settings/OptionsPageRegistrar.php +++ b/src/Settings/OptionsPageRegistrar.php @@ -21,6 +21,7 @@ use OWC\My_Services\CMB2\SelectOptgroupType; use OWC\My_Services\Controllers\InformatieobjecttypenCacheController; +use OWC\My_Services\Controllers\ZaaktypenCacheController; use OWC\My_Services\Services\LoggerService; use OWC\My_Services\Traits\Supplier; @@ -114,6 +115,39 @@ public function addSettingsFields(): void ) ); + $options->add_field( + array( + 'name' => __( 'Zaaktypefiltering ondersteunde leveranciers', 'owc-mijn-services' ), + 'desc' => __( 'Selecteer de leveranciers waarvan de Zaken API filteren op zaaktype ondersteunt. Alleen voor geselecteerde leveranciers wordt gefilterd op de zaaktypen die in het \'Mijn zaken\'-blok zijn geselecteerd; voor niet geselecteerde leveranciers worden altijd alle zaken opgehaald.', 'owc-mijn-services' ), + 'id' => 'owc-mijn-services-zaaktype-filtering-suppliers', + 'type' => 'multicheck', + 'select_all_button' => false, + 'options_cb' => function () { + return $this->get_supplier_options(); + }, + 'sanitization_cb' => function ( $value ) { + return is_array( $value ) ? array_values( array_filter( $value, 'is_string' ) ) : array(); + }, + 'show_on_cb' => $allowed_settings_show_on_cb, + ) + ); + + $options->add_field( + array( + 'name' => '', // Left blank to avoid duplicating the label_cb heading below. + 'desc' => __( 'De zaaktypen die gebruikt worden voor de zaaktypefilter in het \'Mijn zaken\'-blok worden dagelijks automatisch ververst. Gebruik onderstaande knop om ze direct opnieuw op te halen.', 'owc-mijn-services' ), + 'id' => 'owc-mijn-services-zaaktypen-cache', + 'type' => 'title', + 'label_cb' => function () { // 'title' fields have no label_cb by default, so restore it to match other rows. + return sprintf( '', esc_html__( 'Zaaktypen', 'owc-mijn-services' ) ); + }, + 'after' => function () { + ( new ZaaktypenCacheController() )->render_refetch_button(); + }, + 'show_on_cb' => $allowed_settings_show_on_cb, + ) + ); + $options->add_field( array( 'name' => __( 'Productiecontroles uitschakelen', 'owc-mijn-services' ), @@ -179,6 +213,24 @@ private function get_informatieobjecttype_options(): array return ( new InformatieobjecttypeCatalog() )->per_supplier(); } + /** + * Builds the list of configured suppliers as a name => name map, to use as options for the + * 'Zaaktypefiltering ondersteunde leveranciers' multicheck field. + * + * @return array + * @since NEXT + */ + private function get_supplier_options(): array + { + $options = array(); + + foreach ($this->get_configured_suppliers() as $supplier) { + $options[ $supplier['name'] ] = $supplier['name']; + } + + return $options; + } + private function handle_unchecked_checkbox( mixed $value ): ?string { if ( ! is_string( $value ) || 'on' !== $value) { diff --git a/src/Traits/Supplier.php b/src/Traits/Supplier.php index 35b7e07..0241599 100644 --- a/src/Traits/Supplier.php +++ b/src/Traits/Supplier.php @@ -19,6 +19,8 @@ exit; } +use OWC\My_Services\ContainerResolver; + /** * Supplier trait. * @@ -59,4 +61,19 @@ function ( $client ) { return array_values( $clients ); } + + /** + * Whether filtering zaken on zaaktype is supported for the given supplier. Governed by the + * 'Zaaktypefiltering ondersteunde leveranciers' setting, since not every supplier's Zaken API + * supports filtering on the zaaktype parameter. Disabled by default; a supplier must be + * explicitly selected in the setting before zaaktype filtering is applied for it. + * + * @since NEXT + */ + public function supports_zaaktype_filtering( string $supplier_name ): bool + { + $supported = (array) ContainerResolver::make()->get( 'display.zaaktype-filtering-suppliers' ); + + return in_array( $supplier_name, $supported, true ); + } } diff --git a/src/WPCron/Events/PopulateZaaktypen.php b/src/WPCron/Events/PopulateZaaktypen.php new file mode 100644 index 0000000..fd66013 --- /dev/null +++ b/src/WPCron/Events/PopulateZaaktypen.php @@ -0,0 +1,62 @@ +get_configured_suppliers() as $supplier) { + $this->populate_for_supplier( $supplier ); + } + } + + private function populate_for_supplier( array $supplier ): void + { + try { + $client = apiClientManager()->getClient( $supplier['name'] ); + } catch (Exception $e) { + LoggerService::log( 'error', sprintf( 'Error initializing API client for supplier %s: %s', $supplier['name'], $e->getMessage() ) ); + + return; + } + + if ( ! $client->supports( 'zaaktypen' )) { + return; + } + + ( new ZaaktypeAdapter( client: $client, supplier_name: $supplier['name'], is_cron: true ) )->handle(); + } +} From 69ff3c4afe29854e70c986286fdfcd75217f607c Mon Sep 17 00:00:00 2001 From: Mike van den Hoek Date: Tue, 22 Sep 2026 11:59:29 +0200 Subject: [PATCH 2/4] feat: use placeholder component in owc-my-services/zaak block --- build/zaak/index.asset.php | 2 +- build/zaak/index.js | 2 +- resources/blocks/zaak/edit.js | 21 ++++++++++++--------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/build/zaak/index.asset.php b/build/zaak/index.asset.php index 9cb1876..d7a90d3 100644 --- a/build/zaak/index.asset.php +++ b/build/zaak/index.asset.php @@ -1 +1 @@ - array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => '27206ca7dc09304c66a0'); + array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => '25cca51eb2e610a50d16'); diff --git a/build/zaak/index.js b/build/zaak/index.js index 38f231e..a61c39f 100644 --- a/build/zaak/index.js +++ b/build/zaak/index.js @@ -1 +1 @@ -(()=>{"use strict";var e,i={502:(e,i,n)=>{const t=window.wp.blocks,r=window.wp.element,s=window.wp.blockEditor,o=window.wp.components,l=window.wp.serverSideRender;var a=n.n(l);const c=window.wp.i18n,d=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"owc-my-services/zaak","version":"1.0.0","title":"OWC Zaak","description":"Toont Zaak blok.","attributes":{"zaakClient":{"type":"string","default":""},"zaakClients":{"type":"array","default":[]},"byBSN":{"type":"boolean","default":true},"byKVK":{"type":"boolean","default":false}},"supports":{"html":false},"textdomain":"owc-my-services","editorScript":"file:./index.js","editorStyle":"file:./editor.css","style":"file:./style-index.css","viewScript":"file:./view.js"}'),p=window.ReactJSXRuntime;(0,t.registerBlockType)(d,{edit:function({attributes:e,setAttributes:i}){const{zaakClient:n,zaakClients:t,byBSN:l,byKVK:u}=e,w=(window?.owcMyServices?.zaakClientOptions??[]).filter((e=>""!==e.value)),v=(window?.owcMyServices?.productionChecksEnabled??!0)&&!l&&!(u&&!b),b=window?.owcMyServices?.disableKVKFiltering??!1;return(0,r.useEffect)((()=>{n&&0===t.length&&i({zaakClients:[n],zaakClient:""})}),[]),(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(s.InspectorControls,{children:(0,p.jsxs)(o.PanelBody,{title:(0,c.__)("Instellingen","owc-mijn-services"),initialOpen:!0,children:[w.length>0?(0,p.jsx)(o.BaseControl,{id:"owc-my-services-zaak-clients-checkbox-selection",label:(0,c.__)("Zaaksystemen","owc-mijn-services"),help:(0,c.__)("Selecteer de zaaksystemen waarvan zaken op deze pagina getoond kunnen worden.","owc-mijn-services"),children:w.map((e=>(0,p.jsx)(o.CheckboxControl,{label:e.label,checked:t.includes(e.value),onChange:n=>{const r=n?[...t,e.value]:t.filter((i=>i!==e.value));i({zaakClients:r})}},e.value)))}):(0,p.jsx)("p",{children:(0,c.__)("Geen leveranciers geconfigureerd.","owc-mijn-services")}),v&&(0,p.jsx)(o.Notice,{status:"warning",isDismissible:!1,children:b?(0,c.__)("Schakel de filteroptie Filter op BSN in.","owc-mijn-services"):(0,c.__)("Selecteer minimaal één filteroptie: Filter op BSN of Filter op KVK.","owc-mijn-services")}),(0,p.jsx)(o.CheckboxControl,{label:"Filter op BSN",help:"Filter zaken die aangemaakt zijn door de ingelogde gebruiker op basis van het BSN nummer.",checked:l,onChange:e=>i({byBSN:e})}),!b&&(0,p.jsx)(o.CheckboxControl,{label:"Filter op KVK",help:"Filter zaken die aangemaakt zijn door de ingelogde gebruiker op basis van het KVK nummer.",checked:u,onChange:e=>i({byKVK:e})}),b&&(0,p.jsx)(o.Notice,{status:"warning",isDismissible:!1,children:(0,c.__)("Filteren op KVK is uitgeschakeld in de instellingen van de plugin.","owc-mijn-services")})]})}),(0,p.jsx)("div",{...(0,s.useBlockProps)(),children:(0,p.jsx)(o.Disabled,{children:(0,p.jsx)(a(),{block:d.name,attributes:e})})})]})},save:function(){return null}})}},n={};function t(e){var r=n[e];if(void 0!==r)return r.exports;var s=n[e]={exports:{}};return i[e](s,s.exports,t),s.exports}t.m=i,e=[],t.O=(i,n,r,s)=>{if(!n){var o=1/0;for(d=0;d=s)&&Object.keys(t.O).every((e=>t.O[e](n[a])))?n.splice(a--,1):(l=!1,s0&&e[d-1][2]>s;d--)e[d]=e[d-1];e[d]=[n,r,s]},t.n=e=>{var i=e&&e.__esModule?()=>e.default:()=>e;return t.d(i,{a:i}),i},t.d=(e,i)=>{for(var n in i)t.o(i,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:i[n]})},t.o=(e,i)=>Object.prototype.hasOwnProperty.call(e,i),(()=>{var e={613:0,785:0};t.O.j=i=>0===e[i];var i=(i,n)=>{var r,s,[o,l,a]=n,c=0;if(o.some((i=>0!==e[i]))){for(r in l)t.o(l,r)&&(t.m[r]=l[r]);if(a)var d=a(t)}for(i&&i(n);ct(502)));r=t.O(r)})(); \ No newline at end of file +(()=>{"use strict";var e,i={446:()=>{const e=window.wp.blocks,i=window.wp.element,n=window.wp.blockEditor,s=window.wp.components,t=window.wp.i18n,o=window.ReactJSXRuntime,a=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"owc-my-services/zaak","version":"1.0.0","title":"OWC Zaak","description":"Toont Zaak blok.","attributes":{"zaakClient":{"type":"string","default":""},"zaakClients":{"type":"array","default":[]},"byBSN":{"type":"boolean","default":true},"byKVK":{"type":"boolean","default":false}},"supports":{"html":false},"textdomain":"owc-my-services","editorScript":"file:./index.js","editorStyle":"file:./editor.css","style":"file:./style-index.css","viewScript":"file:./view.js"}');(0,e.registerBlockType)(a,{edit:function({attributes:e,setAttributes:a}){const{zaakClient:l,zaakClients:r,byBSN:c,byKVK:d}=e,p=(window?.owcMyServices?.zaakClientOptions??[]).filter((e=>""!==e.value)),v=(window?.owcMyServices?.productionChecksEnabled??!0)&&!c&&!(d&&!w),w=window?.owcMyServices?.disableKVKFiltering??!1;return(0,i.useEffect)((()=>{l&&0===r.length&&a({zaakClients:[l],zaakClient:""})}),[]),(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.InspectorControls,{children:(0,o.jsxs)(s.PanelBody,{title:(0,t.__)("Instellingen","owc-mijn-services"),initialOpen:!0,children:[p.length>0?(0,o.jsx)(s.BaseControl,{id:"owc-my-services-zaak-clients-checkbox-selection",label:(0,t.__)("Zaaksystemen","owc-mijn-services"),help:(0,t.__)("Selecteer de zaaksystemen waarvan zaken op deze pagina getoond kunnen worden.","owc-mijn-services"),children:p.map((e=>(0,o.jsx)(s.CheckboxControl,{label:e.label,checked:r.includes(e.value),onChange:i=>{const n=i?[...r,e.value]:r.filter((i=>i!==e.value));a({zaakClients:n})}},e.value)))}):(0,o.jsx)("p",{children:(0,t.__)("Geen leveranciers geconfigureerd.","owc-mijn-services")}),v&&(0,o.jsx)(s.Notice,{status:"warning",isDismissible:!1,children:w?(0,t.__)("Schakel de filteroptie Filter op BSN in.","owc-mijn-services"):(0,t.__)("Selecteer minimaal één filteroptie: Filter op BSN of Filter op KVK.","owc-mijn-services")}),(0,o.jsx)(s.CheckboxControl,{label:"Filter op BSN",help:"Filter zaken die aangemaakt zijn door de ingelogde gebruiker op basis van het BSN nummer.",checked:c,onChange:e=>a({byBSN:e})}),!w&&(0,o.jsx)(s.CheckboxControl,{label:"Filter op KVK",help:"Filter zaken die aangemaakt zijn door de ingelogde gebruiker op basis van het KVK nummer.",checked:d,onChange:e=>a({byKVK:e})}),w&&(0,o.jsx)(s.Notice,{status:"warning",isDismissible:!1,children:(0,t.__)("Filteren op KVK is uitgeschakeld in de instellingen van de plugin.","owc-mijn-services")})]})}),(0,o.jsx)("div",{...(0,n.useBlockProps)(),children:(0,o.jsx)(s.Placeholder,{icon:"list-view",label:(0,t.__)("Detailpagina van een zaak","owc-mijn-services"),instructions:(0,t.__)("Toont de details van een specifieke zaak.","owc-mijn-services")})})]})},save:function(){return null}})}},n={};function s(e){var t=n[e];if(void 0!==t)return t.exports;var o=n[e]={exports:{}};return i[e](o,o.exports,s),o.exports}s.m=i,e=[],s.O=(i,n,t,o)=>{if(!n){var a=1/0;for(d=0;d=o)&&Object.keys(s.O).every((e=>s.O[e](n[r])))?n.splice(r--,1):(l=!1,o0&&e[d-1][2]>o;d--)e[d]=e[d-1];e[d]=[n,t,o]},s.o=(e,i)=>Object.prototype.hasOwnProperty.call(e,i),(()=>{var e={613:0,785:0};s.O.j=i=>0===e[i];var i=(i,n)=>{var t,o,[a,l,r]=n,c=0;if(a.some((i=>0!==e[i]))){for(t in l)s.o(l,t)&&(s.m[t]=l[t]);if(r)var d=r(s)}for(i&&i(n);cs(446)));t=s.O(t)})(); \ No newline at end of file diff --git a/resources/blocks/zaak/edit.js b/resources/blocks/zaak/edit.js index 4a10bef..3885769 100644 --- a/resources/blocks/zaak/edit.js +++ b/resources/blocks/zaak/edit.js @@ -5,18 +5,16 @@ import { useEffect } from '@wordpress/element'; import { InspectorControls, useBlockProps } from '@wordpress/block-editor'; import { PanelBody, - Disabled, BaseControl, CheckboxControl, Notice, + Placeholder, } from '@wordpress/components'; -import ServerSideRender from '@wordpress/server-side-render'; import { __ } from '@wordpress/i18n'; /** * Internal dependencies. */ -import metadata from './block.json'; import './editor.css'; export default function Edit( { attributes, setAttributes } ) { @@ -120,12 +118,17 @@ export default function Edit( { attributes, setAttributes } ) {
- - - +
); From 97d3e5bb708412df29329c660bf12d1048e3b81c Mon Sep 17 00:00:00 2001 From: Mike van den Hoek Date: Tue, 22 Sep 2026 14:07:20 +0200 Subject: [PATCH 3/4] fix: bsnKvkMissing reads disableKVKFiltering one line before its const declaration --- build/zaak/index.asset.php | 2 +- build/zaak/index.js | 2 +- resources/blocks/zaak/edit.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/zaak/index.asset.php b/build/zaak/index.asset.php index d7a90d3..0b603f3 100644 --- a/build/zaak/index.asset.php +++ b/build/zaak/index.asset.php @@ -1 +1 @@ - array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => '25cca51eb2e610a50d16'); + array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => 'f5a762891a7715127f5c'); diff --git a/build/zaak/index.js b/build/zaak/index.js index a61c39f..25d1f97 100644 --- a/build/zaak/index.js +++ b/build/zaak/index.js @@ -1 +1 @@ -(()=>{"use strict";var e,i={446:()=>{const e=window.wp.blocks,i=window.wp.element,n=window.wp.blockEditor,s=window.wp.components,t=window.wp.i18n,o=window.ReactJSXRuntime,a=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"owc-my-services/zaak","version":"1.0.0","title":"OWC Zaak","description":"Toont Zaak blok.","attributes":{"zaakClient":{"type":"string","default":""},"zaakClients":{"type":"array","default":[]},"byBSN":{"type":"boolean","default":true},"byKVK":{"type":"boolean","default":false}},"supports":{"html":false},"textdomain":"owc-my-services","editorScript":"file:./index.js","editorStyle":"file:./editor.css","style":"file:./style-index.css","viewScript":"file:./view.js"}');(0,e.registerBlockType)(a,{edit:function({attributes:e,setAttributes:a}){const{zaakClient:l,zaakClients:r,byBSN:c,byKVK:d}=e,p=(window?.owcMyServices?.zaakClientOptions??[]).filter((e=>""!==e.value)),v=(window?.owcMyServices?.productionChecksEnabled??!0)&&!c&&!(d&&!w),w=window?.owcMyServices?.disableKVKFiltering??!1;return(0,i.useEffect)((()=>{l&&0===r.length&&a({zaakClients:[l],zaakClient:""})}),[]),(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.InspectorControls,{children:(0,o.jsxs)(s.PanelBody,{title:(0,t.__)("Instellingen","owc-mijn-services"),initialOpen:!0,children:[p.length>0?(0,o.jsx)(s.BaseControl,{id:"owc-my-services-zaak-clients-checkbox-selection",label:(0,t.__)("Zaaksystemen","owc-mijn-services"),help:(0,t.__)("Selecteer de zaaksystemen waarvan zaken op deze pagina getoond kunnen worden.","owc-mijn-services"),children:p.map((e=>(0,o.jsx)(s.CheckboxControl,{label:e.label,checked:r.includes(e.value),onChange:i=>{const n=i?[...r,e.value]:r.filter((i=>i!==e.value));a({zaakClients:n})}},e.value)))}):(0,o.jsx)("p",{children:(0,t.__)("Geen leveranciers geconfigureerd.","owc-mijn-services")}),v&&(0,o.jsx)(s.Notice,{status:"warning",isDismissible:!1,children:w?(0,t.__)("Schakel de filteroptie Filter op BSN in.","owc-mijn-services"):(0,t.__)("Selecteer minimaal één filteroptie: Filter op BSN of Filter op KVK.","owc-mijn-services")}),(0,o.jsx)(s.CheckboxControl,{label:"Filter op BSN",help:"Filter zaken die aangemaakt zijn door de ingelogde gebruiker op basis van het BSN nummer.",checked:c,onChange:e=>a({byBSN:e})}),!w&&(0,o.jsx)(s.CheckboxControl,{label:"Filter op KVK",help:"Filter zaken die aangemaakt zijn door de ingelogde gebruiker op basis van het KVK nummer.",checked:d,onChange:e=>a({byKVK:e})}),w&&(0,o.jsx)(s.Notice,{status:"warning",isDismissible:!1,children:(0,t.__)("Filteren op KVK is uitgeschakeld in de instellingen van de plugin.","owc-mijn-services")})]})}),(0,o.jsx)("div",{...(0,n.useBlockProps)(),children:(0,o.jsx)(s.Placeholder,{icon:"list-view",label:(0,t.__)("Detailpagina van een zaak","owc-mijn-services"),instructions:(0,t.__)("Toont de details van een specifieke zaak.","owc-mijn-services")})})]})},save:function(){return null}})}},n={};function s(e){var t=n[e];if(void 0!==t)return t.exports;var o=n[e]={exports:{}};return i[e](o,o.exports,s),o.exports}s.m=i,e=[],s.O=(i,n,t,o)=>{if(!n){var a=1/0;for(d=0;d=o)&&Object.keys(s.O).every((e=>s.O[e](n[r])))?n.splice(r--,1):(l=!1,o0&&e[d-1][2]>o;d--)e[d]=e[d-1];e[d]=[n,t,o]},s.o=(e,i)=>Object.prototype.hasOwnProperty.call(e,i),(()=>{var e={613:0,785:0};s.O.j=i=>0===e[i];var i=(i,n)=>{var t,o,[a,l,r]=n,c=0;if(a.some((i=>0!==e[i]))){for(t in l)s.o(l,t)&&(s.m[t]=l[t]);if(r)var d=r(s)}for(i&&i(n);cs(446)));t=s.O(t)})(); \ No newline at end of file +(()=>{"use strict";var e,i={446:()=>{const e=window.wp.blocks,i=window.wp.element,n=window.wp.blockEditor,s=window.wp.components,t=window.wp.i18n,o=window.ReactJSXRuntime,a=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"owc-my-services/zaak","version":"1.0.0","title":"OWC Zaak","description":"Toont Zaak blok.","attributes":{"zaakClient":{"type":"string","default":""},"zaakClients":{"type":"array","default":[]},"byBSN":{"type":"boolean","default":true},"byKVK":{"type":"boolean","default":false}},"supports":{"html":false},"textdomain":"owc-my-services","editorScript":"file:./index.js","editorStyle":"file:./editor.css","style":"file:./style-index.css","viewScript":"file:./view.js"}');(0,e.registerBlockType)(a,{edit:function({attributes:e,setAttributes:a}){const{zaakClient:l,zaakClients:r,byBSN:c,byKVK:d}=e,p=(window?.owcMyServices?.zaakClientOptions??[]).filter((e=>""!==e.value)),v=window?.owcMyServices?.productionChecksEnabled??!0,w=window?.owcMyServices?.disableKVKFiltering??!1,u=v&&!c&&!(d&&!w);return(0,i.useEffect)((()=>{l&&0===r.length&&a({zaakClients:[l],zaakClient:""})}),[]),(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.InspectorControls,{children:(0,o.jsxs)(s.PanelBody,{title:(0,t.__)("Instellingen","owc-mijn-services"),initialOpen:!0,children:[p.length>0?(0,o.jsx)(s.BaseControl,{id:"owc-my-services-zaak-clients-checkbox-selection",label:(0,t.__)("Zaaksystemen","owc-mijn-services"),help:(0,t.__)("Selecteer de zaaksystemen waarvan zaken op deze pagina getoond kunnen worden.","owc-mijn-services"),children:p.map((e=>(0,o.jsx)(s.CheckboxControl,{label:e.label,checked:r.includes(e.value),onChange:i=>{const n=i?[...r,e.value]:r.filter((i=>i!==e.value));a({zaakClients:n})}},e.value)))}):(0,o.jsx)("p",{children:(0,t.__)("Geen leveranciers geconfigureerd.","owc-mijn-services")}),u&&(0,o.jsx)(s.Notice,{status:"warning",isDismissible:!1,children:w?(0,t.__)("Schakel de filteroptie Filter op BSN in.","owc-mijn-services"):(0,t.__)("Selecteer minimaal één filteroptie: Filter op BSN of Filter op KVK.","owc-mijn-services")}),(0,o.jsx)(s.CheckboxControl,{label:"Filter op BSN",help:"Filter zaken die aangemaakt zijn door de ingelogde gebruiker op basis van het BSN nummer.",checked:c,onChange:e=>a({byBSN:e})}),!w&&(0,o.jsx)(s.CheckboxControl,{label:"Filter op KVK",help:"Filter zaken die aangemaakt zijn door de ingelogde gebruiker op basis van het KVK nummer.",checked:d,onChange:e=>a({byKVK:e})}),w&&(0,o.jsx)(s.Notice,{status:"warning",isDismissible:!1,children:(0,t.__)("Filteren op KVK is uitgeschakeld in de instellingen van de plugin.","owc-mijn-services")})]})}),(0,o.jsx)("div",{...(0,n.useBlockProps)(),children:(0,o.jsx)(s.Placeholder,{icon:"list-view",label:(0,t.__)("Detailpagina van een zaak","owc-mijn-services"),instructions:(0,t.__)("Toont de details van een specifieke zaak.","owc-mijn-services")})})]})},save:function(){return null}})}},n={};function s(e){var t=n[e];if(void 0!==t)return t.exports;var o=n[e]={exports:{}};return i[e](o,o.exports,s),o.exports}s.m=i,e=[],s.O=(i,n,t,o)=>{if(!n){var a=1/0;for(d=0;d=o)&&Object.keys(s.O).every((e=>s.O[e](n[r])))?n.splice(r--,1):(l=!1,o0&&e[d-1][2]>o;d--)e[d]=e[d-1];e[d]=[n,t,o]},s.o=(e,i)=>Object.prototype.hasOwnProperty.call(e,i),(()=>{var e={613:0,785:0};s.O.j=i=>0===e[i];var i=(i,n)=>{var t,o,[a,l,r]=n,c=0;if(a.some((i=>0!==e[i]))){for(t in l)s.o(l,t)&&(s.m[t]=l[t]);if(r)var d=r(s)}for(i&&i(n);cs(446)));t=s.O(t)})(); \ No newline at end of file diff --git a/resources/blocks/zaak/edit.js b/resources/blocks/zaak/edit.js index 3885769..4364142 100644 --- a/resources/blocks/zaak/edit.js +++ b/resources/blocks/zaak/edit.js @@ -25,8 +25,8 @@ export default function Edit( { attributes, setAttributes } ) { ); const productionChecksEnabled = window?.owcMyServices?.productionChecksEnabled ?? true; - const bsnKvkMissing = productionChecksEnabled && ! byBSN && ! ( byKVK && ! disableKVKFiltering ); const disableKVKFiltering = window?.owcMyServices?.disableKVKFiltering ?? false; + const bsnKvkMissing = productionChecksEnabled && ! byBSN && ! ( byKVK && ! disableKVKFiltering ); // Migrate legacy single zaakClient string to zaakClients array. useEffect( () => { From 43d38f22ba0d89bb7625785c421e227fd8627935 Mon Sep 17 00:00:00 2001 From: Mike van den Hoek Date: Tue, 22 Sep 2026 14:11:00 +0200 Subject: [PATCH 4/4] fix: re-sort merged zaken by orderBy before truncating to perPage --- src/Blocks/MijnZaken.php | 41 ++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/Blocks/MijnZaken.php b/src/Blocks/MijnZaken.php index 8e371ad..3b81691 100644 --- a/src/Blocks/MijnZaken.php +++ b/src/Blocks/MijnZaken.php @@ -56,6 +56,13 @@ function ( $zaak ) use ( $attributes ) { ); } + $order = $this->resolve_order( $attributes ); + + if (null !== $order) { + [ $field, $reverse ] = $order; + $zaken = $zaken->sortByAttribute( $field, $reverse ); + } + $zaken = $zaken->take( (int) ( $attributes['perPage'] ?? 10 ) ); return owc_mijn_services_render_view( @@ -74,17 +81,39 @@ function ( $zaak ) use ( $attributes ) { */ protected function handle_filter_ordering( array $attributes ): void { - if ( ! is_string( $attributes['orderBy'] ?? null ) || '' === $attributes['orderBy']) { + $order = $this->resolve_order( $attributes ); + + if (null === $order) { return; } - if ( ! is_string( $attributes['orderByDirection'] ?? null )) { - $attributes['orderByDirection'] = '-'; - } elseif ( $attributes['orderByDirection'] !== '-' ) { - $attributes['orderByDirection'] = ''; + [ $field, $reverse ] = $order; + + $this->zaken_filter->orderBy( sprintf( '%s%s', $reverse ? '-' : '', $field ) ); + } + + /** + * Resolves the validated orderBy field and direction from the block attributes. Shared by + * handle_filter_ordering(), which applies it to the live API request, and render_block(), + * which re-applies it as a PHP-side sort after fetching: merging zaken from multiple + * zaaktypen and/or suppliers means each individual API request comes back correctly ordered, + * but the merged result as a whole is not, so it must be re-sorted before it's truncated to + * perPage. + * + * @since NEXT + * + * @return array{0: string, 1: bool}|null Tuple of [orderBy field, reverse], or null when no + * ordering is configured. + */ + private function resolve_order( array $attributes ): ?array + { + if ( ! is_string( $attributes['orderBy'] ?? null ) || '' === $attributes['orderBy']) { + return null; } - $this->zaken_filter->orderBy( sprintf( '%s%s', $attributes['orderByDirection'], $attributes['orderBy'] ) ); + $reverse = ! is_string( $attributes['orderByDirection'] ?? null ) || '-' === $attributes['orderByDirection']; + + return array( $attributes['orderBy'], $reverse ); } /**