From 5c8accb8cf636e9920d18591ecc5d8898e28b0f1 Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Fri, 16 Aug 2024 13:06:47 +0300 Subject: [PATCH 01/23] VKT(Frontend): Improve front page legibility --- .../vkt/public/i18n/fi-FI/public.json | 29 +-- .../vkt/public/i18n/sv-SE/public.json | 25 ++- .../publicExamEvent/PublicExamEventGrid.tsx | 190 +++++++++++++----- .../src/styles/pages/_public-homepage.scss | 12 ++ 4 files changed, 179 insertions(+), 77 deletions(-) diff --git a/frontend/packages/vkt/public/i18n/fi-FI/public.json b/frontend/packages/vkt/public/i18n/fi-FI/public.json index 685789cde..97d3137f7 100644 --- a/frontend/packages/vkt/public/i18n/fi-FI/public.json +++ b/frontend/packages/vkt/public/i18n/fi-FI/public.json @@ -183,7 +183,7 @@ "title": "Vahvista asiakirjan poisto" }, "helpText1": "Voit todistaa täyttäväsi perusteen maksuttomaan tutkintoon todistusasiakirjoilla. Opetushallituksen virkailija tarkastaa, täyttävätkö lähettämäsi asiakirjat maksuttomuuden ehdot. ", - "helpText2": "Voit lisätä enimmillään 10 asiakirjaa. Asiakirja voi olla hyvälaatuinen pdf- tai kuvatiedosto. Liitä kopio alkuperäisestä tutkintotodistuksesta tai korkeakoulun opiskeluoikeudesta todistavasta asiakirjasta. Liitä asiakirjasta myös käännös suomeksi, ruotsiksi tai englanniksi, jos alkuperäisen asiakirjan kieli on muu kuin suomi, ruotsi tai englanti. Nimeä liite selvästi (esim. tutkintotodistus Bachelor.pdf, tutkintotodistus kaannos.pdf, opiskeluoikeus.pdf)", + "helpText2": "Voit lisätä enimmillään 10 asiakirjaa. Asiakirja voi olla hyvälaatuinen PDF- tai kuvatiedosto. Liitä kopio alkuperäisestä tutkintotodistuksesta tai korkeakoulun opiskeluoikeudesta todistavasta asiakirjasta. Liitä asiakirjasta myös käännös suomeksi, ruotsiksi tai englanniksi, jos alkuperäisen asiakirjan kieli on muu kuin suomi, ruotsi tai englanti. Nimeä liite selvästi (esim. tutkintotodistus Bachelor.pdf, tutkintotodistus kaannos.pdf, opiskeluoikeus.pdf)", "maxAttachmentsReached": "Olet lisännyt jo 10 asiakirjaa. Et voi enää lisätä uusia asiakirjoja.", "title": "Lähetä tutkintotodistus tai opiskelutodistus *", "uploadFile": "Lähetä tiedosto" @@ -234,24 +234,25 @@ "publicExamEventGrid": { "description": { "bulletPoints": { - "point1": "suullisen taidon tutkinto (= puhumisen ja puheen ymmärtämisen osakokeet)", - "point2": "kirjallisen taidon tutkinto (= kirjoittamisen ja tekstin ymmärtämisen osakokeet)", - "point3": "ymmärtämisen taidon tutkinto (= tekstin ymmärtämisen ja puheen ymmärtämisen osakokeet)" + "point1": "<0>suullisen taidon tutkinto (= puhumisen ja puheen ymmärtämisen osakokeet)", + "point2": "<0>kirjallisen taidon tutkinto (= kirjoittamisen ja tekstin ymmärtämisen osakokeet)", + "point3": "<0>ymmärtämisen taidon tutkinto (= tekstin ymmärtämisen ja puheen ymmärtämisen osakokeet)" }, - "line1": "Valtionhallinnon kielitutkinnot (VKT) on tarkoitettu julkishallinnon henkilöstön toisen kotimaisen kielen hallinnan osoittamiseen. Tutkinnoilla osoitetaan suomen tai ruotsin kielen suullinen, kirjallinen ja ymmärtämisen taito.", - "line2": "Valtionhallinnon erinomaisen taidon kielitutkintoja ovat" + + "skills": "Valtionhallinnon erinomaisen taidon kielitutkintoja ovat", + "title": "Yleistä valtionhallinnon kielitutkinnoista" }, "enrollment": { "link": { "label": "Opetushallituksen verkkosivulla.", "url": "https://www.oph.fi/fi/koulutus-ja-tutkinnot/erinomaisen-taidon-tutkinnot" }, - "part1": "Ilmoittautumista varten sinun täytyy tunnistautua suomi.fi-palvelun kautta.", + "part1": "<0>Ilmoittautumista varten sinun täytyy tunnistautua suomi.fi-palvelun kautta.", "part2": "Tunnistautumisen jälkeen järjestelmä tarkastaa maksuttomuuden ehdot täyttävät koulutustiedot KOSKI-tietovarannosta.", - "part3": "Jos ehdot täyttäviä koulutustietoja ei löydy, mutta olet oikeutettu maksuttomaan tutkintoon, voit liittää ilmoittautumislomakkeelle todistusasiakirjoja.", + "part3": "Jos ehdot täyttäviä koulutustietoja ei löydy, mutta olet oikeutettu maksuttomaan tutkintoon, <0>voit liittää ilmoittautumislomakkeelle todistusasiakirjoja.", "part4": "Opetushallituksen virkailija tarkastaa asiakirjat.", "part5": "Lisätietoa", - "title": "Ilmoittautuminen ja maksuttomuuden ehtojen tarkistus" + "title": "Ilmoittautuminen ja maksuttomuuden ehtojen tarkastus" }, "freeExamination": { "conditions": { @@ -259,16 +260,20 @@ "label": "Opetushallituksen verkkosivuilla.", "url": "https://www.oph.fi/fi/koulutus-ja-tutkinnot/erinomaisen-taidon-tutkinnot" }, - "part1": "Valtionhallinnon kielitutkintojen erinomaisen taidon tutkinnot ovat maksuttomia tietyin ehdoin 1.8.2024 alkaen. Maksuttomuuden ehdoista löytyy lisätietoa", - "part2": "Maksuttomaan ilmoittaumiseen oikeutettu henkilö saa ilmoittautua tutkintoon maksutta kolme kertaa. Koska tutkinnon voi suorittaa osissa, maksuttomaan tutkintoon oikeutettu henkilö voi ilmoittautua kolme kertaa maksutta sekä suullisen että kirjallisen taidon tutkintoon." + "part1": "Valtionhallinnon kielitutkintojen <0>erinomaisen taidon tutkinnot ovat maksuttomia tietyin ehdoin 1.8.2024 alkaen. Maksuttomuuden ehdoista löytyy lisätietoa", + "part2": "<0>Maksuttomaan ilmoittaumiseen oikeutettu henkilö saa ilmoittautua tutkintoon maksutta kolme kertaa. Koska tutkinnon voi suorittaa osissa, maksuttomaan tutkintoon oikeutettu henkilö voi ilmoittautua kolme kertaa maksutta sekä suullisen että kirjallisen taidon tutkintoon." }, "ineligibility": { - "description": "Henkilöt, jotka eivät ole oikeutettuja maksuttomaan tutkintoon, maksavat ilmoittautumisen yhteydessä tutkintomaksun.", + "description": "<0>Henkilöt, jotka eivät ole oikeutettuja maksuttomaan tutkintoon, maksavat ilmoittautumisen yhteydessä tutkintomaksun:", "fullExaminationPayment": "Tutkintomaksu on 514 euroa, jos suoritat suullisen ja kirjallisen taidon tutkinnot samalla kertaa.", "partialExaminationPayment": "Tutkintomaksu on 257 euroa, jos suoritat joko suullisen taidon tutkinnon, kirjallisen taidon tutkinnon tai yksittäisen osakokeen." }, "title": "Tutkinnon maksuttomuus" }, + "introduction": { + "line1": "Valtionhallinnon kielitutkinnot (VKT) on tarkoitettu julkishallinnon henkilöstön toisen kotimaisen kielen hallinnan osoittamiseen.", + "line2": "Tutkinnoilla osoitetaan suomen tai ruotsin kielen suullinen, kirjallinen ja ymmärtämisen taito." + }, "title": "Valtionhallinnon kielitutkinnot (VKT) – ilmoittautuminen erinomaisen taidon tutkintoihin" }, "publicExamEventListing": { diff --git a/frontend/packages/vkt/public/i18n/sv-SE/public.json b/frontend/packages/vkt/public/i18n/sv-SE/public.json index f2d96cd78..d57c9474a 100644 --- a/frontend/packages/vkt/public/i18n/sv-SE/public.json +++ b/frontend/packages/vkt/public/i18n/sv-SE/public.json @@ -183,7 +183,7 @@ "title": "Bekräfta radering av dokumentet" }, "helpText1": "Med intyg kan du bevisa att du har rätt till en avgiftsfri examen. Dina dokument granskas på Utbildningsstyrelsen.", - "helpText2": "Du kan bifoga högst tio dokument. Dokumenten kan vara pdf- eller bildfiler av god kvalitet. Bifoga en kopia av det ursprungliga examensintyget eller studieintyget. Bifoga även en översättning av dokumentet till finska, svenska eller engelska ifall det ursprungliga dokumentet är på något annat språk. Namnge bilagorna tydligt (t.ex. examensintyg.pdf, studieintyg.jpg, oversattning_examensintyg.pdf).", + "helpText2": "Du kan bifoga högst tio dokument. Dokumenten kan vara PDF- eller bildfiler av god kvalitet. Bifoga en kopia av det ursprungliga examensintyget eller studieintyget. Bifoga även en översättning av dokumentet till finska, svenska eller engelska ifall det ursprungliga dokumentet är på något annat språk. Namnge bilagorna tydligt (t.ex. examensintyg.pdf, studieintyg.jpg, oversattning_examensintyg.pdf).", "maxAttachmentsReached": "Du har redan bifogat tio dokument. Du kan inte lägga till fler dokument.", "title": "Skicka examensintyg eller studieintyg *", "uploadFile": "Skicka filen" @@ -234,21 +234,24 @@ "publicExamEventGrid": { "description": { "bulletPoints": { - "point1": "examen som gäller förmåga att använda finska eller svenska i tal (med delproven hörförståelse och muntlig färdighet)", - "point2": "examen som gäller förmåga att använda finska eller svenska i skrift (med delproven läsförståelse och skriftlig färdighet)", - "point3": "examen som gäller förmåga att förstå finska eller svenska (med delproven hörförståelse och läsförståelse)" + "point1": "<0>examen som gäller förmåga att använda finska eller svenska i tal (med delproven hörförståelse och muntlig färdighet)", + "point2": "<0>examen som gäller förmåga att använda finska eller svenska i skrift (med delproven läsförståelse och skriftlig färdighet)", + "point3": "<0>examen som gäller förmåga att förstå finska eller svenska (med delproven hörförståelse och läsförståelse)" }, - "line1": "Språkexamina för statsförvaltningen är avsedda för att visa sådana språkkunskaper i det andra inhemska språket som krävs av offentligt anställda. Med examensintygen kan man visa förmåga att använda finska eller svenska i tal och i skrift samt förmåga att förstå språket.", - "line2": "Examina som gäller utmärkta språkkunskaper är" + "introduction": { + "line1": "Språkexamina för statsförvaltningen är avsedda för att visa sådana språkkunskaper i det andra inhemska språket som krävs av offentligt anställda.", + "line2": "Med examensintygen kan man visa förmåga att använda finska eller svenska i tal och i skrift samt förmåga att förstå språket." + }, + "skills": "Examina som gäller utmärkta språkkunskaper är" }, "enrollment": { "link": { "label": "på Utbildningsstyrelsens webbplats.", "url": "https://www.oph.fi/sv/utbildning-och-examina/examina-som-galler-utmarkta-sprakkunskaper" }, - "part1": "För att anmäla dig till examen ska du identifiera dig via tjänsten Suomi.fi.", + "part1": "<0>För att anmäla dig till examen ska du identifiera dig via tjänsten Suomi.fi.", "part2": "Efter detta kontrollerar systemet i informationsresursen KOSKI om du har rätt till avgiftsfri examen.", - "part3": "Om uppgifter om din utbildning inte hittas och du har rätt till avgiftsfri examen, kan du bifoga intyg till din anmälan.", + "part3": "Om uppgifter om din utbildning inte hittas och du har rätt till avgiftsfri examen, <0>kan du bifoga intyg till din anmälan.", "part4": "Dina dokument granskas vid Utbildningsstyrelsen.", "part5": "Mer information", "title": "Anmälan och kontroll av rätten till avgiftsfri examen" @@ -259,11 +262,11 @@ "label": "på Utbildningsstyrelsens webbplats.", "url": "https://www.oph.fi/sv/utbildning-och-examina/examina-som-galler-utmarkta-sprakkunskaper" }, - "part1": "Språkexamina för statsförvaltningen som gäller utmärkta språkkunskaper är avgiftsfria med vissa villkor från och med 1 augusti 2024. Mer information om villkoren för avgiftsfri examen", - "part2": "Den som har rätt till avgiftsfri examen kan anmäla sig till examen avgiftsfritt tre gånger. Eftersom examen kan avläggas i delar, kan den som har rätt till avgiftsfri examen anmäla sig avgiftsfritt tre gånger både till examen som gäller förmåga att använda språket i tal och till examen som gäller förmåga att använda språket i skrift." + "part1": "Språkexamina för statsförvaltningen som gäller utmärkta språkkunskaper är <0>avgiftsfria med vissa villkor från och med 1 augusti 2024. Mer information om villkoren för avgiftsfri examen", + "part2": "<0>Den som har rätt till avgiftsfri examen kan anmäla sig till examen avgiftsfritt tre gånger. Eftersom examen kan avläggas i delar, kan den som har rätt till avgiftsfri examen anmäla sig avgiftsfritt tre gånger både till examen som gäller förmåga att använda språket i tal och till examen som gäller förmåga att använda språket i skrift." }, "ineligibility": { - "description": "Den som inte har rätt till avgiftsfri examen, ska i samband med anmälning betala även examensavgiften.", + "description": "<0>Den som inte har rätt till avgiftsfri examen, ska i samband med anmälning betala även examensavgiften:", "fullExaminationPayment": "Examensavgiften är 514 euro om muntlig och skriftlig examen avläggs samtidigt.", "partialExaminationPayment": "Examensavgiften är 257 euro om du avlägger antingen examen som gäller förmåga att använda språket i tal eller examen som gäller förmåga att använda språket i skrift eller ett av delproven." }, diff --git a/frontend/packages/vkt/src/components/publicExamEvent/PublicExamEventGrid.tsx b/frontend/packages/vkt/src/components/publicExamEvent/PublicExamEventGrid.tsx index 3043c2524..6b7e29db6 100644 --- a/frontend/packages/vkt/src/components/publicExamEvent/PublicExamEventGrid.tsx +++ b/frontend/packages/vkt/src/components/publicExamEvent/PublicExamEventGrid.tsx @@ -1,7 +1,11 @@ import OpenInNewIcon from '@mui/icons-material/OpenInNew'; -import { Grid, Typography } from '@mui/material'; +import { Container, Grid, Typography } from '@mui/material'; +import { TFunction } from 'i18next'; import { useEffect } from 'react'; +import { Trans } from 'react-i18next'; import { H1, H2, HeaderSeparator, Text, WebLink } from 'shared/components'; +import { I18nNamespace } from 'shared/enums'; +import { useWindowProperties } from 'shared/hooks'; import { PublicExamEventListing } from 'components/publicExamEvent/listing/PublicExamEventListing'; import { useCommonTranslation, usePublicTranslation } from 'configs/i18n'; @@ -10,25 +14,142 @@ import { resetPublicEnrollment } from 'redux/reducers/publicEnrollment'; import { loadPublicExamEvents } from 'redux/reducers/publicExamEvent'; import { publicExamEventsSelector } from 'redux/selectors/publicExamEvent'; -const BulletList = ({ points }: { points: Array }) => { +const BoldedTranslationString = ({ + i18nKey, + t, +}: { + i18nKey: string; + t: TFunction; +}) => { + return ]} />; +}; + +const BulletList = ({ + keyPrefix, + points, +}: { + keyPrefix: string; + points: Array; +}) => { + const { t } = usePublicTranslation({ + keyPrefix, + }); + return ( {points.map((point, i) => ( -
  • {point}
  • +
  • + +
  • ))}
    ); }; +const DescriptionBox = () => { + const { t } = usePublicTranslation({ + keyPrefix: 'vkt.component.publicExamEventGrid.description', + }); + const translateCommon = useCommonTranslation(); + + return ( + +
    +

    {t('title')}

    +
    + {t('skills')} + +
    + + {translateCommon('info.selectExam')} + {translateCommon('info.previousEnrollment')} +
    +
    + ); +}; + +const FreeExaminationBox = () => { + const { t } = usePublicTranslation({ + keyPrefix: 'vkt.component.publicExamEventGrid.freeExamination', + }); + + return ( + +
    +

    {t('title')}

    + + {' '} + } + /> + + + + +
    + + {' '} + + +
    +
    +
    + ); +}; + +const EnrollmentBox = () => { + const { t } = usePublicTranslation({ + keyPrefix: 'vkt.component.publicExamEventGrid.enrollment', + }); + + return ( + +
    +

    {t('title')}

    + + +
    + {t('part2')} +
    + + +
    + {t('part4')} +
    + + {t('part5')}{' '} + } + /> + +
    +
    + ); +}; + export const PublicExamEventGrid = () => { const { t } = usePublicTranslation({ keyPrefix: 'vkt.component.publicExamEventGrid', }); - const translateCommon = useCommonTranslation(); const dispatch = useAppDispatch(); const { status } = useAppSelector(publicExamEventsSelector); + const { isPhone } = useWindowProperties(); + useEffect(() => { dispatch(resetPublicEnrollment()); dispatch(loadPublicExamEvents()); @@ -40,59 +161,20 @@ export const PublicExamEventGrid = () => {

    {t('title')}

    - {t('description.line1')} -
    - {t('description.line2')} - -
    - {translateCommon('info.selectExam')} - {translateCommon('info.previousEnrollment')} -
    -
    -

    {t('freeExamination.title')}

    - - {t('freeExamination.conditions.part1')}{' '} - } - /> - - {t('freeExamination.conditions.part2')} - - {t('freeExamination.ineligibility.description')} -
    - {t('freeExamination.ineligibility.fullExaminationPayment')} -
    - {t('freeExamination.ineligibility.partialExaminationPayment')} -
    -
    -
    -

    {t('enrollment.title')}

    - {t('enrollment.part1')} + {t('introduction.line1')}
    - {t('enrollment.part2')} -
    - - {t('enrollment.part3')} -
    - {t('enrollment.part4')} -
    - - {t('enrollment.part5')}{' '} - } - /> + {t('introduction.line2')} +
    + + + +
    diff --git a/frontend/packages/vkt/src/styles/pages/_public-homepage.scss b/frontend/packages/vkt/src/styles/pages/_public-homepage.scss index 81802a5f4..d8ffb2002 100644 --- a/frontend/packages/vkt/src/styles/pages/_public-homepage.scss +++ b/frontend/packages/vkt/src/styles/pages/_public-homepage.scss @@ -22,4 +22,16 @@ } } } + + & &__info-box { + background-color: $color-blue-200; + + @include phone { + padding: 2rem 1rem; + } + + @include not-phone { + padding: 3rem 1rem; + } + } } From a3b4f41b06b44cd52a89aa8c3fd6cd3c929cc6ae Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Fri, 16 Aug 2024 14:03:36 +0300 Subject: [PATCH 02/23] VKT(Frontend): Drop pagination from exam listing table --- .../listing/PublicExamEventListing.tsx | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/frontend/packages/vkt/src/components/publicExamEvent/listing/PublicExamEventListing.tsx b/frontend/packages/vkt/src/components/publicExamEvent/listing/PublicExamEventListing.tsx index 77da40b70..26fd19995 100644 --- a/frontend/packages/vkt/src/components/publicExamEvent/listing/PublicExamEventListing.tsx +++ b/frontend/packages/vkt/src/components/publicExamEvent/listing/PublicExamEventListing.tsx @@ -1,7 +1,7 @@ import { SelectChangeEvent } from '@mui/material'; import { Box } from '@mui/system'; import { useEffect, useRef } from 'react'; -import { CustomCircularProgress, H2, PaginatedTable } from 'shared/components'; +import { CustomCircularProgress, CustomTable, H2 } from 'shared/components'; import { APIResponseStatus, Color } from 'shared/enums'; import { useWindowProperties } from 'shared/hooks'; @@ -81,21 +81,15 @@ export const PublicExamEventListing = ({

    {t('title')}

    - - } + + } getRowDetails={getRowDetails} - initialRowsPerPage={20} - rowsPerPageOptions={[20, 50]} - rowsPerPageLabel={translateCommon('rowsPerPageLabel')} - stickyHeader + header={} /> ); From e2dc7d7f53f07a6e8d5c8a05a7c27290025ef3e6 Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Fri, 16 Aug 2024 14:43:30 +0300 Subject: [PATCH 03/23] VKT(Frontend): File upload instructions as a bullet point list [deploy] --- .../packages/vkt/public/i18n/fi-FI/public.json | 12 ++++++++++-- .../packages/vkt/public/i18n/sv-SE/public.json | 11 +++++++++-- .../publicEnrollment/steps/EducationDetails.tsx | 15 +++++++++++++-- .../integration/mobile_public_home_page.spec.ts | 2 +- .../cypress/integration/public_home_page.spec.ts | 2 +- .../support/page-objects/publicHomePage.ts | 6 ++---- 6 files changed, 36 insertions(+), 12 deletions(-) diff --git a/frontend/packages/vkt/public/i18n/fi-FI/public.json b/frontend/packages/vkt/public/i18n/fi-FI/public.json index 97d3137f7..2b6dd6ade 100644 --- a/frontend/packages/vkt/public/i18n/fi-FI/public.json +++ b/frontend/packages/vkt/public/i18n/fi-FI/public.json @@ -182,8 +182,16 @@ "description": "Haluatko varmasti poistaa lisäämäsi asiakirjan <0>{{fileName}}?", "title": "Vahvista asiakirjan poisto" }, - "helpText1": "Voit todistaa täyttäväsi perusteen maksuttomaan tutkintoon todistusasiakirjoilla. Opetushallituksen virkailija tarkastaa, täyttävätkö lähettämäsi asiakirjat maksuttomuuden ehdot. ", - "helpText2": "Voit lisätä enimmillään 10 asiakirjaa. Asiakirja voi olla hyvälaatuinen PDF- tai kuvatiedosto. Liitä kopio alkuperäisestä tutkintotodistuksesta tai korkeakoulun opiskeluoikeudesta todistavasta asiakirjasta. Liitä asiakirjasta myös käännös suomeksi, ruotsiksi tai englanniksi, jos alkuperäisen asiakirjan kieli on muu kuin suomi, ruotsi tai englanti. Nimeä liite selvästi (esim. tutkintotodistus Bachelor.pdf, tutkintotodistus kaannos.pdf, opiskeluoikeus.pdf)", + "instructions": { + "part1": "Voit lisätä enimmillään 10 asiakirjaa.", + "part2": "Asiakirja voi olla hyvälaatuinen PDF- tai kuvatiedosto.", + "part3": "Liitä kopio alkuperäisestä tutkintotodistuksesta tai korkeakoulun opiskeluoikeudesta todistavasta asiakirjasta.", + "part4": "Liitä asiakirjasta myös käännös suomeksi, ruotsiksi tai englanniksi, jos alkuperäisen asiakirjan kieli on muu kuin suomi, ruotsi tai englanti.", + "part5": "Nimeä liite selvästi (esim. tutkintotodistus Bachelor.pdf, tutkintotodistus kaannos.pdf, opiskeluoikeus.pdf).", + "title": "Ohjeita tiedoston lähettämiseksi:" + }, + "helpText1": "Voit todistaa täyttäväsi perusteen maksuttomaan tutkintoon todistusasiakirjoilla.", + "helpText2": "Opetushallituksen virkailija tarkastaa, täyttävätkö lähettämäsi asiakirjat maksuttomuuden ehdot.", "maxAttachmentsReached": "Olet lisännyt jo 10 asiakirjaa. Et voi enää lisätä uusia asiakirjoja.", "title": "Lähetä tutkintotodistus tai opiskelutodistus *", "uploadFile": "Lähetä tiedosto" diff --git a/frontend/packages/vkt/public/i18n/sv-SE/public.json b/frontend/packages/vkt/public/i18n/sv-SE/public.json index d57c9474a..8e47b1ae2 100644 --- a/frontend/packages/vkt/public/i18n/sv-SE/public.json +++ b/frontend/packages/vkt/public/i18n/sv-SE/public.json @@ -182,8 +182,15 @@ "description": "Är du säker på att du vill radera dokumentet <0>{{fileName}} som du har bifogat?", "title": "Bekräfta radering av dokumentet" }, - "helpText1": "Med intyg kan du bevisa att du har rätt till en avgiftsfri examen. Dina dokument granskas på Utbildningsstyrelsen.", - "helpText2": "Du kan bifoga högst tio dokument. Dokumenten kan vara PDF- eller bildfiler av god kvalitet. Bifoga en kopia av det ursprungliga examensintyget eller studieintyget. Bifoga även en översättning av dokumentet till finska, svenska eller engelska ifall det ursprungliga dokumentet är på något annat språk. Namnge bilagorna tydligt (t.ex. examensintyg.pdf, studieintyg.jpg, oversattning_examensintyg.pdf).", + "instructions": { + "part1": "Du kan bifoga högst tio dokument.", + "part2": "Dokumenten kan vara PDF- eller bildfiler av god kvalitet.", + "part3": "Bifoga en kopia av det ursprungliga examensintyget eller studieintyget.", + "part4": "Bifoga även en översättning av dokumentet till finska, svenska eller engelska ifall det ursprungliga dokumentet är på något annat språk.", + "part5": "Namnge bilagorna tydligt (t.ex. examensintyg.pdf, studieintyg.jpg, oversattning_examensintyg.pdf)." + }, + "helpText1": "Med intyg kan du bevisa att du har rätt till en avgiftsfri examen.", + "helpText2": "Dina dokument granskas på Utbildningsstyrelsen.", "maxAttachmentsReached": "Du har redan bifogat tio dokument. Du kan inte lägga till fler dokument.", "title": "Skicka examensintyg eller studieintyg *", "uploadFile": "Skicka filen" diff --git a/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx b/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx index b8f836150..8f5fce8ed 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx @@ -166,8 +166,19 @@ const UploadAttachments = ({ return ( <>

    {t('title')}

    - {t('helpText1')} - {t('helpText2')} + + {t('helpText1')} +
    + {t('helpText2')} +
    + + {t('instructions.title')} +
      + {[1, 2, 3, 4, 5].map((i) => ( +
    • {t('instructions.part' + i)}
    • + ))} +
    +
    {attachmentsCount < 10 && ( { cy.openPublicHomePage(); }); - it('should show the filtered amount of exam events in table pagination', () => { + it('should allow filtering exam events based on exam language', () => { onPublicHomePage.expectFilteredExamEventsCount(publicExamEvents11.length); onPublicHomePage.filterByLanguage(ExamLanguage.FI); diff --git a/frontend/packages/vkt/src/tests/cypress/integration/public_home_page.spec.ts b/frontend/packages/vkt/src/tests/cypress/integration/public_home_page.spec.ts index 02818d90c..fbc3046f8 100644 --- a/frontend/packages/vkt/src/tests/cypress/integration/public_home_page.spec.ts +++ b/frontend/packages/vkt/src/tests/cypress/integration/public_home_page.spec.ts @@ -14,7 +14,7 @@ describe('PublicHomePage', () => { onCookieBanner.getBanner().should('not.exist'); }); - it('should show the filtered amount of exam events in table pagination', () => { + it('should allow filtering exam events based on exam language', () => { onPublicHomePage.expectFilteredExamEventsCount(publicExamEvents11.length); onPublicHomePage.filterByLanguage(ExamLanguage.FI); diff --git a/frontend/packages/vkt/src/tests/cypress/support/page-objects/publicHomePage.ts b/frontend/packages/vkt/src/tests/cypress/support/page-objects/publicHomePage.ts index 89b15fb55..e0017f351 100644 --- a/frontend/packages/vkt/src/tests/cypress/support/page-objects/publicHomePage.ts +++ b/frontend/packages/vkt/src/tests/cypress/support/page-objects/publicHomePage.ts @@ -9,8 +9,8 @@ class PublicHomePage { examEventRow: (id: number) => cy.findByTestId(row(id)), examEventRowCheckbox: (id: number) => cy.findByTestId(row(id)).find('input[type=checkbox]'), + examEventRows: () => cy.get('.public-homepage__grid-container__result-box').find('table > tbody > tr'), languageFilter: () => cy.findByTestId('exam-events__language-filter'), - pagination: () => cy.get('.table__head-box__pagination'), reservationTimerText: () => cy.findByTestId('public-enrollment__reservation-timer-text'), reservationRenewButton: () => @@ -35,9 +35,7 @@ class PublicHomePage { } expectFilteredExamEventsCount(count: number) { - this.elements - .pagination() - .should('contain.text', `1 - ${count} / ${count}`); + this.elements.examEventRows().should('have.length', count); } expectEnrollButtonText(examEventId: number, text: string) { From 00f8c162f10dd5a1200745c1c13aacc2125d1351 Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Wed, 21 Aug 2024 16:30:30 +0300 Subject: [PATCH 04/23] VKT(Frontend): Fix DOM nesting --- .../publicEnrollment/steps/EducationDetails.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx b/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx index 8f5fce8ed..9f8b2b009 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx @@ -7,6 +7,7 @@ import { FormHelperText, Radio, RadioGroup, + Typography, } from '@mui/material'; import { ChangeEvent, useEffect } from 'react'; import { Trans } from 'react-i18next'; @@ -171,14 +172,16 @@ const UploadAttachments = ({
    {t('helpText2')} - - {t('instructions.title')} +
    + {t('instructions.title')}
      {[1, 2, 3, 4, 5].map((i) => ( -
    • {t('instructions.part' + i)}
    • + + {t('instructions.part' + i)} + ))}
    - +
    {attachmentsCount < 10 && ( Date: Wed, 21 Aug 2024 16:32:16 +0300 Subject: [PATCH 05/23] VKT(Frontend): Separate step for education details, move address details to same step as other contact details [deploy] --- .../vkt/public/i18n/fi-FI/common.json | 1 + .../vkt/public/i18n/fi-FI/public.json | 12 +-- .../vkt/public/i18n/sv-SE/common.json | 1 + .../vkt/public/i18n/sv-SE/public.json | 8 +- .../PublicEnrollmentControlButtons.tsx | 1 + .../PublicEnrollmentStepContents.tsx | 10 +++ .../{selectExam => }/CertificateShipping.tsx | 4 +- .../steps/EducationDetails.tsx | 83 +++++++++++++------ .../steps/FillContactDetails.tsx | 65 +++++---------- .../publicEnrollment/steps/SelectExam.tsx | 24 +----- frontend/packages/vkt/src/enums/app.ts | 1 + .../vkt/src/enums/publicEnrollment.ts | 1 + .../packages/vkt/src/routers/AppRouter.tsx | 10 +++ .../vkt/src/utils/publicEnrollment.ts | 21 +++-- frontend/packages/vkt/src/utils/routes.ts | 6 ++ 15 files changed, 135 insertions(+), 113 deletions(-) rename frontend/packages/vkt/src/components/publicEnrollment/steps/{selectExam => }/CertificateShipping.tsx (97%) diff --git a/frontend/packages/vkt/public/i18n/fi-FI/common.json b/frontend/packages/vkt/public/i18n/fi-FI/common.json index 71db5ac5f..41f84649a 100644 --- a/frontend/packages/vkt/public/i18n/fi-FI/common.json +++ b/frontend/packages/vkt/public/i18n/fi-FI/common.json @@ -144,6 +144,7 @@ "clerkExamOverview": "Virkailija tutkintosivu", "clerkHomepage": "Virkailija", "contactDetails": "Ilmoittautuminen - täytä yhteystietosi", + "educationDetails": "Ilmoittautuminen - koulutustiedot", "done": "Ilmoittautuminen - valmis", "frontPage": "Etusivu", "logoutSuccess": "Uloskirjautuminen onnnistui", diff --git a/frontend/packages/vkt/public/i18n/fi-FI/public.json b/frontend/packages/vkt/public/i18n/fi-FI/public.json index 2b6dd6ade..68ec03b3a 100644 --- a/frontend/packages/vkt/public/i18n/fi-FI/public.json +++ b/frontend/packages/vkt/public/i18n/fi-FI/public.json @@ -61,8 +61,9 @@ "common": { "Authenticate": "Tunnistaudu", "Done": "Valmis", - "DoneQueued": "Valmis – jonopaikka varattu", - "FillContactDetails": "Täytä tiedot", + "DoneQueued": "Valmis - jonopaikka varattu", + "EducationDetails": "Koulutustiedot", + "FillContactDetails": "Täytä yhteystietosi", "Payment": "Maksua ei suoritettu", "PaymentSuccess": "Valmis - ilmoittautuminen onnistui", "Preview": "Esikatsele", @@ -84,7 +85,8 @@ "step": { "Authenticate": "Tunnistaudu", "Done": "Valmis", - "FillContactDetails": "Täytä tiedot", + "EducationDetails": "Koulutustiedot", + "FillContactDetails": "Täytä yhteystietosi", "Payment": "Maksu", "PaymentSuccess": "Valmis", "Preview": "Esikatsele", @@ -95,8 +97,8 @@ "authenticate": { "auth": "Tunnistaudu suomi.fi:n kautta" }, - "certificateShipping": { - "title": "Tutkintotodistuksen toimitus" + "addressDetails": { + "title": "Osoitetiedot" }, "done": { "description": "Ilmoittautuminen tutkintoon onnistui! Sinulle lähetetään vahvistus osoitteeseen", diff --git a/frontend/packages/vkt/public/i18n/sv-SE/common.json b/frontend/packages/vkt/public/i18n/sv-SE/common.json index 56e5e799f..31b67ca63 100644 --- a/frontend/packages/vkt/public/i18n/sv-SE/common.json +++ b/frontend/packages/vkt/public/i18n/sv-SE/common.json @@ -134,6 +134,7 @@ "notFound": "Sidan hittades inte", "authenticate": "Anmälan - identifiera dig", "contactDetails": "Anmälan - fyll i dina kontaktuppgifter", + "educationDetails": "Anmälan - utbildningsuppgifter", "selectExam": "Anmälan - välj examen", "preview": "Anmälan - förhandsgranska", "paymentFail": "Anmälan - avgiften har inte betalats", diff --git a/frontend/packages/vkt/public/i18n/sv-SE/public.json b/frontend/packages/vkt/public/i18n/sv-SE/public.json index 8e47b1ae2..1642ca333 100644 --- a/frontend/packages/vkt/public/i18n/sv-SE/public.json +++ b/frontend/packages/vkt/public/i18n/sv-SE/public.json @@ -61,7 +61,8 @@ "Authenticate": "Identifiera dig", "Done": "Färdig", "DoneQueued": "Färdig - du har en plats i kön", - "FillContactDetails": "Fyll i uppgifter", + "EducationDetails": "Utbildningsuppgifter", + "FillContactDetails": "Fyll i dina kontaktuppgifter", "Payment": "Avgiften har inte betalats", "PaymentSuccess": "Färdigt - anmälan lyckades", "Preview": "Förhandsgranska", @@ -83,6 +84,7 @@ "step": { "Authenticate": "Identifiera dig", "Done": "Färdigt", + "EducationDetails": "Utbildningsuppgifter", "FillContactDetails": "Fyll i dina kontaktuppgifter", "Payment": "Betalning", "PaymentSuccess": "Färdig", @@ -94,7 +96,9 @@ "authenticate": { "auth": "Identifiera dig via suomi.fi -tjänsten" }, - "certificateShipping": { "title": "Leverans av examensintyget" }, + "addressDetails": { + "title": "Adressinformation" + }, "done": { "description": "Du har anmält dig till examen! Du får en bekräftelse till adressen", "descriptionQueued": "Du har en plats i kön för examen! Du får en bekräftelse till adressen", diff --git a/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentControlButtons.tsx b/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentControlButtons.tsx index 4862105c4..77bb8e495 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentControlButtons.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentControlButtons.tsx @@ -247,6 +247,7 @@ export const PublicEnrollmentControlButtons = ({ const renderNext = [ PublicEnrollmentFormStep.FillContactDetails, + PublicEnrollmentFormStep.EducationDetails, PublicEnrollmentFormStep.SelectExam, ].includes(activeStep); diff --git a/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentStepContents.tsx b/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentStepContents.tsx index 4bff1e867..dacc0f5aa 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentStepContents.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentStepContents.tsx @@ -3,6 +3,7 @@ import { useNavigate } from 'react-router'; import { Authenticate } from 'components/publicEnrollment/steps/Authenticate'; import { Done } from 'components/publicEnrollment/steps/Done'; +import { EducationDetails } from 'components/publicEnrollment/steps/EducationDetails'; import { FillContactDetails } from 'components/publicEnrollment/steps/FillContactDetails'; import { PaymentFail } from 'components/publicEnrollment/steps/PaymentFail'; import { PaymentSuccess } from 'components/publicEnrollment/steps/PaymentSuccess'; @@ -50,6 +51,15 @@ export const PublicEnrollmentStepContents = ({ showValidation={showValidation} /> ); + case PublicEnrollmentFormStep.EducationDetails: + return ( + + ); case PublicEnrollmentFormStep.SelectExam: return ( { const { t } = usePublicTranslation({ - keyPrefix: 'vkt.component.publicEnrollment.steps.certificateShipping', + keyPrefix: 'vkt.component.publicEnrollment.steps.addressDetails', }); const translateCommon = useCommonTranslation(); const digitalConsentEnabled = false; @@ -148,7 +148,7 @@ export const CertificateShipping = ({ {translateCommon('enrollment.certificateShipping.description')} -
    +
    void; + enrollment: PublicEnrollment; }) => { const { t } = usePublicTranslation({ keyPrefix: @@ -342,9 +346,7 @@ export const EducationDetails = ({ }); const dispatch = useAppDispatch(); - const { enrollment, freeEnrollmentDetails } = useAppSelector( - publicEnrollmentSelector, - ); + const { freeEnrollmentDetails } = useAppSelector(publicEnrollmentSelector); const { status: educationStatus, education: educations } = useAppSelector( publicEducationSelector, ); @@ -368,6 +370,31 @@ export const EducationDetails = ({ freeEnrollmentBasis.type !== EducationType.None && isFree; + const isEducationValid = EnrollmentUtils.isValidFreeBasisIfRequired( + enrollment, + freeEnrollmentDetails, + ); + const isAttachmentsValid = + EnrollmentUtils.isValidAttachmentsIfRequired(enrollment); + + const handleEductionChangeFn: HandleChange = ( + isFree: boolean, + freeEnrollmentBasis?: PublicFreeEnrollmentBasis, + ) => { + dispatch( + updatePublicEnrollment({ + isFree, + freeEnrollmentBasis, + }), + ); + }; + const handleEducationChange = useCallback(handleEductionChangeFn, [dispatch]); + + useEffect(() => { + setIsStepValid(isEducationValid && isAttachmentsValid), + [setIsStepValid, isEducationValid, isAttachmentsValid]; + }); + return ( EnrollmentUtils.hasFreeEnrollmentsLeft(freeEnrollmentDetails) && (
    @@ -381,30 +408,32 @@ export const EducationDetails = ({ {t('errorWaitEducations')} )} - + {foundSuitableEducationDetails && ( )} - {!isEducationLoading && !foundSuitableEducationDetails && ( - <> - - {attachmentsRequired && ( - + - )} - - )} + {attachmentsRequired && ( + + )} + + )}
    ) ); diff --git a/frontend/packages/vkt/src/components/publicEnrollment/steps/FillContactDetails.tsx b/frontend/packages/vkt/src/components/publicEnrollment/steps/FillContactDetails.tsx index 18f235722..a89dfedfd 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/steps/FillContactDetails.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/steps/FillContactDetails.tsx @@ -1,25 +1,20 @@ -import { ChangeEvent, useCallback, useEffect, useState } from 'react'; +import { Divider } from '@mui/material'; +import { ChangeEvent, useEffect, useState } from 'react'; import { H2, LabeledTextField, Text } from 'shared/components'; import { InputAutoComplete, TextFieldTypes } from 'shared/enums'; +import { useWindowProperties } from 'shared/hooks'; import { TextField } from 'shared/interfaces'; import { FieldErrors, getErrors, hasErrors } from 'shared/utils'; -import { EducationDetails } from 'components/publicEnrollment/steps/EducationDetails'; +import { CertificateShipping } from 'components/publicEnrollment/steps/CertificateShipping'; import { PersonDetails } from 'components/publicEnrollment/steps/PersonDetails'; import { useCommonTranslation, usePublicTranslation } from 'configs/i18n'; -import { useAppDispatch, useAppSelector } from 'configs/redux'; -import { - HandleChange, - PublicFreeEnrollmentBasis, -} from 'interfaces/publicEducation'; +import { useAppDispatch } from 'configs/redux'; import { PublicEnrollment, PublicEnrollmentContactDetails, } from 'interfaces/publicEnrollment'; import { updatePublicEnrollment } from 'redux/reducers/publicEnrollment'; -import { featureFlagsSelector } from 'redux/selectors/featureFlags'; -import { publicEnrollmentSelector } from 'redux/selectors/publicEnrollment'; -import { EnrollmentUtils } from 'utils/enrollment'; const fields: Array> = [ { @@ -77,8 +72,6 @@ export const FillContactDetails = ({ keyPrefix: 'vkt.component.publicEnrollment.steps.fillContactDetails', }); const translateCommon = useCommonTranslation(); - const { freeEnrollmentAllowed } = useAppSelector(featureFlagsSelector); - const { freeEnrollmentDetails } = useAppSelector(publicEnrollmentSelector); const [dirtyFields, setDirtyFields] = useState< Array @@ -94,12 +87,11 @@ export const FillContactDetails = ({ dirtyFields: dirty, extraValidation: emailsMatch.bind(this, t), }); - const isEducationValid = EnrollmentUtils.isValidFreeBasisIfRequired( - enrollment, - freeEnrollmentDetails, - ); - const isAttachmentsValid = - EnrollmentUtils.isValidAttachmentsIfRequired(enrollment); + + const [isValidCertificateShipping, setIsValidCertificateShipping] = + useState(false); + const setCertificateShipping = (isValid: boolean) => + setIsValidCertificateShipping(isValid); useEffect(() => { setIsStepValid( @@ -108,17 +100,14 @@ export const FillContactDetails = ({ values: enrollment, t: translateCommon, extraValidation: emailsMatch.bind(this, t), - }) && - isEducationValid && - isAttachmentsValid, + }) && isValidCertificateShipping, ); }, [ setIsStepValid, enrollment, + isValidCertificateShipping, t, translateCommon, - isEducationValid, - isAttachmentsValid, ]); const handleChange = @@ -131,19 +120,6 @@ export const FillContactDetails = ({ ); }; - const handleEductionChangeFn: HandleChange = ( - isFree: boolean, - freeEnrollmentBasis?: PublicFreeEnrollmentBasis, - ) => { - dispatch( - updatePublicEnrollment({ - isFree, - freeEnrollmentBasis, - }), - ); - }; - const handleEducationChange = useCallback(handleEductionChangeFn, [dispatch]); - const handleBlur = (fieldName: keyof PublicEnrollmentContactDetails) => () => { if (!dirtyFields.includes(fieldName)) { @@ -177,6 +153,8 @@ export const FillContactDetails = ({ disabled: isLoading, }); + const { isPhone } = useWindowProperties(); + return (
    @@ -211,14 +189,13 @@ export const FillContactDetails = ({ type={TextFieldTypes.PhoneNumber} autoComplete={InputAutoComplete.PhoneNumber} /> - {freeEnrollmentAllowed && ( - - )} + {!isPhone && } +
    ); }; diff --git a/frontend/packages/vkt/src/components/publicEnrollment/steps/SelectExam.tsx b/frontend/packages/vkt/src/components/publicEnrollment/steps/SelectExam.tsx index 8d98bff4b..9ea925b9a 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/steps/SelectExam.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/steps/SelectExam.tsx @@ -1,7 +1,6 @@ import { useEffect, useState } from 'react'; import { H2, Text } from 'shared/components'; -import { CertificateShipping } from 'components/publicEnrollment/steps/selectExam/CertificateShipping'; import { PartialExamsSelection } from 'components/publicEnrollment/steps/selectExam/PartialExamsSelection'; import { PreviousEnrollment } from 'components/publicEnrollment/steps/selectExam/PreviousEnrollment'; import { useCommonTranslation, usePublicTranslation } from 'configs/i18n'; @@ -27,28 +26,15 @@ export const SelectExam = ({ useState(false); const [isValidPartialExamsSelection, setIsValidPartialExamsSelection] = useState(false); - const [isValidCertificateShipping, setIsValidCertificateShipping] = - useState(false); const setPreviousEnrollment = (isValid: boolean) => setIsValidPreviousEnrollment(isValid); const setPartialExamsSelection = (isValid: boolean) => setIsValidPartialExamsSelection(isValid); - const setCertificateShipping = (isValid: boolean) => - setIsValidCertificateShipping(isValid); useEffect(() => { - setIsStepValid( - isValidPreviousEnrollment && - isValidPartialExamsSelection && - isValidCertificateShipping, - ); - }, [ - setIsStepValid, - isValidPreviousEnrollment, - isValidPartialExamsSelection, - isValidCertificateShipping, - ]); + setIsStepValid(isValidPreviousEnrollment && isValidPartialExamsSelection); + }, [setIsStepValid, isValidPreviousEnrollment, isValidPartialExamsSelection]); return (
    @@ -71,12 +57,6 @@ export const SelectExam = ({ setValid={setPreviousEnrollment} showValidation={showValidation} /> -
    ); }; diff --git a/frontend/packages/vkt/src/enums/app.ts b/frontend/packages/vkt/src/enums/app.ts index af305cbbc..c48f75c63 100644 --- a/frontend/packages/vkt/src/enums/app.ts +++ b/frontend/packages/vkt/src/enums/app.ts @@ -8,6 +8,7 @@ export enum AppRoutes { PublicEnrollment = '/vkt/ilmoittaudu', PublicAuth = '/vkt/ilmoittaudu/:examEventId/tunnistaudu', PublicEnrollmentContactDetails = '/vkt/ilmoittaudu/:examEventId/tiedot', + PublicEnrollmentEducationDetails = '/vkt/ilmoittaudu/:examEventId/koulutus', PublicEnrollmentSelectExam = '/vkt/ilmoittaudu/:examEventId/tutkinto', PublicEnrollmentPreview = '/vkt/ilmoittaudu/:examEventId/esikatsele', PublicEnrollmentPaymentFail = '/vkt/ilmoittaudu/:examEventId/maksu/peruutettu', diff --git a/frontend/packages/vkt/src/enums/publicEnrollment.ts b/frontend/packages/vkt/src/enums/publicEnrollment.ts index d7cb24313..a180893ba 100644 --- a/frontend/packages/vkt/src/enums/publicEnrollment.ts +++ b/frontend/packages/vkt/src/enums/publicEnrollment.ts @@ -1,6 +1,7 @@ export enum PublicEnrollmentFormStep { Authenticate = 1, FillContactDetails, + EducationDetails, SelectExam, Preview, Payment, diff --git a/frontend/packages/vkt/src/routers/AppRouter.tsx b/frontend/packages/vkt/src/routers/AppRouter.tsx index 078a51653..65253aa7e 100644 --- a/frontend/packages/vkt/src/routers/AppRouter.tsx +++ b/frontend/packages/vkt/src/routers/AppRouter.tsx @@ -108,6 +108,16 @@ export const AppRouter: FC = () => { } /> + + + + } + /> Date: Thu, 22 Aug 2024 12:50:27 +0300 Subject: [PATCH 06/23] VKT(Frontend): Remove now obsolete privacy policy page --- .../vkt/public/i18n/fi-FI/privacy.json | 120 -------- .../vkt/public/i18n/sv-SE/privacy.json | 120 -------- frontend/packages/vkt/src/configs/i18n.ts | 15 - .../vkt/src/pages/PrivacyPolicyPage.tsx | 256 ------------------ .../packages/vkt/src/routers/AppRouter.tsx | 9 - .../styles/pages/_privacy-policy-page.scss | 35 --- frontend/packages/vkt/src/styles/styles.scss | 1 - 7 files changed, 556 deletions(-) delete mode 100644 frontend/packages/vkt/public/i18n/fi-FI/privacy.json delete mode 100644 frontend/packages/vkt/public/i18n/sv-SE/privacy.json delete mode 100644 frontend/packages/vkt/src/pages/PrivacyPolicyPage.tsx delete mode 100644 frontend/packages/vkt/src/styles/pages/_privacy-policy-page.scss diff --git a/frontend/packages/vkt/public/i18n/fi-FI/privacy.json b/frontend/packages/vkt/public/i18n/fi-FI/privacy.json deleted file mode 100644 index 9504e419f..000000000 --- a/frontend/packages/vkt/public/i18n/fi-FI/privacy.json +++ /dev/null @@ -1,120 +0,0 @@ -{ - "vkt": { - "privacy": { - "automatedDecisions": { - "description": "Rekisterin sisältämiä tietoja ei käytetä profilointiin eikä tietoihin kohdisteta automaattista päätöksentekoa.", - "heading": "Tiedot automaattisen päätöksenteon, ml. profiloinnin olemassaolosta, sekä ainakin näissä tapauksissa merkitykselliset tiedot käsittelyyn liittyvästä logiikasta samoin kuin kyseisen käsittelyn merkittävyys ja mahdolliset seuraukset rekisteröidylle" - }, - "common": { - "email": "Sähköposti", - "group": "Ryhmä", - "phoneSwitch": "Puhelin: 029 533 1000 (vaihde)" - }, - "complaints": { - "description": "Rekisteröidyllä on oikeus tehdä kantelu valvontaviranomaiselle, erityisesti siinä jäsenvaltiossa, jossa hänen vakinainen asuinpaikkansa tai työpaikkansa on, tai jossa väitetty tietosuoja-asetuksen rikkominen on tapahtunut.", - "heading": "Oikeus tehdä valitus valvontaviranomaiselle" - }, - "dataContents": { - "group1": { - "dataProcessing": { - "description1": "Rekisteröidyn tiedot poistetaan käytöstä ilman aiheetonta viivytystä ja viimeistään 3 vuoden kuluttua tutkintopäivästä, johon rekisteröity on ilmoittautunut.", - "description2": "Rekisteröidyn henkilötietojen käsittely on tarpeen ja oikeasuhtaista viranomaisen toiminnassa yleisen edun mukaisen tehtävän suorittamiseksi.", - "description3": "Erityisiä henkilötietoja ei käsitellä. Salassa pidettäviä henkilötietoja ei käsitellä." - }, - "givenDetails": { - "description": "Henkilön nykyinen nimi, sähköpostiosoite, postiosoite ja puhelinnumero.", - "heading": "Tutkintoon ilmoittautujan henkilötiedot" - }, - "otherDetails": { - "heading": "Muut merkittävät tiedot", - "ul1": "tutkintopäivä", - "ul2": "tutkintokieli", - "ul3": "tutkinnot ja osakokeet", - "ul4": "tutkintomaksun viite, summa ja maksupäivä", - "ul5": "onko osallistunut aiemmin Valtionhallinnon kielitutkintoon" - } - }, - "heading": "Rekisterin tietosisältö / käsiteltävät henkilötietoryhmät" - }, - "dataSources": { - "description": "Tiedot kerätään tutkintoon ilmoittautujilta itseltään.", - "heading": "Tiedot siitä, mistä henkilötiedot on saatu sekä tarvittaessa siitä, onko tiedot saatu yleisesti saatavilla olevista lähteistä" - }, - "dataTransfers": { - "description": "Tietoja ei siirretä EU:n tai Euroopan talousalueen ulkopuolelle.", - "heading": "Tiedot tietojen siirrosta kolmansiin maihin ja tiedot käytettävistä suojatoimista (sis. tiedon komission tietosuojan riittävyyttä koskevasta päätöksen olemassaolosta tai puuttumisesta) ja keinot saada kopio tai tieto niiden sisällöstä" - }, - "description": "EU:n tietosuoja-asetus 2016/679 (GDPR).", - "handlingPurpose": { - "description": "Valtionhallinnon kielitutkintojen toimeenpanosta vastaa Opetushallitus. Tätä varten Opetushallituksella on rekisteri (VKT), johon on kerätty henkilöiden yhteystiedot Valtionhallinnon kielitutkintojen (VKT) erinomaisen taidon tutkintoon ilmoittautumista varten. Ilmoittautumiseen, tutkinnon suorittamiseen ja maksamiseen liittyvää asiointia varten rekisteriin kerätään henkilöiden yhteystiedot.", - "heading": "Henkilötietojen käsittelyn tarkoitus sekä käsittelyn oikeusperuste", - "law": { - "heading": "Lakiperusteet", - "part1": { - "content": "481/2003", - "description": "Valtioneuvoston asetus suomen ja ruotsin kielen taidon osoittamisesta valtionhallinnossa (<0>).", - "link": "https://www.finlex.fi/fi/laki/alkup/2003/20030481" - }, - "part2": { - "description": "EU:n yleisen tietosuoja-asetuksen 6 artiklan 1c-kohta." - } - } - }, - "heading": "Tietosuojaseloste / Tiedonanto", - "holdingPeriod": { - "description1": "Rekisteröidyn tiedot poistetaan käytöstä ilman aiheetonta viivytystä ja viimeistään 3 vuoden kuluttua tutkintopäivästä, johon rekisteröity on ilmoittautunut.", - "description2": "Palvelun henkilötietojen säilytysajat ovat arkistonmuodostussuunnitelman ja tiedonohjaussuunnitelman määrittämien säilytysaikojen mukaisia. Asiakirjat, joiden säilytysaika on päättynyt, hävitetään järjestelmästä vuosittain.", - "heading": "Henkilötietojen säilyttämisaika" - }, - "receivers": { - "description1": "Opetushallituksen on viranomaisten toiminnan julkisuudesta annetun lain (21.5.1999/621) mukaan annettava tieto julkisesta asiakirjasta pyytäjälle, vaikka asiakirja sisältäisi henkilötietoja. Salassa pidettävän tiedon antaminen tai luovuttaminen edellyttää erityistä perustetta: asianosaisasema tai laissa säädetty oikeus tiedon saamiseen tai sen henkilön suostumus, jonka suojaksi salassapidosta on säädetty.", - "description2": "Henkilötietoja voidaan luovuttaa tieteellistä tai historiallista tutkimusta taikka tilastointia varten tietosuojalain (1050/2018) 4 §:n mukaisin edellytyksin.", - "description3": "Tietojärjestelmän palveluntarjoajat (henkilötietojen käsittelijät) pääsevät tarkastelemaan rekisterin sisältämiä henkilötietoja Opetushallituksen määrittämässä laajuudessa.", - "description4": "Tietoja ei luovuteta suoramarkkinointiin.", - "heading": "Henkilötietojen vastaanottajat tai vastaanottajaryhmät" - }, - "registeredRights": { - "description1": "Rekisteröidyllä on oikeus saada rekisterinpitäjältä vahvistus siitä, että häntä koskevia henkilötietoja käsitellään tai että niitä ei käsitellä. Rekisterinpitäjän on toimitettava pyynnöstä jäljennös käsiteltävistä henkilötiedoista.", - "description2": "Rekisteröidyllä on oikeus vaatia, että rekisterinpitäjä oikaisee ilman aiheetonta viivytystä rekisteröityä koskevat epätarkat ja virheelliset henkilötiedot. Rekisteröidyn tulee yksilöidä ja perustella, mitä tietoa hän vaatii korjattavaksi, mikä on hänen mielestään oikea tieto ja miten korjaus halutaan tehtäväksi.", - "description3": "Mikäli käsittely perustuu tietosuoja-asetuksen 6 artiklan 1a -kohtaan tai 9 artiklan 2a -kohtaan eli rekisteröidyn suostumukseen, on rekisteröidyllä oikeus tietojen poistamiseen.", - "description4": "Rekisteröidyllä on oikeus käsittelyn rajoittamiseen tietyissä tilanteissa.", - "description5": "Rekisteröidyllä on oikeus siihen, että rekisterinpitäjä ilmoittaa henkilötietojesi oikaisusta tai poistosta tai käsittelyn rajoituksesta sille, jolle tietoja on edelleen luovutettu, mikäli tietoja luovutetaan eteenpäin.", - "description6": "Rekisteröidyllä on oikeus saada tiedot siirrettyä järjestelmästä toiseen, jos käsittely suoritetaan automaattisesti.", - "description7": "Oikeuksien käyttöön liittyvät pyynnöt tulee osoittaa rekisterin yhteyshenkilölle: Opetushallitus, PL 380, 00531 Helsinki. Tarkastuspyyntöön rekisteröidyn tulee liittää tietojen etsimiseen tarvittavat tiedot (nimi ja henkilötunnus).", - "description8": "Jos rekisteröidyn käyttämästä henkilötietojen tarkastusoikeudesta on kulunut vähemmän kuin yksi vuosi, voi rekisterinpitäjä periä tietojen antamisesta aiheutuvat hallinnollisiin kustannuksiin perustuvan maksun (artikla 12 [5]).", - "heading": "Rekisteröidyn oikeudet", - "rights": { - "right1": "Oikeus saada pääsy henkilötietoihin", - "right2": "Oikeus tietojen oikaisemiseen", - "right3": "Oikeus tietojen poistamiseen", - "right4": "Oikeus käsittelyn rajoittamiseen", - "right5": "Vastustamisoikeus", - "right6": "Oikeus siirtää tiedot järjestelmästä toiseen" - } - }, - "registerName": { - "description": "Valtionhallinnon kielitutkintojen erinomaisen taidon tutkinnon ilmoittautuminen ja tutkintomaksun maksaminen.", - "heading": "Rekisterin nimi" - }, - "registrar": { - "contact": { - "address": "PL 380, 00531 Helsinki (käyntiosoite Hakaniemenranta 6, 00530 Helsinki).", - "name": "Opetushallitus", - "otherDetails": "Muut yhteystiedot", - "phoneSwitch": "Puhelinvaihde: 029 533 1000" - }, - "heading": "Rekisterin pitäjä" - }, - "registrarContactPerson": { - "heading": "Rekisterinpitäjän edustaja (yhteyshenkilö)", - "liable": { - "description": "Tietosuojavastaavan yhteystiedot", - "name": "Jyrki Tuohela" - }, - "person": { - "name": "Niina Juuti" - } - } - } - } -} diff --git a/frontend/packages/vkt/public/i18n/sv-SE/privacy.json b/frontend/packages/vkt/public/i18n/sv-SE/privacy.json deleted file mode 100644 index d55f367b3..000000000 --- a/frontend/packages/vkt/public/i18n/sv-SE/privacy.json +++ /dev/null @@ -1,120 +0,0 @@ -{ - "vkt": { - "privacy": { - "automatedDecisions": { - "description": "Registrets uppgifter används inte för profilering och uppgifterna omfattas inte av automatiskt beslutsfattande.", - "heading": "Information om automatiskt beslutsfattande, inkl. förekomsten av profilering, och åtminstone i dessa fall betydelsefulla uppgifter om hanteringens logik, samt den aktuella behandlingens betydelse och eventuella konsekvenser för den registrerade" - }, - "common": { - "email": "E-post", - "group": "Grupp", - "phoneSwitch": "Telefon: 029 533 1000 (växel)" - }, - "complaints": { - "description": "Den registrerade har rätt att lämna in ett klagomål till tillsynsmyndigheten, särskilt i den medlemsstat där hen är stadigvarande bosatt eller har sin arbetsplats, eller där den påstådda överträdelsen av dataskyddsförordningen har skett.", - "heading": "Rätt att lämna in klagomål till tillsynsmyndigheten" - }, - "dataContents": { - "group1": { - "dataProcessing": { - "description1": "Den registrerades uppgifter tas ur användning utan oskäligt dröjsmål och senast 3 år efter det examensdatum som den registrerade har anmält sig till.", - "description2": "Behandlingen av den registrerades personuppgifter är nödvändig och proportionerlig för att utföra en uppgift av allmänt intresse som en del av den personuppgiftsansvariges myndighetsutövning.", - "description3": "Särskilda personuppgifter behandlas inte. Sekretessbelagda personuppgifter behandlas inte." - }, - "givenDetails": { - "description": "Personens nuvarande namn, e-postadress, postadress och telefonnummer.", - "heading": "Personuppgifter för personen som anmält sig till examen" - }, - "otherDetails": { - "heading": "Andra uppgifter som ska anges", - "ul1": "examensdag", - "ul2": "examensspråk", - "ul3": "examina och delprov", - "ul4": "examensavgiftens referensnummer, belopp och betalningsdag", - "ul5": "om personen tidigare har deltagit i språkexamen för statsförvaltningen" - } - }, - "heading": "Registrets datainnehåll / kategorier av personuppgifter som behandlas" - }, - "dataSources": { - "description": "Uppgifterna samlas in direkt av personerna som anmäler sig till examen.", - "heading": "Information om varifrån personuppgifterna kommer och i förekommande fall huruvida de har sitt ursprung i allmänt tillgängliga källor" - }, - "dataTransfers": { - "description": "Uppgifter överförs inte till länder utanför EU eller EES.", - "heading": "Information om överföring av uppgifter till tredje land och de skyddsåtgärder som vidtas (inkl. information om huruvida kommissionens beslut om adekvat dataskydd existerar eller saknas) och metoder för att få en kopia eller information om vad de innehåller" - }, - "description": "EU:s dataskyddsförordning 2016/679 (GDPR).", - "handlingPurpose": { - "description": "Utbildningsstyrelsen ansvarar för verkställandet av språkexamina för statsförvaltningen. För detta har Utbildningsstyrelsen ett register, som innehåller kontaktuppgifter för personer som anmält sig till språkexamina för statsförvaltningen som gäller utmärkta kunskaper. Kontaktuppgifterna samlas in i registret för anmälan, avläggande av examen och betalning.", - "heading": "Syftet med behandlingen av personuppgifter samt den rättsliga grunden för behandlingen", - "law": { - "heading": "Laggrunder", - "part1": { - "content": "481/2003", - "description": "Statsrådets förordning om bedömning av kunskaper i finska och svenska inom statsförvaltningen (<0>).", - "link": "https://www.finlex.fi/sv/laki/alkup/2003/20030481" - }, - "part2": { - "description": "Artikel 6.1 c i EU:s allmänna dataskyddsförordning." - } - } - }, - "heading": "Dataskyddsbeskrivning / Meddelande", - "holdingPeriod": { - "description1": "Den registrerades uppgifter tas ur användning utan oskäligt dröjsmål och senast 3 år efter det examensdatum som den registrerade har anmält sig till.", - "description2": "Personuppgifternas förvaringstid i tjänsten överensstämmer med förvaringstiderna som fastställs i arkivbildningsplanen och planen för styrning av information. Handlingar vilkas förvaringstid har upphört stryks ur registret årligen.", - "heading": "Personuppgifternas förvaringstid" - }, - "receivers": { - "description1": "Enligt lagen om offentlighet i myndigheternas verksamhet (21.5.1999/621) ska Utbildningsstyrelsen ge uppgifter från en offentlig handling enligt begäran, även om handlingen innehåller personuppgifter. Utlämnande eller överlåtande av sekretessbelagda uppgifter förutsätter särskilda grunder: partsställning eller lagstadgad rätt att få uppgifter eller samtycke av den som sekretessen gäller.", - "description2": "Personuppgifter kan lämnas ut för vetenskaplig eller historisk forskning eller för statistikföring under de förutsättningar som anges i 4 § i dataskyddslagen (1050/2018).", - "description3": "Informationssystemets tjänsteleverantörer (personuppgiftsbiträden) kan granska personuppgifterna i registret i den omfattning som Utbildningsstyrelsen bestämmer.", - "description4": "Uppgifterna lämnas inte ut för direktmarknadsföring.", - "heading": "Personuppgifternas mottagare eller mottagargrupper" - }, - "registeredRights": { - "description1": "Den registrerade har rätt att av den personuppgiftsansvarige få bekräftelse på att personuppgifter som gäller hen behandlas eller inte behandlas. Den personuppgiftsansvarige skall på begäran sända en kopia av de personuppgifter som behandlas.", - "description2": "Den registrerade har rätt att kräva att den personuppgiftsansvarige utan obefogat dröjsmål rättar inexakta och felaktiga personuppgifter om den registrerade. Den registrerade ska specificera och motivera vilken information hen kräver att ska korrigeras, vilken information hen anser vara korrekt och hur man vill att korrigeringen ska göras.", - "description3": "Om behandlingen grundar sig på artikel 6 punkt 1a eller artikel 9 punkt 2a i dataskyddsförordningen, dvs. den registrerades samtycke, har den registrerade rätt att radera uppgifterna.", - "description4": "Den registrerade har rätt att begränsa behandlingen av uppgifter i vissa situationer.", - "description5": "Den registrerade har rätt att bli informerad om dennes personuppgifter har rättats eller raderats, eller om att behandlingen begränsats till den till vilken uppgifterna har vidareutlämnats, om uppgifterna lämnas vidare.", - "description6": "Den registrerade har rätt att få uppgifterna överförda från ett system till ett annat om handläggningen sker automatiskt.", - "description7": "Begäran om utövande av rättigheter ska riktas till registrets kontaktperson: Utbildningsstyrelsen, PB 380, 00531 Helsingfors. Till begäran om insyn ska den registrerade bifoga de uppgifter som behövs för att söka uppgifterna (namn och personbeteckning).", - "description8": "Om det har gått mindre än ett år sedan den registrerade använde sin rätt till insyn i personuppgifter, kan den registernsvarige ta ut en avgift som grundar sig på de administrativa kostnaderna för att lämna ut uppgifterna (artikel 12 [5]).", - "heading": "Den registrerades rättigheter", - "rights": { - "right1": "Rätten att få tillgång till personuppgifter", - "right2": "Rätten att rätta uppgifter", - "right3": "Rätten att radera uppgifter", - "right4": "Rätten att begränsa behandlingen av uppgifter", - "right5": "Rätten att göra invändningar", - "right6": "Rätten att överföra uppgifter från ett system till ett annat" - } - }, - "registerName": { - "description": "Anmälan till språkexamina för statsförvaltningen som gäller utmärkta kunskaper och betalning av examensavgiften.", - "heading": "Registrets namn" - }, - "registrar": { - "contact": { - "address": "PB 380, 00531 Helsingfors (besöksadress Hagnäskajen 6, 00530 Helsingfors).", - "name": "Utbildningsstyrelsen", - "otherDetails": "Övriga kontaktuppgifter", - "phoneSwitch": "Telefonväxel: 029 533 1000" - }, - "heading": "Personuppgiftsansvarig" - }, - "registrarContactPerson": { - "heading": "Företrädare för personuppgiftsansvarig (kontaktperson)", - "liable": { - "description": "Dataskyddsombudets kontaktuppgifter", - "name": "Jyrki Tuohela" - }, - "person": { - "name": "Niina Juuti" - } - } - } - } -} \ No newline at end of file diff --git a/frontend/packages/vkt/src/configs/i18n.ts b/frontend/packages/vkt/src/configs/i18n.ts index 4938598ac..284908c08 100644 --- a/frontend/packages/vkt/src/configs/i18n.ts +++ b/frontend/packages/vkt/src/configs/i18n.ts @@ -11,12 +11,10 @@ import { DateUtils } from 'shared/utils'; import accessibilityFI from 'public/i18n/fi-FI/accessibility.json'; import clerkFI from 'public/i18n/fi-FI/clerk.json'; import commonFI from 'public/i18n/fi-FI/common.json'; -import privacyFI from 'public/i18n/fi-FI/privacy.json'; import publicFI from 'public/i18n/fi-FI/public.json'; import accessibilitySV from 'public/i18n/sv-SE/accessibility.json'; import clerkSV from 'public/i18n/sv-SE/clerk.json'; import commonSV from 'public/i18n/sv-SE/common.json'; -import privacySV from 'public/i18n/sv-SE/privacy.json'; import publicSV from 'public/i18n/sv-SE/public.json'; // Defaults and resources @@ -30,14 +28,12 @@ const resources = { [I18nNamespace.Accessibility]: accessibilityFI, [I18nNamespace.Clerk]: clerkFI, [I18nNamespace.Common]: commonFI, - [I18nNamespace.Privacy]: privacyFI, [I18nNamespace.Public]: publicFI, }, [langSV]: { [I18nNamespace.Accessibility]: accessibilitySV, [I18nNamespace.Clerk]: clerkSV, [I18nNamespace.Common]: commonSV, - [I18nNamespace.Privacy]: privacySV, [I18nNamespace.Public]: publicSV, }, }; @@ -107,17 +103,6 @@ export const useCommonTranslation = () => { return t; }; -export const usePrivacyTranslation = () => { - const { t } = useAppTranslation( - { - keyPrefix: 'vkt.privacy', - }, - I18nNamespace.Privacy, - ); - - return t; -}; - export const usePublicTranslation = ( options: UseTranslationOptions, ) => { diff --git a/frontend/packages/vkt/src/pages/PrivacyPolicyPage.tsx b/frontend/packages/vkt/src/pages/PrivacyPolicyPage.tsx deleted file mode 100644 index 9d9e2723f..000000000 --- a/frontend/packages/vkt/src/pages/PrivacyPolicyPage.tsx +++ /dev/null @@ -1,256 +0,0 @@ -import { - ArrowBackIosOutlined as ArrowBackIosOutlinedIcon, - OpenInNew as OpenInNewIcon, -} from '@mui/icons-material'; -import { Grid, Paper } from '@mui/material'; -import { useEffect } from 'react'; -import { Trans } from 'react-i18next'; -import { useLocation } from 'react-router-dom'; -import { - CustomButtonLink, - H1, - H2, - H3, - HeaderSeparator, - Text, - WebLink, -} from 'shared/components'; -import { Variant } from 'shared/enums'; -import { CommonUtils } from 'shared/utils'; - -import { useCommonTranslation, usePrivacyTranslation } from 'configs/i18n'; -import { AppRoutes } from 'enums/app'; - -const BackButton = () => { - const translateCommon = useCommonTranslation(); - - return ( - } - className="color-secondary-dark" - > - {translateCommon('backToHomePage')} - - ); -}; - -const BulletList = ({ - localisationKeys, -}: { - localisationKeys: Array; -}) => { - const translatePrivacy = usePrivacyTranslation(); - - return ( -
      - - {localisationKeys.map((key, i) => ( -
    • {translatePrivacy(key)}
    • - ))} -
      -
    - ); -}; - -export const PrivacyPolicyPage = () => { - const translatePrivacy = usePrivacyTranslation(); - const { pathname } = useLocation(); - - useEffect(() => { - CommonUtils.scrollToTop(); - }, [pathname]); - - return ( - - - - - -

    {translatePrivacy('heading')}

    - - {translatePrivacy('description')} -
    - - -
    -

    {translatePrivacy('registerName.heading')}

    - {translatePrivacy('registerName.description')} -
    -
    -

    {translatePrivacy('registrar.heading')}

    -
    - {translatePrivacy('registrar.contact.name')} - {translatePrivacy('registrar.contact.address')} -
    - - {translatePrivacy('registrar.contact.otherDetails')} -
    - {translatePrivacy('common.email')}:{' '} - - {', '} - -
    - {translatePrivacy('registrar.contact.phoneSwitch')} -
    -
    -
    -

    {translatePrivacy('registrarContactPerson.heading')}

    - - {translatePrivacy('registrarContactPerson.person.name')} -
    - {translatePrivacy('common.email')}:{' '} - -
    - {translatePrivacy('common.phoneSwitch')} -
    - - {translatePrivacy('registrarContactPerson.liable.description')} - {':'} -
    - {translatePrivacy('registrarContactPerson.liable.name')} -
    - {translatePrivacy('common.email')}:{' '} - -
    - {translatePrivacy('common.phoneSwitch')} -
    -
    -
    -

    {translatePrivacy('handlingPurpose.heading')}

    - {translatePrivacy('handlingPurpose.description')} -
    -

    {translatePrivacy('handlingPurpose.law.heading')}

    - - - } - /> - - - - {translatePrivacy('handlingPurpose.law.part2.description')} - -
    -
    -
    -

    {translatePrivacy('dataContents.heading')}

    -
    - - {translatePrivacy('dataContents.group1.givenDetails.heading')}: - - - {translatePrivacy( - 'dataContents.group1.givenDetails.description', - )} - -
    - - {translatePrivacy('dataContents.group1.otherDetails.heading')}: - - - - {translatePrivacy( - 'dataContents.group1.dataProcessing.description1', - )} - - - {translatePrivacy( - 'dataContents.group1.dataProcessing.description2', - )} - - - {translatePrivacy( - 'dataContents.group1.dataProcessing.description3', - )} - -
    -
    -

    {translatePrivacy('receivers.heading')}

    - {translatePrivacy('receivers.description1')} - {translatePrivacy('receivers.description2')} - {translatePrivacy('receivers.description3')} - {translatePrivacy('receivers.description4')} -
    -
    -

    {translatePrivacy('dataTransfers.heading')}

    - {translatePrivacy('dataTransfers.description')} -
    -
    -

    {translatePrivacy('holdingPeriod.heading')}

    - {translatePrivacy('holdingPeriod.description1')} - {translatePrivacy('holdingPeriod.description2')} -
    -
    -

    - {translatePrivacy('registeredRights.heading')} - -

    - {translatePrivacy('registeredRights.description1')} - {translatePrivacy('registeredRights.description2')} - {translatePrivacy('registeredRights.description3')} - {translatePrivacy('registeredRights.description4')} - {translatePrivacy('registeredRights.description5')} - {translatePrivacy('registeredRights.description6')} - {translatePrivacy('registeredRights.description7')} - {translatePrivacy('registeredRights.description8')} -
    -
    -

    {translatePrivacy('complaints.heading')}

    - {translatePrivacy('complaints.description')} -
    -
    -

    {translatePrivacy('dataSources.heading')}

    - {translatePrivacy('dataSources.description')} -
    -
    -

    {translatePrivacy('automatedDecisions.heading')}

    - {translatePrivacy('automatedDecisions.description')} -
    -
    -
    -
    - ); -}; diff --git a/frontend/packages/vkt/src/routers/AppRouter.tsx b/frontend/packages/vkt/src/routers/AppRouter.tsx index 65253aa7e..9c9fb3e7a 100644 --- a/frontend/packages/vkt/src/routers/AppRouter.tsx +++ b/frontend/packages/vkt/src/routers/AppRouter.tsx @@ -29,7 +29,6 @@ import { ClerkExamEventOverviewPage } from 'pages/ClerkExamEventOverviewPage'; import { ClerkHomePage } from 'pages/ClerkHomePage'; import { LogoutSuccess } from 'pages/LogoutSuccess'; import { NotFoundPage } from 'pages/NotFoundPage'; -import { PrivacyPolicyPage } from 'pages/PrivacyPolicyPage'; import { PublicEnrollmentPage } from 'pages/PublicEnrollmentPage'; import { PublicHomePage } from 'pages/PublicHomePage'; import { loadFeatureFlags } from 'redux/reducers/featureFlags'; @@ -187,14 +186,6 @@ export const AppRouter: FC = () => { } /> - - - - } - /> Date: Fri, 23 Aug 2024 12:00:43 +0300 Subject: [PATCH 07/23] VKT(Frontend): Fix layout for education details --- .../vkt/public/i18n/fi-FI/public.json | 1 - .../vkt/public/i18n/sv-SE/public.json | 1 - .../publicEnrollment/PublicEnrollmentGrid.tsx | 3 +- .../steps/EducationDetails.tsx | 61 ++++++++++--------- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/frontend/packages/vkt/public/i18n/fi-FI/public.json b/frontend/packages/vkt/public/i18n/fi-FI/public.json index 68ec03b3a..87648c41e 100644 --- a/frontend/packages/vkt/public/i18n/fi-FI/public.json +++ b/frontend/packages/vkt/public/i18n/fi-FI/public.json @@ -126,7 +126,6 @@ "title": "Yhteystietosi", "educationDetails": { "errorWaitEducations": "Odota koulutustietojen latautumista.", - "educationInfoTitle": "Koulutustiedot", "freeEnrollmentDescription": "Tietojemme mukaan olet suorittanut tai suorittamassa seuraavan tutkinnon:", "freeEnrollmentDescription2": "Tämä voi oikeuttaa sinut ilmoittautumaan tutkintoon maksuttomasti kolme kertaa.", "type": { diff --git a/frontend/packages/vkt/public/i18n/sv-SE/public.json b/frontend/packages/vkt/public/i18n/sv-SE/public.json index 1642ca333..58e42d69b 100644 --- a/frontend/packages/vkt/public/i18n/sv-SE/public.json +++ b/frontend/packages/vkt/public/i18n/sv-SE/public.json @@ -125,7 +125,6 @@ "title": "Dina kontaktuppgifter", "educationDetails": { "errorWaitEducations": "Utbildningsuppgiter laddas ner. Var god och vänta.", - "educationInfoTitle": "Utbildningsuppgifter", "freeEnrollmentDescription": "Enligt våra uppgifter har du avlagt eller studerar i syfte att avlägga följande examen:", "freeEnrollmentDescription2": "Du kan därmed ha rätt att delta språkexamen avgiftsfritt tre gånger.", "type": { diff --git a/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentGrid.tsx b/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentGrid.tsx index 9b171ee09..7702ff7e4 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentGrid.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentGrid.tsx @@ -150,7 +150,8 @@ export const PublicEnrollmentGrid = ({ const isPreviewPassed = activeStep > PublicEnrollmentFormStep.Preview; const isExamEventDetailsAvailable = - activeStep !== PublicEnrollmentFormStep.FillContactDetails; + activeStep !== PublicEnrollmentFormStep.FillContactDetails && + activeStep !== PublicEnrollmentFormStep.EducationDetails; const isPaymentSumAvailable = isPreviewStepActive && (!!reservation || isShiftedFromQueue); diff --git a/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx b/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx index 7d9476d05..6fa3e1417 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx @@ -14,7 +14,6 @@ import { Trans } from 'react-i18next'; import { CustomButton, FileUpload, - H2, H3, LoadingProgressIndicator, Text, @@ -169,7 +168,7 @@ const UploadAttachments = ({ }; return ( - <> +

    {t('title')}

    {t('helpText1')} @@ -209,7 +208,7 @@ const UploadAttachments = ({ {translateCommon('errors.customTextField.required')} )} - +
    ); }; @@ -242,7 +241,7 @@ const SelectEducation = ({ const showError = showValidation && !isEducationValid; return ( - <> +
    {t('educationSelectHelpText')} {t('educationSelectChooseOne')}
    @@ -287,7 +286,7 @@ const SelectEducation = ({ )}
    - +
    ); }; @@ -370,10 +369,12 @@ export const EducationDetails = ({ freeEnrollmentBasis.type !== EducationType.None && isFree; - const isEducationValid = EnrollmentUtils.isValidFreeBasisIfRequired( - enrollment, - freeEnrollmentDetails, - ); + const isEducationValid = + !!freeEnrollmentBasis && + EnrollmentUtils.isValidFreeBasisIfRequired( + enrollment, + freeEnrollmentDetails, + ); const isAttachmentsValid = EnrollmentUtils.isValidAttachmentsIfRequired(enrollment); @@ -396,26 +397,26 @@ export const EducationDetails = ({ }); return ( - EnrollmentUtils.hasFreeEnrollmentsLeft(freeEnrollmentDetails) && ( -
    -

    {t('educationInfoTitle')}

    - {isEducationLoading && showValidation && ( - - {t('errorWaitEducations')} - +
    + {isEducationLoading && showValidation && ( + + {t('errorWaitEducations')} + + )} + + {foundSuitableEducationDetails && ( + )} - - {foundSuitableEducationDetails && ( - - )} - {!isLoading && !isEducationLoading && !foundSuitableEducationDetails && ( @@ -434,7 +435,7 @@ export const EducationDetails = ({ )} )} -
    - ) + +
    ); }; From 92d8e27f3c215d83275a4c7930056dbfe8a6ce98 Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Fri, 23 Aug 2024 14:38:47 +0300 Subject: [PATCH 08/23] VKT(Frontend): Bump Cypress version --- frontend/package.json | 2 +- frontend/yarn.lock | 39 ++++++++++++++++++--------------------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 6991fa5a0..e4521b4bd 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -75,7 +75,7 @@ "compression-webpack-plugin": "^10.0.0", "copy-webpack-plugin": "^11.0.0", "css-loader": "^6.8.1", - "cypress": "^13.4.0", + "cypress": "^13.13.3", "eslint": "^8.53.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-webpack": "^0.13.8", diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 4354be0f4..85c19ad95 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1549,7 +1549,7 @@ __metadata: languageName: node linkType: hard -"@cypress/request@npm:^3.0.0": +"@cypress/request@npm:^3.0.1": version: 3.0.1 resolution: "@cypress/request@npm:3.0.1" dependencies: @@ -2637,7 +2637,7 @@ __metadata: compression-webpack-plugin: "npm:^10.0.0" copy-webpack-plugin: "npm:^11.0.0" css-loader: "npm:^6.8.1" - cypress: "npm:^13.4.0" + cypress: "npm:^13.13.3" dayjs: "npm:^1.11.10" eslint: "npm:^8.53.0" eslint-config-prettier: "npm:^9.0.0" @@ -3225,7 +3225,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:^18.17.5": +"@types/node@npm:*": version: 18.18.8 resolution: "@types/node@npm:18.18.8" dependencies: @@ -4678,7 +4678,7 @@ __metadata: languageName: node linkType: hard -"buffer@npm:^5.5.0, buffer@npm:^5.6.0": +"buffer@npm:^5.5.0, buffer@npm:^5.7.1": version: 5.7.1 resolution: "buffer@npm:5.7.1" dependencies: @@ -5441,19 +5441,18 @@ __metadata: languageName: node linkType: hard -"cypress@npm:^13.4.0": - version: 13.4.0 - resolution: "cypress@npm:13.4.0" +"cypress@npm:^13.13.3": + version: 13.13.3 + resolution: "cypress@npm:13.13.3" dependencies: - "@cypress/request": "npm:^3.0.0" + "@cypress/request": "npm:^3.0.1" "@cypress/xvfb": "npm:^1.2.4" - "@types/node": "npm:^18.17.5" "@types/sinonjs__fake-timers": "npm:8.1.1" "@types/sizzle": "npm:^2.3.2" arch: "npm:^2.2.0" blob-util: "npm:^2.0.2" bluebird: "npm:^3.7.2" - buffer: "npm:^5.6.0" + buffer: "npm:^5.7.1" cachedir: "npm:^2.3.0" chalk: "npm:^4.1.0" check-more-types: "npm:^2.24.0" @@ -5471,7 +5470,7 @@ __metadata: figures: "npm:^3.2.0" fs-extra: "npm:^9.1.0" getos: "npm:^3.2.1" - is-ci: "npm:^3.0.0" + is-ci: "npm:^3.0.1" is-installed-globally: "npm:~0.4.0" lazy-ass: "npm:^1.6.0" listr2: "npm:^3.8.3" @@ -5485,12 +5484,12 @@ __metadata: request-progress: "npm:^3.0.0" semver: "npm:^7.5.3" supports-color: "npm:^8.1.1" - tmp: "npm:~0.2.1" + tmp: "npm:~0.2.3" untildify: "npm:^4.0.0" yauzl: "npm:^2.10.0" bin: cypress: bin/cypress - checksum: 25423cde87e40c739b5de97ca418102d7b3f12289e67de163e309a483dd6982420c077a80733aad73cbda73ffd69aaace59e604623e635bd7996f9680a5f0145 + checksum: 8f4a7f27f4f3374247ef39be52027c1614f0447993d50dd83b98c4e5f1903fd9b506164cd5614bd03f2b5b1e604fb3bdb646530002bafda01e0510480530415f languageName: node linkType: hard @@ -8078,7 +8077,7 @@ __metadata: languageName: node linkType: hard -"is-ci@npm:^3.0.0": +"is-ci@npm:^3.0.1": version: 3.0.1 resolution: "is-ci@npm:3.0.1" dependencies: @@ -11466,7 +11465,7 @@ __metadata: languageName: node linkType: hard -"rimraf@npm:^3.0.0, rimraf@npm:^3.0.2": +"rimraf@npm:^3.0.2": version: 3.0.2 resolution: "rimraf@npm:3.0.2" dependencies: @@ -12622,12 +12621,10 @@ __metadata: languageName: node linkType: hard -"tmp@npm:~0.2.1": - version: 0.2.1 - resolution: "tmp@npm:0.2.1" - dependencies: - rimraf: "npm:^3.0.0" - checksum: 445148d72df3ce99356bc89a7857a0c5c3b32958697a14e50952c6f7cf0a8016e746ababe9a74c1aa52f04c526661992f14659eba34d3c6701d49ba2f3cf781b +"tmp@npm:~0.2.3": + version: 0.2.3 + resolution: "tmp@npm:0.2.3" + checksum: 7b13696787f159c9754793a83aa79a24f1522d47b87462ddb57c18ee93ff26c74cbb2b8d9138f571d2e0e765c728fb2739863a672b280528512c6d83d511c6fa languageName: node linkType: hard From 14114c305ccb0eb332101ae53e28632884d80278 Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Fri, 23 Aug 2024 14:39:49 +0300 Subject: [PATCH 09/23] VKT(Frontend): Fix tests [deploy] --- .../integration/public_enrollment.spec.ts | 52 ++++++++++++++----- .../public_free_enrollment.spec.ts | 26 ++++++---- .../page-objects/publicEnrollmentPage.ts | 45 +++++++++++++--- .../support/page-objects/publicHomePage.ts | 5 +- .../packages/vkt/src/tests/msw/handlers.ts | 2 +- 5 files changed, 98 insertions(+), 32 deletions(-) diff --git a/frontend/packages/vkt/src/tests/cypress/integration/public_enrollment.spec.ts b/frontend/packages/vkt/src/tests/cypress/integration/public_enrollment.spec.ts index 7d4f4c207..88ed678cd 100644 --- a/frontend/packages/vkt/src/tests/cypress/integration/public_enrollment.spec.ts +++ b/frontend/packages/vkt/src/tests/cypress/integration/public_enrollment.spec.ts @@ -60,6 +60,7 @@ describe('Public enrollment', () => { it('should be able to fill out enrollment info', () => { cy.tick(3000); + onPublicEnrollmentPage.expectStepHeading('Täytä yhteystietosi'); onPublicEnrollmentPage.expectEnrollmentPersonDetails( 'Sukunimi:TestiläEtunimet:Tessa', ); @@ -72,11 +73,7 @@ describe('Public enrollment', () => { 'test@test.invalid', ); onPublicEnrollmentPage.fillOutContactDetails('phoneNumber', '040112233'); - onPublicEnrollmentPage.clickNext(); - onPublicEnrollmentPage.checkEnrollmentPreviouslyEnrolledCheckbox( - 'previously-enrolled-no', - ); - onPublicEnrollmentPage.enrollmentFullExamCheckbox(); + onPublicEnrollmentPage.fillOutCertificateShippingDetails( 'street', 'Katu', @@ -94,6 +91,20 @@ describe('Public enrollment', () => { 'Suomi', ); onPublicEnrollmentPage.clickNext(); + + onPublicEnrollmentPage.expectStepHeading('Koulutustiedot'); + onPublicEnrollmentPage.selectRadioButton( + 'Ei perustetta maksuttomalle kielitutkinnolle', + ); + onPublicEnrollmentPage.clickNext(); + + onPublicEnrollmentPage.checkEnrollmentPreviouslyEnrolledRadio( + 'previously-enrolled-no', + ); + onPublicEnrollmentPage.enrollmentFullExamRadio(); + + onPublicEnrollmentPage.clickNext(); + onPublicEnrollmentPage.expectEnrollmentDetails( 'Tutkinto: Ruotsi, erinomainen taitoTutkintopäivä: 22.3.2022Ilmoittautuminen sulkeutuu: 15.3.2022Paikkoja vapaana: 6', ); @@ -148,13 +159,6 @@ describe('Public enrollment', () => { ); onPublicEnrollmentPage.fillOutContactDetails('phoneNumber', '040112233'); onPublicEnrollmentPage.expectContactDetailsErrorNotExist('phoneNumber'); - onPublicEnrollmentPage.clickNext(); - onPublicEnrollmentPage.clickNext(); - onPublicEnrollmentPage.expectPreviuoslyEnrolledError(); - onPublicEnrollmentPage.checkEnrollmentPreviouslyEnrolledCheckbox( - 'previously-enrolled-no', - ); - onPublicEnrollmentPage.expectPreviouslyEnrolledErrorNotExist(); onPublicEnrollmentPage.expectCertificateShippingDetailsError('street'); onPublicEnrollmentPage.fillOutCertificateShippingDetails( @@ -192,6 +196,30 @@ describe('Public enrollment', () => { ); onPublicEnrollmentPage.clickNext(); + onPublicEnrollmentPage.expectStepHeading('Koulutustiedot'); + onPublicEnrollmentPage.clickNext(); + onPublicEnrollmentPage.expectEducationDetailsError(); + onPublicEnrollmentPage.selectRadioButton( + 'Ei perustetta maksuttomalle kielitutkinnolle', + ); + onPublicEnrollmentPage.expectEducationDetailsErrorNotExist(); + onPublicEnrollmentPage.clickNext(); + + onPublicEnrollmentPage.expectStepHeading('Valitse tutkinto'); + onPublicEnrollmentPage.clickNext(); + onPublicEnrollmentPage.expectFullExamError(); + onPublicEnrollmentPage.enrollmentFullExamRadio(); + onPublicEnrollmentPage.expectFullExamErrorNotExist(); + + onPublicEnrollmentPage.expectPreviouslyEnrolledError(); + onPublicEnrollmentPage.checkEnrollmentPreviouslyEnrolledRadio( + 'previously-enrolled-no', + ); + onPublicEnrollmentPage.expectPreviouslyEnrolledErrorNotExist(); + + onPublicEnrollmentPage.clickNext(); + onPublicEnrollmentPage.expectStepHeading('Esikatsele'); + // TODO: test when consent error handling is added // onPublicEnrollmentPage.clickSubmit(); }); diff --git a/frontend/packages/vkt/src/tests/cypress/integration/public_free_enrollment.spec.ts b/frontend/packages/vkt/src/tests/cypress/integration/public_free_enrollment.spec.ts index 15059459f..7d1b337c5 100644 --- a/frontend/packages/vkt/src/tests/cypress/integration/public_free_enrollment.spec.ts +++ b/frontend/packages/vkt/src/tests/cypress/integration/public_free_enrollment.spec.ts @@ -4,22 +4,13 @@ import { examEventIdWithKoskiEducationDetailsFound } from 'tests/msw/fixtures/pu describe('Public enrollment without payment', () => { it('is possible when suitable education credentials are returned from KOSKI', () => { cy.openPublicEnrollmentPage(examEventIdWithKoskiEducationDetailsFound); - onPublicEnrollmentPage.expectTextContents( - 'Tietojemme mukaan olet suorittanut tai suorittamassa seuraavan tutkinnon:', - ); - onPublicEnrollmentPage.expectTextContents('Ylioppilastutkinto'); - + onPublicEnrollmentPage.expectStepHeading('Täytä yhteystietosi'); onPublicEnrollmentPage.fillOutContactDetails('email', 'test@test.invalid'); onPublicEnrollmentPage.fillOutContactDetails( 'emailConfirmation', 'test@test.invalid', ); onPublicEnrollmentPage.fillOutContactDetails('phoneNumber', '040112233'); - onPublicEnrollmentPage.clickNext(); - onPublicEnrollmentPage.checkEnrollmentPreviouslyEnrolledCheckbox( - 'previously-enrolled-no', - ); - onPublicEnrollmentPage.enrollmentFullExamCheckbox(); onPublicEnrollmentPage.fillOutCertificateShippingDetails('street', 'Katu'); onPublicEnrollmentPage.fillOutCertificateShippingDetails( 'postalCode', @@ -35,6 +26,21 @@ describe('Public enrollment without payment', () => { ); onPublicEnrollmentPage.clickNext(); + onPublicEnrollmentPage.expectStepHeading('Koulutustiedot'); + onPublicEnrollmentPage.expectTextContents( + 'Tietojemme mukaan olet suorittanut tai suorittamassa seuraavan tutkinnon:', + ); + onPublicEnrollmentPage.expectTextContents('Ylioppilastutkinto'); + onPublicEnrollmentPage.clickNext(); + + onPublicEnrollmentPage.expectStepHeading('Valitse tutkinto'); + onPublicEnrollmentPage.checkEnrollmentPreviouslyEnrolledRadio( + 'previously-enrolled-no', + ); + onPublicEnrollmentPage.enrollmentFullExamRadio(); + onPublicEnrollmentPage.clickNext(); + + onPublicEnrollmentPage.expectStepHeading('Esikatsele'); onPublicEnrollmentPage.expectPaymentSum('Maksuton'); }); }); diff --git a/frontend/packages/vkt/src/tests/cypress/support/page-objects/publicEnrollmentPage.ts b/frontend/packages/vkt/src/tests/cypress/support/page-objects/publicEnrollmentPage.ts index c8442ba9a..836b73dc2 100644 --- a/frontend/packages/vkt/src/tests/cypress/support/page-objects/publicEnrollmentPage.ts +++ b/frontend/packages/vkt/src/tests/cypress/support/page-objects/publicEnrollmentPage.ts @@ -24,15 +24,20 @@ class PublicEnrollmentPage { cy.findByTestId('public-enrollment__controlButtons__back'), submitButton: () => cy.findByTestId('public-enrollment__controlButtons__submit'), - enrollmentPreviouslyEnrolledCheckbox: (checkboxName: string) => - cy.findByTestId(`enrollment-checkbox-${checkboxName}`).find('span>input'), + enrollmentPreviouslyEnrolledRadio: (radioLabel: string) => + cy.findByTestId(`enrollment-checkbox-${radioLabel}`).find('span>input'), enrollmentPreviouslyEnrolledError: () => cy.get(`#has-previous-enrollment-error`), - enrollmentFullExamCheckbox: () => + enrollmentFullExamRadio: () => cy.findByTestId('enrollment-checkbox-full-exam').find('input'), + fullExamError: () => cy.get('#full-exam-error'), + educationDetailsError: () => cy.get('#has-select-education-error'), formTextContents: () => cy.get('div.public-enrollment__grid__form-container'), paymentSumHeading: () => cy.findByTestId('public-enrollment__payment-sum'), + stepHeading: (heading: string) => + cy.findByRole('heading', { name: heading }), + radioButton: (label: string) => cy.findByRole('radio', { name: label }), }; expectEnrollmentDetails(details: string) { @@ -64,7 +69,7 @@ class PublicEnrollmentPage { expectContactDetailsErrorNotExist(field: string) { this.elements.enrollmentContactDetailsFieldError(field).should('not.exist'); } - expectPreviuoslyEnrolledError() { + expectPreviouslyEnrolledError() { this.elements .enrollmentPreviouslyEnrolledError() .should('be.visible') @@ -84,6 +89,24 @@ class PublicEnrollmentPage { .enrollmentCertificateShippingDetailsError(field) .should('not.exist'); } + expectEducationDetailsError() { + this.elements + .educationDetailsError() + .should('be.visible') + .should('have.text', 'Tieto on pakollinen'); + } + expectEducationDetailsErrorNotExist() { + this.elements.educationDetailsError().should('not.exist'); + } + expectFullExamError() { + this.elements + .fullExamError() + .should('be.visible') + .should('have.text', 'Tieto on pakollinen'); + } + expectFullExamErrorNotExist() { + this.elements.fullExamError().should('not.exist'); + } fillOutContactDetails(field: string, details: string) { this.elements .enrollmentContactDetailsField(field) @@ -104,14 +127,14 @@ class PublicEnrollmentPage { clickSubmit() { this.elements.submitButton().should('be.visible').click(); } - checkEnrollmentPreviouslyEnrolledCheckbox(checkboxName: string) { + checkEnrollmentPreviouslyEnrolledRadio(radioName: string) { this.elements - .enrollmentPreviouslyEnrolledCheckbox(checkboxName) + .enrollmentPreviouslyEnrolledRadio(radioName) .should('be.exist') .check(); } - enrollmentFullExamCheckbox() { - this.elements.enrollmentFullExamCheckbox().should('be.exist').check(); + enrollmentFullExamRadio() { + this.elements.enrollmentFullExamRadio().should('be.exist').check(); } expectTextContents(contents: string) { this.elements.formTextContents().should('contain.text', contents); @@ -119,6 +142,12 @@ class PublicEnrollmentPage { expectPaymentSum(sum: string) { this.elements.paymentSumHeading().should('contain.text', sum); } + expectStepHeading(heading: string) { + this.elements.stepHeading(heading).should('be.visible'); + } + selectRadioButton(label: string) { + this.elements.radioButton(label).click(); + } } export const onPublicEnrollmentPage = new PublicEnrollmentPage(); diff --git a/frontend/packages/vkt/src/tests/cypress/support/page-objects/publicHomePage.ts b/frontend/packages/vkt/src/tests/cypress/support/page-objects/publicHomePage.ts index e0017f351..41f1fa9c9 100644 --- a/frontend/packages/vkt/src/tests/cypress/support/page-objects/publicHomePage.ts +++ b/frontend/packages/vkt/src/tests/cypress/support/page-objects/publicHomePage.ts @@ -9,7 +9,10 @@ class PublicHomePage { examEventRow: (id: number) => cy.findByTestId(row(id)), examEventRowCheckbox: (id: number) => cy.findByTestId(row(id)).find('input[type=checkbox]'), - examEventRows: () => cy.get('.public-homepage__grid-container__result-box').find('table > tbody > tr'), + examEventRows: () => + cy + .get('.public-homepage__grid-container__result-box') + .find('table > tbody > tr'), languageFilter: () => cy.findByTestId('exam-events__language-filter'), reservationTimerText: () => cy.findByTestId('public-enrollment__reservation-timer-text'), diff --git a/frontend/packages/vkt/src/tests/msw/handlers.ts b/frontend/packages/vkt/src/tests/msw/handlers.ts index 9dcf9bdd2..a04a7d71c 100644 --- a/frontend/packages/vkt/src/tests/msw/handlers.ts +++ b/frontend/packages/vkt/src/tests/msw/handlers.ts @@ -37,7 +37,7 @@ export const handlers = [ http.get(APIEndpoints.PublicEducation, ({ request }) => { if ( request.referrer.endsWith( - `/vkt/ilmoittaudu/${examEventIdWithKoskiEducationDetailsFound}/tiedot`, + `/vkt/ilmoittaudu/${examEventIdWithKoskiEducationDetailsFound}/koulutus`, ) ) { return new Response( From 3940cfb8986d38c7be6a35822571c9cf6250f7ac Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Mon, 26 Aug 2024 12:51:47 +0300 Subject: [PATCH 10/23] SHARED(Frontend): Include a file drop zone by default on desktop with the FileUpload component --- frontend/packages/shared/CHANGELOG.MD | 5 +++ frontend/packages/shared/package.json | 2 +- .../src/components/FileUpload/FileUpload.scss | 42 +++++++++++-------- .../src/components/FileUpload/FileUpload.tsx | 34 +++++++++++---- 4 files changed, 57 insertions(+), 26 deletions(-) diff --git a/frontend/packages/shared/CHANGELOG.MD b/frontend/packages/shared/CHANGELOG.MD index c1ebf84a9..5f3483021 100644 --- a/frontend/packages/shared/CHANGELOG.MD +++ b/frontend/packages/shared/CHANGELOG.MD @@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Released] +## [1.10.8] - 2024-08-26 + +### Changed +- Include a file drop zone by default on desktop with the file upload component + ## [1.10.7] - 2024-08-07 ### Added diff --git a/frontend/packages/shared/package.json b/frontend/packages/shared/package.json index a2a8b5290..952ef52b3 100644 --- a/frontend/packages/shared/package.json +++ b/frontend/packages/shared/package.json @@ -1,6 +1,6 @@ { "name": "@opetushallitus/kieli-ja-kaantajatutkinnot.shared", - "version": "1.10.7", + "version": "1.10.8", "description": "Shared Frontend Package", "exports": { "./components": "./src/components/index.tsx", diff --git a/frontend/packages/shared/src/components/FileUpload/FileUpload.scss b/frontend/packages/shared/src/components/FileUpload/FileUpload.scss index 9cf928bd0..0ed6930f7 100644 --- a/frontend/packages/shared/src/components/FileUpload/FileUpload.scss +++ b/frontend/packages/shared/src/components/FileUpload/FileUpload.scss @@ -2,24 +2,30 @@ @use '../../styles/abstracts/colors'; @use '../../styles/abstracts/maps'; -.custom-fileupload input { - width: fit-content; - border: 1px dashed colors.$color-secondary; - font-size: 120%; - display: none; -} - -.custom-fileupload.file-upload-error input { - border: 1px dashed colors.$color-red-500; -} +.custom-fileupload { + input { + display: none; + } -.custom-fileupload.file-upload-error input::file-selector-button { - background: colors.$color-red-500; -} + &.file-upload-error { + .file-dropzone { + border-top: 1px dashed colors.$color-red-500; + border-right: 1px dashed colors.$color-red-500; + border-bottom: 1px dashed colors.$color-red-500; + p { + color: colors.$color-red-500; + } + } + } -.custom-fileupload input::file-selector-button { - background: colors.$color-secondary; - border: 1px solid colors.$color-primary; - color: colors.$color-primary; - padding: 10px; + .file-dropzone { + align-content: center; + height: 100%; + border-top: 1px dashed colors.$color-secondary; + border-right: 1px dashed colors.$color-secondary; + border-bottom: 1px dashed colors.$color-secondary; + padding-left: 1vw; + padding-right: 10vw; + cursor: copy; + } } diff --git a/frontend/packages/shared/src/components/FileUpload/FileUpload.tsx b/frontend/packages/shared/src/components/FileUpload/FileUpload.tsx index 51069b115..c948618b6 100644 --- a/frontend/packages/shared/src/components/FileUpload/FileUpload.tsx +++ b/frontend/packages/shared/src/components/FileUpload/FileUpload.tsx @@ -1,33 +1,39 @@ import FileUploadIcon from '@mui/icons-material/FileUpload'; import { Button } from '@mui/material'; -import { ChangeEvent, FC } from 'react'; +import { ChangeEvent, DragEvent, FC } from 'react'; + import './FileUpload.scss'; +import { Text } from '../../components'; import { Color, Variant } from '../../enums'; +import { useWindowProperties } from '../../hooks'; type FileUploadProps = { accept?: string; error?: boolean; onChange: (files: FileList) => void; - labelText: string; + buttonText: string; + dropZoneText: string; }; export const FileUpload: FC = ({ accept, onChange, error, - labelText, + buttonText, + dropZoneText, }) => { const handleChange = (event: ChangeEvent) => { if (event.target.files) { onChange(event.target.files); } }; + const { isPhone } = useWindowProperties(); return (
    + {!isPhone && ( +
    ) => { + e.preventDefault(); + }} + onDrop={(e: DragEvent) => { + e.preventDefault(); + onChange(e.dataTransfer.files); + }} + > + {dropZoneText} +
    + )}
    ); }; From d51433d1922f8d32c72473b02f5c42c2f5c9c269 Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Mon, 26 Aug 2024 12:52:44 +0300 Subject: [PATCH 11/23] VKT(Frontend): Take updated FileUpload component into use [deploy] --- frontend/packages/vkt/package.json | 2 +- frontend/packages/vkt/public/i18n/fi-FI/public.json | 3 ++- frontend/packages/vkt/public/i18n/sv-SE/public.json | 3 ++- .../components/publicEnrollment/steps/EducationDetails.tsx | 3 ++- frontend/yarn.lock | 4 ++-- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/frontend/packages/vkt/package.json b/frontend/packages/vkt/package.json index 022a3ef06..689951db3 100644 --- a/frontend/packages/vkt/package.json +++ b/frontend/packages/vkt/package.json @@ -26,6 +26,6 @@ }, "dependencies": { "reduxjs-toolkit-persist": "^7.2.1", - "shared": "npm:@opetushallitus/kieli-ja-kaantajatutkinnot.shared@1.10.7" + "shared": "npm:@opetushallitus/kieli-ja-kaantajatutkinnot.shared@1.10.8" } } diff --git a/frontend/packages/vkt/public/i18n/fi-FI/public.json b/frontend/packages/vkt/public/i18n/fi-FI/public.json index 87648c41e..12853fdf3 100644 --- a/frontend/packages/vkt/public/i18n/fi-FI/public.json +++ b/frontend/packages/vkt/public/i18n/fi-FI/public.json @@ -195,7 +195,8 @@ "helpText2": "Opetushallituksen virkailija tarkastaa, täyttävätkö lähettämäsi asiakirjat maksuttomuuden ehdot.", "maxAttachmentsReached": "Olet lisännyt jo 10 asiakirjaa. Et voi enää lisätä uusia asiakirjoja.", "title": "Lähetä tutkintotodistus tai opiskelutodistus *", - "uploadFile": "Lähetä tiedosto" + "uploadFile": "Lähetä tiedosto", + "dropFile": "Pudota tiedosto tähän" } }, "preview": { diff --git a/frontend/packages/vkt/public/i18n/sv-SE/public.json b/frontend/packages/vkt/public/i18n/sv-SE/public.json index 58e42d69b..2afb6edc6 100644 --- a/frontend/packages/vkt/public/i18n/sv-SE/public.json +++ b/frontend/packages/vkt/public/i18n/sv-SE/public.json @@ -196,7 +196,8 @@ "helpText2": "Dina dokument granskas på Utbildningsstyrelsen.", "maxAttachmentsReached": "Du har redan bifogat tio dokument. Du kan inte lägga till fler dokument.", "title": "Skicka examensintyg eller studieintyg *", - "uploadFile": "Skicka filen" + "uploadFile": "Skicka filen", + "dropFile": "Släpp filen här" } }, "preview": { diff --git a/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx b/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx index 6fa3e1417..1070741a4 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx @@ -193,7 +193,8 @@ const UploadAttachments = ({ accept="application/pdf,image/jpeg,image/png,image/heic,image/tiff,image/webp" onChange={handleFileUpload} error={showError} - labelText={t('uploadFile')} + buttonText={t('uploadFile')} + dropZoneText={t('dropFile')} /> )} diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 85c19ad95..75a9953f1 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -2687,7 +2687,7 @@ __metadata: languageName: unknown linkType: soft -"@opetushallitus/kieli-ja-kaantajatutkinnot.shared@workspace:packages/shared, shared@npm:@opetushallitus/kieli-ja-kaantajatutkinnot.shared@1.10.7": +"@opetushallitus/kieli-ja-kaantajatutkinnot.shared@workspace:packages/shared, shared@npm:@opetushallitus/kieli-ja-kaantajatutkinnot.shared@1.10.8": version: 0.0.0-use.local resolution: "@opetushallitus/kieli-ja-kaantajatutkinnot.shared@workspace:packages/shared" languageName: unknown @@ -2698,7 +2698,7 @@ __metadata: resolution: "@opetushallitus/kieli-ja-kaantajatutkinnot.vkt@workspace:packages/vkt" dependencies: reduxjs-toolkit-persist: "npm:^7.2.1" - shared: "npm:@opetushallitus/kieli-ja-kaantajatutkinnot.shared@1.10.7" + shared: "npm:@opetushallitus/kieli-ja-kaantajatutkinnot.shared@1.10.8" languageName: unknown linkType: soft From 43daae8242f62bc980bb6b2a8ee9f6f9792a01a9 Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Tue, 27 Aug 2024 11:49:47 +0300 Subject: [PATCH 12/23] VKT(Frontend): Minor fixes [deploy] --- frontend/packages/vkt/public/i18n/fi-FI/common.json | 2 +- frontend/packages/vkt/public/i18n/fi-FI/public.json | 2 +- frontend/packages/vkt/public/i18n/sv-SE/common.json | 2 +- .../components/publicExamEvent/PublicExamEventGrid.tsx | 10 ++++++++-- .../vkt/src/styles/pages/_public-homepage.scss | 3 ++- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/frontend/packages/vkt/public/i18n/fi-FI/common.json b/frontend/packages/vkt/public/i18n/fi-FI/common.json index 41f84649a..982a98a75 100644 --- a/frontend/packages/vkt/public/i18n/fi-FI/common.json +++ b/frontend/packages/vkt/public/i18n/fi-FI/common.json @@ -108,7 +108,7 @@ } }, "info": { - "previousEnrollment": "Voit suorittaa suullisen ja kirjallisen taidon tutkinnot joko samalla kertaa tai osissa eri suorituskertojen aikana. Jos suoritat tutkinnon osissa, sinulla on kolme vuotta aikaa suorittaa koko tutkinto loppuun. Aika lasketaan ensimmäisen osan suorittamispäivästä alkaen.", + "previousEnrollment": "<0>Voit suorittaa suullisen ja kirjallisen taidon tutkinnot joko samalla kertaa tai osissa eri suorituskertojen aikana. Jos suoritat tutkinnon osissa, <1>sinulla on kolme vuotta aikaa suorittaa koko tutkinto loppuun. Aika lasketaan ensimmäisen osan suorittamispäivästä alkaen.", "selectExam": "Kun olet suorittanut hyväksytysti suullisen ja kirjallisen taidon tutkinnot, saat todistukseen merkinnän myös ymmärtämisen taidon tutkinnon suorittamisesta." }, "languageFilter": { diff --git a/frontend/packages/vkt/public/i18n/fi-FI/public.json b/frontend/packages/vkt/public/i18n/fi-FI/public.json index 12853fdf3..9cccd63f3 100644 --- a/frontend/packages/vkt/public/i18n/fi-FI/public.json +++ b/frontend/packages/vkt/public/i18n/fi-FI/public.json @@ -254,7 +254,7 @@ }, "enrollment": { "link": { - "label": "Opetushallituksen verkkosivulla.", + "label": "Opetushallituksen verkkosivuilla.", "url": "https://www.oph.fi/fi/koulutus-ja-tutkinnot/erinomaisen-taidon-tutkinnot" }, "part1": "<0>Ilmoittautumista varten sinun täytyy tunnistautua suomi.fi-palvelun kautta.", diff --git a/frontend/packages/vkt/public/i18n/sv-SE/common.json b/frontend/packages/vkt/public/i18n/sv-SE/common.json index 31b67ca63..73db44729 100644 --- a/frontend/packages/vkt/public/i18n/sv-SE/common.json +++ b/frontend/packages/vkt/public/i18n/sv-SE/common.json @@ -108,7 +108,7 @@ } }, "info": { - "previousEnrollment": "Du kan avlägga examina som gäller förmåga att använda språket i tal och skrift antingen vid ett och samma tillfälle eller i delar under olika tillfällen. Om du avlägger examen i delar, ska du avlägga hela examen inom tre års tid från och med det datum när du avlade den första examen.", + "previousEnrollment": "<0>Du kan avlägga examina som gäller förmåga att använda språket i tal och skrift antingen vid ett och samma tillfälle eller i delar under olika tillfällen. Om du avlägger examen i delar, <1>ska du avlägga hela examen inom tre års tid från och med det datum när du avlade den första examen.", "selectExam": "När du har blivit godkänd i examina som gäller förmåga att använda språket i tal och i skrift får du ett intyg även för förmågan att förstå språket." }, "languageFilter": { diff --git a/frontend/packages/vkt/src/components/publicExamEvent/PublicExamEventGrid.tsx b/frontend/packages/vkt/src/components/publicExamEvent/PublicExamEventGrid.tsx index 6b7e29db6..733b5d178 100644 --- a/frontend/packages/vkt/src/components/publicExamEvent/PublicExamEventGrid.tsx +++ b/frontend/packages/vkt/src/components/publicExamEvent/PublicExamEventGrid.tsx @@ -65,7 +65,13 @@ const DescriptionBox = () => {
    {translateCommon('info.selectExam')} - {translateCommon('info.previousEnrollment')} + + , ]} + > +
    ); @@ -168,7 +174,7 @@ export const PublicExamEventGrid = () => {
    diff --git a/frontend/packages/vkt/src/styles/pages/_public-homepage.scss b/frontend/packages/vkt/src/styles/pages/_public-homepage.scss index d8ffb2002..dbd87ebaf 100644 --- a/frontend/packages/vkt/src/styles/pages/_public-homepage.scss +++ b/frontend/packages/vkt/src/styles/pages/_public-homepage.scss @@ -25,13 +25,14 @@ & &__info-box { background-color: $color-blue-200; + border-radius: 4px; @include phone { padding: 2rem 1rem; } @include not-phone { - padding: 3rem 1rem; + padding: 3rem 2rem; } } } From ecb1f4794971247feafa97c3f91d050e550fd6ce Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Mon, 2 Sep 2024 16:01:21 +0300 Subject: [PATCH 13/23] VKT(Frontend): Try to fix focusing on stepper heading --- .../publicEnrollment/PublicEnrollmentStepHeading.tsx | 12 +++++++++++- .../publicEnrollment/PublicEnrollmentStepper.tsx | 6 ------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentStepHeading.tsx b/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentStepHeading.tsx index 3f1230a19..2701d7cbd 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentStepHeading.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentStepHeading.tsx @@ -1,4 +1,6 @@ +import { useEffect } from 'react'; import { H1, HeaderSeparator } from 'shared/components'; +import { useFocus, useWindowProperties } from 'shared/hooks'; import { usePublicTranslation } from 'configs/i18n'; import { PublicEnrollmentFormStep } from 'enums/publicEnrollment'; @@ -13,6 +15,14 @@ export const PublicEnrollmentStepHeading = ({ const { t } = usePublicTranslation({ keyPrefix: 'vkt.component.publicEnrollment.stepHeading', }); + const [ref, setFocus] = useFocus(); + const { isPhone } = useWindowProperties(); + + useEffect(() => { + if (!isPhone) { + setFocus(); + } + }, [setFocus, isPhone]); const headingText = activeStep === PublicEnrollmentFormStep.Authenticate @@ -22,7 +32,7 @@ export const PublicEnrollmentStepHeading = ({ : t(`common.${PublicEnrollmentFormStep[activeStep]}`); return ( -
    +

    {headingText}

    diff --git a/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentStepper.tsx b/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentStepper.tsx index 82334a585..7cc156c60 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentStepper.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentStepper.tsx @@ -1,5 +1,4 @@ import { Step, StepLabel, Stepper } from '@mui/material'; -import { useEffect } from 'react'; import { CircularStepper } from 'shared/components'; import { Color } from 'shared/enums'; import { useWindowProperties } from 'shared/hooks'; @@ -15,11 +14,6 @@ export const PublicEnrollmentStepper = ({ activeStep: PublicEnrollmentFormStep; includePaymentStep: boolean; }) => { - useEffect(() => { - document - .getElementById(`public-enrollment-step-label-${activeStep}`) - ?.focus(); - }, [activeStep]); const { isPhone } = useWindowProperties(); const { t } = usePublicTranslation({ From 1a392f6b7e52e3caca0a91f77229e2f58695ffc9 Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Mon, 2 Sep 2024 17:45:40 +0300 Subject: [PATCH 14/23] VKT(Frontend): Add dividers between sections of preview page, move address details together with other contact details [deploy] --- .../publicEnrollment/steps/Preview.tsx | 92 ++++++------------- 1 file changed, 30 insertions(+), 62 deletions(-) diff --git a/frontend/packages/vkt/src/components/publicEnrollment/steps/Preview.tsx b/frontend/packages/vkt/src/components/publicEnrollment/steps/Preview.tsx index c333717f8..327db03a7 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/steps/Preview.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/steps/Preview.tsx @@ -1,5 +1,10 @@ import OpenInNewIcon from '@mui/icons-material/OpenInNew'; -import { Checkbox, FormControlLabel, FormHelperText } from '@mui/material'; +import { + Checkbox, + Divider, + FormControlLabel, + FormHelperText, +} from '@mui/material'; import { useEffect } from 'react'; import { Trans } from 'react-i18next'; import { H2, Text, WebLink } from 'shared/components'; @@ -59,27 +64,22 @@ const EducationDetails = ({ ); }; -const ContactDetails = ({ - email, - phoneNumber, -}: { - email: string; - phoneNumber: string; -}) => { +const ContactDetails = ({ enrollment }: { enrollment: PublicEnrollment }) => { const { t } = usePublicTranslation({ keyPrefix: 'vkt.component.publicEnrollment.steps.preview.contactDetails', }); + const translateCommon = useCommonTranslation(); return (

    {t('title')}

    -
    +
    {t('email')} {':'} - {email} + {enrollment.email}
    @@ -87,57 +87,24 @@ const ContactDetails = ({ {':'} - {phoneNumber} + {enrollment.phoneNumber}
    -
    -
    - ); -}; - -const CertificateShippingDetails = ({ - enrollment, -}: { - enrollment: PublicEnrollment; -}) => { - const { t } = usePublicTranslation({ - keyPrefix: - 'vkt.component.publicEnrollment.steps.preview.certificateShippingDetails', - }); - const translateCommon = useCommonTranslation(); - - const digitalConsentEnabled = false; - - return ( -
    -

    {t('title')}

    - {digitalConsentEnabled && ( -
    +
    - {translateCommon('enrollment.certificateShipping.consent')} + {translateCommon('enrollment.certificateShipping.addressTitle')} {':'} - - {enrollment.digitalCertificateConsent - ? translateCommon('yes') - : translateCommon('no')} + + {enrollment.street} + {', '} + {enrollment.postalCode} + {', '} + {enrollment.town} + {', '} + {enrollment.country}
    - )} -
    - - {t('addressLabel')} - {':'} - - - {enrollment.street} - {', '} - {enrollment.postalCode} - {', '} - {enrollment.town} - {', '} - {enrollment.country} -
    ); @@ -205,19 +172,20 @@ export const Preview = ({
    - + {EnrollmentUtils.hasFreeBasis(enrollment) && enrollment.freeEnrollmentBasis && ( - + <> + + + )}
    + - +

    {translateCommon('acceptTerms')}

    From e5e40ba925a5425c41c01b3506648ae0a57aea00 Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Mon, 2 Sep 2024 17:56:55 +0300 Subject: [PATCH 15/23] VKT(Frontend): Fix translation string [deploy] --- frontend/packages/vkt/public/i18n/fi-FI/public.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/packages/vkt/public/i18n/fi-FI/public.json b/frontend/packages/vkt/public/i18n/fi-FI/public.json index 9cccd63f3..f86d58f20 100644 --- a/frontend/packages/vkt/public/i18n/fi-FI/public.json +++ b/frontend/packages/vkt/public/i18n/fi-FI/public.json @@ -244,7 +244,7 @@ "publicExamEventGrid": { "description": { "bulletPoints": { - "point1": "<0>suullisen taidon tutkinto (= puhumisen ja puheen ymmärtämisen osakokeet)", + "point1": "<0>suullisen taidon tutkinto (= puhumisen ja puheen ymmärtämisen osakokeet)", "point2": "<0>kirjallisen taidon tutkinto (= kirjoittamisen ja tekstin ymmärtämisen osakokeet)", "point3": "<0>ymmärtämisen taidon tutkinto (= tekstin ymmärtämisen ja puheen ymmärtämisen osakokeet)" }, From ccb907a673e5bf0425f2c2930bebcc2985714651 Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Thu, 5 Sep 2024 16:57:57 +0300 Subject: [PATCH 16/23] VKT(Frontend): Show UploadAttachments also when user has run out of free enrollments --- .../components/publicEnrollment/steps/EducationDetails.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx b/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx index 1070741a4..5cab918f9 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/steps/EducationDetails.tsx @@ -350,7 +350,7 @@ export const EducationDetails = ({ const { status: educationStatus, education: educations } = useAppSelector( publicEducationSelector, ); - const { isFree, freeEnrollmentBasis } = enrollment; + const { freeEnrollmentBasis } = enrollment; useEffect(() => { if (educationStatus === APIResponseStatus.NotStarted) { @@ -367,8 +367,8 @@ export const EducationDetails = ({ const attachmentsRequired = freeEnrollmentBasis && - freeEnrollmentBasis.type !== EducationType.None && - isFree; + freeEnrollmentBasis.source === FreeBasisSource.User && + freeEnrollmentBasis.type !== EducationType.None; const isEducationValid = !!freeEnrollmentBasis && From 3839ab50ba599a85b6a07ac33250bdfdf7e48bac Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Thu, 5 Sep 2024 16:58:31 +0300 Subject: [PATCH 17/23] VKT(Frontend): Fix error handling when using fetch to POST instead of axios [deploy] --- frontend/packages/vkt/src/redux/sagas/publicFileUpload.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/packages/vkt/src/redux/sagas/publicFileUpload.ts b/frontend/packages/vkt/src/redux/sagas/publicFileUpload.ts index 45d1e43a2..101cd0f4c 100644 --- a/frontend/packages/vkt/src/redux/sagas/publicFileUpload.ts +++ b/frontend/packages/vkt/src/redux/sagas/publicFileUpload.ts @@ -80,10 +80,14 @@ function* startFileUploadSaga( // For some reason trying to POST with axios couldn't be made to work - // according to S3 error, enctype=multipart/form-data was not set, no matter what. // Using fetch however works fine. - yield call(fetch, bucketURI, { + + const response: Response = yield call(fetch, bucketURI, { method: 'POST', body: formData, }); + if (!response.ok) { + throw new Error(`POSTing to s3 failed, status: ${response.status}`); + } yield put(acceptFileUpload()); yield put( storeUploadedFileAttachment({ From d5f36789b0c38f687e2622a402cda0533bea5dc6 Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Fri, 6 Sep 2024 12:53:39 +0300 Subject: [PATCH 18/23] VKT(Frontend): Improve enrollment preview step layout --- .../steps/FillContactDetails.tsx | 2 +- .../publicEnrollment/steps/PersonDetails.tsx | 10 +++++-- .../publicEnrollment/steps/Preview.tsx | 26 +++++++++---------- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/frontend/packages/vkt/src/components/publicEnrollment/steps/FillContactDetails.tsx b/frontend/packages/vkt/src/components/publicEnrollment/steps/FillContactDetails.tsx index a89dfedfd..1ccc318d1 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/steps/FillContactDetails.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/steps/FillContactDetails.tsx @@ -157,7 +157,7 @@ export const FillContactDetails = ({ return (
    - +

    {t('title')}

    {translateCommon('requiredFieldsInfo')} diff --git a/frontend/packages/vkt/src/components/publicEnrollment/steps/PersonDetails.tsx b/frontend/packages/vkt/src/components/publicEnrollment/steps/PersonDetails.tsx index ab8bc59c6..55d9525a1 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/steps/PersonDetails.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/steps/PersonDetails.tsx @@ -5,7 +5,11 @@ import { useAppSelector } from 'configs/redux'; import { PublicPerson } from 'interfaces/publicPerson'; import { publicEnrollmentSelector } from 'redux/selectors/publicEnrollment'; -export const PersonDetails = () => { +export const PersonDetails = ({ + isPreviewStep, +}: { + isPreviewStep: boolean; +}) => { const { t } = usePublicTranslation({ keyPrefix: 'vkt.component.publicEnrollment.steps.personDetails', }); @@ -30,7 +34,9 @@ export const PersonDetails = () => {

    {t('title')}

    {displayField('lastName')} diff --git a/frontend/packages/vkt/src/components/publicEnrollment/steps/Preview.tsx b/frontend/packages/vkt/src/components/publicEnrollment/steps/Preview.tsx index 327db03a7..799cf913f 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/steps/Preview.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/steps/Preview.tsx @@ -73,7 +73,7 @@ const ContactDetails = ({ enrollment }: { enrollment: PublicEnrollment }) => { return (

    {t('title')}

    -
    +
    {t('email')} @@ -170,19 +170,17 @@ export const Preview = ({ return (
    -
    - - - {EnrollmentUtils.hasFreeBasis(enrollment) && - enrollment.freeEnrollmentBasis && ( - <> - - - - )} -
    + + + {EnrollmentUtils.hasFreeBasis(enrollment) && + enrollment.freeEnrollmentBasis && ( + <> + + + + )} From 3c779b439c07ed71dcca08e75d8bf1b0038a4545 Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Fri, 6 Sep 2024 12:54:42 +0300 Subject: [PATCH 19/23] VKT(Frontend): Fix overflow of privacy checkbox label on mobile --- .../components/publicEnrollment/_public-enrollment.scss | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/packages/vkt/src/styles/components/publicEnrollment/_public-enrollment.scss b/frontend/packages/vkt/src/styles/components/publicEnrollment/_public-enrollment.scss index d1bff2437..33de1b945 100644 --- a/frontend/packages/vkt/src/styles/components/publicEnrollment/_public-enrollment.scss +++ b/frontend/packages/vkt/src/styles/components/publicEnrollment/_public-enrollment.scss @@ -79,8 +79,10 @@ padding-left: 1rem; width: 70%; - & span:last-child { - margin-bottom: -3rem; + @include not-phone { + & span:last-child { + margin-bottom: -3rem; + } } } } From 908980231d4763c9b7cf0c10dc06463a8eb38bc6 Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Fri, 6 Sep 2024 13:05:35 +0300 Subject: [PATCH 20/23] VKT(Frontend): Allow step contents to grow more on phone, add some more padding as a hack [deploy] --- .../components/publicEnrollment/PublicEnrollmentPhoneGrid.tsx | 2 +- .../styles/components/publicEnrollment/_public-enrollment.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentPhoneGrid.tsx b/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentPhoneGrid.tsx index 72244e2c7..93792a7a4 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentPhoneGrid.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/PublicEnrollmentPhoneGrid.tsx @@ -156,7 +156,7 @@ export const PublicEnrollmentPhoneGrid = ({
    Date: Fri, 6 Sep 2024 14:22:49 +0300 Subject: [PATCH 21/23] VKT(Backend): Fix saving files to localstack on Linux [deploy] Instant.now() may set time with nanosecond precision, depending on platform. At least the Localstack S3 implementation requires pre-signed url expiration timestamp precision be six null-padded microsecond digits. Overwriting expiration timestamp microsecond part to 000001 fixes this problem. Localstack implementation is: POLICY_EXPIRATION_FORMAT2 = "%Y-%m-%dT%H:%M:%S.%fZ" https://github.com/localstack/localstack/blob/0b4846bc9b28247a2156fce40fcdd61da74b9d76/localstack-core/localstack/services/s3/presigned_url.py#L87 --- backend/vkt/src/main/java/fi/oph/vkt/service/aws/S3Service.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/vkt/src/main/java/fi/oph/vkt/service/aws/S3Service.java b/backend/vkt/src/main/java/fi/oph/vkt/service/aws/S3Service.java index 3ffa6aa3f..9cf78f8f2 100644 --- a/backend/vkt/src/main/java/fi/oph/vkt/service/aws/S3Service.java +++ b/backend/vkt/src/main/java/fi/oph/vkt/service/aws/S3Service.java @@ -68,7 +68,7 @@ public Map getPresignedPostRequest(String key, String extension) S3PostObjectRequest.Builder requestBuilder = S3PostObjectRequest .builder() .bucket(s3Config.getBucketName()) - .expiration(POST_POLICY_VALID_FOR_ONE_MIN) + .expiration(Instant.now().with(ChronoField.MICRO_OF_SECOND, 1).plus(POST_POLICY_VALID_FOR_ONE_MIN)) .withCondition(Conditions.keyStartsWith(key)) .withCondition(Conditions.contentLengthRange(0, MAX_SIZE_100_MB)) .withCondition(Conditions.contentTypeHeaderEquals(contentType)) From 8fd24b84f8f44904a5aaed314ec0f4a310ef0c73 Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Fri, 6 Sep 2024 16:04:46 +0300 Subject: [PATCH 22/23] VKT(Backend): Add missing imports [deploy] --- backend/vkt/src/main/java/fi/oph/vkt/service/aws/S3Service.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/vkt/src/main/java/fi/oph/vkt/service/aws/S3Service.java b/backend/vkt/src/main/java/fi/oph/vkt/service/aws/S3Service.java index 9cf78f8f2..7304d38ad 100644 --- a/backend/vkt/src/main/java/fi/oph/vkt/service/aws/S3Service.java +++ b/backend/vkt/src/main/java/fi/oph/vkt/service/aws/S3Service.java @@ -3,9 +3,11 @@ import fi.oph.vkt.util.exception.APIException; import fi.oph.vkt.util.exception.APIExceptionType; import java.time.Duration; +import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoField; import java.util.HashMap; import java.util.Map; import lombok.RequiredArgsConstructor; From 2554b41a9ab7dfb661535810776ed9031fd134ac Mon Sep 17 00:00:00 2001 From: Pyry Koivisto Date: Fri, 6 Sep 2024 16:51:10 +0300 Subject: [PATCH 23/23] VKT(Frontend): Rework enrollment preview structure on mobile to better match designs [deploy] --- .../vkt/public/i18n/fi-FI/public.json | 7 +- .../vkt/public/i18n/sv-SE/public.json | 7 +- .../steps/ExamEventDetails.tsx | 246 +++++++++++++----- 3 files changed, 198 insertions(+), 62 deletions(-) diff --git a/frontend/packages/vkt/public/i18n/fi-FI/public.json b/frontend/packages/vkt/public/i18n/fi-FI/public.json index f86d58f20..e2e59e47e 100644 --- a/frontend/packages/vkt/public/i18n/fi-FI/public.json +++ b/frontend/packages/vkt/public/i18n/fi-FI/public.json @@ -217,7 +217,12 @@ }, "examEventDetails": { "previousEnrollmentLabel": "Aikaisempiin erinomaisen taidon tutkintoihin osallistuminen", - "selectedSkillsLabel": "Valitut tutkinnot", + "desktop": { + "selectedSkillsLabel": "Valitut tutkinnot" + }, + "phone": { + "selectedSkillLabel": "Valittu tutkinto" + }, "selectedPartialExamsLabel": "Valitut osakokeet", "title": "Tutkinnon tiedot" }, diff --git a/frontend/packages/vkt/public/i18n/sv-SE/public.json b/frontend/packages/vkt/public/i18n/sv-SE/public.json index 2afb6edc6..f730dbcb2 100644 --- a/frontend/packages/vkt/public/i18n/sv-SE/public.json +++ b/frontend/packages/vkt/public/i18n/sv-SE/public.json @@ -218,7 +218,12 @@ }, "examEventDetails": { "previousEnrollmentLabel": "Deltagande i tidigare språkexamina för statsförvaltingen som gäller utmärkta språkkunskaper", - "selectedSkillsLabel": "Valda examina", + "desktop": { + "selectedSkillsLabel": "Valda examina" + }, + "phone": { + "selectedSkillLabel": "Valt examen" + }, "selectedPartialExamsLabel": "Valda delprov", "title": "Uppgifter om examen" }, diff --git a/frontend/packages/vkt/src/components/publicEnrollment/steps/ExamEventDetails.tsx b/frontend/packages/vkt/src/components/publicEnrollment/steps/ExamEventDetails.tsx index 93df7c095..401c9ca4b 100644 --- a/frontend/packages/vkt/src/components/publicEnrollment/steps/ExamEventDetails.tsx +++ b/frontend/packages/vkt/src/components/publicEnrollment/steps/ExamEventDetails.tsx @@ -1,85 +1,87 @@ +import { Divider } from '@mui/material'; import { H2, Text } from 'shared/components'; +import { useWindowProperties } from 'shared/hooks'; import { useCommonTranslation, usePublicTranslation } from 'configs/i18n'; import { useAppSelector } from 'configs/redux'; import { ClerkEnrollment } from 'interfaces/clerkEnrollment'; import { PartialExamsAndSkills } from 'interfaces/common/enrollment'; +import { PublicFreeEnrollmentDetails } from 'interfaces/publicEducation'; import { PublicEnrollment } from 'interfaces/publicEnrollment'; import { publicEnrollmentSelector } from 'redux/selectors/publicEnrollment'; import { EnrollmentUtils } from 'utils/enrollment'; import { ENROLLMENT_SKILL_PRICE } from 'utils/publicEnrollment'; -export const ExamEventDetails = ({ + +const getFreeEnrollmentsLeft = ( + skill: string, + freeEnrollmentDetails?: PublicFreeEnrollmentDetails, +) => { + if (!freeEnrollmentDetails) { + return ''; + } + + switch (skill) { + case 'textualSkill': + return freeEnrollmentDetails.freeTextualSkillLeft; + case 'oralSkill': + return freeEnrollmentDetails.freeOralSkillLeft; + default: + return ''; + } +}; + +const getEnrollmentSkillPrice = ( + skill: string, + enrollment: PublicEnrollment | ClerkEnrollment, + freeEnrollmentDetails?: PublicFreeEnrollmentDetails, +) => { + if (!freeEnrollmentDetails || !EnrollmentUtils.hasFreeBasis(enrollment)) { + return ENROLLMENT_SKILL_PRICE; + } + + switch (skill) { + case 'textualSkill': + return freeEnrollmentDetails.freeTextualSkillLeft > 0 + ? 0 + : ENROLLMENT_SKILL_PRICE; + case 'oralSkill': + return freeEnrollmentDetails.freeOralSkillLeft > 0 + ? 0 + : ENROLLMENT_SKILL_PRICE; + default: + return ENROLLMENT_SKILL_PRICE; + } +}; + +const DesktopSkillsList = ({ enrollment, - clerkView = false, + clerkView, }: { enrollment: PublicEnrollment | ClerkEnrollment; - clerkView?: boolean; + clerkView: boolean; }) => { + const translateCommon = useCommonTranslation(); const { t } = usePublicTranslation({ keyPrefix: 'vkt.component.publicEnrollment.steps.preview', }); - const translateCommon = useCommonTranslation(); const publicEnrollment = useAppSelector(publicEnrollmentSelector); const freeEnrollmentDetails = (enrollment as ClerkEnrollment).freeEnrollmentDetails || publicEnrollment.freeEnrollmentDetails; - - const skills = ['textualSkill', 'oralSkill'].filter( - (skill) => !!enrollment[skill as keyof PartialExamsAndSkills], - ); - - const partialExams = [ - 'writingPartialExam', - 'readingComprehensionPartialExam', - 'speakingPartialExam', - 'speechComprehensionPartialExam', - ].filter((exam) => !!enrollment[exam as keyof PartialExamsAndSkills]); - - const getFreeEnrollmentsLeft = (skill: string) => { - if (!freeEnrollmentDetails) { - return ''; - } - - switch (skill) { - case 'textualSkill': - return freeEnrollmentDetails.freeTextualSkillLeft; - case 'oralSkill': - return freeEnrollmentDetails.freeOralSkillLeft; - default: - return ''; - } - }; - - const getEnrollmentSkillPrice = (skill: string) => { - if (!freeEnrollmentDetails || !EnrollmentUtils.hasFreeBasis(enrollment)) { - return ENROLLMENT_SKILL_PRICE; - } - - switch (skill) { - case 'textualSkill': - return freeEnrollmentDetails.freeTextualSkillLeft > 0 - ? 0 - : ENROLLMENT_SKILL_PRICE; - case 'oralSkill': - return freeEnrollmentDetails.freeOralSkillLeft > 0 - ? 0 - : ENROLLMENT_SKILL_PRICE; - default: - return ENROLLMENT_SKILL_PRICE; - } - }; - const hasFreeEnrollments = freeEnrollmentDetails && EnrollmentUtils.hasFreeBasis(enrollment) && (freeEnrollmentDetails.freeTextualSkillLeft > 0 || freeEnrollmentDetails.freeOralSkillLeft > 0); + const skills = ['textualSkill', 'oralSkill'].filter( + (skill) => !!enrollment[skill as keyof PartialExamsAndSkills], + ); - const displaySkillsList = () => ( + return (
    - {t('examEventDetails.selectedPartialExamsLabel')} + {t('examEventDetails.desktop.selectedSkillsLabel')} {hasFreeEnrollments && !clerkView && ( @@ -96,36 +98,160 @@ export const ExamEventDetails = ({ {translateCommon(`enrollment.partialExamsAndSkills.${skill}`)} {(enrollment.isFree || EnrollmentUtils.hasFreeBasis(enrollment)) && - !clerkView && {getFreeEnrollmentsLeft(skill)} / 3} - {!clerkView && {getEnrollmentSkillPrice(skill)}€} + !clerkView && ( + + {getFreeEnrollmentsLeft(skill, freeEnrollmentDetails)} / 3 + + )} + {!clerkView && ( + + {getEnrollmentSkillPrice( + skill, + enrollment, + freeEnrollmentDetails, + )} + € + + )}
    ))}
    ); +}; + +const DesktopExamsList = ({ + enrollment, +}: { + enrollment: ClerkEnrollment | PublicEnrollment; +}) => { + const { t } = usePublicTranslation({ + keyPrefix: 'vkt.component.publicEnrollment.steps.preview.examEventDetails', + }); + const translateCommon = useCommonTranslation(); - const displayExamsList = () => ( + const partialExams = [ + 'writingPartialExam', + 'readingComprehensionPartialExam', + 'speakingPartialExam', + 'speechComprehensionPartialExam', + ].filter((exam) => !!enrollment[exam as keyof PartialExamsAndSkills]); + + return (
    - {t('examEventDetails.selectedSkillsLabel')} + {t('selectedPartialExamsLabel')} {':'}
      - {partialExams.map((skill, i) => ( + {partialExams.map((exam, i) => (
    • - {translateCommon(`enrollment.partialExamsAndSkills.${skill}`)} + {translateCommon(`enrollment.partialExamsAndSkills.${exam}`)}
    • ))}
    ); +}; + +const PhoneSkillsAndExamsList = ({ + enrollment, +}: { + enrollment: ClerkEnrollment | PublicEnrollment; +}) => { + const translateCommon = useCommonTranslation(); + const { t } = usePublicTranslation({ + keyPrefix: 'vkt.component.publicEnrollment.steps.preview', + }); + const publicEnrollment = useAppSelector(publicEnrollmentSelector); + const freeEnrollmentDetails = + (enrollment as ClerkEnrollment).freeEnrollmentDetails || + publicEnrollment.freeEnrollmentDetails; + const skills = ['textualSkill', 'oralSkill'].filter( + (skill) => !!enrollment[skill as keyof PartialExamsAndSkills], + ); + const partialExams = [ + 'writingPartialExam', + 'readingComprehensionPartialExam', + 'speakingPartialExam', + 'speechComprehensionPartialExam', + ].filter((exam) => !!enrollment[exam as keyof PartialExamsAndSkills]); + + return ( + <> + {skills.map((skill) => ( +
    +
    + + + {t('examEventDetails.phone.selectedSkillLabel')}:{' '} + {translateCommon(`enrollment.partialExamsAndSkills.${skill}`)} + + + + {t('educationDetails.freeEnrollmentsLeft')} + + + {getFreeEnrollmentsLeft(skill, freeEnrollmentDetails)}/3 + + + {t('educationDetails.price')} + + + {getEnrollmentSkillPrice( + skill, + enrollment, + freeEnrollmentDetails, + )} +  € + +
    + +
    + ))} +
    + + {t('examEventDetails.selectedPartialExamsLabel')}: + +
      + {partialExams.map((exam) => ( + +
    • + {' '} + {translateCommon(`enrollment.partialExamsAndSkills.${exam}`)} +
    • +
      + ))} +
    +
    + + ); +}; + +export const ExamEventDetails = ({ + enrollment, + clerkView = false, +}: { + enrollment: PublicEnrollment | ClerkEnrollment; + clerkView?: boolean; +}) => { + const { t } = usePublicTranslation({ + keyPrefix: 'vkt.component.publicEnrollment.steps.preview', + }); + const translateCommon = useCommonTranslation(); + const { isPhone } = useWindowProperties(); return (

    {t('examEventDetails.title')}

    - {displaySkillsList()} - {displayExamsList()} + {isPhone && } + {!isPhone && ( + <> + + + + )} {!clerkView && (