diff --git a/.eslintrc.js b/.eslintrc.js index 36e201e5d..73cc8cf0b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -30,6 +30,7 @@ module.exports = { ], "rules": { "react/prop-types": 0, + "no-unused-vars": "warn", }, globals: { process: true, diff --git a/package.json b/package.json index 7ecbe37cb..89342795c 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "is-url": "^1.2.4", "leaflet": "^1.7.1", "moment": "^2.29.1", + "moment-range": "^4.0.2", "oidc-client-ts": "^3.0.1", "proj4": "^2.7.2", "proj4leaflet": "^1.0.2", @@ -52,7 +53,10 @@ "reselect": "^4.1.7", "sass": "1.69.4", "semantic-ui-css": "^2.4.1", - "semantic-ui-react": "2.1.4" + "semantic-ui-react": "2.1.5", + "vis-data": "^7.1.9", + "vis-timeline": "^7.7.3", + "vis-util": "^5.0.7" }, "resolutions": { "crypto-js": "4.2.0", diff --git a/public/locales/fi/translation.json b/public/locales/fi/translation.json index d643fa60b..ded7ff6e9 100644 --- a/public/locales/fi/translation.json +++ b/public/locales/fi/translation.json @@ -74,8 +74,12 @@ "error": "Virhe: {{error}}", "warning": "Päivitettyjen aikataulutietojen tallentaminen saattaa kestää hieman pidempään kun Kaavapino tekee laskutoimituksia.", "estimated": "Kaavapinon arvio", - "project-stopped": "Projekti on toistaiseksi keskeytetty.", - "timeline-error": "Projekti ei ole ajan tasalla.", + "project-stopped": "Projekti on keskeytetty", + "project-stopped-text": "Projekti vastuuhenkilö on keskeyttänyt projektin toistaiseksi. Hän voi aktivoida projektin uudelleen muokkausnäkymästä.", + "timeline-error": "Projekti ei ole ajan tasalla", + "timeline-error-text": "Projektin vastuuhenkilön tulee päivittää aikataulu.", + "timelime-modal-error-text-1": "Seuraavien päivämäärien siirtäminen ei ole mahdollista, koska minimietäisyys viereisiin etappeihin on täyttynyt.", + "timelime-modal-error-text-2": "Siirrä ensiksi muita etappeja.", "months": { "jan": "Tammi", "feb": "Helmi", @@ -96,15 +100,28 @@ "shown": "nähtävillä", "reset-project-deadlines": "Tyhjennä aikataulut", "reset-confirm-dialog-title": "Aikataulujen uudelleen luominen", - "reset-confirm-dialog-question": "Oletko varma, että haluat luoda aikataulut uudestaan? Tapahtumaa ei voi perua." + "reset-confirm-dialog-question": "Oletko varma, että haluat luoda aikataulut uudestaan? Tapahtumaa ei voi perua.", + "dates-are-preliminary": "Aikataulutiedot ovat alustavia, kunnes ne on vahvistettu.", + "cancel-confirmation":"Peruuta päivämäärien vahvistus", + "confirm-dates":"Vahvista päivämäärät", + "dates-confirmed":"Aikataulutiedot on vahvistettu.", + "new-esillaolo":"Lisää uusi esilläolo", + "delete-esillaolo":"Poista esilläolo", + "delete-first-esillaolo":"Ensimmäistä esilläoloa ei voi poistaa.", + "delete-first-lautakunta":"Ensimmäistä lautakuntaa ei voi poistaa.", + "delete-first-nahtavillaolo":"Ensimmäistä nähtävilläoloa ei voi poistaa.", + "timeline-group-header": "Vaiheiden etapit", + "modify-timeline":"Muokkaa aikataulua" }, "common": { "cancel": "Peruuta", "save": "Tallenna", + "save-timeline":"Tallenna aikataulu", "continue": "Jatka", "person":"Henkilö", "unit":"Yksikkö tai tiimi", - "keyword":"Hakusana" + "keyword":"Hakusana", + "close":"Sulje" }, "messages": { "deadlines-successfully-saved": "Aikataulut tallennettu", @@ -143,7 +160,11 @@ "addfield":"Kentän lisäys.", "total":"Yhteensä", "fields":"kenttää.", - "general-save-error":"Tallennus epäonnistui" + "general-save-error":"Tallennus epäonnistui", + "error-with-dates":"Päivämäärät tarkistettu:", + "fixed-timeline-dates":"Päivämäärät muutettu:", + "checking-dates":"Tarkistetaan päivämääriä", + "dates-confirmed":"Päivämäärät validoitu" }, "floor-areas": { "title": "Päivitä kerrosalatiedot", @@ -238,7 +259,10 @@ "error-prevent-add":"Virhe lomakkeella estää lisäyksen", "fieldset-info":"Yhteensä {{fieldAmount}} tietuetta.", "no-fields":"Suodatinvalinnalla ei löytynyt tämän otsikon alta suodatettavia kenttiä.", - "link-to-map":"Linkki projektin karttapalveluun." + "link-to-map":"Linkki projektin karttapalveluun.", + "add-new-board":"Lisää uusi lautakunta", + "add-new-presence":"Lisää uusi esilläolo", + "add-new-review": "Lisää uusi nähtävilläolo" }, "nav-header": { "latest-update": "Viimeisin muokkaus: {{latestUpdate}}", diff --git a/src/actions/projectActions.js b/src/actions/projectActions.js index 5e81949ee..7bb2a4d8a 100644 --- a/src/actions/projectActions.js +++ b/src/actions/projectActions.js @@ -104,7 +104,56 @@ export const FORM_ERROR_LIST = "formErrorList" export const RESET_FORM_ERRORS = "resetFormErrors" export const GET_ATTRIBUTE_DATA = "getAttributeData" export const SET_ATTRIBUTE_DATA = "setAttributeData" - +export const FETCH_DISABLED_DATES_START = 'fetchDisabledDatesStart'; +export const FETCH_DISABLED_DATES_SUCCESS = 'fetchDisabledDatesSuccess'; +export const FETCH_DISABLED_DATES_FAILURE = 'fetchDisabledDatesFailure'; +export const VALIDATE_DATE = 'validateDate'; +export const SET_DATE_VALIDATION_RESULT = 'setDateValidationResult'; +export const REMOVE_DEADLINES = 'removeDeadlines'; +export const UPDATE_DATE_TIMELINE = "updateDateTimeline" +export const RESET_ATTRIBUTE_DATA = "resetAttributeData" +export const VALIDATE_PROJECT_TIMETABLE = "validateProjectTimetable" +export const UPDATE_PROJECT_FAILURE = 'updateProjectFailure'; + +export const updateProjectFailure = (errorData) => ({ + type: UPDATE_PROJECT_FAILURE, + payload: errorData, +}); +export const validateProjectTimetable = () => ({ + type: VALIDATE_PROJECT_TIMETABLE +}); +export const resetAttributeData = (initialData) => ({ + type: RESET_ATTRIBUTE_DATA, + payload: {initialData}, +}); +export const updateDateTimeline = (field, newDate, formValues, isAdd, deadlineSections) => ({ + type: UPDATE_DATE_TIMELINE, + payload: { field, newDate, formValues, isAdd, deadlineSections}, +}); +export const removeDeadlines = (deadlines) => ({ + type: REMOVE_DEADLINES, + payload: deadlines, +}); +export const setDateValidationResult = (valid,result) => ({ + type: SET_DATE_VALIDATION_RESULT, + payload: {valid,result} +}); +export const validateDateAction = (field,projectName,date) => ({ + type: VALIDATE_DATE, + payload: {field,projectName,date} +}); +export const fetchDisabledDatesStart = (startDate, endDate) => ({ + type: FETCH_DISABLED_DATES_START, + payload: { startDate, endDate }, +}); +export const fetchDisabledDatesSuccess = (disabledDates) => ({ + type: FETCH_DISABLED_DATES_SUCCESS, + payload: disabledDates, +}); +export const fetchDisabledDatesFailure = (error) => ({ + type: FETCH_DISABLED_DATES_FAILURE, + payload: error, +}); export const setAttributeData = (fieldName,data,formName, set, nulledFields,i) =>({ type: SET_ATTRIBUTE_DATA, payload:{fieldName,data,formName, set, nulledFields,i} diff --git a/src/assets/icons/alert-icon-yellow.svg b/src/assets/icons/alert-icon-yellow.svg new file mode 100644 index 000000000..03320ee9c --- /dev/null +++ b/src/assets/icons/alert-icon-yellow.svg @@ -0,0 +1,3 @@ + diff --git a/src/assets/icons/angle-right.svg b/src/assets/icons/angle-right.svg new file mode 100644 index 000000000..f0fda1247 --- /dev/null +++ b/src/assets/icons/angle-right.svg @@ -0,0 +1,3 @@ + diff --git a/src/assets/icons/checkmark-icon-green.svg b/src/assets/icons/checkmark-icon-green.svg new file mode 100644 index 000000000..097504de2 --- /dev/null +++ b/src/assets/icons/checkmark-icon-green.svg @@ -0,0 +1,3 @@ + diff --git a/src/assets/icons/icon-error-red.svg b/src/assets/icons/icon-error-red.svg new file mode 100644 index 000000000..2ddcc1e09 --- /dev/null +++ b/src/assets/icons/icon-error-red.svg @@ -0,0 +1,3 @@ + diff --git a/src/assets/icons/lock-blue.svg b/src/assets/icons/lock-blue.svg new file mode 100644 index 000000000..e213697b6 --- /dev/null +++ b/src/assets/icons/lock-blue.svg @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/src/assets/icons/lock-open-blue.svg b/src/assets/icons/lock-open-blue.svg new file mode 100644 index 000000000..27566c6cc --- /dev/null +++ b/src/assets/icons/lock-open-blue.svg @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/src/assets/icons/lock-open.svg b/src/assets/icons/lock-open.svg new file mode 100644 index 000000000..cbb758db6 --- /dev/null +++ b/src/assets/icons/lock-open.svg @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/src/assets/icons/lock.svg b/src/assets/icons/lock.svg new file mode 100644 index 000000000..4bd53adce --- /dev/null +++ b/src/assets/icons/lock.svg @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/src/assets/icons/plus-blue.svg b/src/assets/icons/plus-blue.svg new file mode 100644 index 000000000..fd97d8a9e --- /dev/null +++ b/src/assets/icons/plus-blue.svg @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/src/assets/icons/plus.svg b/src/assets/icons/plus.svg new file mode 100644 index 000000000..158c6e813 --- /dev/null +++ b/src/assets/icons/plus.svg @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/src/assets/icons/trash-blue.svg b/src/assets/icons/trash-blue.svg new file mode 100644 index 000000000..b16caf352 --- /dev/null +++ b/src/assets/icons/trash-blue.svg @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/src/assets/icons/trash-grey.svg b/src/assets/icons/trash-grey.svg new file mode 100644 index 000000000..7d2f21d0d --- /dev/null +++ b/src/assets/icons/trash-grey.svg @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/src/components/ProjectTimeline/AddGroupModal.js b/src/components/ProjectTimeline/AddGroupModal.js new file mode 100644 index 000000000..05cc45aed --- /dev/null +++ b/src/components/ProjectTimeline/AddGroupModal.js @@ -0,0 +1,80 @@ +import React, { useEffect } from 'react'; +import { change } from 'redux-form' +import { useDispatch } from 'react-redux'; +import { EDIT_PROJECT_TIMETABLE_FORM } from '../../constants' +import { IconPlus,Button } from 'hds-react' +import { useTranslation } from 'react-i18next' +import PropTypes from 'prop-types' + +const AddGroupModal = ({toggleOpenAddDialog,addDialogStyle,addDialogData,closeAddDialog, allowedToEdit, isAdmin, timelineAddButton}) => { + const {t} = useTranslation() + const dispatch = useDispatch(); + + const addNew = (addedKey) => { + if(addedKey){ + dispatch(change(EDIT_PROJECT_TIMETABLE_FORM, addedKey, true)); + if (addedKey.includes("jarjestetaan_ehdotus_esillaolo")) { + const parts = addedKey.split("_"); + const index = "_"+ (parseInt(parts[parts.length - 1], 10)); + dispatch(change(EDIT_PROJECT_TIMETABLE_FORM, "kaavaehdotus_uudelleen_nahtaville"+index.toString(), true)); + } + closeAddDialog() + } + else{ + closeAddDialog() + } + } + + useEffect(() => { + if (timelineAddButton) { + if (toggleOpenAddDialog) { + timelineAddButton.classList.add("menu-open"); + } else { + const timelineAddButtons = document.getElementsByClassName('timeline-add-button'); + Array.from(timelineAddButtons).forEach(button => { + button.classList.remove("menu-open"); + }); + } + } + }, [toggleOpenAddDialog]) + + return ( +
{t('deadlines.project-stopped-text')}
+{t('deadlines.timeline-error-text')}
+{props.label}: {value} pv
+ :