From 4054745695165b13feeb02197ca5f7e48e72382f Mon Sep 17 00:00:00 2001 From: Vitalii Kiiko Date: Thu, 5 Sep 2024 17:15:57 +0200 Subject: [PATCH] - updated version; --- src/assets/scss/components/appForm.scss | 2 + src/assets/scss/components/flowBuilder.scss | 19 +++ src/assets/scss/components/layout.scss | 2 +- src/assets/scss/components/reactFlow.scss | 4 - .../scss/components/statsBigBadges.scss | 4 + src/assets/scss/theme.scss | 2 +- .../components/NodeInitialForm/index.js | 55 ++++++++ .../components/NodeIntermediateForm/index.js | 71 ++++++++++ src/components/FlowBuilder/index.js | 41 +++--- src/components/FormFieldRepeaterFaq/index.js | 38 ++++-- .../UnsavedChangesDetector/index.js | 31 ++--- .../components/AppSidebar/index.js | 15 ++- .../Bandi/components/AllBandiTable/index.js | 2 +- src/pages/Bandi/index.js | 2 +- .../components/BandoEditFormStep1/index.js | 19 +-- .../components/BandoEditFormStep2/index.js | 14 +- src/pages/BandoEdit/index.js | 16 +-- src/pages/BandoFlowEdit/index.js | 46 +++++-- src/pages/BandoForms/index.js | 10 +- src/pages/BandoFormsEdit/index.js | 9 +- src/pages/BandoFormsPreview/index.js | 2 +- src/pages/BandoView/index.js | 4 +- src/pages/Bids/index.js | 44 +++++++ .../components/LatestBandiTable/index.js | 6 +- src/pages/Dashboard/index.js | 15 ++- .../LatestUsersActivityTable/index.js | 123 ------------------ .../index.js | 62 ++++----- src/pages/DashboardBenefeciario/index.js | 62 ++++++--- src/pages/Login/index.js | 4 +- src/routes.js | 20 +-- src/store/actions.js | 10 ++ src/store/initial.js | 8 +- src/tempData.js | 50 ++++++- 33 files changed, 516 insertions(+), 296 deletions(-) create mode 100644 src/assets/scss/components/flowBuilder.scss delete mode 100644 src/assets/scss/components/reactFlow.scss create mode 100644 src/components/FlowBuilder/components/NodeInitialForm/index.js create mode 100644 src/components/FlowBuilder/components/NodeIntermediateForm/index.js create mode 100644 src/pages/Bids/index.js delete mode 100644 src/pages/DashboardBenefeciario/components/LatestUsersActivityTable/index.js rename src/pages/DashboardBenefeciario/components/{LatestBandiTable => MyLatestSubmissionsTable}/index.js (75%) diff --git a/src/assets/scss/components/appForm.scss b/src/assets/scss/components/appForm.scss index 843e5b9..7989898 100644 --- a/src/assets/scss/components/appForm.scss +++ b/src/assets/scss/components/appForm.scss @@ -88,7 +88,9 @@ display: flex; flex-direction: column; gap: 14px; + } + > div:not(.appForm__field) { label { font-weight: 400; } diff --git a/src/assets/scss/components/flowBuilder.scss b/src/assets/scss/components/flowBuilder.scss new file mode 100644 index 0000000..d4401fe --- /dev/null +++ b/src/assets/scss/components/flowBuilder.scss @@ -0,0 +1,19 @@ +.flowBuilder__wrapper { + width: 100%; + height: 500px; +} + +.nodeInitialForm { + padding: 10px 20px; + background-color: white; + border: 1px solid black; + border-radius: 4px; + display: flex; + flex-direction: column; + gap: 10px; + + label { + font-size: 13px; + text-align: center; + } +} \ No newline at end of file diff --git a/src/assets/scss/components/layout.scss b/src/assets/scss/components/layout.scss index 9b246f2..79a50c0 100644 --- a/src/assets/scss/components/layout.scss +++ b/src/assets/scss/components/layout.scss @@ -10,7 +10,7 @@ body { flex-direction: column; flex-grow: 1; margin: 0; - font-family: 'Montserrat'; + font-family: "Montserrat", sans-serif; p, span:not(.p-button-label, .p-button-icon, .p-badge), input, label:not(.p-error), textarea, a, li, h1, h2, h3, h4, h5, h6, div, th, td { color: var(--global-textColor); diff --git a/src/assets/scss/components/reactFlow.scss b/src/assets/scss/components/reactFlow.scss deleted file mode 100644 index 91514cb..0000000 --- a/src/assets/scss/components/reactFlow.scss +++ /dev/null @@ -1,4 +0,0 @@ -.reactFlow__wrapper { - width: 100%; - height: 500px; -} \ No newline at end of file diff --git a/src/assets/scss/components/statsBigBadges.scss b/src/assets/scss/components/statsBigBadges.scss index 92a806f..a77f6cf 100644 --- a/src/assets/scss/components/statsBigBadges.scss +++ b/src/assets/scss/components/statsBigBadges.scss @@ -7,6 +7,10 @@ grid-template-columns: repeat(2, 1fr); gap: 1rem; width: 100%; + + &.grid-3 { + grid-template-columns: repeat(3, 1fr); + } } .statsBigBadges__grid .statsBigBadges__gridItem span { diff --git a/src/assets/scss/theme.scss b/src/assets/scss/theme.scss index abac453..362d6c4 100644 --- a/src/assets/scss/theme.scss +++ b/src/assets/scss/theme.scss @@ -36,4 +36,4 @@ @import "./components/formBuilder.scss"; @import "./components/misc.scss"; @import "./components/login.scss"; -@import "./components/reactFlow.scss"; \ No newline at end of file +@import "./components/flowBuilder.scss"; \ No newline at end of file diff --git a/src/components/FlowBuilder/components/NodeInitialForm/index.js b/src/components/FlowBuilder/components/NodeInitialForm/index.js new file mode 100644 index 0000000..ad01314 --- /dev/null +++ b/src/components/FlowBuilder/components/NodeInitialForm/index.js @@ -0,0 +1,55 @@ +import React, { useEffect, useState } from 'react'; +import { Handle, Position } from '@xyflow/react'; +import { isEmpty, head } from 'ramda'; + +// store +import { storeGet, storeSet } from '../../../../store'; + +const NodeInitialForm = ({ data: { id, label = '' } }) => { + const [options, setOptions] = useState([]); + const [value, setValue] = useState(''); + + const onChangeFn = (e) => { + const { value } = e.target; + const data = { + formId: String(id), + chosenField: value, + chosenValue: '' + } + setValue(value); + storeSet.main.addFlowData(data); + } + + useEffect(() => { + const forms = storeGet.main.flowForms(); + const form = head(forms.filter(o => String(o.id) === String(id))) + const relevantFields = form + ? form.content + .filter(o => ['radio', 'select'].includes(o.name)) + .map(o => ({ name: o.id, label: o.label })) + : []; + setOptions(relevantFields); + }, [id]); + + return ( +
+ + {options && !isEmpty(options) + ? : null} + +
+ ); +} + +export default NodeInitialForm; \ No newline at end of file diff --git a/src/components/FlowBuilder/components/NodeIntermediateForm/index.js b/src/components/FlowBuilder/components/NodeIntermediateForm/index.js new file mode 100644 index 0000000..ea53143 --- /dev/null +++ b/src/components/FlowBuilder/components/NodeIntermediateForm/index.js @@ -0,0 +1,71 @@ +import React, { useEffect, useState } from 'react'; +import { Handle, Position } from '@xyflow/react'; +import { head, isEmpty } from 'ramda'; + +import { useStore, storeSet, storeGet } from '../../../../store'; + +const NodeIntermediateForm = ({ data: { id, label = '' } }) => { + const flowEdges = useStore().main.flowEdges(); + const flowData = useStore().main.flowData(); + const [options, setOptions] = useState([]); + const [value, setValue] = useState(''); + + const onChangeFn = (e) => { + const { value } = e.target; + const data = { + formId: String(id), + chosenField: '', + chosenValue: value + } + setValue(value); + storeSet.main.addFlowData(data); + } + + useEffect(() => { + const edge = head(flowEdges.filter(o => o.target === String(id))); + if (edge) { + const sourceForm = edge.source; + const sourceFormData = head(flowData.filter(o => o.formId === sourceForm)); + const flowForms = storeGet.main.flowForms(); + const form = head(flowForms.filter(o => String(o.id) === String(sourceForm))); + if (form && sourceFormData) { + const { chosenField } = sourceFormData; + const field = head(form.content.filter(o => o.id === chosenField)); + if (field) { + const options = head(field.settings.filter(o => o.name === 'options')); + if (options) { + setOptions(options.value); + } + } + } + + } + }, [flowEdges, flowData]); + + return ( +
+ + + {options && !isEmpty(options) + ? : null} + +
+ ); +} + +export default NodeIntermediateForm; \ No newline at end of file diff --git a/src/components/FlowBuilder/index.js b/src/components/FlowBuilder/index.js index 62b6292..dbc5935 100644 --- a/src/components/FlowBuilder/index.js +++ b/src/components/FlowBuilder/index.js @@ -1,19 +1,26 @@ import React, { useEffect, useState } from 'react'; import { ReactFlow, - Background, - useNodesState, - useEdgesState, - addEdge, - getIncomers, - getOutgoers, - getConnectedEdges, + Background } from '@xyflow/react'; import { isEmpty } from 'ramda'; import '@xyflow/react/dist/style.css'; -const FlowBuilder = ({ initialForm = 0, finalForm = 0, forms = [], updateFn }) => { +// store +import { useStore, storeSet } from '../../store'; + +// nodes +import NodeInitialForm from './components/NodeInitialForm'; +import NodeIntermediateForm from './components/NodeIntermediateForm'; + +const nodeTypes = { + initialForm: NodeInitialForm, + intermediateForm: NodeIntermediateForm +}; + +const FlowBuilder = ({ initialForm = 0, finalForm = 0 }) => { + const forms = useStore().main.flowForms(); const [nodes, setNodes] = useState([]); const [edges, setEdges] = useState([]); @@ -35,22 +42,23 @@ const FlowBuilder = ({ initialForm = 0, finalForm = 0, forms = [], updateFn }) = if (o.id === initialForm) { obj = { id: String(o.id), - type: 'input', - data: { label: o.label }, + type: 'initialForm', + data: { label: o.label, id: o.id }, position: { x: 0, y: 0 }, } } else if (o.id === finalForm) { obj = { id: String(o.id), type: 'output', - data: { label: o.label }, + data: { label: o.label, id: o.id }, position: { x: 0, y: 300 }, } } else { const x = coordinates.splice(0, 1); obj = { id: String(o.id), - data: { label: o.label }, + type: 'intermediateForm', + data: { label: o.label, id: o.id }, position: { x, y: 150 }, } } @@ -60,14 +68,14 @@ const FlowBuilder = ({ initialForm = 0, finalForm = 0, forms = [], updateFn }) = let edges = []; forms.map(o => { if (o.id !== initialForm && o.id !== finalForm) { - edges.push({ id: `${initialForm}->${o.id}`, source: String(initialForm), target: String(o.id) }); - edges.push({ id: `${o.id}->${finalForm}`, source: String(o.id), target: String(finalForm) }); + edges.push({ id: `${initialForm}->${o.id}`, source: String(initialForm), target: String(o.id), type: 'smoothstep' }); + edges.push({ id: `${o.id}->${finalForm}`, source: String(o.id), target: String(finalForm), type: 'smoothstep' }); } }); setNodes(initialNodes); setEdges(edges); - updateFn(edges); + storeSet.main.flowEdges(edges); } else { setNodes([]); setEdges([]); @@ -76,13 +84,14 @@ const FlowBuilder = ({ initialForm = 0, finalForm = 0, forms = [], updateFn }) = return ( !isEmpty(nodes) && !isEmpty(edges) - ?
+ ?
diff --git a/src/components/FormFieldRepeaterFaq/index.js b/src/components/FormFieldRepeaterFaq/index.js index 506e763..2c7dc94 100644 --- a/src/components/FormFieldRepeaterFaq/index.js +++ b/src/components/FormFieldRepeaterFaq/index.js @@ -27,6 +27,7 @@ const FormFieldRepeaterFaq = ({ const [stateOptionsData, setStateOptionsData] = useState([]); const [question, setQuestion] = useState(''); const [answer, setAnswer] = useState(''); + const [title, setTitle] = useState(''); const [editDataIndex, setEditDataIndex] = useState(null); const [isVisibleEditDialog, setIsVisibleEditDialog] = useState(false); @@ -37,14 +38,13 @@ const FormFieldRepeaterFaq = ({ const selectItem = (e) => { const targetedOption = head(stateOptionsData.filter(o => o.value === e.value)); - console.log('selected:', e, stateOptionsData, targetedOption) if (targetedOption) { - setStateFieldData([...stateFieldData, targetedOption]); + setStateFieldData([...stateFieldData, {...targetedOption, isVisible: true}]); } } const addNewItem = () => { - const newItem = { id: null, lookUpDataId: null, title: '', value: '', isVisible: true }; + const newItem = { id: null, lookUpDataId: null, title: '', value: '', response: '', isVisible: true }; setStateFieldData([...stateFieldData, newItem]); } @@ -76,6 +76,8 @@ const FormFieldRepeaterFaq = ({ const onChangeEditItem = (value, key) => { if (key === 'title') { + setTitle(value); + } else if (key === 'value') { setQuestion(value); } else { setAnswer(value) @@ -85,8 +87,9 @@ const FormFieldRepeaterFaq = ({ const saveEditDialog = () => { const newData = stateFieldData.map((o, i) => { if (i === editDataIndex) { - o.title = question; - o.value = answer; + o.title = title; + o.value = question; + o.response = answer; return o } else { return o; @@ -106,7 +109,10 @@ const FormFieldRepeaterFaq = ({ const footerEditDialog = () => { return
} @@ -151,6 +157,7 @@ const FormFieldRepeaterFaq = ({ selectItem(e)} optionDisabled={(opt) => usedExistingValues().includes(opt.title)} options={stateOptionsData} + placeholder={__('Scegli tra quelli pre-creati', 'gepafin')} optionLabel="title"/>
@@ -164,8 +171,13 @@ const FormFieldRepeaterFaq = ({ onLabel="" offLabel="" checked={o.isVisible} - onChange={(e) => setChecked(e, i)}/> - {o.title} + onChange={(e) => { + console.log('e', e); + e.preventDefault(); + e.stopPropagation(); + setChecked(e, i); + }}/> + {o.value}
diff --git a/src/pages/BandoForms/index.js b/src/pages/BandoForms/index.js index 254cf20..960262b 100644 --- a/src/pages/BandoForms/index.js +++ b/src/pages/BandoForms/index.js @@ -24,26 +24,26 @@ const BandoForms = () => { const [forms, setForms] = useState([]); const doCreateNewForm = () => { - navigate(`/bandi/${id}/forms/new`); + navigate(`/tenders/${id}/forms/new`); } const goToEditBando = () => { - navigate(`/bandi/${id}`); + navigate(`/tenders/${id}`); } const openBandoFlowManagement = () => { - navigate(`/bandi/${id}/flow`); + navigate(`/tenders/${id}/flow`); } const goToEditForm = () => { if (selectedForm && selectedForm !== 0) { - navigate(`/bandi/${id}/forms/${selectedForm}`); + navigate(`/tenders/${id}/forms/${selectedForm}`); } } const goToEditFormFromTemplate = () => { console.log('goToEditFormFromTemplate', selectedTemplate) - //navigate(`/bandi/${id}`); + //navigate(`/tenders/${id}`); } const getFormsCallback = (data) => { diff --git a/src/pages/BandoFormsEdit/index.js b/src/pages/BandoFormsEdit/index.js index 956d2e3..d736275 100644 --- a/src/pages/BandoFormsEdit/index.js +++ b/src/pages/BandoFormsEdit/index.js @@ -32,7 +32,7 @@ const BandoFormsEdit = () => { const goBack = () => { const bandoId = getBandoId(); - navigate(`/bandi/${bandoId}/forms`); + navigate(`/tenders/${bandoId}/forms`); } const doSave = (shouldRedirect = false) => { @@ -59,11 +59,11 @@ const BandoFormsEdit = () => { const bandoId = getBandoId(); if (shouldRedirect) { - navigate(`/bandi/${bandoId}/forms/${data.data.id}/preview`); + navigate(`/tenders/${bandoId}/forms/${data.data.id}/preview`); return; } if (data.data.id) { - navigate(`/bandi/${bandoId}/forms/${data.data.id}`); + navigate(`/tenders/${bandoId}/forms/${data.data.id}`); } } } @@ -102,7 +102,7 @@ const BandoFormsEdit = () => { const formDeleteCallback = (data) => { if (data.status === 'SUCCESS') { const bandoId = getBandoId(); - navigate(`/bandi/${bandoId}/forms`); + navigate(`/tenders/${bandoId}/forms`); } storeSet.main.unsetAsyncRequest(); } @@ -199,7 +199,6 @@ const BandoFormsEdit = () => { label={__('Indietro', 'gepafin')} icon="pi pi-arrow-left" iconPos="left"/>