diff --git a/src/App.js b/src/App.js index 0272f17..e3e9e7c 100644 --- a/src/App.js +++ b/src/App.js @@ -14,6 +14,7 @@ const i18n = createI18n({}, 'gepafin'); function App() { const role = useStore().main.getRole(); + const chosenCompanyId = useStore().main.chosenCompanyId(); const callback = (data) => { //console.log('app /me', data); @@ -30,7 +31,7 @@ function App() { storeSet.main.unsetAsyncRequest(); } - const companyCallback = (data) => { + /*const companyCallback = (data) => { if (data.status === 'SUCCESS') { storeSet.main.companies(data.data); } @@ -40,13 +41,16 @@ function App() { const errCompanyCallback = (data) => { storeSet.main.doLogout(); storeSet.main.unsetAsyncRequest(); - } + }*/ useEffect(() => { if (role === 'ROLE_BENEFICIARY') { - storeSet.main.setAsyncRequest(); + //storeSet.main.setAsyncRequest(); const userData = storeGet.main.userData(); - CompanyService.getCompanyForUser(userData.id, companyCallback, errCompanyCallback) + if (userData.companies) { + storeSet.main.companies(userData.companies); + } + //CompanyService.getCompanyForUser(userData.id, companyCallback, errCompanyCallback) } }, [role]) @@ -65,7 +69,7 @@ function App() { return ( - + ); diff --git a/src/components/FileuploadStandalone/index.js b/src/components/FileuploadDelega/index.js similarity index 78% rename from src/components/FileuploadStandalone/index.js rename to src/components/FileuploadDelega/index.js index 60d49d1..d09a0d3 100644 --- a/src/components/FileuploadStandalone/index.js +++ b/src/components/FileuploadDelega/index.js @@ -7,22 +7,21 @@ import FileUploadService from '../../service/file-upload-service'; import { FileUpload } from 'primereact/fileupload'; import { Tag } from 'primereact/tag'; import { Button } from 'primereact/button'; +import CompanyService from '../../service/company-service'; -const FileuploadStandalone = ({ +const FileuploadDelega = ({ fieldName, setDataFn, defaultValue = [], - accept = ['image/*'], - doctype = 'images', + accept = [], maxSize = 100000000, emptyText = __('Trascina qui il tuo file', 'gepafin'), - chooseLabel = __('Aggiungi immagine', 'gepafin'), + chooseLabel = __('Aggiungi delega', 'gepafin'), multiple = false, - sourceId = 0, - source = 'application', + companyId = 0, disabled = false }) => { - const [stateFieldData, setStateFieldData] = useState([]); + const [stateFieldData, setStateFieldData] = useState({}); const [acceptFormats, setAcceptFormats] = useState(''); const inputRef = useRef(); @@ -31,10 +30,7 @@ const FileuploadStandalone = ({ for (const file of event.files) { formData.append('file', file) } - FileUploadService.uploadFile(sourceId, formData, callback, errorCallback, [ - ['documentType', doctype.toUpperCase()], - ['sourceType', source.toUpperCase()] - ]); + CompanyService.uploadCompanyDelega(companyId, formData, callback, errorCallback); }; const callback = (data) => { @@ -51,11 +47,12 @@ const FileuploadStandalone = ({ } const itemTemplate = (file) => { + console.log('file', file) return (
- {file.name} + {file.fileName}
@@ -77,11 +74,10 @@ const FileuploadStandalone = ({ const onTemplateRemove = (file) => { if (file.id) { - FileUploadService.deleteFile( - {}, + CompanyService.deleteDelega( + companyId, (data) => dCallback(data, file.id), - dErrorCallback, - [['id', file.id]] + dErrorCallback ); } else { const files = inputRef.current.getFiles() @@ -120,7 +116,9 @@ const FileuploadStandalone = ({ const MIMEtype = new RegExp(acceptFormats); return Array.prototype.every.call(files, function passesAcceptedFormat(file) { - return MIMEtype.test(file.type); + const fileExtension = `.${file.name.split('.').pop().toLowerCase()}`; + const fileType = file.type; + return MIMEtype.test(fileType) || MIMEtype.test(fileExtension); }); } @@ -128,6 +126,13 @@ const FileuploadStandalone = ({ setStateFieldData(defaultValue); }, []); + useEffect(() => { + if (inputRef.current) { + inputRef.current.setUploadedFiles(multiple ? defaultValue : [defaultValue]); + console.log('inputRef.current', inputRef.current, multiple ? defaultValue : [defaultValue]) + } + }, [defaultValue]); + useEffect(() => { // eslint-disable-next-line no-useless-escape setAcceptFormats(accept.join(',').replace(/\*/g, '.\*').replace(/,/g, '|')); @@ -135,13 +140,14 @@ const FileuploadStandalone = ({ useEffect(() => { if (inputRef.current) { - inputRef.current.setUploadedFiles(stateFieldData); + inputRef.current.setUploadedFiles(multiple ? stateFieldData : [stateFieldData]); } - setDataFn(fieldName, [...stateFieldData], { shouldValidate: true }); + + setDataFn(fieldName, multiple ? [...stateFieldData] : stateFieldData, { shouldValidate: true }); }, [stateFieldData]) return ( - sourceId && sourceId !== 0 + companyId && companyId !== 0 ? { command: () => { navigate('/profilo-aziendale') }, - enable: !intersection(permissions, ['MANAGE_TENDERS']).length + enable: !intersection(permissions, ['MANAGE_TENDERS']).length && companies.length > 0 }, { label: __('Seleziona azienda', 'gepafin'), items: companyItems, - enable: true + enable: companies.length + }, + { + label: __('Aggiungi Azienda', 'gepafin'), + command: () => { + navigate('/agguingi-azienda') + }, + enable: !intersection(permissions, ['MANAGE_TENDERS']).length }, { separator: true, diff --git a/src/configData.js b/src/configData.js index c1d903d..343fe94 100644 --- a/src/configData.js +++ b/src/configData.js @@ -1,6 +1,6 @@ export const mimeTypes = [ { name: 'PDF', code: 'application/pdf' }, - /*{ name: 'Firmato PDF o Word', code: 'application/pkcs7-mime' },*/ + { name: 'p7m', ext: '.p7m,application/pkcs7-mime,application/x-pkcs7-mime' }, { name: 'ZIP', code: 'application/zip' }, { name: 'Immagine', code: 'image/*' }, { diff --git a/src/pages/AddCompany/index.js b/src/pages/AddCompany/index.js new file mode 100644 index 0000000..a04264c --- /dev/null +++ b/src/pages/AddCompany/index.js @@ -0,0 +1,334 @@ +import React, { useEffect, useRef } from 'react'; +import { __ } from '@wordpress/i18n'; +import { isEmpty, isNil, head } from 'ramda'; +import { klona } from 'klona'; +import { useDebounce } from 'primereact/hooks'; +import { useNavigate } from 'react-router-dom'; + +// store +import { storeSet, useStore, storeGet } from '../../store'; + +// components +import { Messages } from 'primereact/messages'; +import FormField from '../../components/FormField'; +import { Button } from 'primereact/button'; +import { useForm } from 'react-hook-form'; +import BlockingOverlay from '../../components/BlockingOverlay'; + +// api +import CompanyService from '../../service/company-service'; + +// tools +import { isPIVA, isEmail, isEmailPEC } from '../../helpers/validators'; +import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; + +const AddCompany = () => { + const navigate = useNavigate(); + const isAsyncRequest = useStore().main.isAsyncRequest(); + const infoMsgs = useRef(null); + const [, debouncedPivaValue, setInputPiva] = useDebounce('', 1000); + + const { + control, + handleSubmit, + formState: { errors }, + setValue, + getValues, + watch + } = useForm({ + defaultValues: {}, + mode: 'onChange' + }); + const values = getValues(); + const emptyValues = Object.values(values).filter(v => isEmpty(v) || isNil(v)).length; + const isPiva = watch('vatNumber') + + const setEmptyValues = () => { + const formData = { + cap: '', + pec: '', + email: '', + city: '', + codiceFiscale: '', + address: '', + companyName: '' + } + Object.keys(formData).map(k => setValue(k, formData[k])); + } + + const onSubmit = (formData) => { + infoMsgs.current.clear(); + storeSet.main.setAsyncRequest(); + + CompanyService.createCompany(formData, updateCallback, updateError); + }; + + const updateCallback = (data) => { + if (data.status === 'SUCCESS') { + 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); + + if (company.isLegalRepresentant) { + navigate('/'); + } else { + navigate('/profilo-aziendale'); + } + + } + storeSet.main.unsetAsyncRequest(); + } + + const updateError = (data) => { + set404FromErrorResponse(data); + storeSet.main.unsetAsyncRequest(); + } + + const checkVatNumber = (value) => { + infoMsgs.current.clear(); + const isValid = isPIVA(value); + + if (isValid) { + storeSet.main.setAsyncRequest(); + CompanyService.checkVat(checkVatCallback, errCheckVatCallback, [['vatNumber', value]]) + } else { + setEmptyValues(); + } + } + + const checkVatCallback = (data) => { + if (data.status === 'SUCCESS') { + const resp = data.data.data; + if (!isEmpty(resp)) { + const { + cap, cf, denominazione, piva, indirizzo, comune, dettaglio: { pec } + } = resp; + + const formData = { + cap, + pec, + email: pec, + city: comune, + codiceFiscale: cf, + address: indirizzo, + vatNumber: piva, + companyName: denominazione + } + Object.keys(formData).map(k => setValue(k, formData[k])); + } + //setData(getFormattedBandiData(data.data)); + } else { + setEmptyValues(); + } + storeSet.main.unsetAsyncRequest(); + } + + const errCheckVatCallback = (data) => { + setEmptyValues(); + set404FromErrorResponse(data); + storeSet.main.unsetAsyncRequest(); + } + + useEffect(() => { + setInputPiva(isPiva); + }, [isPiva]); + + useEffect(() => { + checkVatNumber(debouncedPivaValue); + }, [debouncedPivaValue]) + + return ( +
+
+

{__('Profilo aziendale', 'gepafin')}

+
+ +
+ + +
+ +
+

{__('Informazioni aziendali', 'gepafin')}

+

+ {__('Inserisci P.IVA e i dati aziendali verranno inseriti automaticamente per le aziende già esistenti', 'gepafin')} +

+ +
+ +
+ +
+ + + +
+ +
+ + + + + {/**/} +
+ +
+ + + + + +
+ +
+ + + +
+
+ +
+ +
+ + +
+ +
+ {__('Azioni rapide', 'gepafin')} +
+ +
+
+
+
+ +
+ ) + +} + +export default AddCompany; \ No newline at end of file diff --git a/src/pages/ProfileCompany/index.js b/src/pages/ProfileCompany/index.js index a286a6a..78ea120 100644 --- a/src/pages/ProfileCompany/index.js +++ b/src/pages/ProfileCompany/index.js @@ -1,12 +1,19 @@ import React, { useEffect, useMemo, useRef, useState } from 'react'; import { __ } from '@wordpress/i18n'; -import { isEmpty, isNil, pathOr, head } from 'ramda'; +import { isEmpty, pathOr, head } from 'ramda'; import { klona } from 'klona'; import { wrap } from 'object-path-immutable'; // store import { storeSet, useStore, storeGet } from '../../store'; +// api +import CompanyService from '../../service/company-service'; + +// tools +import { isPIVA, isEmail, isEmailPEC } from '../../helpers/validators'; +import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; + // components import { Messages } from 'primereact/messages'; import FormField from '../../components/FormField'; @@ -14,17 +21,11 @@ import { Button } from 'primereact/button'; import { useForm } from 'react-hook-form'; import BlockingOverlay from '../../components/BlockingOverlay'; import { InputText } from 'primereact/inputtext'; - -// api -import CompanyService from '../../service/company-service'; - -// tools -import { isPIVA, isCodiceFiscale, isEmail, isEmailPEC } from '../../helpers/validators'; -import set404FromErrorResponse from '../../helpers/set404FromErrorResponse'; -import FileuploadStandalone from '../../components/FileuploadStandalone'; +import FileuploadDelega from '../../components/FileuploadDelega'; const ProfileCompany = () => { const isAsyncRequest = useStore().main.isAsyncRequest(); + const chosenCompanyId = useStore().main.chosenCompanyId(); const companies = useStore().main.companies(); const infoMsgs = useRef(null); const [formInitialData, setFormInitialData] = useState({}); @@ -37,17 +38,13 @@ const ProfileCompany = () => { handleSubmit, formState: { errors }, setValue, - getValues, watch, - register } = useForm({ defaultValues: useMemo(() => { return formInitialData; }, [formInitialData]), mode: 'onChange' }); - const values = getValues(); - const emptyValues = Object.values(values).filter(v => isEmpty(v) || isNil(v)).length; const isLegalRepresentant = watch('isLegalRepresentant') const setEmptyValues = () => { @@ -67,11 +64,7 @@ const ProfileCompany = () => { infoMsgs.current.clear(); storeSet.main.setAsyncRequest(); - if (isNil(formData.id)) { - CompanyService.createCompany(formData, updateCallback, updateError); - } else { - CompanyService.updateCompany(formData.id, formData, updateCallback, updateError); - } + CompanyService.updateCompany(formData.id, formData, updateCallback, updateError); }; const updateCallback = (data) => { @@ -148,9 +141,47 @@ const ProfileCompany = () => { setDelegaData(newDelegaData) } - const setDelegaFile = (data) => { - console.log('setDelegaFile', data) - setDelega(data); + const setDelegaFile = (name, value) => { + console.log('setDelegaFile', value) + setDelega(value); + } + + const getDellegaCallback = (data) => { + console.log(data) + if (data.data) { + setDelega(data.data); + } + storeSet.main.unsetAsyncRequest(); + } + + const errDellegaCallback = () => { + storeSet.main.unsetAsyncRequest(); + } + + const downloadDelega = () => { + storeSet.main.setAsyncRequest(); + const data = { + codiceFiscale: delegaCodiceFiscale, + firstName: delegaFirstName, + lastName: delegaLastName + } + CompanyService.downloadCompanyDelega(formInitialData.id, data, getDellegaDownloadCallback, errDellegaDownloadCallback) + } + + const getDellegaDownloadCallback = (data) => { + const pdfFile = new Blob([data], { type: 'application/octet-stream' }) + const url = window.URL.createObjectURL(pdfFile); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', 'delega.docx'); + document.body.appendChild(link); + link.click(); + link.remove(); + storeSet.main.unsetAsyncRequest(); + } + + const errDellegaDownloadCallback = () => { + storeSet.main.unsetAsyncRequest(); } useEffect(() => { @@ -159,9 +190,43 @@ const ProfileCompany = () => { }, [formInitialData]); useEffect(() => { - const chosenCompany = pathOr({}, [0], companies); - setFormInitialData(chosenCompany); - }, [companies]); + let chosenCompany = {}; + + if (chosenCompanyId) { + chosenCompany = head(companies.filter(o => o.id === chosenCompanyId)); + } + + if (!chosenCompany) { + chosenCompany = pathOr({}, [0], companies); + } + + const { + cap, codiceFiscale, companyName, vatNumber, address, city, pec, email, + contactName, contactEmail, isLegalRepresentant, id + } = chosenCompany; + const companyData = { + id, + cap, + pec, + email, + city, + codiceFiscale, + address, + vatNumber, + companyName, + contactName, + contactEmail, + isLegalRepresentant + } + setFormInitialData(companyData); + }, [chosenCompanyId, companies]); + + useEffect(() => { + if (formInitialData.id) { + storeSet.main.setAsyncRequest(); + CompanyService.getCompanyDelega(formInitialData.id, getDellegaCallback, errDellegaCallback); + } + }, [formInitialData]) return (
@@ -179,7 +244,6 @@ const ProfileCompany = () => {
{ {
{ {
{ { {
{
diff --git a/src/routes.js b/src/routes.js index 93f5485..d261ceb 100644 --- a/src/routes.js +++ b/src/routes.js @@ -23,8 +23,10 @@ import LoginAdmin from './pages/LoginAdmin'; import Profile from './pages/Profile'; import ProfileCompany from './pages/ProfileCompany'; import Users from './pages/Users'; +import AddCompany from './pages/AddCompany'; + +const routes = ({ role, chosenCompanyId }) => { -const routes = ({ role }) => { return ( }> @@ -78,7 +80,11 @@ const routes = ({ role }) => { }/> {'ROLE_SUPER_ADMIN' === role ? : null} - {'ROLE_BENEFICIARY' === role ? : null} + {'ROLE_BENEFICIARY' === role && chosenCompanyId > 0 ? : } + }/> + + {'ROLE_SUPER_ADMIN' === role ? : null} + {'ROLE_BENEFICIARY' === role ? : null} }/> {'ROLE_SUPER_ADMIN' === role ? : null} diff --git a/src/service/company-service.js b/src/service/company-service.js index 894cf6d..7f96156 100644 --- a/src/service/company-service.js +++ b/src/service/company-service.js @@ -9,7 +9,7 @@ export default class CompanyService { }; static updateCompany = (id, body, callback, errCallback) => { - NetworkService.post(`${API_BASE_URL}/company/${id}`, body, callback, errCallback); + NetworkService.put(`${API_BASE_URL}/company/${id}`, body, callback, errCallback); }; static checkVat = (callback, errCallback, queryParams) => { @@ -19,4 +19,20 @@ export default class CompanyService { static getCompanyForUser = (id, callback, errCallback) => { NetworkService.get(`${API_BASE_URL}/company/user/${id}`, callback, errCallback); }; + + static getCompanyDelega = (id, callback, errCallback) => { + NetworkService.get(`${API_BASE_URL}/company/${id}/delegation`, callback, errCallback); + }; + + static downloadCompanyDelega = (id, body, callback, errCallback) => { + NetworkService.postBlob(`${API_BASE_URL}/company/${id}/delegation/download`, body, callback, errCallback); + }; + + static uploadCompanyDelega = (id, body, callback, errCallback, queryParams) => { + NetworkService.postMultiPart(`${API_BASE_URL}/company/${id}/delegation/upload`, body, callback, errCallback, queryParams); + }; + + static deleteDelega = (id, callback, errCallback) => { + NetworkService.delete(`${API_BASE_URL}/company/${id}/delegation`, {}, callback, errCallback); + }; } diff --git a/src/service/network-service.js b/src/service/network-service.js index 2d74df5..6a47b21 100644 --- a/src/service/network-service.js +++ b/src/service/network-service.js @@ -126,6 +126,47 @@ export class NetworkService { .catch(err => errorCallback(err)); }; + static postBlob = (url, body, callback, errorCallback, queryParams) => { + + if (queryParams) { + url += '?' + for (let i = 0; i < queryParams.length; i++) { + if (queryParams[i] && this.isNotBlank(queryParams[i][0]) && this.isNotBlank(queryParams[i][1])) { + let param = queryParams[i][0] + '=' + queryParams[i][1] + + if (i !== queryParams.length - 1) + param += '&' + + url += param; + } + } + + if (url.charAt(url.length) === '&') + url = url.substring(0, url.length - 1); + } + + fetch(url, { + method: 'POST', + mode: 'cors', + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + storeGet.main.getToken(), + }, + body: JSON.stringify(body) + }) + .then(async response => { + let status = response.status; + return { response: await response.blob(), status: status } + }) + .then(data => { + if (data.status >= 400 && data.status <= 599) + errorCallback(data.response) + else + callback(data.response) + }) + .catch(err => errorCallback(err)); + }; + static unauthorizedPost = (url, body, callback, errorCallback, queryParams) => { if (queryParams) { url += '?'