form-craft-package 1.7.9-dev.1 → 1.7.9-dev.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/src/components/common/custom-hooks/use-find-dynamic-form.hook.ts +30 -11
- package/src/components/common/custom-hooks/use-many-to-many-connector.hook.ts +30 -0
- package/src/components/common/not-found.tsx +21 -0
- package/src/components/companies/1-authenticated/change-password.tsx +1 -1
- package/src/components/form/1-list/index.tsx +4 -5
- package/src/components/form/1-list/table-header.tsx +5 -5
- package/src/components/form/1-list/table.tsx +10 -12
- package/src/components/form/2-details/index.tsx +53 -40
- package/src/components/form/layout-renderer/1-row/index.tsx +2 -1
- package/src/components/form/layout-renderer/3-element/1-dynamic-button/index.tsx +57 -87
- package/src/components/form/layout-renderer/3-element/1-dynamic-button/use-button-navigate.hook.tsx +88 -0
- package/src/components/form/layout-renderer/3-element/1-dynamic-button/use-create-data.hook.ts +22 -23
- package/src/components/form/layout-renderer/3-element/1-dynamic-button/use-generate-report.hook.tsx +3 -4
- package/src/components/form/layout-renderer/3-element/1-dynamic-button/use-save-data.hook.ts +2 -2
- package/src/components/form/layout-renderer/3-element/11-breadcrumb.tsx +3 -2
- package/src/components/form/layout-renderer/3-element/2-field-element.tsx +4 -1
- package/src/components/form/layout-renderer/3-element/8-fields-with-options.tsx +9 -12
- package/src/components/form/layout-renderer/3-element/9-form-data-render.tsx +48 -79
- package/src/components/modals/report-filters.modal/helper-functions.ts +3 -6
- package/src/constants.ts +7 -1
- package/src/enums/form.enum.ts +5 -3
- package/src/functions/forms/breadcrumb-handlers.ts +21 -0
- package/src/functions/forms/data-render-functions.tsx +1 -0
- package/src/functions/forms/extended-json-handlers.ts +56 -0
- package/src/functions/forms/index.ts +17 -11
- package/src/functions/reports/index.tsx +2 -1
- package/src/types/forms/index.ts +1 -0
- package/src/types/forms/layout-elements/button.ts +11 -3
- package/src/types/forms/layout-elements/index.ts +6 -2
- package/src/types/forms/layout-elements/sanitization.ts +6 -1
- package/src/types/forms/relationship/index.ts +12 -1
- package/src/functions/forms/json-handlers.ts +0 -19
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useNotification } from '../../../../common/custom-hooks'
|
|
1
|
+
import { useNavigate } from 'react-router-dom'
|
|
2
|
+
import { useFindDynamiForm, useNotification } from '../../../../common/custom-hooks'
|
|
3
3
|
import { useCheckElementConditions } from '../../../../common/custom-hooks/use-check-element-conditions.hook'
|
|
4
|
-
import { memo, useCallback,
|
|
4
|
+
import { memo, useCallback, useState } from 'react'
|
|
5
5
|
import { useFormPreservedItemValues } from '../../../../common/custom-hooks/use-preserved-form-items.hook'
|
|
6
|
-
import { constructDynamicFormHref } from '../../../../../functions/forms'
|
|
7
6
|
import { useDuplicateDataAction } from './use-duplicate-data.hook'
|
|
8
7
|
import { useDeleteDataAction } from './use-delete-data.hook'
|
|
9
8
|
import { usePublishDataAction } from './use-publish-data.hook'
|
|
@@ -16,36 +15,33 @@ import { Button_FillerPortal } from '../../../../common/button'
|
|
|
16
15
|
import { getButtonRenderProps } from '../../../../../functions/forms/get-element-props'
|
|
17
16
|
import WarningIcon from '../../../../common/warning-icon'
|
|
18
17
|
import FormDataLoadingIndicatorModal from '../../../../modals/form-data-loading.modal'
|
|
19
|
-
import { useBreadcrumb } from '../../../../common/custom-hooks/use-breadcrumb.hook'
|
|
20
18
|
import { IFormContext } from '../../1-row'
|
|
19
|
+
import { ButtonActionCategoryEnum, FormLoadingModalTypeEnum } from '../../../../../enums'
|
|
20
|
+
import { useButtonNavigateAction } from './use-button-navigate.hook'
|
|
21
|
+
import { constructDynamicFormHref } from '../../../../../functions'
|
|
21
22
|
import {
|
|
22
23
|
IButtonElementProps,
|
|
23
24
|
IFormLayoutElementConditions,
|
|
24
25
|
IButtonProps_Other,
|
|
25
26
|
IButtonProps_Navigate,
|
|
26
27
|
} from '../../../../../types'
|
|
27
|
-
import {
|
|
28
|
-
ButtonActionCategoryEnum,
|
|
29
|
-
FormLoadingModalTypeEnum,
|
|
30
|
-
NavigateButtonCustomComponentType,
|
|
31
|
-
NavigateButtonTypesEnum,
|
|
32
|
-
} from '../../../../../enums'
|
|
33
28
|
|
|
34
29
|
export const DynamicFormButtonRender = memo((props: IDynamicButton) => {
|
|
35
30
|
const { displayStateProps = {}, formContext = {}, onCustomFunctionCall = () => {} } = props
|
|
36
31
|
const { btnProps, conditions, defaultDisabled = false } = displayStateProps as IDynamicButton_DisplayStateProps
|
|
37
|
-
const { formDataId, formRef
|
|
32
|
+
const { formDataId, formRef } = formContext as IFormContext
|
|
38
33
|
|
|
39
|
-
const
|
|
34
|
+
const { getFormById } = useFindDynamiForm()
|
|
40
35
|
const navigate = useNavigate()
|
|
41
|
-
const { updateCrumb } = useBreadcrumb()
|
|
42
36
|
const { success, warning, error, confirmModal } = useNotification()
|
|
43
37
|
const { isElementDisabled, isElementHidden } = useCheckElementConditions({ formRef, conditions, defaultDisabled })
|
|
44
38
|
const [loading, setLoading] = useState(false)
|
|
45
39
|
const [dataLoadingType, setDataLoadingType] = useState<FormLoadingModalTypeEnum | undefined>()
|
|
46
|
-
const { inPreviewMode, isPublic = false } = useFormPreservedItemValues(formRef)
|
|
40
|
+
const { inPreviewMode, isPublic = false, submissionPdfConfig } = useFormPreservedItemValues(formRef)
|
|
47
41
|
|
|
48
|
-
const
|
|
42
|
+
const formInfo = btnProps.formId ? getFormById(btnProps.formId) : undefined
|
|
43
|
+
formContext.formId = btnProps.formId
|
|
44
|
+
formContext.formName = formInfo?.name
|
|
49
45
|
|
|
50
46
|
const displayResultMessage = useCallback(
|
|
51
47
|
(isSuccess: boolean = true) => {
|
|
@@ -55,24 +51,49 @@ export const DynamicFormButtonRender = memo((props: IDynamicButton) => {
|
|
|
55
51
|
[btnProps.messages, success, error],
|
|
56
52
|
)
|
|
57
53
|
|
|
54
|
+
const onButtonNavigate = useButtonNavigateAction({
|
|
55
|
+
...formContext,
|
|
56
|
+
onSuccess: () => {},
|
|
57
|
+
onError: () => {},
|
|
58
|
+
onFinal: () => {},
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const handleSecondaryAction = useCallback(
|
|
62
|
+
(formDataId?: string) => {
|
|
63
|
+
if (!btnProps.secondaryAction) {
|
|
64
|
+
if (formInfo?.name) navigate(`${constructDynamicFormHref(formInfo.name)}/${formDataId}`, { replace: true })
|
|
65
|
+
setTimeout(() => {
|
|
66
|
+
setDataLoadingType(undefined)
|
|
67
|
+
displayResultMessage()
|
|
68
|
+
}, 500)
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const { category } = btnProps.secondaryAction
|
|
73
|
+
if (category === ButtonActionCategoryEnum.Navigate) onButtonNavigate(btnProps.secondaryAction)
|
|
74
|
+
else if (category === ButtonActionCategoryEnum.CustomFunction) {
|
|
75
|
+
onCustomFunctionCall(btnProps.secondaryAction.functionName, btnProps.messages ?? defaultMessage)
|
|
76
|
+
setTimeout(() => setLoading(false), 500)
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
[btnProps, onButtonNavigate, formInfo],
|
|
80
|
+
)
|
|
81
|
+
|
|
58
82
|
const onDuplicateData = useDuplicateDataAction({
|
|
59
83
|
...formContext,
|
|
60
|
-
onSuccess: () =>
|
|
84
|
+
onSuccess: () => handleSecondaryAction(),
|
|
61
85
|
onError: () => displayResultMessage(false),
|
|
62
86
|
onFinal: () => setLoading(false),
|
|
63
87
|
})
|
|
64
88
|
const onDeleteData = useDeleteDataAction({
|
|
65
89
|
...formContext,
|
|
66
|
-
onSuccess: () =>
|
|
67
|
-
displayResultMessage(true)
|
|
68
|
-
navigate(baseDynamicUrl)
|
|
69
|
-
},
|
|
90
|
+
onSuccess: () => handleSecondaryAction(),
|
|
70
91
|
onError: () => displayResultMessage(false),
|
|
71
92
|
onFinal: () => setLoading(false),
|
|
72
93
|
})
|
|
73
94
|
const onPublishData = usePublishDataAction({
|
|
74
95
|
...formContext,
|
|
75
|
-
onSuccess: () =>
|
|
96
|
+
onSuccess: () => handleSecondaryAction(),
|
|
76
97
|
onError: () => displayResultMessage(false),
|
|
77
98
|
onFinal: () => setLoading(false),
|
|
78
99
|
})
|
|
@@ -83,22 +104,14 @@ export const DynamicFormButtonRender = memo((props: IDynamicButton) => {
|
|
|
83
104
|
setDataLoadingType(undefined)
|
|
84
105
|
setLoading(false)
|
|
85
106
|
},
|
|
86
|
-
onSuccess: () =>
|
|
87
|
-
setDataLoadingType(undefined)
|
|
88
|
-
displayResultMessage()
|
|
89
|
-
},
|
|
107
|
+
onSuccess: (formDataId?: string) => handleSecondaryAction(formDataId),
|
|
90
108
|
onError: () => displayResultMessage(false),
|
|
91
109
|
onFinal: () => setLoading(false),
|
|
92
110
|
})
|
|
93
111
|
const onSaveExistingData = useSaveExistingDataAction({
|
|
94
112
|
...formContext,
|
|
95
113
|
setDataLoadingType,
|
|
96
|
-
onSuccess: () =>
|
|
97
|
-
setTimeout(() => {
|
|
98
|
-
setDataLoadingType(undefined)
|
|
99
|
-
displayResultMessage()
|
|
100
|
-
}, 500)
|
|
101
|
-
},
|
|
114
|
+
onSuccess: () => handleSecondaryAction(),
|
|
102
115
|
onError: () => displayResultMessage(false),
|
|
103
116
|
onFinal: () => setLoading(false),
|
|
104
117
|
})
|
|
@@ -113,56 +126,14 @@ export const DynamicFormButtonRender = memo((props: IDynamicButton) => {
|
|
|
113
126
|
const handleButtonClick = useCallback(async () => {
|
|
114
127
|
switch (btnProps.category) {
|
|
115
128
|
case ButtonActionCategoryEnum.Navigate:
|
|
116
|
-
|
|
117
|
-
case NavigateButtonTypesEnum.NewDataPage:
|
|
118
|
-
if (formDataId !== NEW_FORM_DATA_IDENTIFIER)
|
|
119
|
-
updateCrumb(location.pathname, { formJoins: parentFormJoins, formDataId })
|
|
120
|
-
navigate(`${baseDynamicUrl}/${NEW_FORM_DATA_IDENTIFIER}`)
|
|
121
|
-
break
|
|
122
|
-
|
|
123
|
-
case NavigateButtonTypesEnum.ViewDataDetails:
|
|
124
|
-
if (formDataId) navigate(`${baseDynamicUrl}/${formDataId}`)
|
|
125
|
-
else error({ message: CUSTOM_ERROR_MESSAGES.DataIdNotFound })
|
|
126
|
-
break
|
|
127
|
-
|
|
128
|
-
case NavigateButtonTypesEnum.ReturnToList:
|
|
129
|
-
navigate(baseDynamicUrl)
|
|
130
|
-
break
|
|
131
|
-
|
|
132
|
-
case NavigateButtonTypesEnum.Custom:
|
|
133
|
-
if (Array.isArray(btnProps.urlComponents)) {
|
|
134
|
-
const validComponents = btnProps.urlComponents.filter((c) => !!c.type && !!c.value)
|
|
135
|
-
const formData = formRef?.getFieldsValue() ?? {}
|
|
136
|
-
|
|
137
|
-
const finalUrl = validComponents
|
|
138
|
-
.map((c) => {
|
|
139
|
-
if (c.type === NavigateButtonCustomComponentType.DynamicPath) {
|
|
140
|
-
const data = formData[c.value] ?? ''
|
|
141
|
-
return data.replaceAll(' ', '')
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return c.value
|
|
145
|
-
})
|
|
146
|
-
.join('/')
|
|
147
|
-
|
|
148
|
-
window.open(finalUrl, '_blank')
|
|
149
|
-
}
|
|
150
|
-
break
|
|
151
|
-
|
|
152
|
-
case NavigateButtonTypesEnum.ReturnOneBack:
|
|
153
|
-
default:
|
|
154
|
-
navigate(-1)
|
|
155
|
-
break
|
|
156
|
-
}
|
|
157
|
-
// window.location.href = `${baseDynamicUrl}/${NEW_FORM_DATA_IDENTIFIER}`
|
|
158
|
-
|
|
129
|
+
onButtonNavigate(btnProps)
|
|
159
130
|
setLoading(false)
|
|
160
131
|
break
|
|
161
132
|
|
|
162
133
|
case ButtonActionCategoryEnum.DuplicateData:
|
|
163
134
|
if (formDataId) await onDuplicateData()
|
|
164
135
|
else {
|
|
165
|
-
error({ message:
|
|
136
|
+
error({ message: BUTTON_CUSTOM_ERROR_MESSAGES.DataIdNotFound })
|
|
166
137
|
setLoading(false)
|
|
167
138
|
}
|
|
168
139
|
break
|
|
@@ -170,7 +141,7 @@ export const DynamicFormButtonRender = memo((props: IDynamicButton) => {
|
|
|
170
141
|
case ButtonActionCategoryEnum.DeleteData:
|
|
171
142
|
if (formDataId) await onDeleteData()
|
|
172
143
|
else {
|
|
173
|
-
error({ message:
|
|
144
|
+
error({ message: BUTTON_CUSTOM_ERROR_MESSAGES.DataIdNotFound })
|
|
174
145
|
setLoading(false)
|
|
175
146
|
}
|
|
176
147
|
break
|
|
@@ -178,7 +149,7 @@ export const DynamicFormButtonRender = memo((props: IDynamicButton) => {
|
|
|
178
149
|
case ButtonActionCategoryEnum.PublishDataChanges:
|
|
179
150
|
if (formDataId) await onPublishData()
|
|
180
151
|
else {
|
|
181
|
-
error({ message:
|
|
152
|
+
error({ message: BUTTON_CUSTOM_ERROR_MESSAGES.DataIdNotFound })
|
|
182
153
|
setLoading(false)
|
|
183
154
|
}
|
|
184
155
|
break
|
|
@@ -187,7 +158,7 @@ export const DynamicFormButtonRender = memo((props: IDynamicButton) => {
|
|
|
187
158
|
await onSaveSignature()
|
|
188
159
|
|
|
189
160
|
if (formDataId === NEW_FORM_DATA_IDENTIFIER) {
|
|
190
|
-
if (isPublic) onGeneratePdfProof()
|
|
161
|
+
if (isPublic && submissionPdfConfig) onGeneratePdfProof()
|
|
191
162
|
else onCreateNewData()
|
|
192
163
|
} else onSaveExistingData()
|
|
193
164
|
|
|
@@ -222,12 +193,10 @@ export const DynamicFormButtonRender = memo((props: IDynamicButton) => {
|
|
|
222
193
|
break
|
|
223
194
|
}
|
|
224
195
|
}, [
|
|
225
|
-
location.pathname,
|
|
226
|
-
parentFormJoins,
|
|
227
196
|
btnProps,
|
|
228
|
-
baseDynamicUrl,
|
|
229
197
|
formDataId,
|
|
230
198
|
isPublic,
|
|
199
|
+
submissionPdfConfig,
|
|
231
200
|
onCustomFunctionCall,
|
|
232
201
|
onDuplicateData,
|
|
233
202
|
onDeleteData,
|
|
@@ -236,6 +205,7 @@ export const DynamicFormButtonRender = memo((props: IDynamicButton) => {
|
|
|
236
205
|
onGeneratePdfProof,
|
|
237
206
|
onSaveExistingData,
|
|
238
207
|
onGenerateReport,
|
|
208
|
+
onButtonNavigate,
|
|
239
209
|
setDataLoadingType,
|
|
240
210
|
])
|
|
241
211
|
|
|
@@ -253,7 +223,7 @@ export const DynamicFormButtonRender = memo((props: IDynamicButton) => {
|
|
|
253
223
|
if (
|
|
254
224
|
isPublic &&
|
|
255
225
|
formDataId === NEW_FORM_DATA_IDENTIFIER &&
|
|
256
|
-
|
|
226
|
+
[ButtonActionCategoryEnum.SaveDataChanges, ButtonActionCategoryEnum.Navigate].includes(btnProps.category)
|
|
257
227
|
)
|
|
258
228
|
return
|
|
259
229
|
setLoading(true)
|
|
@@ -272,9 +242,9 @@ export const DynamicFormButtonRender = memo((props: IDynamicButton) => {
|
|
|
272
242
|
{isPublic &&
|
|
273
243
|
formDataId === NEW_FORM_DATA_IDENTIFIER &&
|
|
274
244
|
btnProps.category !== ButtonActionCategoryEnum.SaveDataChanges && (
|
|
275
|
-
<WarningIcon tooltip={
|
|
245
|
+
<WarningIcon tooltip={BUTTON_CUSTOM_ERROR_MESSAGES.UnavailableForPublic} />
|
|
276
246
|
)}
|
|
277
|
-
{inPreviewMode && <WarningIcon tooltip={
|
|
247
|
+
{inPreviewMode && <WarningIcon tooltip={BUTTON_CUSTOM_ERROR_MESSAGES.InPreviewMode} />}
|
|
278
248
|
{btnProps.label}
|
|
279
249
|
</Button_FillerPortal>
|
|
280
250
|
{!!dataLoadingType && (
|
|
@@ -309,14 +279,14 @@ export interface ICustomFunctionCall {
|
|
|
309
279
|
) => void
|
|
310
280
|
}
|
|
311
281
|
export interface IOnSuccessFunctions {
|
|
312
|
-
onSuccess: () => void
|
|
282
|
+
onSuccess: (formDataId?: string) => void
|
|
313
283
|
onError: () => void
|
|
314
284
|
onFinal: () => void
|
|
315
285
|
}
|
|
316
286
|
|
|
317
287
|
const defaultMessage = { success: 'Successfully completed!', error: 'Error occured' }
|
|
318
288
|
|
|
319
|
-
const
|
|
289
|
+
export const BUTTON_CUSTOM_ERROR_MESSAGES = {
|
|
320
290
|
DataIdNotFound: 'Data id was not found!',
|
|
321
291
|
FormInstanceNotFound: 'Form ref was not found!',
|
|
322
292
|
UnavailableForPublic: 'Button action is NOT allowed for public use!',
|
package/src/components/form/layout-renderer/3-element/1-dynamic-button/use-button-navigate.hook.tsx
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { useCallback } from 'react'
|
|
2
|
+
import { IButtonProps_Navigate } from '../../../../../types'
|
|
3
|
+
import { useFindDynamiForm, useNotification } from '../../../../common/custom-hooks'
|
|
4
|
+
import { constructDynamicFormHref } from '../../../../../functions/forms'
|
|
5
|
+
import { NavigateButtonCustomComponentType, NavigateButtonTypesEnum } from '../../../../../enums'
|
|
6
|
+
import { IFormContext } from '../../1-row'
|
|
7
|
+
import { BUTTON_CUSTOM_ERROR_MESSAGES, IOnSuccessFunctions } from '.'
|
|
8
|
+
import { useNavigate } from 'react-router-dom'
|
|
9
|
+
import { NEW_FORM_DATA_IDENTIFIER } from '../../../../../constants'
|
|
10
|
+
import { useBreadcrumb } from '../../../../common/custom-hooks/use-breadcrumb.hook'
|
|
11
|
+
|
|
12
|
+
/* --------------------------------------------------------------------------
|
|
13
|
+
Navigation button action handler
|
|
14
|
+
-------------------------------------------------------------------------- */
|
|
15
|
+
export const useButtonNavigateAction = ({
|
|
16
|
+
onSuccess,
|
|
17
|
+
onError,
|
|
18
|
+
onFinal,
|
|
19
|
+
...formContext
|
|
20
|
+
}: IOnSuccessFunctions & IFormContext) => {
|
|
21
|
+
const { formRef, formDataId, parentFormJoins, manyToManyRelInfo } = formContext
|
|
22
|
+
const { getFormById } = useFindDynamiForm()
|
|
23
|
+
const { error } = useNotification()
|
|
24
|
+
const { updateCrumb } = useBreadcrumb()
|
|
25
|
+
const navigate = useNavigate()
|
|
26
|
+
|
|
27
|
+
const onButtonNavigate = useCallback(
|
|
28
|
+
async (btnProps: IButtonProps_Navigate) => {
|
|
29
|
+
const formInfo = btnProps.formId ? getFormById(btnProps.formId) : undefined
|
|
30
|
+
const baseDynamicUrl = formInfo ? constructDynamicFormHref(formInfo.name) : ''
|
|
31
|
+
|
|
32
|
+
switch (btnProps.navigateType) {
|
|
33
|
+
case NavigateButtonTypesEnum.NewDataPage:
|
|
34
|
+
let newDatapageNavigateUrl = `${baseDynamicUrl}/${NEW_FORM_DATA_IDENTIFIER}`
|
|
35
|
+
if (manyToManyRelInfo && parentFormJoins && formDataId) {
|
|
36
|
+
const middleFormInfo = getFormById(manyToManyRelInfo.middleFormId)
|
|
37
|
+
|
|
38
|
+
if (middleFormInfo)
|
|
39
|
+
newDatapageNavigateUrl = `${constructDynamicFormHref(middleFormInfo.name)}/${NEW_FORM_DATA_IDENTIFIER}`
|
|
40
|
+
}
|
|
41
|
+
if (formDataId !== NEW_FORM_DATA_IDENTIFIER)
|
|
42
|
+
updateCrumb(location.pathname, { formJoins: parentFormJoins, formDataId, manyToManyRelInfo })
|
|
43
|
+
|
|
44
|
+
navigate(newDatapageNavigateUrl)
|
|
45
|
+
break
|
|
46
|
+
|
|
47
|
+
case NavigateButtonTypesEnum.ViewDataDetails:
|
|
48
|
+
if (formDataId) navigate(`${baseDynamicUrl}/${formDataId}`)
|
|
49
|
+
else error({ message: BUTTON_CUSTOM_ERROR_MESSAGES.DataIdNotFound })
|
|
50
|
+
break
|
|
51
|
+
|
|
52
|
+
case NavigateButtonTypesEnum.GoToDataList:
|
|
53
|
+
navigate(baseDynamicUrl)
|
|
54
|
+
break
|
|
55
|
+
|
|
56
|
+
case NavigateButtonTypesEnum.Custom:
|
|
57
|
+
if (btnProps.customUrl) {
|
|
58
|
+
navigate(btnProps.customUrl)
|
|
59
|
+
} else if (Array.isArray(btnProps.urlComponents)) {
|
|
60
|
+
const validComponents = btnProps.urlComponents.filter((c) => !!c.type && !!c.value)
|
|
61
|
+
const formData = formRef?.getFieldsValue() ?? {}
|
|
62
|
+
|
|
63
|
+
const finalUrl = validComponents
|
|
64
|
+
.map((c) => {
|
|
65
|
+
if (c.type === NavigateButtonCustomComponentType.DynamicPath) {
|
|
66
|
+
const data = formData[c.value] ?? ''
|
|
67
|
+
return data.replaceAll(' ', '')
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return c.value
|
|
71
|
+
})
|
|
72
|
+
.join('/')
|
|
73
|
+
|
|
74
|
+
window.open(finalUrl, '_blank')
|
|
75
|
+
}
|
|
76
|
+
break
|
|
77
|
+
|
|
78
|
+
case NavigateButtonTypesEnum.GoBack:
|
|
79
|
+
default:
|
|
80
|
+
navigate(-1 * (btnProps.navigateBackCount ?? 1))
|
|
81
|
+
break
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
[parentFormJoins, manyToManyRelInfo, formRef],
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
return onButtonNavigate
|
|
88
|
+
}
|
package/src/components/form/layout-renderer/3-element/1-dynamic-button/use-create-data.hook.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { useCallback } from 'react'
|
|
2
2
|
import { FormLoadingModalTypeEnum } from '../../../../../enums'
|
|
3
3
|
import { useFormPreservedItemValues } from '../../../../common/custom-hooks/use-preserved-form-items.hook'
|
|
4
|
-
import {
|
|
4
|
+
import { toMongoDbExtendedJSON } from '../../../../../functions/forms/extended-json-handlers'
|
|
5
5
|
import client from '../../../../../api/client'
|
|
6
|
-
import {
|
|
6
|
+
import { objectToQueryParams } from '../../../../../functions/forms'
|
|
7
7
|
import { useNotification } from '../../../../common/custom-hooks'
|
|
8
8
|
import { useNavigate } from 'react-router-dom'
|
|
9
9
|
import { IFormContext } from '../../1-row'
|
|
10
10
|
import { IOnSuccessFunctions } from '.'
|
|
11
|
+
import { useBreadcrumb } from '../../../../common/custom-hooks/use-breadcrumb.hook'
|
|
11
12
|
|
|
12
13
|
/* --------------------------------------------------------------------------
|
|
13
14
|
- Creates new form data.
|
|
@@ -28,43 +29,40 @@ export const useCreateDataWithPdfActions = ({
|
|
|
28
29
|
const { formRef, formKey, formId, formName, companyKey } = formContext
|
|
29
30
|
|
|
30
31
|
const navigate = useNavigate()
|
|
31
|
-
// const { isModalOpen: isSuccessModalOpen, isPendingTransition: isSuccessModalPending, openModal: openSuccessModal, closeModal: closeSuccessModal } = useLazyModalOpener()
|
|
32
32
|
const { errorModal, confirmModal } = useNotification()
|
|
33
33
|
const { baseServerUrl, submissionPdfConfig, isPublic } = useFormPreservedItemValues(formRef)
|
|
34
|
+
const { breadcrumbs } = useBreadcrumb()
|
|
34
35
|
|
|
35
36
|
const onCreateNewData = useCallback(
|
|
36
37
|
(generatedPdfBlobName?: string) => {
|
|
37
38
|
try {
|
|
38
39
|
formRef?.validateFields().then(async (values) => {
|
|
39
40
|
setDataLoadingType(FormLoadingModalTypeEnum.SavingChanges)
|
|
40
|
-
|
|
41
41
|
const reqData = {
|
|
42
42
|
name: '', // TODO: maybe later, make it dynamic
|
|
43
|
-
data:
|
|
43
|
+
data: JSON.stringify(toMongoDbExtendedJSON({ ...values, generatedPdfBlobName })),
|
|
44
44
|
...(isPublic ? { private: false } : { version: 1 }),
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
const endpoint = isPublic ? `/api/site/${formKey}` : `/api/formdata/${formId}`
|
|
48
48
|
const res = await client.post(endpoint, reqData)
|
|
49
49
|
|
|
50
|
-
if (res.status === 200)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
}, 500)
|
|
50
|
+
if (res.status === 200) {
|
|
51
|
+
onCreateSuccess(res.data)
|
|
52
|
+
if (submissionPdfConfig?.showDownloadModal) {
|
|
53
|
+
confirmModal({
|
|
54
|
+
title: submissionPdfConfig.successTitle ?? 'Successfully generated the PDF!',
|
|
55
|
+
content: submissionPdfConfig.successContent ?? 'Would you like to download the PDF?',
|
|
56
|
+
centered: true,
|
|
57
|
+
okText: 'Download',
|
|
58
|
+
onOk: () => {
|
|
59
|
+
const href = `${baseServerUrl}/api/attachment/${companyKey}/${generatedPdfBlobName}`
|
|
60
|
+
window.open(href, '_blank')
|
|
61
|
+
window.location.reload()
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
}
|
|
68
66
|
})
|
|
69
67
|
} catch (err) {
|
|
70
68
|
if (submissionPdfConfig?.errorMsg) errorModal({ title: submissionPdfConfig.errorMsg })
|
|
@@ -74,6 +72,7 @@ export const useCreateDataWithPdfActions = ({
|
|
|
74
72
|
}
|
|
75
73
|
},
|
|
76
74
|
[
|
|
75
|
+
breadcrumbs,
|
|
77
76
|
formRef,
|
|
78
77
|
formId,
|
|
79
78
|
formKey,
|
package/src/components/form/layout-renderer/3-element/1-dynamic-button/use-generate-report.hook.tsx
CHANGED
|
@@ -4,9 +4,8 @@ import { FaCaretDown } from 'react-icons/fa6'
|
|
|
4
4
|
import { IDynamicForm, IFormSchema, IFormTemplateReport } from '../../../../../types'
|
|
5
5
|
import { Button_FillerPortal } from '../../../../common/button'
|
|
6
6
|
import { useNotification } from '../../../../common/custom-hooks'
|
|
7
|
-
import { fetchFormDataAsLookup, renderData } from '../../../../../functions/forms'
|
|
7
|
+
import { fetchFormDataAsLookup, getIdEqualsQuery, renderData } from '../../../../../functions/forms'
|
|
8
8
|
import client from '../../../../../api/client'
|
|
9
|
-
import { parseJSON } from '../../../../../functions/forms/json-handlers'
|
|
10
9
|
import { FieldElementOptionSourceEnum, LOCAL_STORAGE_KEYS_ENUM } from '../../../../../enums'
|
|
11
10
|
import { IFormContext } from '../../1-row'
|
|
12
11
|
import { IOnSuccessFunctions } from '.'
|
|
@@ -44,14 +43,14 @@ export const useGenerateReportAction = ({
|
|
|
44
43
|
.get(`/api/form/${form.id}`)
|
|
45
44
|
.then((res) => {
|
|
46
45
|
if (res.status === 200) {
|
|
47
|
-
const parsedFormData: IFormSchema | null =
|
|
46
|
+
const parsedFormData: IFormSchema | null = JSON.parse(res.data.data)
|
|
48
47
|
if (parsedFormData) {
|
|
49
48
|
const reports = parsedFormData.generateConfig.templateReports ?? []
|
|
50
49
|
if (reports.length)
|
|
51
50
|
client
|
|
52
51
|
.post(`/api/report/data/${form.id}`, {
|
|
53
52
|
joins: parsedFormData.generateConfig.formJoins,
|
|
54
|
-
match: JSON.stringify(
|
|
53
|
+
match: JSON.stringify(getIdEqualsQuery('', formDataId)),
|
|
55
54
|
})
|
|
56
55
|
.then((res) => {
|
|
57
56
|
if (res.status === 200) {
|
package/src/components/form/layout-renderer/3-element/1-dynamic-button/use-save-data.hook.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback } from 'react'
|
|
2
2
|
import { FormLoadingModalTypeEnum } from '../../../../../enums'
|
|
3
|
-
import {
|
|
3
|
+
import { toMongoDbExtendedJSON } from '../../../../../functions/forms/extended-json-handlers'
|
|
4
4
|
import client from '../../../../../api/client'
|
|
5
5
|
import { IFormContext } from '../../1-row'
|
|
6
6
|
import { IOnSuccessFunctions } from '.'
|
|
@@ -27,7 +27,7 @@ export const useSaveExistingDataAction = ({
|
|
|
27
27
|
setDataLoadingType(FormLoadingModalTypeEnum.SavingChanges)
|
|
28
28
|
const reqData = {
|
|
29
29
|
name: 'Dynamic form data', // TODO: maybe later, make it dynamic
|
|
30
|
-
data:
|
|
30
|
+
data: JSON.stringify(toMongoDbExtendedJSON(values)),
|
|
31
31
|
version: 1, // FIXME: increment
|
|
32
32
|
private: false, // not used anymore, sending it as false by default
|
|
33
33
|
}
|
|
@@ -2,6 +2,7 @@ import { useBreadcrumb } from '../../../common/custom-hooks/use-breadcrumb.hook'
|
|
|
2
2
|
import { Button_FillerPortal } from '../../../common/button'
|
|
3
3
|
import { useNavigate } from 'react-router-dom'
|
|
4
4
|
import { FaChevronRight } from 'react-icons/fa6'
|
|
5
|
+
import React from 'react'
|
|
5
6
|
|
|
6
7
|
export default function LayoutRenderer_Breadcrumb() {
|
|
7
8
|
const navigate = useNavigate()
|
|
@@ -10,7 +11,7 @@ export default function LayoutRenderer_Breadcrumb() {
|
|
|
10
11
|
return (
|
|
11
12
|
<div className="flex items-center text-12">
|
|
12
13
|
{breadcrumbs.map((bc, bcIdx) => (
|
|
13
|
-
|
|
14
|
+
<React.Fragment key={bcIdx}>
|
|
14
15
|
<Button_FillerPortal
|
|
15
16
|
link
|
|
16
17
|
disabled={breadcrumbs.length - 1 === bcIdx}
|
|
@@ -22,7 +23,7 @@ export default function LayoutRenderer_Breadcrumb() {
|
|
|
22
23
|
<span className="font-normal italic">{bc.label}</span>
|
|
23
24
|
</Button_FillerPortal>
|
|
24
25
|
{breadcrumbs.length - 1 !== bcIdx && <FaChevronRight className="text-primary" />}
|
|
25
|
-
|
|
26
|
+
</React.Fragment>
|
|
26
27
|
))}
|
|
27
28
|
</div>
|
|
28
29
|
)
|
|
@@ -50,6 +50,9 @@ export const LayoutRenderer_FieldElement = ({
|
|
|
50
50
|
const sanitizationRule = field.sanitization
|
|
51
51
|
if (!sanitizationRule || sanitizationRule.type === DataSanitizationTypeEnum.Default) return value
|
|
52
52
|
|
|
53
|
+
if (sanitizationRule.type === DataSanitizationTypeEnum.Predefined && sanitizationRule.pattern)
|
|
54
|
+
return formatByPattern(value, sanitizationRule.pattern)
|
|
55
|
+
|
|
53
56
|
if (sanitizationRule.type === DataSanitizationTypeEnum.Custom)
|
|
54
57
|
return formatByPattern(value, sanitizationRule.pattern)
|
|
55
58
|
}}
|
|
@@ -193,7 +196,7 @@ const getField = ({
|
|
|
193
196
|
)
|
|
194
197
|
case ElementTypeEnum.ShortInput:
|
|
195
198
|
default:
|
|
196
|
-
return <Input placeholder={placeholder} disabled={disabled} autoComplete=
|
|
199
|
+
return <Input placeholder={placeholder} disabled={disabled} autoComplete="off" />
|
|
197
200
|
}
|
|
198
201
|
}
|
|
199
202
|
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
IRadioElement,
|
|
19
19
|
ISelectElement,
|
|
20
20
|
} from '../../../../types'
|
|
21
|
+
import { getIdEqualsQuery } from '../../../../functions'
|
|
21
22
|
|
|
22
23
|
export default function LayoutRenderer_FieldsWithOptions({
|
|
23
24
|
formContext,
|
|
@@ -31,6 +32,7 @@ export default function LayoutRenderer_FieldsWithOptions({
|
|
|
31
32
|
const cancelTokenRef = useRef<CancelToken | undefined>(undefined)
|
|
32
33
|
const { breadcrumbs } = useBreadcrumb()
|
|
33
34
|
const [loading, setLoading] = useState(true)
|
|
35
|
+
const isManyToManyPageRef = useRef(false)
|
|
34
36
|
|
|
35
37
|
const { inPreviewMode } = useFormPreservedItemValues(formRef)
|
|
36
38
|
|
|
@@ -38,6 +40,9 @@ export default function LayoutRenderer_FieldsWithOptions({
|
|
|
38
40
|
if (breadcrumbs.length < 2) return { formJoins: [], formDataId: '' }
|
|
39
41
|
|
|
40
42
|
const breadcrumb = breadcrumbs[breadcrumbs.length - 2]
|
|
43
|
+
|
|
44
|
+
if (!!breadcrumb.manyToManyRelInfo) isManyToManyPageRef.current = true
|
|
45
|
+
|
|
41
46
|
return { formJoins: breadcrumb.formJoins ?? [], formDataId: breadcrumb.formDataId ?? '' }
|
|
42
47
|
}, [breadcrumbs])
|
|
43
48
|
|
|
@@ -52,16 +57,8 @@ export default function LayoutRenderer_FieldsWithOptions({
|
|
|
52
57
|
.post(`/api/report/data/${selectedFormId}`, {
|
|
53
58
|
joins: filteredJoins,
|
|
54
59
|
match: JSON.stringify(
|
|
55
|
-
parentRelInfo.formDataId
|
|
56
|
-
? {
|
|
57
|
-
$expr: {
|
|
58
|
-
$eq: [
|
|
59
|
-
lastJoin?.alias ? `$${lastJoin.alias}._id` : '$_id',
|
|
60
|
-
{ $toObjectId: parentRelInfo.formDataId },
|
|
61
|
-
],
|
|
62
|
-
},
|
|
63
|
-
DeletedDate: null,
|
|
64
|
-
}
|
|
60
|
+
parentRelInfo.formDataId && !isManyToManyPageRef.current
|
|
61
|
+
? { DeletedDate: null, ...getIdEqualsQuery(lastJoin?.alias, parentRelInfo.formDataId) }
|
|
65
62
|
: { DeletedDate: null },
|
|
66
63
|
),
|
|
67
64
|
project: JSON.stringify({ value: '$_id', label: `$Data.${selectedFormField}` }),
|
|
@@ -102,9 +99,9 @@ export default function LayoutRenderer_FieldsWithOptions({
|
|
|
102
99
|
.post(`/api/report/data/${lastPath.formId}`, {
|
|
103
100
|
joins: slicedJoinsForLastPath,
|
|
104
101
|
match: JSON.stringify(
|
|
105
|
-
formDataId && lastJoin
|
|
102
|
+
formDataId && lastJoin && !isManyToManyPageRef.current
|
|
106
103
|
? {
|
|
107
|
-
|
|
104
|
+
...getIdEqualsQuery(lastJoin.alias, formDataId),
|
|
108
105
|
DeletedDate: null,
|
|
109
106
|
}
|
|
110
107
|
: { DeletedDate: null },
|