From e37990fde48fe2a8d6163a2f032714466c38cbdd Mon Sep 17 00:00:00 2001 From: kettunenj Date: Tue, 8 Feb 2022 10:19:02 +0200 Subject: [PATCH 1/4] ensimmainen version, kielivalintamuutokset tarvitaan etenemista varten --- common/abstractApi.ts | 6 + src/components/notification/Notification.tsx | 2 + .../projekti/ProjektiSideNavigation.tsx | 11 +- .../aloituskuulutus/AloituskuulutusRO.tsx | 90 +++++++++++ .../projekti/[oid]/aloituskuulutus.tsx | 151 ++++++------------ src/schemas/aloituskuulutus.ts | 94 +++++++++++ src/styles/globals.css | 2 +- .../notification/Notification.module.css | 8 + 8 files changed, 259 insertions(+), 105 deletions(-) create mode 100644 src/components/projekti/aloituskuulutus/AloituskuulutusRO.tsx create mode 100644 src/schemas/aloituskuulutus.ts diff --git a/common/abstractApi.ts b/common/abstractApi.ts index 40c166c89..3fd4ab5eb 100644 --- a/common/abstractApi.ts +++ b/common/abstractApi.ts @@ -1,4 +1,5 @@ import { + AloitusKuulutusTila, AsiakirjaTyyppi, EsikatseleAsiakirjaPDFQueryVariables, Kayttaja, @@ -107,6 +108,11 @@ export abstract class AbstractApi { } as TallennaProjektiMutationVariables); } + async muutaTila(oid: string, tila: AloitusKuulutusTila){ + log.info("Muuta projektin " + oid + " tilaa", tila); + return AloitusKuulutusTila.ODOTTAA_HYVAKSYNTAA; + } + async getVelhoSuunnitelmasByName(nimi: string, requireExactMatch?: boolean): Promise { return await this.callYllapitoAPI(apiConfig.listaaVelhoProjektit, { nimi, diff --git a/src/components/notification/Notification.tsx b/src/components/notification/Notification.tsx index bf1302b89..c8dd5d473 100644 --- a/src/components/notification/Notification.tsx +++ b/src/components/notification/Notification.tsx @@ -7,6 +7,7 @@ import classNames from "classnames"; export enum NotificationType { DEFAULT = "default", INFO = "info", + INFO_GRAY = "info_gray", WARN = "warn", ERROR = "error", } @@ -14,6 +15,7 @@ export enum NotificationType { const defaultIcons = new Map([ [NotificationType.DEFAULT, undefined], [NotificationType.INFO, "info-circle"], + [NotificationType.INFO_GRAY, "info-circle"], [NotificationType.WARN, "exclamation-circle"], [NotificationType.ERROR, "exclamation-triangle"], ]); diff --git a/src/components/projekti/ProjektiSideNavigation.tsx b/src/components/projekti/ProjektiSideNavigation.tsx index 0d11dae1e..58c5e9e72 100644 --- a/src/components/projekti/ProjektiSideNavigation.tsx +++ b/src/components/projekti/ProjektiSideNavigation.tsx @@ -4,7 +4,7 @@ import styles from "@styles/projekti/ProjektiSideNavigation.module.css"; import classNames from "classnames"; import { useRouter } from "next/router"; import useProjekti from "src/hooks/useProjekti"; -import { Status } from "@services/api"; +import { AloitusKuulutusTila, Status } from "@services/api"; interface Route { title: string; @@ -30,7 +30,14 @@ export default function ProjektiSideNavigation(): ReactElement { href: oid && `/yllapito/projekti/${oid}/aloituskuulutus`, disabled: !projekti?.status || projekti?.status === Status.EI_JULKAISTU, }, - { title: "Suunnitteluvaihe", href: oid && `/yllapito/projekti/${oid}/suunnittelu`, disabled: true }, + { + title: "Suunnitteluvaihe", + href: oid && `/yllapito/projekti/${oid}/suunnittelu`, + disabled: + !projekti?.status || + !projekti?.aloitusKuulutus?.tila || + projekti?.aloitusKuulutus.tila === AloitusKuulutusTila.MUOKATTAVISSA, + }, { title: "Nähtävilläolovaihe", href: oid && `/yllapito/projekti/${oid}/nahtavillaolo`, disabled: true }, ]; return ( diff --git a/src/components/projekti/aloituskuulutus/AloituskuulutusRO.tsx b/src/components/projekti/aloituskuulutus/AloituskuulutusRO.tsx new file mode 100644 index 000000000..b5b059c59 --- /dev/null +++ b/src/components/projekti/aloituskuulutus/AloituskuulutusRO.tsx @@ -0,0 +1,90 @@ +import { AloitusKuulutusTila, Projekti } from "@services/api"; +import React, { ReactElement } from "react"; +import Notification, { NotificationType } from "@components/notification/Notification"; +import { capitalize, replace } from "lodash"; +import Button from "@components/button/Button"; + +interface Props { + projekti?: Projekti | null; +} + +const muotoilePvm = (pvm: string | null | undefined) => { + if (!pvm) return; + return new Date(pvm).toLocaleDateString("fi"); +}; + +export default function AloituskuulutusRO({ projekti }: Props): ReactElement { + return ( + <> + {projekti?.aloitusKuulutus?.tila === AloitusKuulutusTila.ODOTTAA_HYVAKSYNTAA && ( + + Aloituskuulutus on hyväksyttävänä projektipäälliköllä. Jos kuulutusta tarvitsee muokata, ota yhteys + projektipäällikköön. + + )} + {projekti?.suunnitteluSopimus && ( + + Hankkeesta on tehty suunnittelusopimus kunnan kanssa +
+
+ {capitalize(projekti.suunnitteluSopimus.kunta)} +
+ {capitalize(projekti.suunnitteluSopimus.etunimi)} {capitalize(projekti.suunnitteluSopimus.sukunimi)}, puh.{" "} + {projekti.suunnitteluSopimus.puhelinnumero},{" "} + {projekti.suunnitteluSopimus.email ? replace(projekti.suunnitteluSopimus.email, "@", "[at]") : ""} +
+ )} +
+

Kuulutuspäivä

+

Kuulutusvaihe päättyy

+

{muotoilePvm(projekti?.aloitusKuulutus?.kuulutusPaiva)}

+

{muotoilePvm(projekti?.aloitusKuulutus?.siirtyySuunnitteluVaiheeseen)}

+
+
+

Kuulutuksessa esitettävät yhteystiedot

+ {projekti?.aloitusKuulutus?.esitettavatYhteystiedot?.map((yhteistieto, index) => ( +

+ {capitalize(yhteistieto?.etunimi)} {capitalize(yhteistieto?.sukunimi)}, puh. {yhteistieto?.puhelinnumero},{" "} + {yhteistieto?.sahkoposti ? replace(yhteistieto?.sahkoposti, "@", "[at]") : ""} +

+ ))} +
+
+

Tiivistetty hankkeen kuvaus ensisijaisella kielellä (suomi)

+

{projekti?.aloitusKuulutus?.hankkeenKuvaus}

+
+ {projekti?.lisakuulutuskieli && ( +
+

+ Tiivistetty hankkeen kuvaus toissijaisella kielellä ({projekti?.lisakuulutuskieli}) +

+

{projekti.aloitusKuulutus?.hankkeenKuvausRuotsi}

+
+ )} +
+

Esikatseltavat tiedostot

+

Kuulutus ja ilmoitus ensisijaisella kielellä (suomi)

+
+ + +
+
+
+

Kuulutus ja ilmoitus toissijaisella kielellä ({projekti?.lisakuulutuskieli})

+
+ + +
+
+ + ); +} +0; diff --git a/src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx b/src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx index 5d506d8b5..f76e7ce47 100644 --- a/src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx +++ b/src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx @@ -5,11 +5,19 @@ import React, { ReactElement, useEffect, useRef, useState } from "react"; import useProjekti from "src/hooks/useProjekti"; import * as Yup from "yup"; import { SchemaOf } from "yup"; -import { useForm, UseFormProps } from "react-hook-form"; +import { FormProvider, useForm, UseFormProps } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import Button from "@components/button/Button"; import Notification, { NotificationType } from "@components/notification/Notification"; -import { AloitusKuulutusInput, api, LaskuriTyyppi, Projekti, Status, TallennaProjektiInput } from "@services/api"; +import { + AloitusKuulutusInput, + AloitusKuulutusTila, + api, + LaskuriTyyppi, + Projekti, + Status, + TallennaProjektiInput, +} from "@services/api"; import log from "loglevel"; import { PageProps } from "@pages/_app"; import DatePicker from "@components/form/DatePicker"; @@ -21,6 +29,8 @@ import { puhelinNumeroSchema } from "src/schemas/puhelinNumero"; import deleteFieldArrayIds from "src/util/deleteFieldArrayIds"; import cloneDeep from "lodash/cloneDeep"; import useSnackbars from "src/hooks/useSnackbars"; +import { aloituskuulutusSchema } from "src/schemas/aloituskuulutus"; +import AloituskuulutusRO from "@components/projekti/aloituskuulutus/AloituskuulutusRO"; type ProjektiFields = Pick; type RequiredProjektiFields = Required<{ @@ -36,94 +46,6 @@ type FormValues = RequiredProjektiFields & { const maxAloituskuulutusLength = 2000; -const draftValidationSchema: SchemaOf = Yup.object().shape({ - oid: Yup.string().required(), - kayttoOikeudet: kayttoOikeudetSchema, - aloitusKuulutus: Yup.object().shape({ - hankkeenKuvaus: Yup.string().max( - maxAloituskuulutusLength, - `Aloituskuulutukseen voidaan kirjoittaa maksimissaan ${maxAloituskuulutusLength} merkkiä` - ), - kuulutusPaiva: Yup.string() - .test("is-valid-date", "Virheellinen päivämäärä", (dateString) => { - // KuulutusPaiva is not required when saved as a draft. - // This test doesn't throw errors if date is not set. - if (!dateString) { - return true; - } - let validDate = false; - try { - const dateString2 = new Date(dateString!).toISOString().split("T")[0]; - if (dateString2 === dateString) { - validDate = true; - } - } catch { - validDate = false; - } - return validDate; - }) - .test("not-in-past", "Aloituskuulutusta ei voida asettaa menneisyyteen", (dateString) => { - // KuulutusPaiva is not required when saved as a draft. - // This test doesn't throw errors if date is not set. - if (!dateString) { - return true; - } - const todayISODate = new Date().toISOString().split("T")[0]; - return dateString >= todayISODate; - }), - siirtyySuunnitteluVaiheeseen: Yup.string().test("is-valid-date", "Virheellinen päivämäärä", (dateString) => { - // KuulutusPaiva is not required when saved as a draft. - // This test doesn't throw errors if date is not set. - if (!dateString) { - return true; - } - let validDate = false; - try { - const dateString2 = new Date(dateString!).toISOString().split("T")[0]; - if (dateString2 === dateString) { - validDate = true; - } - } catch { - validDate = false; - } - return validDate; - }), - esitettavatYhteystiedot: Yup.array() - .notRequired() - .of( - Yup.object() - .shape({ - etunimi: Yup.string().required("Etunimi on pakollinen"), - sukunimi: Yup.string().required("Sukunimi on pakollinen"), - puhelinnumero: puhelinNumeroSchema.test( - "puhelinnumero-not-in-kayttoOikeudet", - "Tieto löytyy projektin henkilöistä. Valitse henkilö projektiin tallennettujen listasta", - function (puhelinnumero) { - const projekti = this.options.context as Projekti; - return !projekti?.kayttoOikeudet?.some( - (kayttaja) => kayttaja.puhelinnumero && kayttaja.puhelinnumero === puhelinnumero - ); - } - ), - sahkoposti: Yup.string() - .required("Sähköpostiosoite on pakollinen") - .email("Virheellinen sähköpostiosoite") - .test( - "sahkoposti-not-in-kayttoOikeudet", - "Tieto löytyy projektin henkilöistä. Valitse henkilö projektiin tallennettujen listasta", - function (sahkoposti) { - const projekti = this.options.context as Projekti; - return !projekti?.kayttoOikeudet?.some((kayttaja) => kayttaja.email && kayttaja.email === sahkoposti); - } - ), - organisaatio: Yup.string().required("Organisaatio on pakollinen"), - id: Yup.string().nullable().notRequired(), - }) - .nullable() - ), - }), -}); - const loadedProjektiValidationSchema = getProjektiValidationSchema([ ProjektiTestType.PROJEKTI_IS_LOADED, ProjektiTestType.PROJEKTI_HAS_PAALLIKKO, @@ -164,7 +86,7 @@ export default function Aloituskuulutus({ setRouteLabels }: PageProps): ReactEle }, [router.isReady, oid, projekti, setRouteLabels]); const formOptions: UseFormProps = { - resolver: yupResolver(draftValidationSchema, { abortEarly: false, recursive: true }), + resolver: yupResolver(aloituskuulutusSchema, { abortEarly: false, recursive: true }), defaultValues: { aloitusKuulutus: { hankkeenKuvaus: "" } }, mode: "onChange", reValidateMode: "onChange", @@ -175,7 +97,7 @@ export default function Aloituskuulutus({ setRouteLabels }: PageProps): ReactEle const { register, handleSubmit, - formState: { errors }, + formState: { errors, isDirty }, reset, watch, setValue, @@ -213,13 +135,17 @@ export default function Aloituskuulutus({ setRouteLabels }: PageProps): ReactEle } }, [projekti, reset]); - const saveDraft = async (formData: FormValues) => { + const saveAloituskuulutus = async (formData: FormValues) => { deleteFieldArrayIds(formData?.aloitusKuulutus?.esitettavatYhteystiedot); - setIsFormSubmitting(true); log.log("formData", formData); + await api.tallennaProjekti(formData); + await reloadProjekti(); + }; + + const saveDraft = async (formData: FormValues) => { + setIsFormSubmitting(true); try { - await api.tallennaProjekti(formData); - await reloadProjekti(); + await saveAloituskuulutus(formData); showSuccessMessage("Tallennus onnistui!"); } catch (e) { log.log("OnSubmit Error", e); @@ -229,8 +155,19 @@ export default function Aloituskuulutus({ setRouteLabels }: PageProps): ReactEle }; const sendToManager = async (formData: FormValues) => { - log.log(formData); - showInfoMessage("Lähetetään projektipäällikölle..."); + setIsFormSubmitting(true); + try { + if (isDirty) { + await saveAloituskuulutus(formData); + // don't show succes toast we still want to send it to manager + } + await api.muutaTila(formData.oid, AloitusKuulutusTila.ODOTTAA_HYVAKSYNTAA); + showSuccessMessage("Lähetys onnistui"); + } catch (error) { + log.error("", error); + showErrorMessage("Lähetyksessä tapahtui virhe"); + } + setIsFormSubmitting(false); }; const showPDFPreview = (formData: FormValues, action: string) => { @@ -257,7 +194,9 @@ export default function Aloituskuulutus({ setRouteLabels }: PageProps): ReactEle return ( -
+ { projekti?.aloitusKuulutus?.tila === AloitusKuulutusTila.MUOKATTAVISSA && ( + <> +

- -
+ + )} + {projekti?.aloitusKuulutus?.tila == AloitusKuulutusTila.ODOTTAA_HYVAKSYNTAA && ( + + + + )} + ); } diff --git a/src/schemas/aloituskuulutus.ts b/src/schemas/aloituskuulutus.ts new file mode 100644 index 000000000..bf04832df --- /dev/null +++ b/src/schemas/aloituskuulutus.ts @@ -0,0 +1,94 @@ +import { Projekti } from "@services/api"; +import * as Yup from "yup"; +import { kayttoOikeudetSchema } from "./kayttoOikeudet"; +import { puhelinNumeroSchema } from "./puhelinNumero"; + +const maxAloituskuulutusLength = 2000; + +export const aloituskuulutusSchema = Yup.object().shape({ + oid: Yup.string().required(), + kayttoOikeudet: kayttoOikeudetSchema, + aloitusKuulutus: Yup.object().shape({ + hankkeenKuvaus: Yup.string() + .max( + maxAloituskuulutusLength, + `Aloituskuulutukseen voidaan kirjoittaa maksimissaan ${maxAloituskuulutusLength} merkkiä` + ) + .required("Hankkeen kuvaus ei voi olla tyhjä") + .nullable(), + kuulutusPaiva: Yup.string() + .required("Kuulutuspäivä ei voi olla tyhjä") + .nullable() + .test("is-valid-date", "Virheellinen päivämäärä", (dateString) => { + let validDate = false; + try { + const dateString2 = new Date(dateString!).toISOString().split("T")[0]; + if (dateString2 === dateString) { + validDate = true; + } + } catch { + validDate = false; + } + return validDate; + }) + .test("not-in-past", "Kuulutuspäivää ei voida asettaa menneisyyteen", (dateString) => { + // KuulutusPaiva is not required when saved as a draft. + // This test doesn't throw errors if date is not set. + if (!dateString) { + return true; + } + const todayISODate = new Date().toISOString().split("T")[0]; + return dateString >= todayISODate; + }), + siirtyySuunnitteluVaiheeseen: Yup.string().test("is-valid-date", "Virheellinen päivämäärä", (dateString) => { + // KuulutusPaiva is not required when saved as a draft. + // This test doesn't throw errors if date is not set. + if (!dateString) { + return true; + } + let validDate = false; + try { + const dateString2 = new Date(dateString!).toISOString().split("T")[0]; + if (dateString2 === dateString) { + validDate = true; + } + } catch { + validDate = false; + } + return validDate; + }), + esitettavatYhteystiedot: Yup.array() + .notRequired() + .of( + Yup.object() + .shape({ + etunimi: Yup.string().required("Etunimi on pakollinen"), + sukunimi: Yup.string().required("Sukunimi on pakollinen"), + puhelinnumero: puhelinNumeroSchema.test( + "puhelinnumero-not-in-kayttoOikeudet", + "Tieto löytyy projektin henkilöistä. Valitse henkilö projektiin tallennettujen listasta", + function (puhelinnumero) { + const projekti = this.options.context as Projekti; + return !projekti?.kayttoOikeudet?.some( + (kayttaja) => kayttaja.puhelinnumero && kayttaja.puhelinnumero === puhelinnumero + ); + } + ), + sahkoposti: Yup.string() + .required("Sähköpostiosoite on pakollinen") + .email("Virheellinen sähköpostiosoite") + .test( + "sahkoposti-not-in-kayttoOikeudet", + "Tieto löytyy projektin henkilöistä. Valitse henkilö projektiin tallennettujen listasta", + function (sahkoposti) { + const projekti = this.options.context as Projekti; + return !projekti?.kayttoOikeudet?.some((kayttaja) => kayttaja.email && kayttaja.email === sahkoposti); + } + ), + organisaatio: Yup.string().required("Organisaatio on pakollinen"), + id: Yup.string().nullable().notRequired(), + }) + .nullable() + ), + }), +}); diff --git a/src/styles/globals.css b/src/styles/globals.css index 4f2c5ec63..196555345 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -230,7 +230,7 @@ } .vayla-label { - font-weight: 400; + font-weight: 700; font-size: 1rem; color: #333333; line-height: normal; diff --git a/src/styles/notification/Notification.module.css b/src/styles/notification/Notification.module.css index b44de6d9b..40f5a7c98 100644 --- a/src/styles/notification/Notification.module.css +++ b/src/styles/notification/Notification.module.css @@ -14,6 +14,10 @@ @apply text-primary-dark; } +.notification .start-icon.info_gray { + @apply text-turquoise; +} + .notification .start-icon.warn { @apply text-orange-dark; } @@ -30,6 +34,10 @@ @apply bg-primary-lightest border-primary-light; } +.notification.info-gray { + @apply bg-gray-lightest border-gray; +} + .notification.warn { @apply bg-orange-light border-orange-dark; } From b39c778501e0be9da122102b2099d35dbbcb7a3a Mon Sep 17 00:00:00 2001 From: kettunenj Date: Tue, 8 Feb 2022 10:23:33 +0200 Subject: [PATCH 2/4] lint --- .../projekti/aloituskuulutus/AloituskuulutusRO.tsx | 13 ++++++++----- .../yllapito/projekti/[oid]/aloituskuulutus.tsx | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/projekti/aloituskuulutus/AloituskuulutusRO.tsx b/src/components/projekti/aloituskuulutus/AloituskuulutusRO.tsx index b5b059c59..8d9ba9be4 100644 --- a/src/components/projekti/aloituskuulutus/AloituskuulutusRO.tsx +++ b/src/components/projekti/aloituskuulutus/AloituskuulutusRO.tsx @@ -3,13 +3,16 @@ import React, { ReactElement } from "react"; import Notification, { NotificationType } from "@components/notification/Notification"; import { capitalize, replace } from "lodash"; import Button from "@components/button/Button"; +import log from "loglevel"; interface Props { projekti?: Projekti | null; } const muotoilePvm = (pvm: string | null | undefined) => { - if (!pvm) return; + if (!pvm) { + return; + } return new Date(pvm).toLocaleDateString("fi"); }; @@ -65,10 +68,10 @@ export default function AloituskuulutusRO({ projekti }: Props): ReactElement {

Esikatseltavat tiedostot

Kuulutus ja ilmoitus ensisijaisella kielellä (suomi)

- -
@@ -76,10 +79,10 @@ export default function AloituskuulutusRO({ projekti }: Props): ReactElement {

Kuulutus ja ilmoitus toissijaisella kielellä ({projekti?.lisakuulutuskieli})

- -
diff --git a/src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx b/src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx index f76e7ce47..4cea299fd 100644 --- a/src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx +++ b/src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx @@ -299,7 +299,7 @@ export default function Aloituskuulutus({ setRouteLabels }: PageProps): ReactEle
)} - {projekti?.aloitusKuulutus?.tila == AloitusKuulutusTila.ODOTTAA_HYVAKSYNTAA && ( + {projekti?.aloitusKuulutus?.tila === AloitusKuulutusTila.ODOTTAA_HYVAKSYNTAA && ( From 5b0c9d2ec29ad10e594eca4251b2508cd0a4b470 Mon Sep 17 00:00:00 2001 From: kettunenj Date: Tue, 8 Feb 2022 10:25:59 +0200 Subject: [PATCH 3/4] more lint --- .../projekti/aloituskuulutus/AloituskuulutusRO.tsx | 3 +-- src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx | 6 +----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/components/projekti/aloituskuulutus/AloituskuulutusRO.tsx b/src/components/projekti/aloituskuulutus/AloituskuulutusRO.tsx index 8d9ba9be4..3180f48f0 100644 --- a/src/components/projekti/aloituskuulutus/AloituskuulutusRO.tsx +++ b/src/components/projekti/aloituskuulutus/AloituskuulutusRO.tsx @@ -89,5 +89,4 @@ export default function AloituskuulutusRO({ projekti }: Props): ReactElement { ); -} -0; +}; diff --git a/src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx b/src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx index 4cea299fd..38e7ad815 100644 --- a/src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx +++ b/src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx @@ -3,8 +3,6 @@ import ProjektiPageLayout from "@components/projekti/ProjektiPageLayout"; import { useRouter } from "next/router"; import React, { ReactElement, useEffect, useRef, useState } from "react"; import useProjekti from "src/hooks/useProjekti"; -import * as Yup from "yup"; -import { SchemaOf } from "yup"; import { FormProvider, useForm, UseFormProps } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import Button from "@components/button/Button"; @@ -24,8 +22,6 @@ import DatePicker from "@components/form/DatePicker"; import { getProjektiValidationSchema, ProjektiTestType } from "src/schemas/projekti"; import ProjektiErrorNotification from "@components/projekti/ProjektiErrorNotification"; import KuulutuksenYhteystiedot from "@components/projekti/aloituskuulutus/KuulutuksenYhteystiedot"; -import { kayttoOikeudetSchema } from "src/schemas/kayttoOikeudet"; -import { puhelinNumeroSchema } from "src/schemas/puhelinNumero"; import deleteFieldArrayIds from "src/util/deleteFieldArrayIds"; import cloneDeep from "lodash/cloneDeep"; import useSnackbars from "src/hooks/useSnackbars"; @@ -180,7 +176,7 @@ export default function Aloituskuulutus({ setRouteLabels }: PageProps): ReactEle } }; - const { showSuccessMessage, showErrorMessage, showInfoMessage } = useSnackbars(); + const { showSuccessMessage, showErrorMessage } = useSnackbars(); const getPaattymispaiva = async (value: string) => { try { From 37bb1e1e2edb88fbe15080a973e48511e0321b31 Mon Sep 17 00:00:00 2001 From: kettunenj Date: Mon, 14 Feb 2022 13:33:32 +0200 Subject: [PATCH 4/4] api ja tietomallimuutokset, kieliasetusten vaikutukset, esikatselut --- common/abstractApi.ts | 6 - .../projekti/ProjektiSideNavigation.tsx | 7 +- .../aloituskuulutus/AloituskuulutusRO.tsx | 125 +++++++--- .../projekti/[oid]/aloituskuulutus.tsx | 229 ++++++++++-------- 4 files changed, 218 insertions(+), 149 deletions(-) diff --git a/common/abstractApi.ts b/common/abstractApi.ts index 3fd4ab5eb..40c166c89 100644 --- a/common/abstractApi.ts +++ b/common/abstractApi.ts @@ -1,5 +1,4 @@ import { - AloitusKuulutusTila, AsiakirjaTyyppi, EsikatseleAsiakirjaPDFQueryVariables, Kayttaja, @@ -108,11 +107,6 @@ export abstract class AbstractApi { } as TallennaProjektiMutationVariables); } - async muutaTila(oid: string, tila: AloitusKuulutusTila){ - log.info("Muuta projektin " + oid + " tilaa", tila); - return AloitusKuulutusTila.ODOTTAA_HYVAKSYNTAA; - } - async getVelhoSuunnitelmasByName(nimi: string, requireExactMatch?: boolean): Promise { return await this.callYllapitoAPI(apiConfig.listaaVelhoProjektit, { nimi, diff --git a/src/components/projekti/ProjektiSideNavigation.tsx b/src/components/projekti/ProjektiSideNavigation.tsx index 58c5e9e72..a022fc757 100644 --- a/src/components/projekti/ProjektiSideNavigation.tsx +++ b/src/components/projekti/ProjektiSideNavigation.tsx @@ -4,7 +4,7 @@ import styles from "@styles/projekti/ProjektiSideNavigation.module.css"; import classNames from "classnames"; import { useRouter } from "next/router"; import useProjekti from "src/hooks/useProjekti"; -import { AloitusKuulutusTila, Status } from "@services/api"; +import { Status } from "@services/api"; interface Route { title: string; @@ -33,10 +33,7 @@ export default function ProjektiSideNavigation(): ReactElement { { title: "Suunnitteluvaihe", href: oid && `/yllapito/projekti/${oid}/suunnittelu`, - disabled: - !projekti?.status || - !projekti?.aloitusKuulutus?.tila || - projekti?.aloitusKuulutus.tila === AloitusKuulutusTila.MUOKATTAVISSA, + disabled: !projekti?.status || !projekti?.aloitusKuulutusJulkaisut, }, { title: "Nähtävilläolovaihe", href: oid && `/yllapito/projekti/${oid}/nahtavillaolo`, disabled: true }, ]; diff --git a/src/components/projekti/aloituskuulutus/AloituskuulutusRO.tsx b/src/components/projekti/aloituskuulutus/AloituskuulutusRO.tsx index 3180f48f0..bf0aa1b80 100644 --- a/src/components/projekti/aloituskuulutus/AloituskuulutusRO.tsx +++ b/src/components/projekti/aloituskuulutus/AloituskuulutusRO.tsx @@ -1,51 +1,67 @@ -import { AloitusKuulutusTila, Projekti } from "@services/api"; -import React, { ReactElement } from "react"; +import { AloitusKuulutusJulkaisu, AloitusKuulutusTila, Kieli } from "@services/api"; +import React, { ReactElement, useRef } from "react"; import Notification, { NotificationType } from "@components/notification/Notification"; import { capitalize, replace } from "lodash"; import Button from "@components/button/Button"; import log from "loglevel"; interface Props { - projekti?: Projekti | null; + oid?: string; + aloituskuulutusjulkaisu?: AloitusKuulutusJulkaisu | null; } -const muotoilePvm = (pvm: string | null | undefined) => { - if (!pvm) { - return; - } - return new Date(pvm).toLocaleDateString("fi"); -}; +export default function AloituskuulutusRO({ aloituskuulutusjulkaisu, oid }: Props): ReactElement { + const pdfFormRef = useRef(null); + + const muotoilePvm = (pvm: string | null | undefined) => { + if (!pvm) { + return; + } + return new Date(pvm).toLocaleDateString("fi"); + }; + + const naytaEsikatselu = async (action: string, kieli: Kieli | undefined | null) => { + log.info("Näytä esikatselu ", kieli); + if (!action) return; + + if (pdfFormRef.current) { + pdfFormRef.current.action = action; + pdfFormRef.current?.submit(); + } + }; -export default function AloituskuulutusRO({ projekti }: Props): ReactElement { return ( <> - {projekti?.aloitusKuulutus?.tila === AloitusKuulutusTila.ODOTTAA_HYVAKSYNTAA && ( + {aloituskuulutusjulkaisu?.tila === AloitusKuulutusTila.ODOTTAA_HYVAKSYNTAA && ( Aloituskuulutus on hyväksyttävänä projektipäälliköllä. Jos kuulutusta tarvitsee muokata, ota yhteys projektipäällikköön. )} - {projekti?.suunnitteluSopimus && ( + {aloituskuulutusjulkaisu?.suunnitteluSopimus && ( Hankkeesta on tehty suunnittelusopimus kunnan kanssa

- {capitalize(projekti.suunnitteluSopimus.kunta)} + {capitalize(aloituskuulutusjulkaisu?.suunnitteluSopimus.kunta)}
- {capitalize(projekti.suunnitteluSopimus.etunimi)} {capitalize(projekti.suunnitteluSopimus.sukunimi)}, puh.{" "} - {projekti.suunnitteluSopimus.puhelinnumero},{" "} - {projekti.suunnitteluSopimus.email ? replace(projekti.suunnitteluSopimus.email, "@", "[at]") : ""} + {capitalize(aloituskuulutusjulkaisu.suunnitteluSopimus.etunimi)}{" "} + {capitalize(aloituskuulutusjulkaisu.suunnitteluSopimus.sukunimi)}, puh.{" "} + {aloituskuulutusjulkaisu.suunnitteluSopimus.puhelinnumero},{" "} + {aloituskuulutusjulkaisu.suunnitteluSopimus.email + ? replace(aloituskuulutusjulkaisu.suunnitteluSopimus.email, "@", "[at]") + : ""}
)}

Kuulutuspäivä

Kuulutusvaihe päättyy

-

{muotoilePvm(projekti?.aloitusKuulutus?.kuulutusPaiva)}

-

{muotoilePvm(projekti?.aloitusKuulutus?.siirtyySuunnitteluVaiheeseen)}

+

{muotoilePvm(aloituskuulutusjulkaisu?.kuulutusPaiva)}

+

{muotoilePvm(aloituskuulutusjulkaisu?.siirtyySuunnitteluVaiheeseen)}

Kuulutuksessa esitettävät yhteystiedot

- {projekti?.aloitusKuulutus?.esitettavatYhteystiedot?.map((yhteistieto, index) => ( + {aloituskuulutusjulkaisu?.yhteystiedot?.map((yhteistieto, index) => (

{capitalize(yhteistieto?.etunimi)} {capitalize(yhteistieto?.sukunimi)}, puh. {yhteistieto?.puhelinnumero},{" "} {yhteistieto?.sahkoposti ? replace(yhteistieto?.sahkoposti, "@", "[at]") : ""} @@ -53,40 +69,87 @@ export default function AloituskuulutusRO({ projekti }: Props): ReactElement { ))}

-

Tiivistetty hankkeen kuvaus ensisijaisella kielellä (suomi)

-

{projekti?.aloitusKuulutus?.hankkeenKuvaus}

+

+ Tiivistetty hankkeen kuvaus ensisijaisella kielellä ({aloituskuulutusjulkaisu?.kielitiedot?.ensisijainenKieli} + ) +

+

+ {aloituskuulutusjulkaisu?.kielitiedot?.ensisijainenKieli === Kieli.SUOMI + ? aloituskuulutusjulkaisu?.hankkeenKuvaus + : aloituskuulutusjulkaisu?.hankkeenKuvausRuotsi} +

- {projekti?.lisakuulutuskieli && ( + {aloituskuulutusjulkaisu?.kielitiedot?.toissijainenKieli && (

- Tiivistetty hankkeen kuvaus toissijaisella kielellä ({projekti?.lisakuulutuskieli}) + Tiivistetty hankkeen kuvaus toissijaisella kielellä ( + {aloituskuulutusjulkaisu?.kielitiedot?.toissijainenKieli}) +

+

+ {aloituskuulutusjulkaisu?.kielitiedot?.toissijainenKieli === Kieli.SUOMI + ? aloituskuulutusjulkaisu?.hankkeenKuvaus + : aloituskuulutusjulkaisu?.hankkeenKuvausRuotsi}

-

{projekti.aloitusKuulutus?.hankkeenKuvausRuotsi}

)}

Esikatseltavat tiedostot

-

Kuulutus ja ilmoitus ensisijaisella kielellä (suomi)

+

Kuulutus ja ilmoitus ensisijaisella kielellä ({aloituskuulutusjulkaisu?.kielitiedot?.ensisijainenKieli})

- -
-

Kuulutus ja ilmoitus toissijaisella kielellä ({projekti?.lisakuulutuskieli})

+

Kuulutus ja ilmoitus toissijaisella kielellä ({aloituskuulutusjulkaisu?.kielitiedot?.toissijainenKieli})

- -
+ + + ); -}; +} diff --git a/src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx b/src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx index 38e7ad815..e3717012f 100644 --- a/src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx +++ b/src/pages/yllapito/projekti/[oid]/aloituskuulutus.tsx @@ -15,6 +15,8 @@ import { Projekti, Status, TallennaProjektiInput, + AloitusKuulutusJulkaisu, + TilasiirtymaToiminto, } from "@services/api"; import log from "loglevel"; import { PageProps } from "@pages/_app"; @@ -23,7 +25,7 @@ import { getProjektiValidationSchema, ProjektiTestType } from "src/schemas/proje import ProjektiErrorNotification from "@components/projekti/ProjektiErrorNotification"; import KuulutuksenYhteystiedot from "@components/projekti/aloituskuulutus/KuulutuksenYhteystiedot"; import deleteFieldArrayIds from "src/util/deleteFieldArrayIds"; -import cloneDeep from "lodash/cloneDeep"; +import { cloneDeep, find } from "lodash"; import useSnackbars from "src/hooks/useSnackbars"; import { aloituskuulutusSchema } from "src/schemas/aloituskuulutus"; import AloituskuulutusRO from "@components/projekti/aloituskuulutus/AloituskuulutusRO"; @@ -131,6 +133,13 @@ export default function Aloituskuulutus({ setRouteLabels }: PageProps): ReactEle } }, [projekti, reset]); + const getAloituskuulutusjulkaisuByTila = (tila: AloitusKuulutusTila): AloitusKuulutusJulkaisu | undefined => { + if (!projekti?.aloitusKuulutusJulkaisut) return undefined; + return find(projekti.aloitusKuulutusJulkaisut, (julkaisu) => { + return julkaisu.tila === tila; + }); + }; + const saveAloituskuulutus = async (formData: FormValues) => { deleteFieldArrayIds(formData?.aloitusKuulutus?.esitettavatYhteystiedot); log.log("formData", formData); @@ -150,14 +159,17 @@ export default function Aloituskuulutus({ setRouteLabels }: PageProps): ReactEle setIsFormSubmitting(false); }; - const sendToManager = async (formData: FormValues) => { + const sendToManager = async () => { + if (!projekti) return; setIsFormSubmitting(true); try { if (isDirty) { - await saveAloituskuulutus(formData); + // should we even allow user to try sending to manager if form is dirty? + // await saveAloituskuulutus(formData); // don't show succes toast we still want to send it to manager } - await api.muutaTila(formData.oid, AloitusKuulutusTila.ODOTTAA_HYVAKSYNTAA); + await api.siirraTila({ oid: projekti.oid, toiminto: TilasiirtymaToiminto.LAHETA_HYVAKSYTTAVAKSI }); + await reloadProjekti(); showSuccessMessage("Lähetys onnistui"); } catch (error) { log.error("", error); @@ -190,117 +202,120 @@ export default function Aloituskuulutus({ setRouteLabels }: PageProps): ReactEle return ( - { projekti?.aloitusKuulutus?.tila === AloitusKuulutusTila.MUOKATTAVISSA && ( + {!projekti?.aloitusKuulutusJulkaisut && ( <> -
-
- - - Aloituskuulutusta ei ole vielä julkaistu palvelun julkisella puolella.{" "} - {watchKuulutusPaiva && !errors.aloitusKuulutus?.kuulutusPaiva - ? `Kuulutuspäivä on ${new Date(watchKuulutusPaiva).toLocaleDateString("fi")}` - : "Kuulutuspäivää ei ole asetettu"} - . Voit edelleen tehdä muutoksia projektin tietoihin. Tallennetut muutokset huomioidaan kuulutuksessa. - -

Suunnittelun aloittamisesta kuuluttaminen

-

- Kun suunnitelman aloittamisesta kuulutetaan, projektista julkaistaan aloituskuulutustiedot tämän palvelun - julkisella puolella. Aloituskuulutuksen näkyvilläoloaika määräytyy annetun kuulutuspäivän mukaan. Projekti - siirtyy määräajan jälkeen automaattisesti suunnitteluvaiheeseen. -

- -
-

Ohjeet

-
    -
  • - Anna päivämäärä, jolloin suunnittelun aloittamisesta kuulutetaan tämän palvelun julkisella puolella. -
  • -
  • - Kuvaa aloituskuulutuksessa esitettävään sisällönkuvauskenttään lyhyesti suunnittelukohteen alueellinen - rajaus (maantiealue ja vaikutusalue), suunnittelun tavoitteet, vaikutukset ja toimenpiteet - pääpiirteittäin karkealla tasolla. Älä lisää tekstiin linkkejä. -
  • -
-
-
-
- { - getPaattymispaiva(event.target.value); - }} - /> - -
-
- -
-