diff --git a/src/App.js b/src/App.js index 7d3a901..ad0f6ef 100644 --- a/src/App.js +++ b/src/App.js @@ -4,7 +4,8 @@ import Routes from './routes'; import { createI18n, setLocaleData } from '@wordpress/i18n'; import { I18nProvider } from '@wordpress/react-i18n'; import './assets/scss/theme.scss'; -import { isEmpty, head } from 'ramda' +import { isEmpty, head } from 'ramda'; +import { addLocale, PrimeReactProvider } from 'primereact/api'; // store import { useStore, storeSet, storeGet } from './store'; @@ -18,6 +19,9 @@ function App() { const role = useStore().main.getRole(); const chosenCompanyId = useStore().main.chosenCompanyId(); const isRedirectedOnceNoCompany = useStore().main.isRedirectedOnceNoCompany(); + const value = { + locale: 'it', + }; const callback = (data) => { if (data.status === 'SUCCESS') { @@ -33,7 +37,7 @@ function App() { } useEffect(() => { - if (role === 'ROLE_BENEFICIARY') { + if (['ROLE_BENEFICIARY', 'ROLE_CONFIDI'].includes(role)) { const userData = storeGet.main.userData(); if (userData.companies && !isEmpty(userData.companies)) { storeSet.main.companies(userData.companies); @@ -59,6 +63,51 @@ function App() { storeSet.main.setAsyncRequest(); AuthenticationService.me(callback, errCallback); + addLocale('it', { + startsWith: 'Inizia con', + contains: 'Contiene', + notContains: 'Non contiene', + endsWith: 'Finisce con', + equals: 'Uguale a', + notEquals: 'Diverso da', + noFilter: 'Nessun filtro', + lt: 'Minore di', + lte: 'Minore o uguale a', + gt: 'Maggiore di', + gte: 'Maggiore o uguale a', + dateIs: 'Data uguale a', + dateIsNot: 'Data diversa da', + dateBefore: 'Data prima di', + dateAfter: 'Data dopo', + custom: 'Personalizzato', + clear: 'Cancella', + apply: 'Applica', + matchAll: 'Tutte le condizioni', + matchAny: 'Qualsiasi condizione', + addRule: 'Aggiungi regola', + removeRule: 'Rimuovi regola', + accept: 'Sì', + reject: 'No', + choose: 'Scegli', + upload: 'Carica', + cancel: 'Annulla', + dayNames: ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'], + dayNamesShort: ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'], + dayNamesMin: ['D', 'L', 'M', 'M', 'G', 'V', 'S'], + monthNames: ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'], + monthNamesShort: ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'], + today: 'Oggi', + weekHeader: 'Sm', + firstDayOfWeek: 1, + dateFormat: 'dd/mm/yy', + weak: 'Debole', + medium: 'Medio', + strong: 'Forte', + passwordPrompt: 'Inserisci una password', + emptyMessage: 'Nessun risultato trovato', + emptyFilterMessage: 'Nessun risultato trovato' + }); + fetch('/languages/en_US.json') .then((res) => res.json()) .then(res => { @@ -69,7 +118,9 @@ function App() { return ( - + + + ); diff --git a/src/assets/scss/components/appForm.scss b/src/assets/scss/components/appForm.scss index dad056e..c6bef3f 100644 --- a/src/assets/scss/components/appForm.scss +++ b/src/assets/scss/components/appForm.scss @@ -109,6 +109,51 @@ background-color: var(--table-border-color) } } + + &.fileselect { + .fileselectInner { + flex-direction: row; + display: flex; + gap: 1rem; + + > div { + flex: 1 1 50%; + } + } + + .fileselectInner__selectionBox { + display: flex; + flex-direction: column; + gap: 10px; + } + + .fileselectInner__selectedFiles { + display: flex; + flex-direction: column; + gap: 10px; + + p { + margin: 0; + font-weight: bold; + font-size: 14px; + } + + ul { + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + gap: 7px; + + li { + display: flex; + gap: 1rem; + justify-content: space-between; + align-items: center; + } + } + } + } } .appForm__field--required.appForm__field--required { diff --git a/src/assets/scss/components/appPage.scss b/src/assets/scss/components/appPage.scss index a07df79..a608ea4 100644 --- a/src/assets/scss/components/appPage.scss +++ b/src/assets/scss/components/appPage.scss @@ -113,6 +113,10 @@ font-weight: 600; line-height: normal; margin: 0 0 24px; + display: flex; + gap: 1rem; + flex-wrap: wrap; + align-items: center; } h3 { diff --git a/src/assets/scss/components/misc.scss b/src/assets/scss/components/misc.scss index 030a350..03bd8f8 100644 --- a/src/assets/scss/components/misc.scss +++ b/src/assets/scss/components/misc.scss @@ -167,6 +167,13 @@ } } +.p-column-filter-overlay .p-column-filter-row-items .p-column-filter-row-item.p-highlight { + color: white; +} +.p-listbox .p-listbox-list .p-listbox-item.p-highlight { + color: white; +} + .p-inputnumber-input[readonly] { background-color: #e1e1e1; } diff --git a/src/components/DataTableAsync/DataTableAsync.js b/src/components/DataTableAsync/DataTableAsync.js new file mode 100644 index 0000000..8e6bb34 --- /dev/null +++ b/src/components/DataTableAsync/DataTableAsync.js @@ -0,0 +1,105 @@ +import React, { useEffect, useState } from 'react'; +import { __ } from '@wordpress/i18n'; + +import translationStrings from '../../translationStringsForComponents'; + +// components +import { DataTable } from 'primereact/datatable'; +import { Column } from 'primereact/column'; +import { Button } from 'primereact/button'; +import BandoService from '../../service/bando-service'; + +const DataTableAsync = () => { + const [localAsyncRequest, setLocalAsyncRequest] = useState(false); + const [items, setItems] = useState(null); + const [totalRecordsNum, setTotalRecordsNum] = useState(0); + const [lazyState, setLazyState] = useState({ + first: 0, + rows: 5, + page: 1, + sortField: null, + sortOrder: null, + filters: { + name: { value: '', matchMode: 'contains' } + } + }); + + const getPaginationQuery = () => { + return { + "globalFilters": { + "page": 0, + "limit": lazyState.rows, + "sortBy": { + "columnName": "ID", + "sortDesc": true + } + } + } + } + + const onPage = (event) => { + setLazyState(event); + }; + + const onSort = (event) => { + setLazyState(event); + }; + + const onFilter = (event) => { + event['first'] = 0; + setLazyState(event); + }; + + const getCallback = (data) => { + if (data.status === 'SUCCESS') { + const { body, totalRecords, currentPage, totalPages, pageSize } = data.data; + setTotalRecordsNum(totalRecords); + const newItems = body.filter(o => o.status === 'PUBLISH'); + setItems(getFormattedBandiData(newItems)); + } + setLocalAsyncRequest(false); + } + + const errGetCallbacks = (data) => { + setLocalAsyncRequest(false); + } + + const getFormattedBandiData = (data) => { + return [...(data || [])].map((d) => { + d.start_date = new Date(d.dates[0]); + d.end_date = new Date(d.dates[1]); + + return d; + }); + }; + + useEffect(() => { + console.log(lazyState) + }, [lazyState]); + + useEffect(() => { + if (!localAsyncRequest) { + setLocalAsyncRequest(true); + const paginationQuery = getPaginationQuery(); + BandoService.getBandiPaginated(paginationQuery, getCallback, errGetCallbacks); + } + }, []); + + return ( +
+ + + +
+ ) +} + +export default DataTableAsync; \ No newline at end of file diff --git a/src/components/FormField/components/FileSelect/index.js b/src/components/FormField/components/FileSelect/index.js new file mode 100644 index 0000000..089b625 --- /dev/null +++ b/src/components/FormField/components/FileSelect/index.js @@ -0,0 +1,212 @@ +import React, { useCallback, useEffect, useRef, useState } from 'react'; +import { classNames } from 'primereact/utils'; +import { __ } from '@wordpress/i18n'; +import { isEmpty, pathOr, pluck } from 'ramda'; + +// service +import FileUploadService from '../../../../service/file-upload-service'; +import CompanyDocumentsService from '../../../../service/company-documents-service'; + +// components +import { ListBox } from 'primereact/listbox'; +import { Button } from 'primereact/button'; +import { Link } from 'react-router-dom'; +import { ConfirmPopup, confirmPopup } from 'primereact/confirmpopup'; + +const FileSelect = ({ + fieldName, + label, + setDataFn, + register, + errors, + defaultValue, + config = {}, + infoText = null, + disabled = false, + options = [], + sourceId = 0, + source = 'DOCUMENT', + documentCategories = [], + saveFormCallback + }) => { + //const [stateFieldData, setStateFieldData] = useState([]); + const stateFieldData = useRef([]); + const [selectedUnconfirmed, setSelectedUnconfirmed] = useState([]); + const [optionsTransformed, setOptionsTransformed] = useState([]); + const [loading, setLoading] = useState(false); + const [addNewMode, setAddNewMode] = useState(false); + + const attachSelectedFiles = useCallback(() => { + const existingIds = pluck('id', stateFieldData.current); + const selectedToBeAdded = selectedUnconfirmed.filter(o => !existingIds.includes(o.id)); + setSelectedUnconfirmed([]); + + setLoading(true); + // eslint-disable-next-line array-callback-return + selectedToBeAdded.map(o => { + CompanyDocumentsService.attachCompanyDocumentToAppl(o.id, callback, errCallback, [ + ['applicationId', sourceId], + ['documentType', source] + ]) + }); + setAddNewMode(false); + }, [selectedUnconfirmed]); + + const doGoBackToListOfFiles = () => { + setSelectedUnconfirmed([]); + setAddNewMode(false); + } + + const callback = (resp) => { + if (resp.status === 'SUCCESS') { + stateFieldData.current = [...stateFieldData.current, resp.data]; + setDataFn(fieldName, stateFieldData.current, { shouldValidate: true }); + saveFormCallback(); + } + setLoading(false); + } + + const errCallback = () => { + setLoading(false); + } + + const removeAttached = (id) => { + FileUploadService.deleteFile( + {}, + (data) => deleteCallback(data, id), + deleteErrorCallback, + [['id', id]] + ); + } + + const deleteCallback = (data, id) => { + if (data.status === 'SUCCESS') { + stateFieldData.current = stateFieldData.current.filter(o => id !== o.id); + setDataFn(fieldName, stateFieldData.current, { shouldValidate: true }); + saveFormCallback(); + } + } + + const deleteErrorCallback = (err) => { + console.log('err', err); + } + + const confirmDelete = (event, id) => { + confirmPopup({ + target: event.currentTarget, + message: __('Sei sicuro di cancellare il file?', 'gepafin'), + acceptLabel: __('Si', 'gepafin'), + icon: 'pi pi-info-circle', + defaultFocus: 'reject', + acceptClassName: 'p-button-danger', + accept: () => removeAttached(id), + reject: () => {} + }); + }; + + useEffect(() => { + stateFieldData.current = defaultValue; + register(fieldName, config) + }, []); + + useEffect(() => { + if (!isEmpty(options)) { + const optionsDefault = options + .filter(o => isEmpty(documentCategories) + ? o + : documentCategories.includes(o.category.id)) + .reduce((acc, cur) => { + const catName = pathOr('', ['category', 'categoryName'], cur); + const catLabel = pathOr('', ['category', 'description'], cur); + + if (!acc[catName]) { + acc[catName] = { + code: catName, + label: catLabel, + items: [] + }; + } + acc[catName].items.push(cur) + return acc; + }, {}); + + setOptionsTransformed(Object.values(optionsDefault)); + } + }, [options]); + + useEffect(() => { + stateFieldData.current = defaultValue; + }, [defaultValue]); + //console.log([...stateFieldData.current]) + return ( + <> + +
+ {addNewMode + ?
+ setSelectedUnconfirmed(e.value)} + options={optionsTransformed} + optionLabel="name" + optionGroupLabel="label" + optionGroupChildren="items" + className="w-full md:w-14rem" + listStyle={{ maxHeight: '130px' }}/> + {!isEmpty(selectedUnconfirmed) + ?
: null} + {!isEmpty(optionsTransformed) && !addNewMode + ?
+

{__('I file selezionati')}

+ +
: null} +
+ {isEmpty(optionsTransformed) + ?
+ + {__('I file caricati sulla pagina Documenti saranno disponibili qui. ', 'gepafin')} + + {__('Vai alla pagina Documenti', 'gepafin')} + + +
+ : null} + {infoText ? {infoText} : null} + + ) +} + +export default FileSelect; \ No newline at end of file diff --git a/src/components/FormField/components/Fileupload/index.js b/src/components/FormField/components/Fileupload/index.js index 0bdcfeb..49cf709 100644 --- a/src/components/FormField/components/Fileupload/index.js +++ b/src/components/FormField/components/Fileupload/index.js @@ -16,6 +16,7 @@ import { Button } from 'primereact/button'; import { defaultMaxFileSize, mimeTypes } from '../../../../configData'; import getFormatedFileSizeText from '../../../../helpers/getFormatedFileSizeText'; +import { ConfirmPopup, confirmPopup } from 'primereact/confirmpopup'; const Fileupload = ({ fieldName, @@ -72,6 +73,20 @@ const Fileupload = ({ console.log('err', err); } + const confirmDelete = (event, file) => { + console.log('confirmDelete', file) + confirmPopup({ + target: event.currentTarget, + message: __('Sei sicuro di cancellare il file?', 'gepafin'), + acceptLabel: __('Si', 'gepafin'), + icon: 'pi pi-info-circle', + defaultFocus: 'reject', + acceptClassName: 'p-button-danger', + accept: () => onTemplateRemove(file), + reject: () => {} + }); + }; + const itemTemplate = (file) => { let fileName = file.fileName ? file.fileName : file.name; return ( @@ -91,7 +106,7 @@ const Fileupload = ({ type="button" disabled={disabled} aria-label={__('Anulla', 'gepafin')} - onClick={() => onTemplateRemove(file)}/> + onClick={(e) => confirmDelete(e, file)}/> ); @@ -213,6 +228,7 @@ const Fileupload = ({ onBeforeSelect={onBeforeSelect} uploadHandler={customBase64Uploader}/> {infoText ? {infoText} : null} + : null ) diff --git a/src/components/FormField/components/Wysiwyg/index.js b/src/components/FormField/components/Wysiwyg/index.js index 8c33a69..35252b0 100644 --- a/src/components/FormField/components/Wysiwyg/index.js +++ b/src/components/FormField/components/Wysiwyg/index.js @@ -8,6 +8,7 @@ import { __ } from '@wordpress/i18n'; import { Editor } from 'primereact/editor'; import BlockingOverlay from '../../../BlockingOverlay'; import { Button } from 'primereact/button'; +import { isNil } from 'ramda'; const Delta = Quill.import('delta'); @@ -53,15 +54,17 @@ const Wysiwyg = ({ <> -