diff --git a/lib/Settings/portals/vo.json b/lib/Settings/portals/vo.json index 657d2e518..9c2f995d2 100644 --- a/lib/Settings/portals/vo.json +++ b/lib/Settings/portals/vo.json @@ -78,7 +78,180 @@ "access", "learniq:studentHourWeeks" ] - } + }, + "breadcrumb": "page" + }, + "publicIndex": { + "$comment": "What learniq hands the portal's public catalogue: the school's documents on the search page (board vaartveld/Zoeken). Read by PortalPublicIndex once it offers declared documents.", + "documents": [ + { + "id": "vv-doc-toetsrooster-tw1-4havo", + "type": "document", + "kind": "Toetsrooster", + "title": "Toetsrooster toetsweek 1, 4 havo", + "date": "2026-09-30", + "meta": [ + "4 havo" + ], + "summary": "Alle toetsen per dag, met tijd, lokaal en wat je mee moet nemen. PDF, 112 kB.", + "facets": { + "Soort": "Toetsroosters en PTA", + "Afdeling": "Havo", + "Leerjaar": "Klas 4" + } + }, + { + "id": "vv-doc-toetsrooster-tw1-5havo", + "type": "document", + "kind": "Toetsrooster", + "title": "Toetsrooster toetsweek 1, 5 havo", + "date": "2026-09-30", + "meta": [ + "5 havo" + ], + "summary": "Alle toetsen per dag, met tijd, lokaal en wat je mee moet nemen.", + "facets": { + "Soort": "Toetsroosters en PTA", + "Afdeling": "Havo", + "Leerjaar": "Klas 5" + } + }, + { + "id": "vv-doc-toetsrooster-tw1-4vwo", + "type": "document", + "kind": "Toetsrooster", + "title": "Toetsrooster toetsweek 1, 4 vwo", + "date": "2026-09-30", + "meta": [ + "4 vwo" + ], + "summary": "Alle toetsen per dag, met tijd, lokaal en wat je mee moet nemen.", + "facets": { + "Soort": "Toetsroosters en PTA", + "Afdeling": "Vwo", + "Leerjaar": "Klas 4" + } + }, + { + "id": "vv-doc-toetsrooster-tw1-5vwo", + "type": "document", + "kind": "Toetsrooster", + "title": "Toetsrooster toetsweek 1, 5 vwo", + "date": "2026-09-30", + "meta": [ + "5 vwo" + ], + "summary": "Alle toetsen per dag, met tijd, lokaal en wat je mee moet nemen.", + "facets": { + "Soort": "Toetsroosters en PTA", + "Afdeling": "Vwo", + "Leerjaar": "Klas 5" + } + }, + { + "id": "vv-doc-toetsrooster-tw1-6vwo", + "type": "document", + "kind": "Toetsrooster", + "title": "Toetsrooster toetsweek 1, 6 vwo", + "date": "2026-09-30", + "meta": [ + "6 vwo" + ], + "summary": "Alle toetsen per dag, met tijd, lokaal en wat je mee moet nemen.", + "facets": { + "Soort": "Toetsroosters en PTA", + "Afdeling": "Vwo", + "Leerjaar": "Klas 6" + } + }, + { + "id": "vv-doc-pta-4havo", + "type": "document", + "kind": "PTA", + "title": "Programma van toetsing en afsluiting 4 havo", + "date": "2026-09-14", + "meta": [ + "4 havo" + ], + "summary": "Welke toetsen meetellen voor het schoolexamen en hoe zwaar. PDF, 640 kB.", + "facets": { + "Soort": "Toetsroosters en PTA", + "Afdeling": "Havo", + "Leerjaar": "Klas 4" + } + }, + { + "id": "vv-doc-brief-tw1-herkansingen", + "type": "document", + "kind": "Brief aan ouders", + "title": "Toetsweek 1 en de herkansingen", + "date": "2026-09-28", + "meta": [ + "Klas 4, 5 en 6" + ], + "summary": "Wat de toetsweek voor uw kind betekent en hoe herkansen werkt.", + "facets": { + "Soort": "Brieven aan ouders" + } + }, + { + "id": "vv-doc-brief-tw1-examenklassen", + "type": "document", + "kind": "Brief aan ouders", + "title": "Toetsweek 1 in de examenklassen", + "date": "2026-09-28", + "meta": [ + "5 havo en 6 vwo" + ], + "summary": "Welke toetsen in toetsweek 1 meetellen voor het schoolexamen van uw kind.", + "facets": { + "Soort": "Brieven aan ouders" + } + }, + { + "id": "vv-doc-brief-mentorgesprekken", + "type": "document", + "kind": "Brief aan ouders", + "title": "De mentorgesprekken en toetsweek 1", + "date": "2026-10-05", + "meta": [ + "Klas 4" + ], + "summary": "Wanneer de mentorgesprekken zijn en hoe uw kind zich voorbereidt op toetsweek 1.", + "facets": { + "Soort": "Brieven aan ouders", + "Leerjaar": "Klas 4" + } + }, + { + "id": "vv-doc-regels-toetsweek", + "type": "document", + "kind": "Regels", + "title": "Regels tijdens een toetsweek", + "date": "2026-09-01", + "meta": [ + "Alle leerjaren" + ], + "summary": "Op tijd komen, ziek zijn op een toetsdag en wat er gebeurt bij te laat komen.", + "facets": { + "Soort": "Schoolgids en regels" + } + }, + { + "id": "vv-doc-schoolgids", + "type": "document", + "kind": "Schoolgids", + "title": "Schoolgids 2026-2027", + "date": "2026-09-01", + "meta": [ + "Alle leerjaren" + ], + "summary": "Hoe de school werkt: de lestijden, de toetsweken, verzuim en de regels.", + "facets": { + "Soort": "Schoolgids en regels" + } + } + ] }, "legacyTitles": [ "Studentenportaal Vaartveld" @@ -182,7 +355,7 @@ { "route": "/", "title": "Home", - "summary": "Vaartveld College, havo en vwo aan de vaart in Zuiddrecht.", + "summary": "Vaartveld College, vmbo-t, havo en vwo aan de vaart in Zuiddrecht.", "body": { "type": "grid", "widgets": [ @@ -211,15 +384,17 @@ "gridHeight": 4, "props": { "title": "Kijk ver vooruit.", - "subtitle": "Vaartveld College is de school voor havo en vwo aan de vaart in Zuiddrecht. Hier leer je kiezen, proberen en doorzetten.", + "subtitle": "Vaartveld College is de school voor vmbo-t, havo en vwo aan de vaart in Zuiddrecht. Hier leer je kiezen, proberen en doorzetten.", "actions": [ { "label": "Kom kennismaken", - "href": "/aanmelden" + "href": "/aanmelden", + "chevron": true }, { "label": "Lees wat er speelt op school", - "href": "/zoeken" + "href": "/zoeken", + "style": "link" } ], "variant": "plain" @@ -245,7 +420,7 @@ { "label": "Ziek melden en verlof", "href": "/praktisch/ziek-melden", - "icon": "alert" + "icon": "heartPlus" }, { "label": "Vakanties en vrije dagen", @@ -255,7 +430,7 @@ { "label": "Cijfers en huiswerk", "href": "/mijn", - "icon": "pencil" + "icon": "documentGrade" }, { "label": "Lestijden en pauzes", @@ -265,12 +440,12 @@ { "label": "Aanmelden voor klas 1", "href": "/aanmelden", - "icon": "personPlus" + "icon": "pencil" }, { "label": "Schoolgids en PTA", "href": "/zoeken", - "icon": "book" + "icon": "bookLines" }, { "label": "Contact met de school", @@ -280,11 +455,12 @@ { "label": "Boeken en schoolkosten", "href": "/praktisch", - "icon": "card" + "icon": "bookStack" } ], "moreLabel": "Alle praktische informatie", - "moreHref": "/praktisch" + "moreHref": "/praktisch", + "iconStyle": "plain" } }, { @@ -352,8 +528,7 @@ }, { "date": "2026-11-03", - "title": "Informatieavond profielkeuze, klas 3", - "href": "/nieuws" + "title": "Informatieavond profielkeuze, klas 3" }, { "date": "2026-11-09", @@ -376,6 +551,23 @@ "props": { "heading": "Ons onderwijs", "columns": [ + { + "title": "Vmbo-t", + "links": [ + { + "label": "De brugklas", + "href": "/onderwijs" + }, + { + "label": "Vakken en profielen", + "href": "/onderwijs" + }, + { + "label": "Examen en doorstromen naar mbo of havo", + "href": "/onderwijs" + } + ] + }, { "title": "Havo", "links": [ @@ -441,7 +633,7 @@ "gridX": 8, "gridY": 0, "gridWidth": 4, - "gridHeight": 16, + "gridHeight": 4, "props": { "heading": "Meer praktische zaken", "links": [ @@ -486,27 +678,18 @@ "props": { "kind": "info", "heading": "Melden duurt een minuut", - "text": "U logt in met DigiD. Liever bellen? Dat kan op schooldagen vanaf 07.45 uur via [telefoonnummer]." - } - }, - { - "id": "vv-ziek-04-nlbuttonlink", - "widgetKey": "nlButtonLink", - "gridX": 0, - "gridY": 4, - "gridWidth": 3, - "gridHeight": 1, - "props": { - "label": "Ziek melden", - "href": "/mijn", - "kind": "primary" + "text": "U logt in met DigiD. Liever bellen? Dat kan op schooldagen vanaf 07.45 uur via [telefoonnummer].", + "action": { + "label": "Ziek melden", + "href": "/mijn" + } } }, { "id": "vv-ziek-05a-nlheading", "widgetKey": "nlHeading", "gridX": 0, - "gridY": 5, + "gridY": 4, "gridWidth": 8, "gridHeight": 1, "props": { @@ -518,7 +701,7 @@ "id": "vv-ziek-05-nltable", "widgetKey": "nlTable", "gridX": 0, - "gridY": 6, + "gridY": 5, "gridWidth": 8, "gridHeight": 4, "props": { @@ -551,18 +734,49 @@ ] ], "display": "boxed", - "captionVisible": false + "captionVisible": false, + "rowHeaders": true } }, { "id": "vv-ziek-06-markdown", "widgetKey": "markdown", "gridX": 0, - "gridY": 10, + "gridY": 9, "gridWidth": 8, "gridHeight": 6, "props": { - "markdown": "## Ziek op de dag van een toets\n\nMeld uw kind ziek voordat de toets begint. Dan mag uw kind de toets inhalen. De docent spreekt daarvoor een moment af. Zonder melding telt de toets als gemist.\n\n## Afwezig zonder melding\n\nStaat uw kind afwezig en hebben wij geen melding? Dan krijgt u dezelfde dag een bericht in Mijn Vaartveld. De mentor neemt contact op als het vaker gebeurt. Bij 16 uur afwezigheid zonder geldige reden in vier weken moet de school dit melden bij de leerplichtambtenaar van de gemeente Zuiddrecht.\n\n## 18 jaar of ouder?\n\nDan meld je jezelf ziek, met je schoolaccount in Mijn Vaartveld.\n\n## Is uw kind lang ziek?\n\nDan denkt de zorgcoördinator, Anouk Visser, met u mee over schoolwerk en terugkomen." + "markdown": "## Ziek op de dag van een toets\n\nMeld uw kind ziek voordat de toets begint. Dan mag uw kind de toets inhalen. De docent spreekt daarvoor een moment af. Zonder melding telt de toets als gemist.\n\n## Afwezig zonder melding\n\nStaat uw kind afwezig en hebben wij geen melding? Dan krijgt u dezelfde dag een bericht in Mijn Vaartveld. De mentor neemt contact op als het vaker gebeurt. Bij 16 uur afwezigheid zonder geldige reden in vier weken moet de school dit melden bij de leerplichtambtenaar van de gemeente Zuiddrecht." + } + }, + { + "id": "vv-ziek-08-nlalert", + "widgetKey": "nlAlert", + "gridX": 8, + "gridY": 4, + "gridWidth": 4, + "gridHeight": 2, + "props": { + "kind": "plain", + "heading": "18 jaar of ouder?", + "text": "Dan meld je jezelf ziek, met je schoolaccount in Mijn Vaartveld." + } + }, + { + "id": "vv-ziek-09-nlalert", + "widgetKey": "nlAlert", + "gridX": 8, + "gridY": 6, + "gridWidth": 4, + "gridHeight": 3, + "props": { + "kind": "plain", + "heading": "Is uw kind lang ziek?", + "text": "Dan denkt de zorgcoördinator, Anouk Visser, met u mee over schoolwerk en terugkomen.", + "action": { + "label": "Contact met de zorgcoördinator", + "href": "/contact" + } } } ] @@ -581,40 +795,68 @@ "gridX": 0, "gridY": 0, "gridWidth": 8, - "gridHeight": 8, + "gridHeight": 10, "props": { - "backLabel": "Terug naar het nieuws" + "backLabel": "Terug naar het nieuws", + "kindLabel": "Nieuws", + "sectionHref": "/zoeken", + "sectionLabel": "Nieuws en documenten" } }, { - "id": "vv-nieuws-02-nlnewslist", - "widgetKey": "nlNewsList", + "id": "vv-nieuws-03-nlsignin", + "widgetKey": "nlSignIn", "gridX": 8, "gridY": 0, "gridWidth": 4, - "gridHeight": 8, + "gridHeight": 3, "props": { - "heading": "Meer nieuws", - "limit": 3, - "featured": false, - "display": "compact", - "articleRoute": "/nieuws" + "heading": "Kom je ook?", + "display": "card", + "intro": "Meld je aan met je ouders, dan weten wij hoeveel stoelen er nodig zijn.", + "buttonLabel": "Aanmelden voor de avond", + "note": "Je logt eerst in bij Mijn Vaartveld.", + "signInHref": "/mijn", + "tone": "light" } }, { - "id": "vv-nieuws-03-nlsignin", - "widgetKey": "nlSignIn", - "gridX": 0, - "gridY": 8, - "gridWidth": 12, + "id": "vv-nieuws-04-nllinklist", + "widgetKey": "nlLinkList", + "gridX": 8, + "gridY": 3, + "gridWidth": 4, "gridHeight": 3, "props": { - "heading": "Kom je ook?", + "heading": "Om alvast te lezen", "display": "card", - "intro": "Meld je aan met je ouders, dan weten wij hoeveel stoelen er nodig zijn. Je logt eerst in bij Mijn Vaartveld.", - "buttonLabel": "Aanmelden voor de avond", - "signInHref": "/mijn", - "tone": "plain" + "links": [ + { + "label": "Profielkeuzeboekje 2026-2027", + "href": "/onderwijs", + "description": "PDF, 1,2 MB" + }, + { + "label": "Vakken per profiel, havo en vwo", + "href": "/onderwijs", + "description": "PDF, 240 kB" + } + ] + } + }, + { + "id": "vv-nieuws-02-nlnewslist", + "widgetKey": "nlNewsList", + "gridX": 8, + "gridY": 6, + "gridWidth": 4, + "gridHeight": 4, + "props": { + "heading": "Meer nieuws", + "limit": 3, + "featured": false, + "display": "compact", + "articleRoute": "/nieuws" } } ] @@ -623,7 +865,7 @@ { "route": "/zoeken", "title": "Nieuws en documenten", - "summary": "Het nieuws, de toetsroosters, brieven aan ouders en de schoolgids.", + "summary": "Zoek in het nieuws van de school, de toetsroosters, brieven aan ouders, de schoolgids en de regels voor het examen.", "body": { "type": "grid", "widgets": [ @@ -647,7 +889,7 @@ "gridWidth": 12, "gridHeight": 1, "props": { - "text": "Het nieuws van de school, de toetsroosters, brieven aan ouders, de schoolgids en de regels voor het examen." + "text": "Zoek in het nieuws van de school, de toetsroosters, brieven aan ouders, de schoolgids en de regels voor het examen." } }, { @@ -660,12 +902,19 @@ "props": { "types": [ "news", - "event" + "document" ], "newsRoute": "/nieuws", "sort": "dateDesc", - "searchLabel": "Zoek in het nieuws en de agenda", - "placeholder": "Bijvoorbeeld toetsweek" + "pageSize": 6, + "searchLabel": "Zoek in het nieuws en de documenten", + "labelHidden": true, + "placeholder": "Bijvoorbeeld toetsweek", + "kindFacet": "Soort", + "facetDisplay": { + "Leerjaar": "select" + }, + "cardStyle": "kind" } } ] @@ -831,7 +1080,7 @@ { "route": "/onderwijs", "title": "Onderwijs", - "summary": "Havo en vwo, van de brugklas tot het examen. In klas 3 kies je een profiel.", + "summary": "Vmbo-t, havo en vwo, van de brugklas tot het examen. In klas 3 kies je een profiel.", "body": { "type": "grid", "widgets": [ @@ -855,7 +1104,7 @@ "gridWidth": 12, "gridHeight": 1, "props": { - "text": "Havo en vwo, van de brugklas tot het examen. In klas 3 kies je een profiel." + "text": "Vmbo-t, havo en vwo, van de brugklas tot het examen. In klas 3 kies je een profiel." } }, { @@ -1086,7 +1335,7 @@ "target": { "schoolRef": "ee020001-0000-4000-8000-000000000001" }, - "body": "In klas 3 kies je een profiel: de vakken waarin je examen doet. Op deze avond hoor je met je ouders hoe dat gaat en wat je met elk profiel kunt.\n\n- **Wanneer:** dinsdag 3 november 2026, 19.30 tot 21.00 uur\n- **Waar:** aula van Vaartveld College, Vaartlaan 40\n- **Voor wie:** leerlingen van 3 havo en 3 vwo en hun ouders\n- **Aanmelden:** tot en met vrijdag 30 oktober\n\nDe decaan legt uit wat een profiel is en wanneer je kiest. Daarna loop je langs de vier profielen. Je kiest niet op deze avond. In december en januari praat je met je mentor en de decaan. Je voorlopige keuze geef je door in februari. Een vraag? Mail de decaan, Marloes Peters, via [e-mailadres decaan].", + "body": "In klas 3 kies je een profiel: de vakken waarin je examen doet. Op deze avond hoor je met je ouders hoe dat gaat en wat je met elk profiel kunt.\n\n- **Wanneer:** Dinsdag 3 november 2026, 19.30 tot 21.00 uur\n- **Waar:** Aula van Vaartveld College, Vaartlaan 40\n- **Voor wie:** Leerlingen van 3 havo en 3 vwo en hun ouders\n- **Aanmelden:** Tot en met vrijdag 30 oktober\n\nDe decaan legt uit wat een profiel is en wanneer je kiest. Daarna loop je langs de vier profielen. Docenten en leerlingen uit klas 4 en 5 vertellen wat je er leert en wat je erna kunt gaan doen.\n\n## De vier profielen\n\n- Cultuur en maatschappij: talen, geschiedenis, kunst en maatschappij\n- Economie en maatschappij: economie, geschiedenis en wiskunde A\n- Natuur en gezondheid: biologie, scheikunde en wiskunde A of B\n- Natuur en techniek: wiskunde B, natuurkunde en scheikunde\n\nJe kiest niet op deze avond. In december en januari praat je met je mentor en de decaan. Je voorlopige keuze geef je door in februari. Een vraag? Mail de decaan, Marloes Peters, via [e-mailadres decaan].", "audienceLabel": "klas 3 havo en vwo" }, { @@ -1139,6 +1388,72 @@ "schoolRef": "ee020001-0000-4000-8000-000000000001" }, "body": "Een korte terugblik op de eerste schoolweek, met de belangrijkste data van dit jaar." + }, + { + "title": "Toetsweek 3: de laatste toetsweek van dit schooljaar", + "publishedAt": "2026-06-08T12:00:00+02:00", + "public": true, + "authorRef": "vo-teamleider-02", + "target": { + "schoolRef": "ee020001-0000-4000-8000-000000000001" + }, + "body": "Van maandag 15 tot en met vrijdag 19 juni is toetsweek 3. Je vindt je eigen rooster in Mijn Vaartveld.", + "audienceLabel": "klas 4 en 5" + }, + { + "title": "Na toetsweek 2: zo werkt herkansen", + "publishedAt": "2026-03-09T12:00:00+01:00", + "public": true, + "authorRef": "vo-teamleider-02", + "target": { + "schoolRef": "ee020001-0000-4000-8000-000000000001" + }, + "body": "Na toetsweek 2 mag je een toets herkansen. Je geeft in Mijn Vaartveld door welke toets je wilt herkansen.", + "audienceLabel": "klas 4, 5 en 6" + }, + { + "title": "Toetsweek 2: het rooster staat online", + "publishedAt": "2026-02-16T12:00:00+01:00", + "public": true, + "authorRef": "vo-teamleider-02", + "target": { + "schoolRef": "ee020001-0000-4000-8000-000000000001" + }, + "body": "De tweede toetsweek is van 2 tot en met 6 maart. Je vindt je eigen rooster in Mijn Vaartveld.", + "audienceLabel": "klas 4, 5 en 6" + }, + { + "title": "Na toetsweek 1: de cijfers staan in Mijn Vaartveld", + "publishedAt": "2025-11-24T12:00:00+01:00", + "public": true, + "authorRef": "vo-teamleider-02", + "target": { + "schoolRef": "ee020001-0000-4000-8000-000000000001" + }, + "body": "Alle cijfers van toetsweek 1 staan in Mijn Vaartveld. Je mentor bespreekt ze met je in het mentoruur.", + "audienceLabel": "klas 4, 5 en 6" + }, + { + "title": "Stilteplek in de bibliotheek tijdens de toetsweek", + "publishedAt": "2025-11-05T12:00:00+01:00", + "public": true, + "authorRef": "vo-teamleider-02", + "target": { + "schoolRef": "ee020001-0000-4000-8000-000000000001" + }, + "body": "In de toetsweek is de bibliotheek een stilteplek. Je kunt er tussen je toetsen door rustig leren.", + "audienceLabel": "klas 4, 5 en 6" + }, + { + "title": "Toetsweek 1: het rooster voor dit schooljaar", + "publishedAt": "2025-10-27T12:00:00+01:00", + "public": true, + "authorRef": "vo-teamleider-02", + "target": { + "schoolRef": "ee020001-0000-4000-8000-000000000001" + }, + "body": "De eerste toetsweek is van 10 tot en met 14 november. Je vindt je eigen rooster in Mijn Vaartveld.", + "audienceLabel": "klas 4, 5 en 6" } ], "accounts": [ diff --git a/openspec/changes/vaartveld-public-pages-follow-the-boards/proposal.md b/openspec/changes/vaartveld-public-pages-follow-the-boards/proposal.md new file mode 100644 index 000000000..cd1dcb57e --- /dev/null +++ b/openspec/changes/vaartveld-public-pages-follow-the-boards/proposal.md @@ -0,0 +1,36 @@ +--- +kind: spec +depends_on: [school-portals-match-their-boards, portal-public-index] +--- + +# Proposal: vaartveld-public-pages-follow-the-boards + +## Why + +Portal proof run 3 (9 October) put Vaartveld College's public pages beside their boards (school-design `vaartveld/preview` Home, Zoeken, Artikel, Contentpagina). Portaliq has since merged the options these boards need (`site-home-follows-the-school-boards`, `site-breadcrumb-follows-the-school-boards`, `site-catalogue-follows-the-school-boards`, `site-article-page-follows-the-board`, `site-callouts-steps-and-tables-follow-the-boards`). What is left sits in the vo declaration, `lib/Settings/portals/vo.json`: + +- Home: the hero says "havo en vwo" where the board says "vmbo-t, havo en vwo", and "Ons onderwijs" has no Vmbo-t column. The second hero action is a button, not a text link; "Kom kennismaken" has no chevron. The "Direct regelen" icons sit in tinted circles and three differ. The agenda's "Informatieavond" is a link. +- Zoeken: no filter column, a visible field label, an intro that differs, and one result for "toetsweek" where the board shows 18 (Nieuws 7, Toetsroosters en PTA 6, Brieven aan ouders 3, Schoolgids en regels 2). +- Artikel: no "Nieuws" pill, a breadcrumb "Nieuws > Nieuws", a full-width dark "Kom je ook?" band instead of a light card beside the article, no "Om alvast te lezen" card, a shorter body without "De vier profielen". +- Contentpagina: the "Ziek melden" button stands outside its callout, "18 jaar of ouder?" and "Is uw kind lang ziek?" are headings in the main column instead of cards beside it, and the table's first column is not bold. + +## What changes + +All in `lib/Settings/portals/vo.json`: + +- `portal.breadcrumb: "page"`: a crumb names a page by its own title ("Nieuws en documenten"). +- Home: the board's hero text; `actions` with `chevron` and `style: link`; `nlQuickTasks.iconStyle: plain` with the board's icons (heartPlus, documentGrade, pencil, bookLines, bookStack); agenda rows without links; "Ons onderwijs" in three columns, Vmbo-t first. The Onderwijs page names vmbo-t too. +- Zoeken: the board's intro; `nlCatalogue` with `kindFacet: "Soort"`, `labelHidden`, `pageSize: 6`, `facetDisplay: {Leerjaar: select}` and `types: [news, document]`. +- Six more public news items about the toetsweken of school year 2025-2026, all older than the home's six, so the home and its news list do not change. +- `publicIndex.documents`: the eleven school documents of the search board (five toetsroosters, the PTA 4 havo, three letters to parents, the toetsweek rules, the school guide) in portaliq's public index item shape, with the facets Soort, Afdeling and Leerjaar. +- Artikel: `kindLabel`, `sectionHref`, `sectionLabel` on `nlNewsArticle`; the right column holds the light "Kom je ook?" card (`tone: light`, `note`), the "Om alvast te lezen" card and "Meer nieuws". The Informatieavond body follows the board: capitalised facts, the paragraph about pupils of klas 4 and 5, "De vier profielen", the closing paragraph. +- Contentpagina: `action` "Ziek melden" inside the callout (the separate button goes); `rowHeaders` on the table; "18 jaar of ouder?" and "Is uw kind lang ziek?" as `nlAlert kind: plain` cards under the side list. + +## Not in this change + +- **The documents in the search results** need learniq's public index to read `publicIndex.documents` (shared `PortalPublicIndex`, lane FIX-L) and to move their dates with the load week. Until then the search shows the seven news items only. +- **`breadcrumb` on a fresh load** needs `breadcrumb` in `ExamplePortalProvisioner::FILLABLE` (lane FIX-L). +- "Toetsweek" finds 17 items, not 18: the PTA's board text does not contain the word, and this change does not alter board text to make a count fit. +- No document links: no file ships with the example set, so the cards have no chevron. "Om alvast te lezen" links to the Onderwijs page. +- Portaliq: "Is uw kind lang ziek?" draws its link as a button (`nlAlert.action`), the board as a text link; a photo place in an article; cards for "De vier profielen" (a plain list here); the facets "Afdeling" and "Periode" on news. +- An instance that loaded the set before keeps its pages and news: the provisioner never overwrites. Remove the portal's pages and load the set again. diff --git a/openspec/changes/vaartveld-public-pages-follow-the-boards/specs/example-sets/spec.md b/openspec/changes/vaartveld-public-pages-follow-the-boards/specs/example-sets/spec.md new file mode 100644 index 000000000..0dbacc5ba --- /dev/null +++ b/openspec/changes/vaartveld-public-pages-follow-the-boards/specs/example-sets/spec.md @@ -0,0 +1,23 @@ +## ADDED Requirements + +### Requirement: Vaartveld's public pages follow their boards + +The vo portal declaration MUST name a page in the breadcrumb by its own title (`breadcrumb: page`). Its home MUST say the school is for vmbo-t, havo and vwo, show "Ons onderwijs" in three columns (Vmbo-t, Havo, Vwo), draw the second hero action as a text link and the first with a chevron, draw the "Direct regelen" icons plain, and show the agenda rows without links. The search page "Nieuws en documenten" MUST filter by "Soort", hide the field's label, and declare the school's documents (toetsroosters, the PTA, letters to parents, rules and the school guide) as public index items with a kind, a date, a line of meta and the facets Soort, Afdeling and Leerjaar. The news article MUST carry the "Nieuws" pill and a crumb through "Nieuws en documenten", with the light "Kom je ook?" card, "Om alvast te lezen" and "Meer nieuws" beside it. The content page "Ziek melden en verlof" MUST put its "Ziek melden" button inside the callout, draw its table's first column as row headers, and show "18 jaar of ouder?" and "Is uw kind lang ziek?" as plain cards under the side list. + +#### Scenario: The home names vmbo-t and links its second action as text +- **GIVEN** the vo portal declaration +- **WHEN** portaliq renders the home +- **THEN** the hero reads "de school voor vmbo-t, havo en vwo", "Lees wat er speelt op school" is a text link, and "Ons onderwijs" opens with the column "Vmbo-t" +- @e2e tests/e2e/portal-design/vaartveld.spec.ts + +#### Scenario: The search page declares the board's documents +- **GIVEN** the vo portal declaration +- **WHEN** a reader looks at `publicIndex.documents` +- **THEN** it holds the toetsrooster of 4 havo, the PTA 4 havo, the letter "Toetsweek 1 en de herkansingen" and "Regels tijdens een toetsweek", each with a kind and the facet "Soort" +- @e2e exclude the documents reach the page only once learniq's public index reads them (FIX-L); covered by PHPUnit `VaartveldPublicPagesTest::testTheSearchPageFollowsTheBoard` + +#### Scenario: The content page holds its button inside the callout +- **GIVEN** the vo portal declaration +- **WHEN** portaliq renders "Ziek melden en verlof" +- **THEN** "Ziek melden" is the action of "Melden duurt een minuut" and the side column shows "18 jaar of ouder?" and "Is uw kind lang ziek?" under "Meer praktische zaken" +- @e2e tests/e2e/portal-design/vaartveld.spec.ts diff --git a/openspec/changes/vaartveld-public-pages-follow-the-boards/tasks.md b/openspec/changes/vaartveld-public-pages-follow-the-boards/tasks.md new file mode 100644 index 000000000..d8fbca1f6 --- /dev/null +++ b/openspec/changes/vaartveld-public-pages-follow-the-boards/tasks.md @@ -0,0 +1,13 @@ +# Tasks: vaartveld-public-pages-follow-the-boards + +- [x] **T1**: `portal.breadcrumb: page`; home hero text and actions, icons, agenda rows, Vmbo-t column, Onderwijs summary + - PHPUnit `VaartveldPublicPagesTest::testTheHomeFollowsTheBoard` +- [x] **T2**: Zoeken: intro, catalogue props, six toetsweek news items, `publicIndex.documents` + - PHPUnit `VaartveldPublicPagesTest::testTheSearchPageFollowsTheBoard` +- [x] **T3**: Artikel: pill, section crumb, light card, reading list, body in the board's order + - PHPUnit `VaartveldPublicPagesTest::testTheArticlePageFollowsTheBoard` +- [x] **T4**: Contentpagina: action in the callout, row headers, the two side cards + - PHPUnit `VaartveldPublicPagesTest::testTheContentPageFollowsTheBoard`, `ExamplePortalDeclarationsTest::testTheDeclarationsFollowTheBoards` +- [x] **T5**: e2e board texts in `tests/e2e/portal-design/vaartveld.spec.ts` +- [ ] **T6**: FIX-L: `PortalPublicIndex` reads `publicIndex.documents` (with the load week's offset); `breadcrumb` in `ExamplePortalProvisioner::FILLABLE` +- [ ] **T7**: live: the four public pages on the proof instance after a fresh site load diff --git a/tests/Unit/Portal/ExamplePortalDeclarationsTest.php b/tests/Unit/Portal/ExamplePortalDeclarationsTest.php index d661dfc04..a42f8d157 100644 --- a/tests/Unit/Portal/ExamplePortalDeclarationsTest.php +++ b/tests/Unit/Portal/ExamplePortalDeclarationsTest.php @@ -242,7 +242,9 @@ public function testTheDeclarationsFollowTheBoards(): void { self::assertSame('boxed', $table['props']['display'], $set); $side = array_values(array_filter($pages[$sideRoute]['body']['widgets'], static fn (array $w): bool => $w['gridX'] === 8)); - self::assertCount(1, $side, $set . ' ' . $sideRoute); + usort($side, static fn (array $a, array $b): int => $a['gridY'] <=> $b['gridY']); + // Cards may follow the list in the side column (vaartveld's "18 jaar of ouder?"). + self::assertNotEmpty($side, $set . ' ' . $sideRoute); self::assertSame(['nlLinkList', 0], [$side[0]['widgetKey'], $side[0]['gridY']], $set . ': the side list starts at the top'); foreach ($pages[$sideRoute]['body']['widgets'] as $widget) { if ($widget['gridX'] < 8) { diff --git a/tests/Unit/Portal/VaartveldPublicPagesTest.php b/tests/Unit/Portal/VaartveldPublicPagesTest.php new file mode 100644 index 000000000..d5a182d40 --- /dev/null +++ b/tests/Unit/Portal/VaartveldPublicPagesTest.php @@ -0,0 +1,179 @@ + + * @copyright 2026 Conduction B.V. + * @license EUPL-1.2 https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * SPDX-License-Identifier: EUPL-1.2 + * + * @version GIT: + * + * @link https://conduction.nl + * + * @spec openspec/changes/vaartveld-public-pages-follow-the-boards/specs/example-sets/spec.md#requirement-vaartvelds-public-pages-follow-their-boards + */ + +declare(strict_types=1); + +namespace OCA\Learniq\Tests\Unit\Portal; + +use OCA\Learniq\Portal\ExamplePortalDeclarations; +use PHPUnit\Framework\TestCase; + +/** + * Reads the real lib/Settings/portals/vo.json. + */ +class VaartveldPublicPagesTest extends TestCase { + + /** + * The vo declaration. + * + * @var array + */ + private array $declaration = []; + + /** + * Read the declaration. + * + * @return void + */ + protected function setUp(): void { + parent::setUp(); + $this->declaration = (new ExamplePortalDeclarations())->forSet(setId: 'vo'); + }//end setUp() + + /** + * The widgets of one page, by id. + * + * @param string $route The page route. + * + * @return array> + */ + private function widgets(string $route): array { + $pages = array_column($this->declaration['pages'], null, 'route'); + return array_column($pages[$route]['body']['widgets'], null, 'id'); + }//end widgets() + + /** + * Home: vmbo-t in the hero and in "Ons onderwijs", a text-link action, plain icons, agenda rows as words. + * + * @return void + * + * @spec openspec/changes/vaartveld-public-pages-follow-the-boards/specs/example-sets/spec.md#requirement-vaartvelds-public-pages-follow-their-boards + */ + public function testTheHomeFollowsTheBoard(): void { + self::assertSame('page', $this->declaration['portal']['breadcrumb']); + + $home = $this->widgets(route: '/'); + $hero = $home['vv-home-02-hero']['props']; + self::assertStringContainsString('de school voor vmbo-t, havo en vwo', $hero['subtitle']); + self::assertTrue($hero['actions'][0]['chevron']); + self::assertSame('link', $hero['actions'][1]['style']); + + $tasks = $home['vv-home-03-nlquicktasks']['props']; + self::assertSame('plain', $tasks['iconStyle']); + $icons = array_column($tasks['items'], 'icon', 'label'); + self::assertSame(['heartPlus', 'documentGrade', 'pencil', 'bookLines', 'bookStack'], [$icons['Ziek melden en verlof'], $icons['Cijfers en huiswerk'], $icons['Aanmelden voor klas 1'], $icons['Schoolgids en PTA'], $icons['Boeken en schoolkosten']]); + + foreach ($home['vv-home-06-nleventlist']['props']['items'] as $item) { + self::assertArrayNotHasKey('href', $item, $item['title'] . ' is not a link on the board'); + } + + self::assertSame(['Vmbo-t', 'Havo', 'Vwo'], array_column($home['vv-home-07-nllinkcolumns']['props']['columns'], 'title')); + }//end testTheHomeFollowsTheBoard() + + /** + * Zoeken: the kind filter, the hidden label, seven toetsweek news items and the board's documents. + * + * @return void + * + * @spec openspec/changes/vaartveld-public-pages-follow-the-boards/specs/example-sets/spec.md#requirement-vaartvelds-public-pages-follow-their-boards + */ + public function testTheSearchPageFollowsTheBoard(): void { + $catalogue = $this->widgets(route: '/zoeken')['vv-zoeken-03-nlcatalogue']['props']; + self::assertSame(['Soort', true, 'select'], [$catalogue['kindFacet'], $catalogue['labelHidden'], $catalogue['facetDisplay']['Leerjaar']]); + self::assertSame(['news', 'document'], $catalogue['types']); + + $toetsweek = array_filter($this->declaration['news'], static fn (array $n): bool => $n['public'] === true && stripos($n['title'], 'toetsweek') !== false); + self::assertCount(7, $toetsweek, 'Nieuws (7) on the board'); + + // The home shows the six newest; the added items are all older than those. + $dates = array_column($this->declaration['news'], 'publishedAt'); + rsort($dates); + $titles = array_column($this->declaration['news'], 'title', 'publishedAt'); + self::assertContains('Informatieavond profielkeuze op dinsdag 3 november', array_map(static fn (string $d): string => $titles[$d], array_slice($dates, 0, 6))); + self::assertNotContains('Stilteplek in de bibliotheek tijdens de toetsweek', array_map(static fn (string $d): string => $titles[$d], array_slice($dates, 0, 6))); + + $documents = array_column($this->declaration['publicIndex']['documents'], null, 'title'); + $soort = array_count_values(array_map(static fn (array $d): string => $d['facets']['Soort'], $documents)); + self::assertSame(['Toetsroosters en PTA' => 6, 'Brieven aan ouders' => 3, 'Schoolgids en regels' => 2], $soort); + self::assertSame(['Toetsrooster', ['4 havo'], 'Havo', 'Klas 4'], [$documents['Toetsrooster toetsweek 1, 4 havo']['kind'], $documents['Toetsrooster toetsweek 1, 4 havo']['meta'], $documents['Toetsrooster toetsweek 1, 4 havo']['facets']['Afdeling'], $documents['Toetsrooster toetsweek 1, 4 havo']['facets']['Leerjaar']]); + foreach (['Programma van toetsing en afsluiting 4 havo', 'Toetsweek 1 en de herkansingen', 'Regels tijdens een toetsweek'] as $title) { + self::assertArrayHasKey($title, $documents); + } + + foreach ($documents as $document) { + // portaliq PublicIndexItems: a machine type, a kind, a title, an id. + self::assertSame('document', $document['type']); + self::assertMatchesRegularExpression('/^vv-doc-[a-z0-9-]+$/', $document['id']); + self::assertMatchesRegularExpression('/^\d{4}-\d{2}-\d{2}$/', $document['date']); + self::assertArrayNotHasKey('href', $document, 'no file ships with the set'); + } + }//end testTheSearchPageFollowsTheBoard() + + /** + * Artikel: the pill, the crumb through "Nieuws en documenten", the light card and the reading list beside the article. + * + * @return void + * + * @spec openspec/changes/vaartveld-public-pages-follow-the-boards/specs/example-sets/spec.md#requirement-vaartvelds-public-pages-follow-their-boards + */ + public function testTheArticlePageFollowsTheBoard(): void { + $page = $this->widgets(route: '/nieuws'); + $article = $page['vv-nieuws-01-nlnewsarticle']['props']; + self::assertSame(['Nieuws', '/zoeken', 'Nieuws en documenten'], [$article['kindLabel'], $article['sectionHref'], $article['sectionLabel']]); + + $card = $page['vv-nieuws-03-nlsignin']; + self::assertSame([8, 0, 4, 'light'], [$card['gridX'], $card['gridY'], $card['gridWidth'], $card['props']['tone']]); + self::assertSame('Je logt eerst in bij Mijn Vaartveld.', $card['props']['note']); + self::assertSame(['Profielkeuzeboekje 2026-2027', 'Vakken per profiel, havo en vwo'], array_column($page['vv-nieuws-04-nllinklist']['props']['links'], 'label')); + self::assertSame(8, $page['vv-nieuws-02-nlnewslist']['gridX']); + + $news = array_column($this->declaration['news'], 'body', 'title'); + $body = $news['Informatieavond profielkeuze op dinsdag 3 november']; + self::assertStringContainsString('- **Wanneer:** Dinsdag 3 november 2026, 19.30 tot 21.00 uur', $body); + self::assertStringContainsString('## De vier profielen', $body); + self::assertLessThan(strpos($body, 'Je kiest niet op deze avond'), strpos($body, '## De vier profielen')); + }//end testTheArticlePageFollowsTheBoard() + + /** + * Contentpagina: the button inside the callout, bold first column, two plain cards under the side list. + * + * @return void + * + * @spec openspec/changes/vaartveld-public-pages-follow-the-boards/specs/example-sets/spec.md#requirement-vaartvelds-public-pages-follow-their-boards + */ + public function testTheContentPageFollowsTheBoard(): void { + $page = $this->widgets(route: '/praktisch/ziek-melden'); + self::assertSame(['label' => 'Ziek melden', 'href' => '/mijn'], $page['vv-ziek-03-nlalert']['props']['action']); + self::assertSame([], array_values(array_filter($page, static fn (array $w): bool => $w['widgetKey'] === 'nlButtonLink')), 'no button outside the callout'); + self::assertTrue($page['vv-ziek-05-nltable']['props']['rowHeaders']); + + $side = array_values(array_filter($page, static fn (array $w): bool => $w['gridX'] === 8)); + usort($side, static fn (array $a, array $b): int => $a['gridY'] <=> $b['gridY']); + self::assertSame(['nlLinkList', 'nlAlert', 'nlAlert'], array_column($side, 'widgetKey')); + self::assertSame(['18 jaar of ouder?', 'Is uw kind lang ziek?'], [$side[1]['props']['heading'], $side[2]['props']['heading']]); + self::assertSame(['plain', 'plain'], [$side[1]['props']['kind'], $side[2]['props']['kind']]); + self::assertStringNotContainsString('18 jaar of ouder', $page['vv-ziek-06-markdown']['props']['markdown']); + + // The side cards start below the side list, so nothing overlaps. + self::assertGreaterThanOrEqual($side[0]['gridY'] + $side[0]['gridHeight'], $side[1]['gridY']); + self::assertGreaterThanOrEqual($side[1]['gridY'] + $side[1]['gridHeight'], $side[2]['gridY']); + }//end testTheContentPageFollowsTheBoard() +}//end class diff --git a/tests/e2e/portal-design/vaartveld.spec.ts b/tests/e2e/portal-design/vaartveld.spec.ts index a76ad540a..563698dd2 100644 --- a/tests/e2e/portal-design/vaartveld.spec.ts +++ b/tests/e2e/portal-design/vaartveld.spec.ts @@ -54,6 +54,9 @@ test.describe('vaartveld: the website', () => { 'Van zaterdag 17 tot en met zondag 25 oktober is de school dicht.', ), 'Kijk ver vooruit.', + // vaartveld-public-pages-follow-the-boards: vmbo-t in the hero and in "Ons onderwijs". + 'de school voor vmbo-t, havo en vwo', + 'Vmbo-t', 'Direct regelen', 'Rooster en wijzigingen', 'Nieuws', @@ -94,6 +97,8 @@ test.describe('vaartveld: the website', () => { 'Wat meldt u hoe?', 'Ziek op de dag van een toets', 'Anouk Visser', + '18 jaar of ouder?', + 'Is uw kind lang ziek?', ...FOOTER, ]) await expectNoSeriousAxeFinding(page) @@ -117,6 +122,8 @@ test.describe('vaartveld: the website', () => { dated('Dinsdag 3 november 2026, 19.30 tot 21.00 uur'), 'Marloes Peters', 'Kom je ook?', + 'Om alvast te lezen', + 'De vier profielen', ]) await boardShot(page, PORTAL, 'Artikel', info) })