diff --git a/src/assets/scss/components/appForm.scss b/src/assets/scss/components/appForm.scss index 6eefda1..22860fa 100644 --- a/src/assets/scss/components/appForm.scss +++ b/src/assets/scss/components/appForm.scss @@ -45,6 +45,20 @@ input[disabled], div.p-disabled:not(.p-inputswitch) { background-color: #e3e3e3; } + + &.table { + div.addNewTableRow { + width: 100%; + text-align: center; + padding: 5px 0; + background: var(--table-border-color); + color: var(--primary-text); + + &:hover { + cursor: pointer; + } + } + } } .appForm__fieldItem { diff --git a/src/assets/scss/components/formBuilder.scss b/src/assets/scss/components/formBuilder.scss index d90b097..3568f39 100644 --- a/src/assets/scss/components/formBuilder.scss +++ b/src/assets/scss/components/formBuilder.scss @@ -61,7 +61,7 @@ .label { p { - margin-bottom: 10px; + margin-bottom: 0; &.ql-indent-1 { padding-left: 3em; @@ -179,4 +179,13 @@ display: flex; flex-direction: column; gap: 0.5rem; +} + +.formElementSettings__repeaterItem { + +} + +.formElementSettings__subRepeater { + padding: 10px 20px; + background-color: #f9f9f9; } \ No newline at end of file diff --git a/src/assets/scss/components/layout.scss b/src/assets/scss/components/layout.scss index 36ed39b..2450cce 100644 --- a/src/assets/scss/components/layout.scss +++ b/src/assets/scss/components/layout.scss @@ -24,6 +24,7 @@ body { flex-direction: column; flex-grow: 1; } + .inner { display: flex; height: 100%; @@ -102,4 +103,48 @@ 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 0bf2216..8a36b6b 100644 --- a/src/assets/scss/components/misc.scss +++ b/src/assets/scss/components/misc.scss @@ -106,6 +106,16 @@ background-color: rgba(255,255,255,0.3) } +.p-inputgroup { + align-items: center; +} + +.flex-1 { + display: flex; + align-items: center; + gap: 0.5em; +} + .mb-2 { margin-bottom: 4px; } diff --git a/src/assets/scss/theme.scss b/src/assets/scss/theme.scss index 08e7c08..9846b19 100644 --- a/src/assets/scss/theme.scss +++ b/src/assets/scss/theme.scss @@ -15,9 +15,10 @@ --global-textColor: #4B5563; --theme-highlight-background: #BADEBE; --primary-text: #3B7C43; + --table-border-color: #B7B7B7B2; --message-error-background: #ffdbdb; --message-error-color: #C2504D; - --message-info-background: rgba(219, 234, 254, 0.70); + --message-info-background: rgba(183, 183, 183, 0.7); --message-info-color: #3B82F6; --card-full-background-color-2: #EEC137; diff --git a/src/components/FormField/components/Table/index.js b/src/components/FormField/components/Table/index.js new file mode 100644 index 0000000..5967ec8 --- /dev/null +++ b/src/components/FormField/components/Table/index.js @@ -0,0 +1,150 @@ +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 } from 'ramda'; +import { wrap } from 'object-path-immutable'; + +const Table = ({ + fieldName, + label, + register, + errors, + config = {}, + defaultValue = [], + tableColumns = [] + }) => { + const [stateFieldData, setStateFieldData] = useState([]); + const [rowsData, setRowsData] = useState([]); + const [isDisabledNewRow, setIsDisabledNewRow] = useState(false); + 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 addNewRow = () => { + const obj = stateFieldData + .reduce((acc, cur) => { + acc[cur.name] = '' + return acc; + }, {}); + setRowsData([...rowsData, obj]); + } + + useEffect(() => { + let shouldDisableNewRows = false; + + const columns = stateFieldData.map((o) => { + const item = { + accessorKey: o.name, + header: () => o.label, + footer: (props) => props.column.id + } + + if (o.predefined) { + shouldDisableNewRows = true; + item.cell = (info) => { + return info.getValue(); + } + } + + return item; + }); + + setIsDisabledNewRow(shouldDisableNewRows); + setColumns(columns); + }, [stateFieldData]); + + useEffect(() => { + const stateFieldData = pathOr([], ['stateFieldData'], tableColumns); + const rowsData = pathOr([], ['rowsData'], tableColumns); + setStateFieldData(stateFieldData); + setRowsData(rowsData); + }, [tableColumns]); + + useEffect(() => { + 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) + ?
{__('Aggiungi una righa', 'gepafin')}
+ : null} + ) +} + +export default Table; \ No newline at end of file diff --git a/src/components/FormField/index.js b/src/components/FormField/index.js index 477ef00..bde12fb 100644 --- a/src/components/FormField/index.js +++ b/src/components/FormField/index.js @@ -15,6 +15,7 @@ import Radio from './components/Radio'; import Wysiwyg from './components/Wysiwyg'; import Checkboxes from './components/Checkboxes'; import Fileupload from './components/Fileupload'; +import Table from './components/Table'; const FormField = (props) => { const fields = { @@ -29,7 +30,8 @@ const FormField = (props) => { select: Select, radio: Radio, wysiwyg: Wysiwyg, - checkboxes: Checkboxes + checkboxes: Checkboxes, + table: Table } const Comp = !isNil(fields[props.type]) ? fields[props.type] : null; diff --git a/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSetting/index.js b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSetting/index.js index 3140fd5..ca6d5d7 100644 --- a/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSetting/index.js +++ b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSetting/index.js @@ -9,6 +9,7 @@ import { MultiSelect } from 'primereact/multiselect'; import { Editor } from 'primereact/editor'; import { mimeTypes } from '../../../../../../configData'; +import ElementSettingTableColumns from '../ElementSettingTableColumns'; const ElementSetting = ({ setting, changeFn, updateDataFn }) => { @@ -18,7 +19,8 @@ const ElementSetting = ({ setting, changeFn, updateDataFn }) => { step: __('Numero Decimali', 'gepafin'), options: __('Opzioni', 'gepafin'), mime: __('Tipo di file', 'gepafin'), - text: __('Testo formattato', 'gepafin') + text: __('Testo formattato', 'gepafin'), + table_columns: __('Colonne', 'gepafin'), } const renderHeader = () => { @@ -41,31 +43,42 @@ const ElementSetting = ({ setting, changeFn, updateDataFn }) => { const header = renderHeader(); - return
- - {setting.name === 'options' - ? { + if (setting.name === 'options') { + return - : setting.name === 'mime' - ? updateDataFn(setting.name, e.value)} - options={mimeTypes} - optionLabel="name" - display="chip" - placeholder={__('Scegli', 'gepafin')} /> - : setting.name === 'text' - ? changeFn(e.htmlValue, setting.name)} - style={{ height: 80 * 4 }} - /> - : changeFn(e.target.value, setting.name)}/>} + } else if (setting.name === 'mime') { + return updateDataFn(setting.name, e.value)} + options={mimeTypes} + optionLabel="name" + display="chip" + placeholder={__('Scegli', 'gepafin')} /> + } else if (setting.name === 'text') { + return changeFn(e.htmlValue, setting.name)} + style={{ height: 80 * 4 }} + /> + } else if (setting.name === 'table_columns') { + return + } else { + return changeFn(e.target.value, setting.name)}/> + } + } + + return
+ + {getProperField(setting)}
} diff --git a/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingRepeater/index.js b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingRepeater/index.js index b430902..abb3ef1 100644 --- a/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingRepeater/index.js +++ b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingRepeater/index.js @@ -45,10 +45,9 @@ const ElementSettingRepeater = ({ }, []); useEffect(() => { - console.log('useEffect', [...stateFieldData]) setDataFn(name, [...stateFieldData]); }, [stateFieldData]) -console.log('stateFieldData', stateFieldData, value) + return (
{stateFieldData.map((o, i) =>
diff --git a/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingTableColumns-old/index.js b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingTableColumns-old/index.js new file mode 100644 index 0000000..ef568c0 --- /dev/null +++ b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingTableColumns-old/index.js @@ -0,0 +1,139 @@ +import React, { useEffect, useState } from 'react'; +import { __ } from '@wordpress/i18n'; +import { wrap } from 'object-path-immutable'; +import { findIndex, propEq } from 'ramda'; + +// components +import { InputText } from 'primereact/inputtext'; +import { Button } from 'primereact/button'; +import { InputSwitch } from 'primereact/inputswitch'; + +// tools +import uniqid from '../../../../../../helpers/uniqid'; + +const ElementSettingTableColumns = ({ + value, + name, + setDataFn + }) => { + const [stateFieldData, setStateFieldData] = useState([]); + const [rowsData, setRowsData] = useState([]); + + const removeItem = (index) => { + const newData = stateFieldData.toSpliced(index, 1); + setStateFieldData(newData); + } + + const addNewItem = () => { + setStateFieldData([...stateFieldData, { name: uniqid('o'), label: '', predefined: false }]); + } + + const addNewRow = (index) => { + const newStateFieldData = wrap(stateFieldData) + .insert([index, 'rows'], { label: '' }, stateFieldData[index].rows.length) + .value(); + setStateFieldData(newStateFieldData); + } + + const removeRow = (index, indexK) => { + const newStateFieldData = wrap(stateFieldData) + .del([index, 'rows', indexK]) + .value(); + setStateFieldData(newStateFieldData); + } + + const onInputChange = (e, index) => { + const { value } = e.target; + const newData = stateFieldData.map((o, i) => { + if (i === index) { + o.label = value; + } + return o; + }) + setStateFieldData(newData); + } + + const onSubInputChange = (e, index, indexK) => { + const { value } = e.target; + const newStateFieldData = wrap(stateFieldData) + .set([index, 'rows', indexK, 'label'], value) + .value(); + setStateFieldData(newStateFieldData); + } + + const setChecked = (value, index) => { + const newData = stateFieldData.map((o, i) => { + if (i === index) { + o.predefined = value; + if (value === false) { + o.rows = []; + } + } + return o; + }) + setStateFieldData(newData); + } + + const properField = (item, i) => { + return <> + onInputChange(e, i)}/> +
+ {__('Predefinito?', 'gepafin')} + setChecked(e.value, i)}/> +
+ + } + + const properSubField = (item, i, k) => { + return onSubInputChange(e, i, k)}/> + } + + useEffect(() => { + const storeFieldData = value ?? []; + setStateFieldData(storeFieldData); + }, []); + + useEffect(() => { + setDataFn(name, [...stateFieldData]); + }, [stateFieldData]); + + stateFieldData.filter(o => o.predefined) + + return ( + <> +
+ {stateFieldData.map((o, i) =>
+
+ {properField(o, i)} +
+
)} +
+ {stateFieldData + .filter(o => o.predefined) + .map((o, i) =>
+
+ +
+ {o.rows.map((c, k) => { + const properIndex = findIndex(propEq(o.name, 'name'))(stateFieldData); + return
+
+ {properSubField(c, properIndex, k)} +
+
+ })} +
+
+
)} + + ) +} + +export default ElementSettingTableColumns; \ No newline at end of file diff --git a/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingTableColumns/index.js b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingTableColumns/index.js new file mode 100644 index 0000000..5815843 --- /dev/null +++ b/src/pages/BandoFormsEdit/components/BuilderElementSettings/components/ElementSettingTableColumns/index.js @@ -0,0 +1,151 @@ +import React, { useEffect, useState } from 'react'; +import { __ } from '@wordpress/i18n'; +import { wrap } from 'object-path-immutable'; +import { pathOr } from 'ramda'; + +// components +import { InputText } from 'primereact/inputtext'; +import { Button } from 'primereact/button'; +import { InputSwitch } from 'primereact/inputswitch'; + +// tools +import uniqid from '../../../../../../helpers/uniqid'; + +const ElementSettingTableColumns = ({ + value, + name, + setDataFn + }) => { + const [stateFieldData, setStateFieldData] = useState([]); + const [rowsData, setRowsData] = useState([]); + + const removeItem = (index) => { + const newData = stateFieldData.toSpliced(index, 1); + setStateFieldData(newData); + } + + const addNewItem = () => { + setStateFieldData([...stateFieldData, { name: uniqid('o'), label: '', predefined: false }]); + } + + const addNewRow = () => { + const obj = stateFieldData + .filter(o => o.predefined) + .reduce((acc, cur) => { + acc[cur.name] = '' + return acc; + }, {}); + setRowsData([...rowsData, obj]); + } + + const removeRow = (index) => { + const newRowsData = wrap(rowsData).del([index]).value(); + setRowsData(newRowsData); + } + + const onInputChange = (e, index) => { + const { value } = e.target; + const newData = stateFieldData.map((o, i) => { + if (i === index) { + o.label = value; + } + return o; + }) + setStateFieldData(newData); + } + + const onSubInputChange = (e, name, index) => { + const { value } = e.target; + const newRowsData = wrap(rowsData).set([index, name], value).value(); + setRowsData(newRowsData); + } + + const setChecked = (value, index) => { + let name = ''; + const newData = stateFieldData.map((o, i) => { + if (i === index) { + o.predefined = value; + name = o.name; + } + return o; + }); + + let newRowsData = []; + + if (value === false) { + newRowsData = rowsData.map(o => wrap(o).set([name], '').value()); + } else { + newRowsData = rowsData.map(o => wrap(o).set([name], '').value()); + } + + setRowsData(newRowsData); + setStateFieldData(newData); + } + + const properField = (item, i) => { + return <> + onInputChange(e, i)}/> +
+ {__('Predefinito?', 'gepafin')} + setChecked(e.value, i)}/> +
+ + } + + const properSubField = (item, i, name) => { + return onSubInputChange(e, name, i)}/> + } + + useEffect(() => { + const stateFieldData = pathOr([], ['stateFieldData'], value); + setStateFieldData(stateFieldData); + const rowsData = pathOr([], ['rowsData'], value); + setRowsData(rowsData); + }, []); + + useEffect(() => { + setDataFn(name, { + stateFieldData, + rowsData + }); + }, [stateFieldData, rowsData]); + + stateFieldData.filter(o => o.predefined) + + return ( + <> +
+ {stateFieldData.map((o, i) =>
+
+ {properField(o, i)} +
+
)} +
+ {stateFieldData + .filter(o => o.predefined) + .map((o, i) =>
+
+ +
+ {rowsData.map((c, k) => { + return
+
+ {properSubField(c, k, o.name)} +
+
+ })} +
+
+
)} + + ) +} + +export default ElementSettingTableColumns; \ No newline at end of file diff --git a/src/pages/BandoFormsPreview/index.js b/src/pages/BandoFormsPreview/index.js index 560b4af..03ed51e 100644 --- a/src/pages/BandoFormsPreview/index.js +++ b/src/pages/BandoFormsPreview/index.js @@ -121,6 +121,7 @@ const BandoFormsPreview = () => { 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 = ''; @@ -166,6 +167,7 @@ const BandoFormsPreview = () => { options={options ? options.value : []} setDataFn={setValue} sourceId={0} + tableColumns={tableColumns.value ? tableColumns.value : {}} /> })} diff --git a/src/routes.js b/src/routes.js index 1e6db3c..93f5485 100644 --- a/src/routes.js +++ b/src/routes.js @@ -73,7 +73,7 @@ const routes = ({ role }) => { {'ROLE_BENEFICIARY' === role ? : null} }/> - {'ROLE_SUPER_ADMIN' === role ? : null} + {'ROLE_SUPER_ADMIN' === role ? : null} {'ROLE_BENEFICIARY' === role ? : null} }/> diff --git a/src/tempData.js b/src/tempData.js index f5317ef..a15f34f 100644 --- a/src/tempData.js +++ b/src/tempData.js @@ -747,7 +747,7 @@ export const elementItems = [ }, { name: "table_columns", - value: "Tabella" + value: {} } ], validators: {}