diff --git a/.distignore b/.distignore new file mode 100644 index 0000000..e07a780 --- /dev/null +++ b/.distignore @@ -0,0 +1,5 @@ +.git +node_modules +build +environments +public \ No newline at end of file diff --git a/package.json b/package.json index c1d79c6..4adab0c 100644 --- a/package.json +++ b/package.json @@ -14,9 +14,11 @@ "@wordpress/react-i18n": "4.8.0", "@xyflow/react": "12.3.1", "codice-fiscale-js": "2.3.22", + "copy-to-clipboard": "^3.3.3", "deep-object-diff": "^1.1.9", "dompurify": "3.1.7", "fast-deep-equal": "3.1.3", + "hotkeys-js": "^3.13.7", "html-react-parser": "5.1.16", "jwt-decode": "4.0.0", "klona": "2.0.6", @@ -44,6 +46,7 @@ "@babel/plugin-syntax-jsx": "7.24.7", "@wordpress/babel-plugin-makepot": "6.8.0", "babel-plugin-macros": "3.1.0", + "node-wp-i18n": "^1.2.7", "sass": "1.79.3", "sass-loader": "16.0.2" }, @@ -55,7 +58,8 @@ "build:dev": "cp environments/dev/* public/loaded-files && rm public/loaded-files/dev.env && cp environments/dev/dev.env .env && react-scripts build --mode development", "build:prod": "cp environments/prod/* public/loaded-files && rm public/loaded-files/prod.env && cp environments/prod/prod.env .env && react-scripts build --mode production", "test": "react-scripts test", - "eject": "react-scripts eject" + "eject": "react-scripts eject", + "make-pot": "wpi18n makepot --domain-path=languages --domain=gepafin" }, "eslintConfig": { "extends": [ diff --git a/src/assets/scss/components/appPage.scss b/src/assets/scss/components/appPage.scss index a347c24..8f40ad9 100644 --- a/src/assets/scss/components/appPage.scss +++ b/src/assets/scss/components/appPage.scss @@ -167,6 +167,7 @@ display: flex; gap: 1rem; align-items: center; + justify-content: space-between; padding: 5px 0; &.rowContent { @@ -178,7 +179,7 @@ p { margin: 0; - flex: 1 1 100%; + /*flex: 1 1 100%;*/ } ul, ol { @@ -251,6 +252,7 @@ flex-direction: row; justify-content: space-between; gap: 16px; + width: 100%; } .appPageSection__checklist { diff --git a/src/assets/scss/components/layout.scss b/src/assets/scss/components/layout.scss index e226e1a..e350503 100644 --- a/src/assets/scss/components/layout.scss +++ b/src/assets/scss/components/layout.scss @@ -153,6 +153,16 @@ button[disabled] { filter: grayscale(1); } +.iconBtn { + background: transparent; + border: none; + + &:hover { + cursor: pointer; + color: var(--primary-text); + } +} + @media (max-width: 800px) { .inner { flex-direction: column; diff --git a/src/assets/scss/components/misc.scss b/src/assets/scss/components/misc.scss index 2aad9b4..ca53588 100644 --- a/src/assets/scss/components/misc.scss +++ b/src/assets/scss/components/misc.scss @@ -8,10 +8,15 @@ .p-badge { color: var(--menuitem-active-color); } -.p-button:not(.p-button-outlined, .p-button-secondary, .p-confirm-popup-reject, .p-button-link), -.p-button:not(.p-button-outlined, .p-button-secondary, .p-confirm-popup-reject, .p-button-link) span { +.p-button:not(.p-button-outlined, .p-button-secondary, .p-confirm-popup-reject, .p-button-link, .p-column-filter-add-button, .p-column-filter-remove-button), +.p-button:not(.p-button-outlined, .p-button-secondary, .p-confirm-popup-reject, .p-button-link, .p-column-filter-add-button, .p-column-filter-remove-button) span { color: var(--menuitem-active-color); } +.p-column-filter-remove-button { + span { + margin: 0 5px; + } +} .p-fileupload-row { .p-button-danger { background-color: #f44336; diff --git a/src/components/UnsavedChangesDetector/index.js b/src/components/UnsavedChangesDetector/index.js index fefef9d..53102cb 100644 --- a/src/components/UnsavedChangesDetector/index.js +++ b/src/components/UnsavedChangesDetector/index.js @@ -9,6 +9,7 @@ import { is, isNil } from 'ramda'; // store import { storeGet } from '../../store'; +import formatDateString from '../../helpers/formatDateString'; const UnsavedChangesDetector = ({ getValuesFn }) => { const warnIfUnsavedChanges = (event) => { @@ -16,16 +17,15 @@ const UnsavedChangesDetector = ({ getValuesFn }) => { formData.dates = []; if (formData.startDate) { - let starDate; + let startDate; if (is(String, formData.startDate)) { - starDate = formData.startDate; + startDate = formData.startDate; } else { - const tzAwareDate = new TZDate(formData.startDate, 'Europe/Berlin'); - starDate = tzAwareDate.toISOString().substring(0, 19); + startDate = formatDateString(formData.startDate); } - formData = wrap(formData).insert(['dates'], starDate, 0).value(); + formData = wrap(formData).insert(['dates'], startDate, 0).value(); delete formData.startDate; } if (formData.endDate) { @@ -34,8 +34,7 @@ const UnsavedChangesDetector = ({ getValuesFn }) => { if (is(String, formData.endDate)) { endDate = formData.endDate; } else { - const tzAwareDate = new TZDate(formData.endDate, 'Europe/Berlin'); - endDate = tzAwareDate.toISOString().substring(0, 19); + endDate = formatDateString(formData.endDate); } formData = wrap(formData).insert(['dates'], endDate, 1).value(); diff --git a/src/helpers/createUTCDate.js b/src/helpers/createUTCDate.js new file mode 100644 index 0000000..0609380 --- /dev/null +++ b/src/helpers/createUTCDate.js @@ -0,0 +1,18 @@ +/** + * + * @param dateObj {Date} + * @return {Date} + */ +const createUTCDate = (dateObj) => { + const comps = { + year: dateObj.getFullYear(), + month: dateObj.getMonth(), + day: dateObj.getDate(), + hours: dateObj.getHours(), + minutes: dateObj.getMinutes(), + seconds: dateObj.getSeconds() + }; + return new Date(Date.UTC(comps.year, comps.month, comps.day, 0, 0, 0)); +} + +export default createUTCDate; \ No newline at end of file diff --git a/src/helpers/formatDateString.js b/src/helpers/formatDateString.js new file mode 100644 index 0000000..9690a1b --- /dev/null +++ b/src/helpers/formatDateString.js @@ -0,0 +1,13 @@ +/** + * + * @param date {Date} + * @return {string} + */ +const formatDateString = (date) => { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + return `${year}-${month}-${day}T00:00:00`; +} + +export default formatDateString; \ No newline at end of file diff --git a/src/pages/Bandi/components/AllBandiTable/index.js b/src/pages/Bandi/components/AllBandiTable/index.js index 236098e..6eeba6a 100644 --- a/src/pages/Bandi/components/AllBandiTable/index.js +++ b/src/pages/Bandi/components/AllBandiTable/index.js @@ -14,9 +14,6 @@ import BandoService from '../../../../service/bando-service'; import { FilterMatchMode, FilterOperator } from 'primereact/api'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; -import { InputText } from 'primereact/inputtext'; -import { IconField } from 'primereact/iconfield'; -import { InputIcon } from 'primereact/inputicon'; import { Dropdown } from 'primereact/dropdown'; import { Button } from 'primereact/button'; import { Calendar } from 'primereact/calendar'; @@ -30,7 +27,6 @@ const AllBandiTable = () => { const [items, setItems] = useState(null); const [filters, setFilters] = useState(null); const [localAsyncRequest, setLocalAsyncRequest] = useState(false); - const [globalFilterValue, setGlobalFilterValue] = useState(''); const [statuses, setStatuses] = useState([]); useEffect(() => { @@ -62,16 +58,6 @@ const AllBandiTable = () => { initFilters(); }; - const onGlobalFilterChange = (e) => { - const value = e.target.value; - let _filters = { ...filters }; - - _filters['global'].value = value; - - setFilters(_filters); - setGlobalFilterValue(value); - }; - const initFilters = () => { setFilters({ global: { value: null, matchMode: FilterMatchMode.CONTAINS }, @@ -80,17 +66,12 @@ const AllBandiTable = () => { end_date: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] }, status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] }, }); - setGlobalFilterValue(''); }; const renderHeader = () => { return (
); }; @@ -134,13 +115,13 @@ const AllBandiTable = () => { return(
setFilters(e.filters)}> { const chosenCompanyId = useStore().main.chosenCompanyId(); @@ -192,8 +192,7 @@ const BandoApplication = () => { let fieldVal = formValues[cur]; if (formValues[cur] && formValues[cur].toISOString) { - const tzAwareDate = new TZDate(formValues[cur], 'Europe/Berlin'); - fieldVal = tzAwareDate.toISOString().substring(0, 19); + fieldVal = formatDateString(formValues[cur]); } fieldVal = isEmpty(fieldVal) ? null : fieldVal; diff --git a/src/pages/BandoEdit/components/BandoEditFormStep1/index.js b/src/pages/BandoEdit/components/BandoEditFormStep1/index.js index 5d1d12b..04c7680 100644 --- a/src/pages/BandoEdit/components/BandoEditFormStep1/index.js +++ b/src/pages/BandoEdit/components/BandoEditFormStep1/index.js @@ -26,6 +26,7 @@ import { isEmail } from '../../../../helpers/validators'; import { storeSet } from '../../../../store'; import set404FromErrorResponse from '../../../../helpers/set404FromErrorResponse'; import getTimeParsedFromString from '../../../../helpers/getTimeParsedFromString'; +import formatDateString from '../../../../helpers/formatDateString'; const BandoEditFormStep1 = forwardRef(function ({ initialData, setInitialData, getFormErrors, status }, ref) { const navigate = useNavigate(); @@ -62,8 +63,7 @@ const BandoEditFormStep1 = forwardRef(function ({ initialData, setInitialData, g if (is(String, formData.startDate)) { starDate = formData.startDate; } else { - const tzAwareDate = new TZDate(formData.startDate, 'Europe/Berlin'); - starDate = tzAwareDate.toISOString().substring(0, 19); + starDate = formatDateString(formData.startDate); } formData = wrap(formData).insert(['dates'], starDate, 0).value(); @@ -74,8 +74,7 @@ const BandoEditFormStep1 = forwardRef(function ({ initialData, setInitialData, g if (is(String, formData.endDate)) { endDate = formData.endDate; } else { - const tzAwareDate = new TZDate(formData.endDate, 'Europe/Berlin'); - endDate = tzAwareDate.toISOString().substring(0, 19); + endDate = formatDateString(formData.endDate); } formData = wrap(formData).insert(['dates'], endDate, 1).value(); diff --git a/src/pages/BandoEdit/components/BandoEditFormStep2/index.js b/src/pages/BandoEdit/components/BandoEditFormStep2/index.js index d8483b2..c933642 100644 --- a/src/pages/BandoEdit/components/BandoEditFormStep2/index.js +++ b/src/pages/BandoEdit/components/BandoEditFormStep2/index.js @@ -23,6 +23,7 @@ import { storeSet } from '../../../../store'; import getTimeParsedFromString from '../../../../helpers/getTimeParsedFromString'; import { mimeTypes } from '../../../../configData'; import { wrap } from 'object-path-immutable'; +import formatDateString from '../../../../helpers/formatDateString'; const BandoEditFormStep2 = forwardRef(function ({ initialData, setInitialData, getFormErrors, status }, ref) { const navigate = useNavigate(); @@ -60,8 +61,7 @@ const BandoEditFormStep2 = forwardRef(function ({ initialData, setInitialData, g if (is(String, formData.startDate)) { starDate = formData.startDate; } else { - const tzAwareDate = new TZDate(formData.startDate, 'Europe/Berlin'); - starDate = tzAwareDate.toISOString().substring(0, 19); + starDate = formatDateString(formData.starDate); } formData = wrap(formData).insert(['dates'], starDate, 0).value(); @@ -72,8 +72,7 @@ const BandoEditFormStep2 = forwardRef(function ({ initialData, setInitialData, g if (is(String, formData.endDate)) { endDate = formData.endDate; } else { - const tzAwareDate = new TZDate(formData.endDate, 'Europe/Berlin'); - endDate = tzAwareDate.toISOString().substring(0, 19); + endDate = formatDateString(formData.endDate); } formData = wrap(formData).insert(['dates'], endDate, 1).value(); diff --git a/src/pages/BandoForms/index.js b/src/pages/BandoForms/index.js index cee1051..db0fdff 100644 --- a/src/pages/BandoForms/index.js +++ b/src/pages/BandoForms/index.js @@ -3,31 +3,36 @@ import { __ } from '@wordpress/i18n'; import { useParams, useNavigate } from 'react-router-dom'; import { isEmpty } from 'ramda'; import { classNames } from 'primereact/utils'; -import { klona } from 'klona'; -// components -import { Button } from 'primereact/button'; -import { Dropdown } from 'primereact/dropdown'; +// store +import { storeSet } from '../../store'; // service import FormsService from '../../service/forms-service'; -// store -import { storeSet } from '../../store'; -import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; -import BandoService from '../../service/bando-service'; +// tools import uniqid from '../../helpers/uniqid'; +import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; + +// components +import { Button } from 'primereact/button'; +import { Dropdown } from 'primereact/dropdown'; +import BandoService from '../../service/bando-service'; import { Toast } from 'primereact/toast'; const BandoForms = () => { const { id } = useParams(); const navigate = useNavigate() - const [templates, setTemplates] = useState(null); - const [selectedTemplate, setSelectedTemplate] = useState(null); const [selectedForm, setSelectedForm] = useState(null); - const [selectedForDuplicateForm, setSelectedForDuplicateForm] = useState(null); + const [selectedForDuplicateForm, setSelectedForDuplicateForm] = useState(0); const [forms, setForms] = useState([]); const [bandoStatus, setBandoStatus] = useState(''); + const [allBandiOptions, setAllBandiOptions] = useState([]); + const [allBandiIsLoading, setAllBandiIsLoading] = useState(false); + const [selectedBandoIdForDuplicate, setSelectedBandoIdForDuplicate] = useState(0); + const [allFormsOptions, setAllFormsOptions] = useState([]); + const [allFormsIsLoading, setAllFormsIsLoading] = useState(false); + const [selectedFormIdForDuplicate, setSelectedFormIdForDuplicate] = useState(0); const toast = useRef(null); const doCreateNewForm = () => { @@ -53,11 +58,11 @@ const BandoForms = () => { if (!isEmpty(selectedFormArr)) { storeSet.main.setAsyncRequest(); - FormsService.getFormById(selectedForDuplicateForm, getFormCallback, errGetFormCallbacks); + FormsService.getFormById(selectedForDuplicateForm, getFormDuplicateCallback, errGetFormDuplicateCallbacks); } } - const getFormCallback = (data) => { + const getFormDuplicateCallback = (data) => { if (data.status === 'SUCCESS') { const newLabel = `${data.data.label} (copy)`; @@ -76,9 +81,10 @@ const BandoForms = () => { errFormCreateCallback ); } + storeSet.main.unsetAsyncRequest(); } - const errGetFormCallbacks = (data) => { + const errGetFormDuplicateCallbacks = (data) => { set404FromErrorResponse(data); storeSet.main.unsetAsyncRequest(); } @@ -141,17 +147,52 @@ const BandoForms = () => { storeSet.main.unsetAsyncRequest(); } + const getAllBandiCallback = (data) => { + if (data.status === 'SUCCESS') { + setAllBandiOptions(data.data.filter(o => o.id !== parseInt(id)).map(o => ({ label: o.name, value: o.id }))) + } + setAllBandiIsLoading(false); + } + + const errGetAllBandiCallback = () => { + setAllBandiIsLoading(false); + } + + const getAllFormsCallback = (data) => { + if (data.status === 'SUCCESS') { + setAllFormsOptions(data.data.map(o => ({ label: o.label, value: o.id }))); + } + setAllFormsIsLoading(false); + } + + const errGetAllFormsCallback = () => { + setAllFormsIsLoading(false); + } + + const doDuplicateFormOfAnotherBando = () => { + if (selectedBandoIdForDuplicate !== 0 && selectedFormIdForDuplicate !== 0) { + storeSet.main.setAsyncRequest(); + FormsService.getFormById(selectedFormIdForDuplicate, getFormDuplicateCallback, errGetFormDuplicateCallbacks); + } + } + + useEffect(() => { + if (selectedBandoIdForDuplicate !== 0) { + setAllFormsIsLoading(true); + FormsService.getFormsForCall(selectedBandoIdForDuplicate, getAllFormsCallback, errGetAllFormsCallback); + } + }, [selectedBandoIdForDuplicate]); + useEffect(() => { const parsed = parseInt(id) const bandoId = !isNaN(parsed) ? parsed : 0; - setTemplates([ - { label: 'Form template', value: 11 } - ]) - storeSet.main.setAsyncRequest(); BandoService.getBando(id, getCallback, errGetCallback); FormsService.getFormsForCall(bandoId, getFormsCallback, errGetFormsCallback); + + setAllBandiIsLoading(true); + BandoService.getBandi(getAllBandiCallback, errGetAllBandiCallback); }, [id]); return ( @@ -164,7 +205,7 @@ const BandoForms = () => {
- +
@@ -191,7 +232,7 @@ const BandoForms = () => {
*/}
-

{__('Crea un nuovo Form da Zero', 'gepafin')}

+

{__('Crea un nuovo Form o duplica', 'gepafin')}

{__('Inizia con un form completamente vuoto e personalizzabile', 'gepafin')}

{__('Duplica il form creato in precedenza', 'gepafin')}

- setSelectedForDuplicateForm(e.value)} - options={forms} - optionLabel="label" - placeholder={__('Seleziona form', 'gepafin')}/> -
+
+ +
+

{__('Duplica il form dal altro bando', 'gepafin')}

+
+ setSelectedBandoIdForDuplicate(e.value)} + options={allBandiOptions} + placeholder={__('Seleziona bando', 'gepafin')}/> + setSelectedFormIdForDuplicate(e.value)} + options={allFormsOptions} + placeholder={__('Seleziona form', 'gepafin')}/> +
diff --git a/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingTableColumns-old/index.js b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingTableColumns-old/index.js index ef568c0..6732a79 100644 --- a/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingTableColumns-old/index.js +++ b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingTableColumns-old/index.js @@ -127,7 +127,7 @@ const ElementSettingTableColumns = ({ })} + ; + }; + const roleBodyTemplate = (rowData) => { return rowData.role.roleName; }; @@ -148,24 +137,25 @@ const AllUsersTable = () => { return (
setFilters(e.filters)}> - + filterElement={statusFilterTemplate}/>