diff --git a/src/assets/scss/components/appForm.scss b/src/assets/scss/components/appForm.scss index 22860fa..10e9017 100644 --- a/src/assets/scss/components/appForm.scss +++ b/src/assets/scss/components/appForm.scss @@ -4,6 +4,7 @@ gap: 24px; } .appForm__field { + position: relative; display: flex; flex-direction: column; gap: 14px; @@ -58,9 +59,58 @@ cursor: pointer; } } + + :where(table) { + width: 100%; + border-collapse: collapse; + border-spacing: 0; + text-indent: 0; + border-right: 1px solid var(--table-border-color); + } + + td, + th { + padding: 10px; + border-top: 1px solid var(--table-border-color); + border-bottom: 1px solid var(--table-border-color); + border-left: 1px solid var(--table-border-color); + background-color: white; + color: var(--global-textColor); + font-size: 15px; + text-align: left; + text-align: start; + } + + th { + padding: 15px 10px; + font-weight: bold; + } + + td { + input { + width: 100%; + padding: 3px 5px; + } + } + + tfoot td, + tfoot th { + border-top: 1px solid var(--table-border-color); + border-bottom: 0 + } + + table.striped tbody tr:nth-child(odd) td, + table.striped tbody tr:nth-child(odd) th { + background-color: var(--table-border-color) + } } } +.appForm__field--required.appForm__field--required { + margin-left: 2px; + color: var(--message-error-color); +} + .appForm__fieldItem { display: flex; gap: 0.5rem; diff --git a/src/assets/scss/components/appPage.scss b/src/assets/scss/components/appPage.scss index a7c67c7..91d5da9 100644 --- a/src/assets/scss/components/appPage.scss +++ b/src/assets/scss/components/appPage.scss @@ -218,6 +218,16 @@ width: 100%; } +.appPageSection__titleClickable { + width: 100%; + height: 100%; + display: block; + + &:hover { + cursor: pointer; + } +} + .appTableHeader { display: flex; justify-content: space-between; diff --git a/src/assets/scss/components/layout.scss b/src/assets/scss/components/layout.scss index 2450cce..844fc06 100644 --- a/src/assets/scss/components/layout.scss +++ b/src/assets/scss/components/layout.scss @@ -103,48 +103,4 @@ body { } } } -} - -:where(table) { - width: 100%; - border-collapse: collapse; - border-spacing: 0; - text-indent: 0; - border-right: 1px solid var(--table-border-color); -} - -td, -th { - padding: 10px; - border-top: 1px solid var(--table-border-color); - border-bottom: 1px solid var(--table-border-color); - border-left: 1px solid var(--table-border-color); - background-color: white; - color: var(--global-textColor); - font-size: 15px; - text-align: left; - text-align: start; -} - -th { - padding: 15px 10px; - font-weight: bold; -} - -td { - input { - width: 100%; - padding: 3px 5px; - } -} - -tfoot td, -tfoot th { - border-top: 1px solid var(--table-border-color); - border-bottom: 0 -} - -table.striped tbody tr:nth-child(odd) td, -table.striped tbody tr:nth-child(odd) th { - background-color: var(--table-border-color) } \ No newline at end of file diff --git a/src/assets/scss/components/misc.scss b/src/assets/scss/components/misc.scss index 8a36b6b..7d54072 100644 --- a/src/assets/scss/components/misc.scss +++ b/src/assets/scss/components/misc.scss @@ -110,6 +110,12 @@ align-items: center; } +.p-accordion-header-text, .p-accordion-content { + p { + margin: 0; + } +} + .flex-1 { display: flex; align-items: center; diff --git a/src/components/FormField/components/Checkboxes/index.js b/src/components/FormField/components/Checkboxes/index.js index ed330f6..80c9b96 100644 --- a/src/components/FormField/components/Checkboxes/index.js +++ b/src/components/FormField/components/Checkboxes/index.js @@ -65,7 +65,7 @@ const Checkboxes = ({ return ( <> {input} {infoText ? {infoText} : null} diff --git a/src/components/FormField/components/Datepicker/index.js b/src/components/FormField/components/Datepicker/index.js index c2a84f0..a82eeae 100644 --- a/src/components/FormField/components/Datepicker/index.js +++ b/src/components/FormField/components/Datepicker/index.js @@ -20,7 +20,7 @@ const Datepicker = ({ return ( <> { + return acceptFormats + .map(v => { + const found = head(mimeTypes.filter(o => o.code === v)); + let res = v; + + if (found) { + res = found.name; + } + + return res; + }) + .join(', '); + } + useEffect(() => { setStateFieldData(defaultValue); register(fieldName, config) @@ -126,7 +144,7 @@ const Fileupload = ({ useEffect(() => { // eslint-disable-next-line no-useless-escape - setAcceptFormats(accept.replace(/\*/g, '.\*').replace(/,/g, '|')); + setAcceptFormats(accept.join(',').replace(/\*/g, '.\*').replace(/,/g, '|')); }, [accept]); useEffect(() => { @@ -140,8 +158,8 @@ const Fileupload = ({ sourceId || sourceId === 0 ? <> { + return acceptFormats + .map(v => { + const found = head(mimeTypes.filter(o => o.code === v)); + let res = v; + + if (found) { + res = found.name; + } + + return res; + }) + .join(', '); + } + useEffect(() => { setStateFieldData(defaultValue); register(fieldName, config) @@ -128,7 +145,7 @@ const FileuploadAsync = ({ useEffect(() => { // eslint-disable-next-line no-useless-escape - setAcceptFormats(accept.replace(/\*/g, '.\*').replace(/,/g, '|')); + setAcceptFormats(accept.join(',').replace(/\*/g, '.\*').replace(/,/g, '|')); }, [accept]); useEffect(() => { @@ -143,7 +160,7 @@ const FileuploadAsync = ({ ? <> { + console.log('defaultValue', defaultValue); const input = {inputgroup - ?
+ ?
{icon} diff --git a/src/components/FormField/components/Radio/index.js b/src/components/FormField/components/Radio/index.js index 37d7037..6bf202c 100644 --- a/src/components/FormField/components/Radio/index.js +++ b/src/components/FormField/components/Radio/index.js @@ -34,7 +34,7 @@ const Radio = ({ return ( <> {input} {infoText ? {infoText} : null} diff --git a/src/components/FormField/components/Select/index.js b/src/components/FormField/components/Select/index.js index f95ef06..6486e20 100644 --- a/src/components/FormField/components/Select/index.js +++ b/src/components/FormField/components/Select/index.js @@ -36,10 +36,10 @@ const Select = ({ return ( <> {inputgroup - ?
+ ?
{icon} diff --git a/src/components/FormField/components/Switch/index.js b/src/components/FormField/components/Switch/index.js index 250ceb2..29efd39 100644 --- a/src/components/FormField/components/Switch/index.js +++ b/src/components/FormField/components/Switch/index.js @@ -36,7 +36,7 @@ const Switch = ({ <>
{offLabel ? {offLabel} : null} diff --git a/src/components/FormField/components/Table/RenderTable/index.js b/src/components/FormField/components/Table/RenderTable/index.js new file mode 100644 index 0000000..cb7b31f --- /dev/null +++ b/src/components/FormField/components/Table/RenderTable/index.js @@ -0,0 +1,79 @@ +import React from 'react'; +import { flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table'; +import { wrap } from 'object-path-immutable'; + +const RenderTable = ({ data, columns, setRowsFn }) => { + const table = useReactTable({ + data, + columns, + defaultColumn: { + cell: ({ getValue, row: { index }, column: { id }, table }) => { + const initialValue = getValue(); + + const onBlur = (e) => { + table.options.meta?.updateData(index, id, e.target.value); + }; + + return ( + table.options.meta?.updateData(index, id, e.target.value)} + onBlur={onBlur} + /> + ); + }, + }, + getCoreRowModel: getCoreRowModel(), + meta: { + updateData: (rowIndex, columnId, value) => { + const newRowsData = wrap(data).set([rowIndex, columnId], value).value(); + setRowsFn(newRowsData); + }, + } + }); + + return ( + + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + ); + })} + + ))} + + + {table.getRowModel().rows.map((row) => { + return ( + + {row.getVisibleCells().map((cell) => { + return ( + + ); + })} + + ); + })} + +
+ {header.isPlaceholder ? null : ( + <> + {flexRender( + header.column.columnDef.header, + header.getContext() + )} + + )} +
+ {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} +
+ ) +} + +export default RenderTable \ No newline at end of file diff --git a/src/components/FormField/components/Table/index.js b/src/components/FormField/components/Table/index.js index 394c635..a35bffa 100644 --- a/src/components/FormField/components/Table/index.js +++ b/src/components/FormField/components/Table/index.js @@ -1,17 +1,16 @@ import React, { useEffect, useState } from 'react'; import { classNames } from 'primereact/utils'; import { __ } from '@wordpress/i18n'; -import { - useReactTable, - getCoreRowModel, - flexRender, -} from '@tanstack/react-table'; import { pathOr, isEmpty, isNil } from 'ramda'; import { wrap } from 'object-path-immutable'; + +//components import { Button } from 'primereact/button'; +import RenderTable from './RenderTable'; const Table = ({ fieldName, + setDataFn, label, register, errors, @@ -19,59 +18,46 @@ const Table = ({ defaultValue = [], tableColumns = [] }) => { - const [stateFieldData, setStateFieldData] = useState([]); - const [rowsData, setRowsData] = useState([]); - const [rowsDataLength, setRowsDataLength] = useState(0); - const [rowIndexToDelete, rowRowIndexToDelete] = useState(null); - const [isDisabledNewRow, setIsDisabledNewRow] = useState(false); + const [columnsCfg, setColumnsCfg] = useState([]); + const [rowsCfg, setRowsCfg] = useState([]); const [columns, setColumns] = useState([]); - const table = useReactTable({ - data: rowsData, - columns, - defaultColumn: { - cell: ({ getValue, row: { index }, column: { id }, table }) => { - const initialValue = getValue(); - - const onBlur = (e) => { - table.options.meta?.updateData(index, id, e.target.value); - }; - - return ( - table.options.meta?.updateData(index, id, e.target.value)} - onBlur={onBlur} - /> - ); - }, - }, - getCoreRowModel: getCoreRowModel(), - meta: { - updateData: (rowIndex, columnId, value) => { - const newRowsData = wrap(rowsData).set([rowIndex, columnId], value).value(); - setRowsData(newRowsData); - }, - }, - debugTable: true, - }); + const [rows, setRows] = useState([]); + const [shouldDisableNewRows, setShouldDisableNewRows] = useState(false); + const [rowIndexToDelete, rowRowIndexToDelete] = useState(null); const addNewRow = () => { - const obj = stateFieldData + const obj = columnsCfg .reduce((acc, cur) => { acc[cur.name] = '' return acc; }, {}); - setRowsData([...rowsData, obj]); + const newRowsData = [...rows, obj]; + setRows(newRowsData); + setDataFn(fieldName, newRowsData, { shouldValidate: true }); } const removeRow = (index) => { - rowRowIndexToDelete(index) + rowRowIndexToDelete(index); + } + + useEffect(() => { + if (!isNil(rowIndexToDelete)) { + const newRowsData = wrap(rows).del([rowIndexToDelete]).value(); + setRows(newRowsData); + setDataFn(fieldName, [...newRowsData], { shouldValidate: true }); + } + rowRowIndexToDelete(null); + }, [rowIndexToDelete]); + + const updateRows = (data) => { + setRows(data); + setDataFn(fieldName, data, { shouldValidate: true }); } useEffect(() => { let shouldDisableNewRows = false; - let columns = stateFieldData.map((o) => { + let newColumns = columnsCfg.map((o) => { const item = { accessorKey: o.name, header: () => o.label, @@ -88,10 +74,10 @@ const Table = ({ return item; }); - setIsDisabledNewRow(shouldDisableNewRows); + setShouldDisableNewRows(shouldDisableNewRows); - if (!shouldDisableNewRows && !isEmpty(columns)) { - columns.push({ + if (!shouldDisableNewRows && !isEmpty(newColumns)) { + newColumns.push({ accessorKey: 'actions', header: () => '', footer: (props) => props.column.id, @@ -104,20 +90,12 @@ const Table = ({ }) } - setColumns(columns); - }, [stateFieldData, rowsDataLength]); + setColumns(newColumns); + }, [columnsCfg]); useEffect(() => { - setRowsDataLength(rowsData.length); - }, [rowsData]); - - useEffect(() => { - if (!isNil(rowIndexToDelete)) { - const newRowsData = wrap(rowsData).del([rowIndexToDelete]).value(); - setRowsData(newRowsData); - } - rowRowIndexToDelete(null); - }, [rowIndexToDelete]); + setRows(rowsCfg); + }, [rowsCfg]); useEffect(() => { const stateFieldData = pathOr([], ['stateFieldData'], tableColumns); @@ -128,60 +106,21 @@ const Table = ({ }, {}); let rowsData = pathOr([obj], ['rowsData'], tableColumns); rowsData = isEmpty(rowsData) ? [obj] : rowsData; - setStateFieldData(stateFieldData); - setRowsData(rowsData); + setColumnsCfg(stateFieldData); + setRowsCfg(rowsData); }, [tableColumns]); useEffect(() => { - register(fieldName, config) + register(fieldName, config); }, []); return ( <> - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - ); - })} - - ))} - - - {table.getRowModel().rows.map((row) => { - return ( - - {row.getVisibleCells().map((cell) => { - return ( - - ); - })} - - ); - })} - -
- {header.isPlaceholder ? null : ( - <> - {flexRender( - header.column.columnDef.header, - header.getContext() - )} - - )} -
- {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} -
- {!isDisabledNewRow && !isEmpty(columns) + + {!isEmpty(columns) && !shouldDisableNewRows ?
{__('Aggiungi una righa', 'gepafin')}
: null} ) diff --git a/src/components/FormField/components/TextArea/index.js b/src/components/FormField/components/TextArea/index.js index f3a5949..6b660bc 100644 --- a/src/components/FormField/components/TextArea/index.js +++ b/src/components/FormField/components/TextArea/index.js @@ -17,7 +17,7 @@ const TextArea = ({ return ( <> {inputgroup - ?
+ ?
{icon} diff --git a/src/components/FormField/components/Wysiwyg/index.js b/src/components/FormField/components/Wysiwyg/index.js index 755396a..b476e52 100644 --- a/src/components/FormField/components/Wysiwyg/index.js +++ b/src/components/FormField/components/Wysiwyg/index.js @@ -2,6 +2,7 @@ import React from 'react'; import { classNames } from 'primereact/utils'; import { Controller } from 'react-hook-form'; import { Editor } from 'primereact/editor'; +import BlockingOverlay from '../../../BlockingOverlay'; const Wysiwyg = ({ fieldName, @@ -12,6 +13,7 @@ const Wysiwyg = ({ defaultValue, config = {}, infoText = null, + placeholder={placeholder}, disabled = false }) => { @@ -36,8 +38,9 @@ const Wysiwyg = ({ return ( <> + field.onChange(e.htmlValue)} style={{ height: 80 * rows }} className={classNames({ 'p-invalid': fieldState.invalid })} diff --git a/src/components/FormFieldRepeaterFaq/index.js b/src/components/FormFieldRepeaterFaq/index.js index c0f3df3..0d16fa3 100644 --- a/src/components/FormFieldRepeaterFaq/index.js +++ b/src/components/FormFieldRepeaterFaq/index.js @@ -9,9 +9,9 @@ import { Button } from 'primereact/button'; import { Dropdown } from 'primereact/dropdown'; import { Accordion, AccordionTab } from 'primereact/accordion'; import { Dialog } from 'primereact/dialog'; -import { InputText } from 'primereact/inputtext'; -import { InputTextarea } from 'primereact/inputtextarea'; import { InputSwitch } from 'primereact/inputswitch'; +import renderHtmlContent from '../../helpers/renderHtmlContent'; +import { Editor } from 'primereact/editor'; const FormFieldRepeaterFaq = ({ data, @@ -108,7 +108,8 @@ const FormFieldRepeaterFaq = ({ const footerEditDialog = () => { return
- + + + + + + + + + + + + ); + }; + + const header = renderHeader(); + useEffect(() => { const storeFieldData = data ?? []; setStateFieldData(storeFieldData); @@ -163,41 +184,42 @@ const FormFieldRepeaterFaq = ({ optionLabel="title"/>
- {stateFieldData.map((o, i) => -
+ {stateFieldData.map((o, i) => + +
- {o.value} + {renderHtmlContent(o.value)} -
-
- {o.isVisible - ? : null} - {!o.isVisible - ? : null} -
-
- } - > -

- {o.response} -

-
)} +
+
+ {o.isVisible + ? : null} + {!o.isVisible + ? : null} +
+
+ } + > +

+ {renderHtmlContent(o.response)} +

+ )} -
- - onChangeEditItem(e.target.value, 'title')}/> + + onChangeEditItem(e.htmlValue, 'title')} + style={{ height: 80 * 1 }} + />
- - onChangeEditItem(e.target.value, 'value')}/> + + onChangeEditItem(e.htmlValue, 'value')} + style={{ height: 80 * 1 }} + />
- - onChangeEditItem(e.target.value, 'response')} - rows={5} - cols={30}/> + + onChangeEditItem(e.htmlValue, 'response')} + style={{ height: 80 * 2 }} + />
- onChangeEditItem(e.value, 'isVisible')}/> + onChangeEditItem(e.value, 'isVisible')}/>
-
) diff --git a/src/configData.js b/src/configData.js index 885d8de..ca88a1a 100644 --- a/src/configData.js +++ b/src/configData.js @@ -1,6 +1,10 @@ export const mimeTypes = [ - { name: 'PDF file', code: 'application/pdf' }, - { name: 'ZIP file', code: 'application/zip' }, + { name: 'PDF', code: 'application/pdf' }, + { name: 'ZIP', code: 'application/zip' }, { name: 'Immagine', code: 'image/*' }, - { name: 'Word doc', code: 'application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document' } + { + name: 'Word doc', + code: 'application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document' + }, + { name: 'Excel doc', code: 'application/vnd.ms-excel' } ]; \ 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 a1a4e17..7600244 100644 --- a/src/pages/Bandi/components/AllBandiTable/index.js +++ b/src/pages/Bandi/components/AllBandiTable/index.js @@ -98,6 +98,10 @@ const AllBandiTable = () => { ); }; + const nameBodyTemplate = (rowData) => { + return {rowData.name} + } + const dateStartBodyTemplate = (rowData) => { return getDateFromISOstring(rowData.dates[0]); }; @@ -137,7 +141,8 @@ const AllBandiTable = () => { globalFilterFields={['name', 'status']} header={header} emptyMessage="Nothing found." onFilter={(e) => setFilters(e.filters)}> - { + const isAsyncRequest = useStore().main.isAsyncRequest(); const [items, setItems] = useState(null); const [filters, setFilters] = useState(null); - const [loading, setLoading] = useState(false); const [expandedRows, setExpandedRows] = useState(null); const [statuses, setStatuses] = useState([]); const navigate = useNavigate(); @@ -47,7 +49,7 @@ const AllBandiAccordion = () => { } const errGetCallbacks = (data) => { - console.log('errGetCallbacks', data) + set404FromErrorResponse(data); storeSet.main.unsetAsyncRequest(); } @@ -58,6 +60,22 @@ const AllBandiAccordion = () => { }); }; + const nameBodyTemplate = (rowData) => { + return { + let newExpandedRows; + if (isNil(expandedRows) || isNil(expandedRows[rowData.id])) { + newExpandedRows = isNil(expandedRows) + ? wrap({}).set([rowData.id], true).value() + : wrap(expandedRows).set([rowData.id], true).value(); + } else { + newExpandedRows = wrap(expandedRows).del([rowData.id]).value(); + } + setExpandedRows(newExpandedRows); + }}>{rowData.name} + } + const amountBodyTemplate = (rowData) => { return getNumberWithCurrency(rowData.amount); }; @@ -108,13 +126,16 @@ const AllBandiAccordion = () => { return(
- setExpandedRows(e.data)} + expandedRows={expandedRows} + onRowToggle={(e) => setExpandedRows(e.data)} rowExpansionTemplate={rowExpansionTemplate} onFilter={(e) => setFilters(e.filters)}> - + { + const rangeArr = range(1, totalSteps + 1); + const items = rangeArr.map(() => ({ label: 'Passo' })); + + // TODO update to using Steps after primereact is updated + return( + 0 !== totalSteps + ? {__('Passo', 'gepafin')}: {activeStepIndex + 1} + : null + ) + + /*return( + 0 !== totalSteps + ? + : null + )*/ +} + +export default ApplicationSteps \ No newline at end of file diff --git a/src/pages/BandoApplication/index.js b/src/pages/BandoApplication/index.js index 8a4f057..1d86840 100644 --- a/src/pages/BandoApplication/index.js +++ b/src/pages/BandoApplication/index.js @@ -2,7 +2,7 @@ import React, { useState, useEffect, useRef } from 'react'; import { __, sprintf } from '@wordpress/i18n'; import { useParams } from 'react-router-dom'; import { klona } from 'klona'; -import { head, range, is, pluck } from 'ramda'; +import { head, is, pluck, isEmpty } from 'ramda'; import { useForm } from 'react-hook-form'; import { TZDate } from '@date-fns/tz'; @@ -30,9 +30,9 @@ import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; import { Skeleton } from 'primereact/skeleton'; import { Button } from 'primereact/button'; import FormField from '../../components/FormField'; -import { Steps } from 'primereact/steps'; import { Toast } from 'primereact/toast'; import { Messages } from 'primereact/messages'; +import ApplicationSteps from './ApplicationSteps'; const BandoApplication = () => { const { id } = useParams(); @@ -43,7 +43,6 @@ const BandoApplication = () => { const [totalSteps, setTotalSteps] = useState(0); const [completedSteps, setCompletedSteps] = useState(0); const [activeStep, setActiveStep] = useState(1); - const [stepItems, setStepItems] = useState([{ label: 'Passo' }]); const isAsyncRequest = useStore().main.isAsyncRequest(); const toast = useRef(null); const formMsgs = useRef(null); @@ -54,7 +53,7 @@ const BandoApplication = () => { setValue, trigger, register, - getValues, + getValues } = useForm({ defaultValues: {}, mode: 'onChange' }); const values = getValues(); const validationFns = { @@ -67,6 +66,7 @@ const BandoApplication = () => { isUrl, isMarcaDaBollo } + const activeStepIndex = activeStep - 1; const onSubmit = () => { const applId = getApplicationId(); @@ -91,7 +91,6 @@ const BandoApplication = () => { } const errSubmitApplicationCallback = (data) => { - console.log(data) storeSet.main.unsetAsyncRequest(); if (data.status === 'VALIDATION_ERROR') { if (formMsgs.current) { @@ -120,7 +119,7 @@ const BandoApplication = () => { } } - const saveDraft = () => { + const saveDraft = (saveAndMove = '') => { trigger(); const formValues = getValues(); const usedFieldsIds = pluck('id', formData); @@ -157,7 +156,7 @@ const BandoApplication = () => { formMsgs.current.clear(); } - ApplicationService.saveDraft(applId, submitData, saveDraftCallback, errSaveDraftCallback, [ + ApplicationService.saveDraft(applId, submitData, (data) => saveDraftCallback(data, saveAndMove), errSaveDraftCallback, [ ['formId', formId] ]); } @@ -168,7 +167,7 @@ const BandoApplication = () => { return !isNaN(parsed) ? parsed : 0; } - const saveDraftCallback = (data) => { + const saveDraftCallback = (data, saveAndMove) => { if (data.status === 'SUCCESS') { if (toast.current) { toast.current.show({ @@ -177,8 +176,16 @@ const BandoApplication = () => { detail: __('Salvato!', 'gepafin') }); } - // update info about application completeness - ApplicationService.getApplicationForm(data.data.id, getStatusCheckCallback, errGetStatusCheckCallbacks); + if (!isEmpty(saveAndMove)) { + storeSet.main.setAsyncRequest(); + ApplicationService.getApplicationForm(data.data.id, getApplFormCallback, errGetApplFormCallbacks, [ + ['formId', formId], + ['action', saveAndMove] + ]); + } else { + // update info about application completeness + ApplicationService.getApplicationForm(data.data.id, getStatusCheckCallback, errGetStatusCheckCallbacks); + } } storeSet.main.unsetAsyncRequest(); } @@ -213,31 +220,37 @@ const BandoApplication = () => { } const goBackward = () => { - if (formId) { + saveDraft('PREVIOUS'); + /*if (formId) { const applId = getApplicationId(); storeSet.main.setAsyncRequest(); ApplicationService.getApplicationForm(applId, getApplFormCallback, errGetApplFormCallbacks, [ ['formId', formId], ['action', 'PREVIOUS'] ]); - } + }*/ } const goForward = () => { - if (formId) { + saveDraft('NEXT'); + /*if (formId) { const applId = getApplicationId(); storeSet.main.setAsyncRequest(); ApplicationService.getApplicationForm(applId, getApplFormCallback, errGetApplFormCallbacks, [ ['formId', formId], ['action', 'NEXT'] ]); - } + }*/ } const getApplFormCallback = (data) => { if (data.status === 'SUCCESS') { setBandoTitle(data.data.callTitle); setFormData(data.data.applicationFormResponse.content); + setFormId(data.data.formId); + setTotalSteps(data.data.totalFormSteps); + setCompletedSteps(data.data.completedSteps); + setActiveStep(data.data.currentStep); if (data.data.applicationFormResponse.formFields) { const submitData = data.data.applicationFormResponse.formFields.map((o) => ({ @@ -246,11 +259,6 @@ const BandoApplication = () => { })); setFormInitialData(submitData) } - - setFormId(data.data.formId); - setTotalSteps(data.data.totalFormSteps); - setCompletedSteps(data.data.completedSteps); - setActiveStep(data.data.currentStep); } storeSet.main.unsetAsyncRequest(); } @@ -285,11 +293,6 @@ const BandoApplication = () => { newFormData.map(o => setValue(o.fieldId, o.fieldValue)); }, [formInitialData]); - useEffect(() => { - const rangeArr = range(1, totalSteps + 1); - setStepItems(rangeArr.map(() => ({ label: 'Passo' }))); - }, [totalSteps]) - useEffect(() => { const applId = getApplicationId(); @@ -312,8 +315,7 @@ const BandoApplication = () => {
- {!isAsyncRequest - ? : null} +
@@ -327,12 +329,13 @@ const BandoApplication = () => { const text = head(o.settings.filter(o => o.name === 'text')); const placeholder = head(o.settings.filter(o => o.name === 'placeholder')); const options = head(o.settings.filter(o => o.name === 'options')); + const tableColumns = head(o.settings.filter(o => o.name === 'table_columns')); const step = head(o.settings.filter(o => o.name === 'step')); const mime = head(o.settings.filter(o => o.name === 'mime')); let mimeValue = ''; if (mime) { - mimeValue = mime.value.map(o => o.code).join(','); + mimeValue = mime.value.map(o => o.code); } const validations = Object.keys(o.validators).reduce((acc, cur) => { @@ -367,13 +370,14 @@ const BandoApplication = () => { register={register} errors={errors} defaultValue={values[o.id]} - maxFractionDigits={step} + maxFractionDigits={step ? step.value : 0} accept={mimeValue} config={validations} options={options ? options.value : []} setDataFn={setValue} sourceId={getApplicationId()} useGrouping={false} + tableColumns={tableColumns ? tableColumns.value : {}} /> })} diff --git a/src/pages/BandoEdit/components/BandoEditFormStep1/index.js b/src/pages/BandoEdit/components/BandoEditFormStep1/index.js index 5d904db..9cbb1d5 100644 --- a/src/pages/BandoEdit/components/BandoEditFormStep1/index.js +++ b/src/pages/BandoEdit/components/BandoEditFormStep1/index.js @@ -162,7 +162,6 @@ const BandoEditFormStep1 = forwardRef(function ({ initialData, getFormErrors, st } const errLookupdataCallback = (data) => { - console.log('errLookupdataCallback', data); storeSet.main.unsetAsyncRequest(); } diff --git a/src/pages/BandoEdit/components/BandoEditFormStep2/index.js b/src/pages/BandoEdit/components/BandoEditFormStep2/index.js index ab6cc67..515a716 100644 --- a/src/pages/BandoEdit/components/BandoEditFormStep2/index.js +++ b/src/pages/BandoEdit/components/BandoEditFormStep2/index.js @@ -242,7 +242,7 @@ const BandoEditFormStep2 = forwardRef(function ({ initialData, getFormErrors, st errors={errors} defaultValue={values['docs']} config={{ required: __('È obbligatorio', 'gepafin') }} - accept="application/pdf,application/vnd.ms-excel" + accept={["application/pdf", "application/vnd.ms-excel"]} chooseLabel={__('Aggiungi documento', 'gepafin')} multiple={true} doctype='document' diff --git a/src/pages/BandoEdit/index.js b/src/pages/BandoEdit/index.js index 2ece294..7ca869d 100644 --- a/src/pages/BandoEdit/index.js +++ b/src/pages/BandoEdit/index.js @@ -22,6 +22,7 @@ import BandoEditFormStep2 from './components/BandoEditFormStep2'; import { Messages } from 'primereact/messages'; import FormsService from '../../service/forms-service'; import BlockingOverlay from '../../components/BlockingOverlay'; +import { Toast } from 'primereact/toast'; const BandoEdit = () => { const isAsyncRequest = useStore().main.isAsyncRequest(); @@ -32,6 +33,7 @@ const BandoEdit = () => { const [forms, setForms] = useState([]); const formRef = useRef(null); const bandoMsgs = useRef(null); + const toast = useRef(null); const stepItems = [ { @@ -81,11 +83,18 @@ const BandoEdit = () => { bandoMsgs.current.show([ { id: '99', - sticky: true, severity: 'success', summary: '', + sticky: true, severity: 'info', summary: '', detail: __('Potrai pubblicare il tuo Bando.', 'gepafin'), closable: false } ]); + if (toast.current) { + toast.current.show({ + severity: 'info', + summary: '', + detail: __('Potrai pubblicare il tuo Bando.', 'gepafin') + }); + } } } storeSet.main.unsetAsyncRequest(); @@ -125,6 +134,13 @@ const BandoEdit = () => { } ]); } + if (toast.current) { + toast.current.show({ + severity: 'success', + summary: '', + detail: __('Pubblicato!', 'gepafin') + }); + } setData(data.data); } storeSet.main.unsetAsyncRequest(); @@ -247,6 +263,7 @@ const BandoEdit = () => {
+ {!isEmpty(data) ? <> diff --git a/src/pages/BandoFormsEdit/components/BuilderElementProperLabel/index.js b/src/pages/BandoFormsEdit/components/BuilderElementProperLabel/index.js index 788875b..bcc7ef3 100644 --- a/src/pages/BandoFormsEdit/components/BuilderElementProperLabel/index.js +++ b/src/pages/BandoFormsEdit/components/BuilderElementProperLabel/index.js @@ -1,5 +1,5 @@ import { useState, useEffect } from 'react' -import { head } from 'ramda'; +import { head, pathOr } from 'ramda'; // store import { useStore } from '../../../../store'; @@ -7,10 +7,11 @@ import renderHtmlContent from '../../../../helpers/renderHtmlContent'; const BuilderElementProperLabel = ({ id, defaultLabel }) => { const elements = useStore().main.formElements(); + const element = head(elements.filter(o => o.id === id)); const [label, setLabel] = useState(''); + const isRequired = pathOr(false, ['validators', 'isRequired'], element) useEffect(() => { - const element = head(elements.filter(o => o.id === id)); const label = head(element.settings.filter(o => o.name === 'label')); const text = head(element.settings.filter(o => o.name === 'text')); @@ -23,7 +24,10 @@ const BuilderElementProperLabel = ({ id, defaultLabel }) => { } }, [elements]); - return
{renderHtmlContent(label)}
+ return
+ {renderHtmlContent(label)} + {isRequired ? * : null} +
} export default BuilderElementProperLabel; \ No newline at end of file diff --git a/src/pages/BandoFormsEdit/index.js b/src/pages/BandoFormsEdit/index.js index aa8cf02..1233076 100644 --- a/src/pages/BandoFormsEdit/index.js +++ b/src/pages/BandoFormsEdit/index.js @@ -23,7 +23,7 @@ import FormsService from '../../service/forms-service'; import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; // TODO temp data -import { elementItems } from '../../tempData'; +//import { elementItems } from '../../tempData'; const BandoFormsEdit = () => { const { id, formId } = useParams(); @@ -168,7 +168,14 @@ const BandoFormsEdit = () => { } const openPreview = () => { - doSave(true); + if ('PUBLISH' !== bandoStatus) { + doSave(true); + } else { + const bandoId = getBandoId(); + const parsedFormId = parseInt(formId) + const bandoFormId = !isNaN(parsedFormId) ? parsedFormId : 0; + navigate(`/bandi/${bandoId}/forms/${bandoFormId}/preview`); + } } const confirmDelete = (event) => { @@ -208,8 +215,8 @@ const BandoFormsEdit = () => { const getElementItemsCallback = (data) => { if (data.status === 'SUCCESS') { - storeSet.main.elementItems(elementItems.sort((a, b) => a.sortOrder - b.sortOrder)); - //storeSet.main.elementItems(data.data.sort((a, b) => a.sortOrder - b.sortOrder)); + //storeSet.main.elementItems(elementItems.sort((a, b) => a.sortOrder - b.sortOrder)); + storeSet.main.elementItems(data.data.sort((a, b) => a.sortOrder - b.sortOrder)); } storeSet.main.unsetAsyncRequest(); } diff --git a/src/pages/BandoFormsPreview/index.js b/src/pages/BandoFormsPreview/index.js index ac87b3d..be57da4 100644 --- a/src/pages/BandoFormsPreview/index.js +++ b/src/pages/BandoFormsPreview/index.js @@ -150,7 +150,7 @@ const BandoFormsPreview = () => { }, {}); return ['paragraph'].includes(o.name) && text - ?
{renderHtmlContent(text.value)}
+ ?
{renderHtmlContent(text.value)}
: { options={options ? options.value : []} setDataFn={setValue} sourceId={0} + useGrouping={false} tableColumns={tableColumns ? tableColumns.value : {}} /> })} diff --git a/src/pages/BandoView/index.js b/src/pages/BandoView/index.js index 6616cd1..c776734 100644 --- a/src/pages/BandoView/index.js +++ b/src/pages/BandoView/index.js @@ -95,10 +95,11 @@ const BandoView = () => { icon="pi pi-arrow-left" iconPos="left"/>
- - - {data.name}/ - + {!isEmpty(data.images) + ? + + {data.name}/ + : null}

{__('Descrizione breve', 'gepafin')}

@@ -187,9 +188,9 @@ const BandoView = () => { {data.faq .filter(o => o.isVisible) - .map((o, i) => + .map((o, i) =>

- {o.response} + {renderHtmlContent(o.response)}

)}
diff --git a/src/pages/BandoViewBeneficiario/index.js b/src/pages/BandoViewBeneficiario/index.js index 703a692..14596ac 100644 --- a/src/pages/BandoViewBeneficiario/index.js +++ b/src/pages/BandoViewBeneficiario/index.js @@ -1,7 +1,7 @@ import React, { useState, useEffect, useRef } from 'react'; import { __, sprintf } from '@wordpress/i18n'; import { useNavigate, useParams } from 'react-router-dom'; -import { is, isEmpty, pathOr, isNil } from 'ramda'; +import { is, isEmpty, isNil } from 'ramda'; // store import { storeSet, useStore } from '../../store'; @@ -16,7 +16,6 @@ import renderHtmlContent from '../../helpers/renderHtmlContent'; import { Skeleton } from 'primereact/skeleton'; import { Accordion } from 'primereact/accordion'; import { AccordionTab } from 'primereact/accordion'; -import { InputTextarea } from 'primereact/inputtextarea'; import { Button } from 'primereact/button'; import { Messages } from 'primereact/messages'; import { Message } from 'primereact/message'; @@ -29,14 +28,13 @@ import { Editor } from 'primereact/editor'; const BandoViewBeneficiario = () => { const isAsyncRequest = useStore().main.isAsyncRequest(); - const companies = useStore().main.companies(); + const chosenCompanyId = useStore().main.chosenCompanyId(); const { id } = useParams(); const navigate = useNavigate(); const [data, setData] = useState({}); const [newQuestion, setNewQuestion] = useState(''); const [applicationObj, setApplicationObj] = useState(true); const bandoMsgs = useRef(null); - const chosenCompanyId = pathOr(0, [0, 'id'], companies); const scaricaBando = () => { @@ -90,12 +88,12 @@ const BandoViewBeneficiario = () => { bandoMsgs.current.clear(); } const obj = { - "id": null, - "lookUpDataId": null, - "title": newQuestion, - "value": newQuestion, - "response": "", - "isVisible": false + 'id': null, + 'lookUpDataId': null, + 'title': newQuestion, + 'value': newQuestion, + 'response': '', + 'isVisible': false } storeSet.main.setAsyncRequest(); FaqItemService.addQuestion(id, obj, createCallBack, errCreateCallback, [['companyId', chosenCompanyId]]) @@ -161,7 +159,7 @@ const BandoViewBeneficiario = () => { const getApplCallback = (data) => { if (data.status === 'SUCCESS') { - if(data.data.length) { + if (data.data.length) { setApplicationObj(data.data[0]); } } @@ -220,10 +218,11 @@ const BandoViewBeneficiario = () => { {!isAsyncRequest && !isEmpty(data) ?
- - - {data.name}/ - + {!isEmpty(data.images) + ? + + {data.name}/ + : null}

{__('Descrizione breve', 'gepafin')}

@@ -312,11 +311,11 @@ const BandoViewBeneficiario = () => { {data.faq .filter(o => o.isVisible) - .map((o, i) => -

- {o.response} -

-
)} + .map((o, i) => +

+ {renderHtmlContent(o.response)} +

+
)}
@@ -345,7 +344,8 @@ const BandoViewBeneficiario = () => { {chosenCompanyId === 0 ? <> - + : null} @@ -387,7 +387,8 @@ const BandoViewBeneficiario = () => {

{__('Contatti per Assistenza', 'gepafin')}

Email: {data.email}

- {!isNil(data.phoneNumber) ?

{__('Telefono', 'gepafin')}: +39 {data.phoneNumber}

: null} + {!isNil(data.phoneNumber) ? +

{__('Telefono', 'gepafin')}: +39 {data.phoneNumber}

: null}
diff --git a/src/pages/ProfileCompany/index.js b/src/pages/ProfileCompany/index.js index 13cf9ed..8b595ef 100644 --- a/src/pages/ProfileCompany/index.js +++ b/src/pages/ProfileCompany/index.js @@ -1,9 +1,10 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'; import { __ } from '@wordpress/i18n'; -import { isEmpty, isNil, pathOr } from 'ramda'; +import { isEmpty, isNil, pathOr, head } from 'ramda'; +import { klona } from 'klona'; // store -import { storeSet, useStore } from '../../store'; +import { storeSet, useStore, storeGet } from '../../store'; // components import { Messages } from 'primereact/messages'; @@ -18,7 +19,6 @@ import CompanyService from '../../service/company-service'; // tools import { isPIVA } from '../../helpers/validators'; import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; -import { klona } from 'klona'; const ProfileCompany = () => { const isAsyncRequest = useStore().main.isAsyncRequest(); @@ -67,7 +67,19 @@ const ProfileCompany = () => { const updateCallback = (data) => { if (data.status === 'SUCCESS') { - //setData(getFormattedBandiData(data.data)); + const company = klona(data.data); + const companies = storeGet.main.companies(); + const existingCompany = head(companies.filter(o => o.id === company.id)); + let newCompanies = []; + + if (existingCompany) { + newCompanies = companies.map(o => o.id === company.id ? company : o) + } else { + newCompanies = [...companies, company]; + storeSet.main.chosenCompanyId(company.id); + } + + storeSet.main.companies(newCompanies); } storeSet.main.unsetAsyncRequest(); } @@ -129,7 +141,6 @@ const ProfileCompany = () => { useEffect(() => { const chosenCompany = pathOr({}, [0], companies); - console.log('chosenCompany', chosenCompany, companies) setFormInitialData(chosenCompany); }, [companies]); diff --git a/src/pages/Registration/index.js b/src/pages/Registration/index.js index 9f863dc..879a231 100644 --- a/src/pages/Registration/index.js +++ b/src/pages/Registration/index.js @@ -161,10 +161,7 @@ const Registration = () => { control={control} errors={errors} config={{ - required: __('È obbligatorio', 'gepafin'), - validate: { - isCodiceFiscale - } + required: __('È obbligatorio', 'gepafin') }} placeholder="ABC1234" /> diff --git a/src/store/initial.js b/src/store/initial.js index 64db6ae..6bbb24e 100644 --- a/src/store/initial.js +++ b/src/store/initial.js @@ -6,6 +6,7 @@ const initialStore = { userData: {}, token: '', companies: [], + chosenCompanyId: 0, // bando form formInitialData: {}, // form builder diff --git a/src/store/zustand-x-opts.js b/src/store/zustand-x-opts.js index 5e8c577..6b4e831 100644 --- a/src/store/zustand-x-opts.js +++ b/src/store/zustand-x-opts.js @@ -6,7 +6,8 @@ const zustandXOpts = { enabled: true, partialize: (state) => ({ //userData: state.userData, - token: state.token + token: state.token, + chosenCompanyId: state.chosenCompanyId, }), } } diff --git a/src/tempData.js b/src/tempData.js index a15f34f..5493696 100644 --- a/src/tempData.js +++ b/src/tempData.js @@ -1,337 +1,3 @@ -export const bandoTest = { - "name": "Innovazione digitale 2024", - "confidi": false, - "descriptionShort": "Supporto alle PMI per progetti di digitalizzazione e innovazione tecnologica.", - "descriptionLong": "Il bando \"Innovazione Digitale 2024\" mira a sostenere le PMI nell'adozione di tecnologie digitali innovative. I progetti finanziabili includono l'implementazione di soluzioni di intelligenza artificiale, blockchain, IoT, e altre tecnologie avanzate che possono migliorare la competitività delle imprese.", - "documentationRequested": "Documentazione richiesta*", - "dates": [ - "2024-08-27T22:00:00.000Z", - "2024-10-29T23:00:00.000Z" - ], - "amount": 10000, - "amountMax": 2500, - "aimedTo": [ - { - "id": 3, - "value": "PMI con sede in Umbria", - "status": "existing" - } - ], - "faq": [ - { - "id": 2, - "question": "Question 1?", - "answer": "Lorem ipsum dolor", - "visible": true, - "status": "existing" - } - ], - status: 'draft', - id: 11, - createdDate: "2024-08-07T08:14:07.849Z", - updatedDate: "2024-08-07T08:14:07.849Z", - "documentation":[ - { - "id":18, - "name":"SCR-20240820-kiwn.pdf", - "filePath":"https://mementoresources.s3.eu-west-1.amazonaws.com/gepafin/SCR-20240820-kiwn.pdf", - "description":null, - "createdDate":"2024-08-26T06:51:11.800799252", - "updatedDate":"2024-08-26T06:51:11.800826092" - } - ], - "criteria":[ - { - "id":null, - "value":"Innovatività del progetto", - "status":"new", - "score":9 - }, - { - "id":null, - "value":"Impatto sulla competitività dell'azienda", - "status":"new", - "score":3 - }, - { - "id":null, - "value":"Sostenibilità economico-finanziaria", - "status":"new", - "score":5 - } - ], - "threshold":11, - "images":[ - { - "id":19, - "name":"photo-1618245318763-a15156d6b23c.avif", - "filePath":"https://mementoresources.s3.eu-west-1.amazonaws.com/gepafin/photo-1618245318763-a15156d6b23c.avif", - "description":null, - "createdDate":"2024-08-26T07:28:16.954763338", - "updatedDate":"2024-08-26T07:28:16.954843237" - } - ], - "checklist":[ - { - "id":null, - "value":"Innovatività del progetto", - "status":"new" - }, - { - "id":null, - "value":"Some new check", - "status":"new" - }, - { - "id":null, - "value":"Check #2", - "status":"new" - } - ] -} - -export const formData = { - id: 15, - label: 'La forma per Innovazione digitale 2024', - content: [ - { - "id": "a9a8aeb479", - "name": "textinput", - "label": "Testo Breve", - "settings": [ - { - "name": "label", - "value": "Testo Breve" - }, - { - "name": "placeholder", - "value": "" - } - ], - "validators": { - "isRequired": true, - "minLength": "3", - "maxLength": null, - "pattern": null, - "custom": null - }, - "dbId": 1 - }, - { - "id": "a20469fc97", - "name": "textarea", - "label": "Testo Lungo", - "settings": [ - { - "name": "label", - "value": "Testo Lungo" - }, - { - "name": "placeholder", - "value": "" - } - ], - "validators": { - "isRequired": false, - "minLength": null, - "maxLength": null, - "pattern": null, - "custom": null - }, - "dbId": 2 - }, - { - "id": "a21dc560f6", - "name": "wysiwyg", - "label": "Campo di Testo Formattato", - "settings": [ - { - "name": "label", - "value": "Testo Formattato" - }, - { - "name": "placeholder", - "value": "" - } - ], - "validators": { - "isRequired": false, - "minLength": null, - "maxLength": null, - "pattern": null, - "custom": null - }, - "dbId": 3 - }, - { - "id": "a5c3860c1a", - "name": "numberinput", - "label": "Campo Numerico", - "settings": [ - { - "name": "label", - "value": "Numero" - }, - { - "name": "placeholder", - "value": 0 - }, - { - "name": "step", - "value": 0 - } - ], - "validators": { - "isRequired": false, - "min": null, - "max": null, - "pattern": null, - "custom": null - }, - "dbId": 4 - }, - { - "id": "a7252ecc8d", - "name": "radio", - "label": "Scelta Singola", - "settings": [ - { - "name": "label", - "value": "Scelta Singola" - }, - { - "name": "options", - "value": [ - { - "name": "o8df4ffa62", - "label": "Radio opzione A" - }, - { - "name": "o3ed6fb4d8", - "label": "Radio opzione B" - } - ] - } - ], - "validators": { - "isRequired": true, - "custom": null - }, - "dbId": 5 - }, - { - "id": "a778783c9d", - "name": "select", - "label": "Menu a Tendina", - "settings": [ - { - "name": "label", - "value": "Menu a Tendina" - }, - { - "name": "options", - "value": [ - { - "name": "od9f50d8a8", - "label": "Opzione A" - }, - { - "name": "o8cb208732", - "label": "Opzione B" - } - ] - } - ], - "validators": { - "isRequired": false, - "custom": null - }, - "dbId": 6 - }, - { - "id": "afee29df1a", - "name": "switch", - "label": "Casella di Spunta", - "settings": [ - { - "name": "label", - "value": "Casella di Spunta" - } - ], - "validators": { - "isRequired": false - }, - "dbId": 8 - }, - { - "id": "a5fdbd77df", - "name": "checkboxes", - "label": "Scelta Multipla", - "settings": [ - { - "name": "label", - "value": "Scelta Multipla" - }, - { - "name": "options", - "value": [ - { - "name": "o55ea20665", - "label": "Opz checkbox A" - }, - { - "name": "oc10db3d79", - "label": "Opz checkbox B" - } - ] - } - ], - "validators": { - "isRequired": true, - "custom": null - }, - "dbId": 7 - }, - { - "id": "a2810fd8a1", - "name": "fileupload", - "label": "Caricamento File", - "settings": [ - { - "name": "label", - "value": "Caricamento File" - }, - { - "name": "mime", - "value": ['image/jpeg', 'image/png'] - } - ], - "validators": { - "isRequired": true, - "maxSize": 100000, - "custom": null - }, - "dbId": 10 - }, - { - "id": "ae14c94da7", - "name": "datepicker", - "label": "Data", - "settings": [ - { - "name": "label", - "value": "Data" - } - ], - "validators": { - "isRequired": true, - "custom": null - }, - "dbId": 9 - } - ] -}; - export const elementItems = [ { id: 1,