form-craft-package 1.10.8-dev.1 → 1.10.9-dev.0
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 +1 -2
- package/src/components/common/custom-hooks/use-duplicate-on-blur.hook.ts +91 -37
- package/src/components/common/duplicate-entry-checker/duplicate-warning.modal.tsx +100 -125
- package/src/components/common/duplicate-entry-checker/index.tsx +8 -16
- package/src/components/form/2-details/index.tsx +32 -30
- package/src/components/form/layout-renderer/3-element/1-dynamic-button/index.tsx +3 -1
- package/src/components/form/layout-renderer/3-element/1-dynamic-button/use-custom-function-call.hook.ts +1 -0
- package/src/components/form/layout-renderer/3-element/1-dynamic-button/use-save-data.hook.ts +2 -1
- package/src/components/form/layout-renderer/3-element/1-dynamic-button/use-send-notification.hook.ts +0 -2
- package/src/components/modals/form-data-loading.modal.tsx +19 -15
- package/src/enums/form.enum.ts +9 -8
- package/src/functions/forms/index.ts +0 -2
- package/src/types/forms/index.ts +3 -0
- package/AJV_JSON_Schema_Guide.md +0 -409
- package/src/ajv/form/form.schema.json +0 -10
- package/src/ajv/form/layout.schema.json +0 -97
- package/src/ajv/form/migration-rules.schema.json +0 -59
- package/src/functions/forms/form-schema-validator.ts +0 -50
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "form-craft-package",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.9-dev.0",
|
|
4
4
|
"main": "index.ts",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@tanstack/query-sync-storage-persister": "^5.77.2",
|
|
15
15
|
"@tanstack/react-query-persist-client": "^5.77.2",
|
|
16
|
-
"ajv": "^8.17.1",
|
|
17
16
|
"axios": "^1.9.0",
|
|
18
17
|
"crypto-js": "^4.2.0",
|
|
19
18
|
"js-cookie": "^3.0.5",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FormInstance } from 'antd'
|
|
2
2
|
import { useEffect, useMemo, useRef } from 'react'
|
|
3
3
|
import { useBlurEventBus } from '../duplicate-entry-checker/blur-event-bus-provider'
|
|
4
|
-
import { IDuplicateCheckConfigGroup } from '../../../types'
|
|
4
|
+
import { DuplicateCheckOrder, IDuplicateCheckConfigGroup } from '../../../types'
|
|
5
5
|
import apiClient from '../../../api/client'
|
|
6
6
|
import { FormPreservedItemKeys } from '../../../enums'
|
|
7
7
|
|
|
@@ -12,11 +12,23 @@ interface IUseDuplicateOnBlur {
|
|
|
12
12
|
groups?: IDuplicateCheckConfigGroup[]
|
|
13
13
|
debounceMs?: number
|
|
14
14
|
functionName?: string
|
|
15
|
+
isEnabled?: boolean
|
|
16
|
+
checkOrder?: DuplicateCheckOrder[]
|
|
15
17
|
onCustomFunctionCall?: CustomFunctionCall
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
export function useDuplicateOnBlur(
|
|
19
|
-
{
|
|
21
|
+
{
|
|
22
|
+
formRef,
|
|
23
|
+
formKey,
|
|
24
|
+
formDataId,
|
|
25
|
+
groups,
|
|
26
|
+
debounceMs = 0,
|
|
27
|
+
functionName,
|
|
28
|
+
isEnabled,
|
|
29
|
+
checkOrder,
|
|
30
|
+
onCustomFunctionCall,
|
|
31
|
+
}: IUseDuplicateOnBlur,
|
|
20
32
|
onResult: (isDuplicateFound: boolean, data?: unknown) => void,
|
|
21
33
|
) {
|
|
22
34
|
const { subscribeBlurEvent: subscribe } = useBlurEventBus()
|
|
@@ -27,12 +39,31 @@ export function useDuplicateOnBlur(
|
|
|
27
39
|
const relevantFieldGroups = useMemo(() => {
|
|
28
40
|
if (!Array.isArray(groups)) return []
|
|
29
41
|
|
|
30
|
-
return groups
|
|
42
|
+
return groups
|
|
43
|
+
.map((group) => (Array.isArray(group.fields) ? group.fields.filter(Boolean) : []))
|
|
44
|
+
.filter((fields) => fields.length)
|
|
31
45
|
}, [groups])
|
|
32
46
|
|
|
33
47
|
useEffect(() => {
|
|
34
|
-
const
|
|
35
|
-
|
|
48
|
+
const canUseDatabase = Boolean(formKey)
|
|
49
|
+
const canUseFunction = Boolean(functionName && onCustomFunctionCall)
|
|
50
|
+
const resolvedOrder = (
|
|
51
|
+
Array.isArray(checkOrder)
|
|
52
|
+
? checkOrder.filter((step) => {
|
|
53
|
+
if (step === 'database') return canUseDatabase
|
|
54
|
+
if (step === 'function') return canUseFunction
|
|
55
|
+
return false
|
|
56
|
+
})
|
|
57
|
+
: []
|
|
58
|
+
) as DuplicateCheckOrder[]
|
|
59
|
+
|
|
60
|
+
if (!resolvedOrder.length) {
|
|
61
|
+
if (canUseDatabase && canUseFunction) resolvedOrder.push('database', 'function')
|
|
62
|
+
else if (canUseDatabase) resolvedOrder.push('database')
|
|
63
|
+
else if (canUseFunction) resolvedOrder.push('function')
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!isEnabled || !relevantFieldGroups.length || !resolvedOrder.length) return
|
|
36
67
|
|
|
37
68
|
const unsub = subscribe((blurredField) => {
|
|
38
69
|
const fieldClone: string = Array.isArray(blurredField) ? blurredField.join('.') : (blurredField as string)
|
|
@@ -51,45 +82,56 @@ export function useDuplicateOnBlur(
|
|
|
51
82
|
formRef.setFieldValue([FormPreservedItemKeys.DuplicateCheckPending], true)
|
|
52
83
|
|
|
53
84
|
// cancel previous request
|
|
54
|
-
if (abortRef.current)
|
|
55
|
-
|
|
85
|
+
if (abortRef.current) {
|
|
86
|
+
abortRef.current.abort()
|
|
87
|
+
abortRef.current = null
|
|
88
|
+
}
|
|
56
89
|
|
|
57
90
|
const matchKeyValuePairs = {
|
|
58
91
|
DeletedDate: null,
|
|
59
92
|
...fieldGroup.reduce((acc, f) => ({ ...acc, [f]: formValues[f.replace('Data.', '')] }), {}),
|
|
60
93
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const duplicateRecords = shouldUseCustomFunction
|
|
64
|
-
? normalizeDuplicateRecords(
|
|
65
|
-
await onCustomFunctionCall?.({
|
|
66
|
-
fnName: functionName as string,
|
|
67
|
-
formData: { ...formValues },
|
|
68
|
-
}),
|
|
69
|
-
)
|
|
70
|
-
: normalizeDuplicateRecords(
|
|
71
|
-
(
|
|
72
|
-
await apiClient.post(
|
|
73
|
-
`/api/site/${formKey}/get`,
|
|
74
|
-
{
|
|
75
|
-
project: JSON.stringify({ _id: '$_id' }),
|
|
76
|
-
match: JSON.stringify(matchKeyValuePairs),
|
|
77
|
-
},
|
|
78
|
-
abortRef.current ? { signal: abortRef.current.signal } : undefined,
|
|
79
|
-
)
|
|
80
|
-
).data,
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
const filteredRecords = filterDuplicateRecords(duplicateRecords, formDataId)
|
|
84
|
-
const isRecordFound = filteredRecords.length > 0
|
|
85
|
-
|
|
86
|
-
const matchFilterKeysOnly = Object.keys(matchKeyValuePairs).join('::')
|
|
87
|
-
|
|
94
|
+
const matchFilterKeysOnly = Object.keys(matchKeyValuePairs).join('::')
|
|
95
|
+
const updateResult = (found: boolean, record?: unknown) => {
|
|
88
96
|
formRef.setFieldsValue({
|
|
89
|
-
[FormPreservedItemKeys.DuplicateDataFound]: { [matchFilterKeysOnly]:
|
|
97
|
+
[FormPreservedItemKeys.DuplicateDataFound]: { [matchFilterKeysOnly]: found },
|
|
90
98
|
})
|
|
99
|
+
onResult(found, record)
|
|
100
|
+
}
|
|
91
101
|
|
|
92
|
-
|
|
102
|
+
try {
|
|
103
|
+
for (const step of resolvedOrder) {
|
|
104
|
+
if (step === 'function') {
|
|
105
|
+
await onCustomFunctionCall?.({
|
|
106
|
+
fnName: functionName as string,
|
|
107
|
+
formData: { ...formValues },
|
|
108
|
+
formRef,
|
|
109
|
+
})
|
|
110
|
+
continue
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
abortRef.current = new AbortController()
|
|
114
|
+
const response = await apiClient.post(
|
|
115
|
+
`/api/site/${formKey}/get`,
|
|
116
|
+
{
|
|
117
|
+
project: JSON.stringify({ _id: '$_id' }),
|
|
118
|
+
match: JSON.stringify(matchKeyValuePairs),
|
|
119
|
+
},
|
|
120
|
+
{ signal: abortRef.current.signal },
|
|
121
|
+
)
|
|
122
|
+
abortRef.current = null
|
|
123
|
+
const duplicateRecords = normalizeDuplicateRecords(response.data)
|
|
124
|
+
|
|
125
|
+
const filteredRecords = filterDuplicateRecords(duplicateRecords, formDataId)
|
|
126
|
+
if (filteredRecords.length) {
|
|
127
|
+
const payload = filteredRecords[0]
|
|
128
|
+
updateResult(true, payload)
|
|
129
|
+
formRef.setFieldValue([FormPreservedItemKeys.DuplicateCheckPending], false)
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
updateResult(false)
|
|
93
135
|
} catch (e: any) {
|
|
94
136
|
if (e?.name === 'AbortError') return
|
|
95
137
|
}
|
|
@@ -103,7 +145,18 @@ export function useDuplicateOnBlur(
|
|
|
103
145
|
if (timerRef.current) clearTimeout(timerRef.current)
|
|
104
146
|
if (abortRef.current) abortRef.current.abort()
|
|
105
147
|
}
|
|
106
|
-
}, [
|
|
148
|
+
}, [
|
|
149
|
+
subscribe,
|
|
150
|
+
relevantFieldGroups,
|
|
151
|
+
formKey,
|
|
152
|
+
formDataId,
|
|
153
|
+
formRef,
|
|
154
|
+
debounceMs,
|
|
155
|
+
functionName,
|
|
156
|
+
onCustomFunctionCall,
|
|
157
|
+
isEnabled,
|
|
158
|
+
checkOrder,
|
|
159
|
+
])
|
|
107
160
|
}
|
|
108
161
|
|
|
109
162
|
const normalizeDuplicateRecords = (payload: any): any[] => {
|
|
@@ -128,4 +181,5 @@ type CustomFunctionCall = (params: {
|
|
|
128
181
|
fnName: string
|
|
129
182
|
messages?: { success?: string; error?: string }
|
|
130
183
|
formData?: { [key: string]: any }
|
|
184
|
+
formRef?: FormInstance
|
|
131
185
|
}) => Promise<any> | any
|
|
@@ -1,125 +1,100 @@
|
|
|
1
|
-
import { Divider, FormInstance, Modal } from 'antd'
|
|
2
|
-
import { useMemo } from 'react'
|
|
3
|
-
import { useTranslation } from '../custom-hooks'
|
|
4
|
-
import { Button_FillerPortal } from '../button'
|
|
5
|
-
import { FormPreservedItemKeys, TranslationTextSubTypeEnum, TranslationTextTypeEnum } from '../../../enums'
|
|
6
|
-
import { FaExclamationTriangle } from 'react-icons/fa'
|
|
7
|
-
import { useNavigate } from 'react-router-dom'
|
|
8
|
-
import { DUPLICATE_CHECK_TRANSLATION_KEY } from '../../../constants'
|
|
9
|
-
|
|
10
|
-
export default function DuplicateWarningModal({
|
|
11
|
-
formRef,
|
|
12
|
-
formId,
|
|
13
|
-
duplicateRecord,
|
|
14
|
-
closeModal,
|
|
15
|
-
}: IDuplicateWarningModal) {
|
|
16
|
-
const navigate = useNavigate()
|
|
17
|
-
const { t } = useTranslation(formId)
|
|
18
|
-
|
|
19
|
-
const [title, primaryMessage, secondaryMessage, okText, cancelText] = useMemo(
|
|
20
|
-
() =>
|
|
21
|
-
t([
|
|
22
|
-
{
|
|
23
|
-
key: DUPLICATE_CHECK_TRANSLATION_KEY,
|
|
24
|
-
type: TranslationTextTypeEnum.Label,
|
|
25
|
-
subType: TranslationTextSubTypeEnum.ConfirmationTitle,
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
key: DUPLICATE_CHECK_TRANSLATION_KEY,
|
|
29
|
-
type: TranslationTextTypeEnum.Label,
|
|
30
|
-
subType: TranslationTextSubTypeEnum.ConfirmationMsg,
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
key: DUPLICATE_CHECK_TRANSLATION_KEY,
|
|
34
|
-
type: TranslationTextTypeEnum.Description,
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
key: DUPLICATE_CHECK_TRANSLATION_KEY,
|
|
38
|
-
type: TranslationTextTypeEnum.Label,
|
|
39
|
-
subType: TranslationTextSubTypeEnum.ConfirmationOk,
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
key: DUPLICATE_CHECK_TRANSLATION_KEY,
|
|
43
|
-
type: TranslationTextTypeEnum.Label,
|
|
44
|
-
subType: TranslationTextSubTypeEnum.ConfirmationCancel,
|
|
45
|
-
},
|
|
46
|
-
]),
|
|
47
|
-
[t],
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
<div className="
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
<div className="text-gray-500 text-[15px] text-center">
|
|
102
|
-
{secondaryMessage || 'Duplicate entries are not allowed in the system.'}
|
|
103
|
-
</div>
|
|
104
|
-
)}
|
|
105
|
-
</div>
|
|
106
|
-
{fieldLabels.length > 0 && (
|
|
107
|
-
<>
|
|
108
|
-
<Divider />
|
|
109
|
-
<div className="bg-background w-full rounded-md p-2 flex flex-col gap-1">
|
|
110
|
-
<span className="font-bold text-primary">Duplicate data found on the following field(s):</span>
|
|
111
|
-
<div className="flex gap-2">{fieldLabels.join(', ')}</div>
|
|
112
|
-
{typeof duplicateRecord === 'object' && <pre>{JSON.stringify(duplicateRecord, null, 2)}</pre>}
|
|
113
|
-
</div>
|
|
114
|
-
</>
|
|
115
|
-
)}
|
|
116
|
-
</Modal>
|
|
117
|
-
)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
interface IDuplicateWarningModal {
|
|
121
|
-
formRef?: FormInstance
|
|
122
|
-
formId?: number
|
|
123
|
-
duplicateRecord?: unknown
|
|
124
|
-
closeModal: () => void
|
|
125
|
-
}
|
|
1
|
+
import { Divider, FormInstance, Modal } from 'antd'
|
|
2
|
+
import { useMemo } from 'react'
|
|
3
|
+
import { useTranslation } from '../custom-hooks'
|
|
4
|
+
import { Button_FillerPortal } from '../button'
|
|
5
|
+
import { FormPreservedItemKeys, TranslationTextSubTypeEnum, TranslationTextTypeEnum } from '../../../enums'
|
|
6
|
+
import { FaExclamationTriangle } from 'react-icons/fa'
|
|
7
|
+
import { useNavigate } from 'react-router-dom'
|
|
8
|
+
import { DUPLICATE_CHECK_TRANSLATION_KEY } from '../../../constants'
|
|
9
|
+
|
|
10
|
+
export default function DuplicateWarningModal({
|
|
11
|
+
formRef,
|
|
12
|
+
formId,
|
|
13
|
+
duplicateRecord,
|
|
14
|
+
closeModal,
|
|
15
|
+
}: IDuplicateWarningModal) {
|
|
16
|
+
const navigate = useNavigate()
|
|
17
|
+
const { t } = useTranslation(formId)
|
|
18
|
+
|
|
19
|
+
const [title, primaryMessage, secondaryMessage, okText, cancelText] = useMemo(
|
|
20
|
+
() =>
|
|
21
|
+
t([
|
|
22
|
+
{
|
|
23
|
+
key: DUPLICATE_CHECK_TRANSLATION_KEY,
|
|
24
|
+
type: TranslationTextTypeEnum.Label,
|
|
25
|
+
subType: TranslationTextSubTypeEnum.ConfirmationTitle,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
key: DUPLICATE_CHECK_TRANSLATION_KEY,
|
|
29
|
+
type: TranslationTextTypeEnum.Label,
|
|
30
|
+
subType: TranslationTextSubTypeEnum.ConfirmationMsg,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
key: DUPLICATE_CHECK_TRANSLATION_KEY,
|
|
34
|
+
type: TranslationTextTypeEnum.Description,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
key: DUPLICATE_CHECK_TRANSLATION_KEY,
|
|
38
|
+
type: TranslationTextTypeEnum.Label,
|
|
39
|
+
subType: TranslationTextSubTypeEnum.ConfirmationOk,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
key: DUPLICATE_CHECK_TRANSLATION_KEY,
|
|
43
|
+
type: TranslationTextTypeEnum.Label,
|
|
44
|
+
subType: TranslationTextSubTypeEnum.ConfirmationCancel,
|
|
45
|
+
},
|
|
46
|
+
]),
|
|
47
|
+
[t],
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<Modal
|
|
52
|
+
open
|
|
53
|
+
title={
|
|
54
|
+
<div className="flex items-center gap-2 text-warning font-normal">
|
|
55
|
+
<FaExclamationTriangle className="text-warning" />
|
|
56
|
+
{title || 'Duplicate Entry Found'}
|
|
57
|
+
</div>
|
|
58
|
+
}
|
|
59
|
+
width={600}
|
|
60
|
+
maskClosable={false}
|
|
61
|
+
closable={false}
|
|
62
|
+
footer={
|
|
63
|
+
<div className="grid grid-cols-[max-content_max-content] gap-2 justify-between">
|
|
64
|
+
<Button_FillerPortal
|
|
65
|
+
danger
|
|
66
|
+
outline
|
|
67
|
+
onClick={() => {
|
|
68
|
+
navigate(-1)
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
{cancelText || 'Cancel and Discard Entry'}
|
|
72
|
+
</Button_FillerPortal>
|
|
73
|
+
<Button_FillerPortal primary outline onClick={closeModal}>
|
|
74
|
+
{okText || 'Continue Editing Entry'}
|
|
75
|
+
</Button_FillerPortal>
|
|
76
|
+
</div>
|
|
77
|
+
}
|
|
78
|
+
>
|
|
79
|
+
<div className="flex flex-col items-center gap-2">
|
|
80
|
+
<div className="text-16 text-center">
|
|
81
|
+
{primaryMessage || "We've found an existing record with the same details."}
|
|
82
|
+
</div>
|
|
83
|
+
{secondaryMessage && (
|
|
84
|
+
<div className="text-gray-500 text-[15px] text-center">
|
|
85
|
+
{secondaryMessage || 'Duplicate entries are not allowed in the system.'}
|
|
86
|
+
</div>
|
|
87
|
+
)}
|
|
88
|
+
</div>
|
|
89
|
+
<Divider />
|
|
90
|
+
<div className="bg-background w-full rounded-md p-2 text-center">Please review and update the form data.</div>
|
|
91
|
+
</Modal>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
interface IDuplicateWarningModal {
|
|
96
|
+
formRef?: FormInstance
|
|
97
|
+
formId?: number
|
|
98
|
+
duplicateRecord?: unknown
|
|
99
|
+
closeModal: () => void
|
|
100
|
+
}
|
|
@@ -2,7 +2,7 @@ import { FormInstance } from 'antd'
|
|
|
2
2
|
import { useLazyModalOpener } from '../custom-hooks'
|
|
3
3
|
import { IDuplicateCheckConfig } from '../../../types'
|
|
4
4
|
import { useDuplicateOnBlur } from '../custom-hooks/use-duplicate-on-blur.hook'
|
|
5
|
-
import { lazy
|
|
5
|
+
import { lazy } from 'react'
|
|
6
6
|
|
|
7
7
|
const DuplicateWarningModal = lazy(() => import('./duplicate-warning.modal'))
|
|
8
8
|
|
|
@@ -15,7 +15,6 @@ export default function DuplicateEntryChecker({
|
|
|
15
15
|
onCustomFunctionCall,
|
|
16
16
|
}: IDuplicateEntryChecker) {
|
|
17
17
|
const { isModalOpen, openModal, closeModal } = useLazyModalOpener()
|
|
18
|
-
const duplicateDataRef = useRef<unknown>()
|
|
19
18
|
|
|
20
19
|
useDuplicateOnBlur(
|
|
21
20
|
{
|
|
@@ -24,26 +23,19 @@ export default function DuplicateEntryChecker({
|
|
|
24
23
|
formDataId,
|
|
25
24
|
groups: duplicateCheckConfig?.groups,
|
|
26
25
|
functionName: duplicateCheckConfig?.functionName,
|
|
26
|
+
isEnabled: duplicateCheckConfig?.isEnabled,
|
|
27
|
+
checkOrder: duplicateCheckConfig?.checkOrder,
|
|
27
28
|
onCustomFunctionCall,
|
|
28
29
|
},
|
|
29
|
-
(isDuplicateFound
|
|
30
|
-
if (isDuplicateFound)
|
|
31
|
-
|
|
32
|
-
openModal()
|
|
33
|
-
} else closeModal()
|
|
30
|
+
(isDuplicateFound) => {
|
|
31
|
+
if (isDuplicateFound) openModal()
|
|
32
|
+
else closeModal()
|
|
34
33
|
},
|
|
35
34
|
)
|
|
36
35
|
|
|
37
|
-
if (!isModalOpen) return
|
|
36
|
+
if (!isModalOpen) return null
|
|
38
37
|
|
|
39
|
-
return
|
|
40
|
-
<DuplicateWarningModal
|
|
41
|
-
formRef={formRef}
|
|
42
|
-
formId={formId}
|
|
43
|
-
closeModal={closeModal}
|
|
44
|
-
duplicateRecord={duplicateDataRef.current}
|
|
45
|
-
/>
|
|
46
|
-
)
|
|
38
|
+
return <DuplicateWarningModal formRef={formRef} formId={formId} closeModal={closeModal} />
|
|
47
39
|
}
|
|
48
40
|
|
|
49
41
|
interface IDuplicateEntryChecker {
|
|
@@ -45,18 +45,18 @@ export default function FormDataDetailsComponent(props: IFormDataDetailsComponen
|
|
|
45
45
|
)
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
function FormDataDetailsComponentChild({
|
|
49
|
-
isPublic,
|
|
50
|
-
formId,
|
|
51
|
-
formKey,
|
|
52
|
-
formDataId,
|
|
53
|
-
formName,
|
|
54
|
-
baseServerUrl,
|
|
55
|
-
initialValues,
|
|
56
|
-
companyKey,
|
|
57
|
-
customComponents,
|
|
58
|
-
onCustomFunctionCall,
|
|
59
|
-
}: IFormDataDetailsComponent) {
|
|
48
|
+
function FormDataDetailsComponentChild({
|
|
49
|
+
isPublic,
|
|
50
|
+
formId,
|
|
51
|
+
formKey,
|
|
52
|
+
formDataId,
|
|
53
|
+
formName,
|
|
54
|
+
baseServerUrl,
|
|
55
|
+
initialValues,
|
|
56
|
+
companyKey,
|
|
57
|
+
customComponents,
|
|
58
|
+
onCustomFunctionCall,
|
|
59
|
+
}: IFormDataDetailsComponent) {
|
|
60
60
|
const { pushCrumb, breadcrumbs } = useBreadcrumb()
|
|
61
61
|
|
|
62
62
|
const location = useLocation()
|
|
@@ -211,6 +211,8 @@ function FormDataDetailsComponentChild({
|
|
|
211
211
|
|
|
212
212
|
useEffect(() => {
|
|
213
213
|
if (!cachedConfig) return
|
|
214
|
+
// const BaskhuuAjiltnuudFormId = 22
|
|
215
|
+
// formDataRef.setFieldValue(FormPreservedItemKeys.IsUserForm, cachedConfig.id === BaskhuuAjiltnuudFormId)
|
|
214
216
|
|
|
215
217
|
formDataRef.setFieldValue(FormPreservedItemKeys.IsUserForm, false)
|
|
216
218
|
}, [cachedConfig])
|
|
@@ -242,20 +244,20 @@ function FormDataDetailsComponentChild({
|
|
|
242
244
|
return deviceLayout
|
|
243
245
|
}, [cachedConfig?.detailsConfig, currentBreakpoint])
|
|
244
246
|
|
|
245
|
-
if (isConfigLoading || !cachedConfig) return <FormDataListSkeleton_Details />
|
|
247
|
+
if (isConfigLoading || !cachedConfig) return <FormDataListSkeleton_Details />
|
|
246
248
|
|
|
247
249
|
if (isNotFound) return <NotFound />
|
|
248
250
|
|
|
249
251
|
return (
|
|
250
252
|
<>
|
|
251
|
-
<DuplicateEntryChecker
|
|
252
|
-
formRef={formDataRef}
|
|
253
|
-
formId={formId}
|
|
254
|
-
formKey={formKey}
|
|
255
|
-
formDataId={formDataId}
|
|
256
|
-
duplicateCheckConfig={cachedConfig.detailsConfig.duplicateCheckConfig}
|
|
257
|
-
onCustomFunctionCall={onCustomFunctionCall}
|
|
258
|
-
/>
|
|
253
|
+
<DuplicateEntryChecker
|
|
254
|
+
formRef={formDataRef}
|
|
255
|
+
formId={formId}
|
|
256
|
+
formKey={formKey}
|
|
257
|
+
formDataId={formDataId}
|
|
258
|
+
duplicateCheckConfig={cachedConfig.detailsConfig.duplicateCheckConfig}
|
|
259
|
+
onCustomFunctionCall={onCustomFunctionCall}
|
|
260
|
+
/>
|
|
259
261
|
<Form
|
|
260
262
|
layout="vertical"
|
|
261
263
|
name="dynamic_form_data_form"
|
|
@@ -302,15 +304,15 @@ function FormDataDetailsComponentChild({
|
|
|
302
304
|
)
|
|
303
305
|
}
|
|
304
306
|
|
|
305
|
-
type IFormDataDetailsComponent = {
|
|
306
|
-
baseServerUrl?: string
|
|
307
|
-
companyKey?: string
|
|
308
|
-
formDataId: string
|
|
309
|
-
formName?: string
|
|
310
|
-
initialValues?: Record<string, any>
|
|
311
|
-
} & (IDataDetailsPublicProps | IDataDetailsPrivateProps) &
|
|
312
|
-
ICustomFunctionCall &
|
|
313
|
-
ICustomComponents
|
|
307
|
+
type IFormDataDetailsComponent = {
|
|
308
|
+
baseServerUrl?: string
|
|
309
|
+
companyKey?: string
|
|
310
|
+
formDataId: string
|
|
311
|
+
formName?: string
|
|
312
|
+
initialValues?: Record<string, any>
|
|
313
|
+
} & (IDataDetailsPublicProps | IDataDetailsPrivateProps) &
|
|
314
|
+
ICustomFunctionCall &
|
|
315
|
+
ICustomComponents
|
|
314
316
|
|
|
315
317
|
interface IDataDetailsPublicProps {
|
|
316
318
|
isPublic: true
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { FormInstance } from 'antd'
|
|
2
|
+
import { useFindDynamiForm, useLazyModalOpener, useNotification } from '../../../../common/custom-hooks'
|
|
2
3
|
import { lazy, memo, useCallback, useMemo, useRef, useState } from 'react'
|
|
3
4
|
import { useFormPreservedItemValues } from '../../../../common/custom-hooks/use-preserved-form-items.hook'
|
|
4
5
|
import { useDuplicateDataAction } from './use-duplicate-data.hook'
|
|
@@ -518,6 +519,7 @@ export interface ICustomFunctionCall {
|
|
|
518
519
|
fnName: string
|
|
519
520
|
messages?: { success?: string; error?: string }
|
|
520
521
|
formData?: { [key: string]: any }
|
|
522
|
+
formRef?: FormInstance
|
|
521
523
|
}) => Promise<any> | any
|
|
522
524
|
}
|
|
523
525
|
export interface IOnSuccessFunctions {
|
package/src/components/form/layout-renderer/3-element/1-dynamic-button/use-save-data.hook.ts
CHANGED
|
@@ -22,7 +22,7 @@ export const useSaveExistingDataAction = ({
|
|
|
22
22
|
setDataLoadingType: (type: FormLoadingModalTypeEnum) => void
|
|
23
23
|
} & IOnSuccessFunctions &
|
|
24
24
|
IFormContext) => {
|
|
25
|
-
const { warning } = useNotification()
|
|
25
|
+
const { warning, destroy } = useNotification()
|
|
26
26
|
const { t } = useTranslation(formId)
|
|
27
27
|
|
|
28
28
|
const onSaveExistingData = useCallback(() => {
|
|
@@ -51,6 +51,7 @@ export const useSaveExistingDataAction = ({
|
|
|
51
51
|
) as string[])
|
|
52
52
|
: []
|
|
53
53
|
|
|
54
|
+
destroy()
|
|
54
55
|
warning({
|
|
55
56
|
message: 'Please fill out all the required fields!',
|
|
56
57
|
description: labels.length > 5 ? `${labels.length} required fields are missing.` : labels.join(', '),
|
package/src/components/form/layout-renderer/3-element/1-dynamic-button/use-send-notification.hook.ts
CHANGED
|
@@ -237,12 +237,10 @@ export const useSendNotificationAction = ({
|
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
if (Array.isArray(typeReqData.attachments)) {
|
|
240
|
-
console.log('typeReqData.attachments', typeReqData.attachments)
|
|
241
240
|
|
|
242
241
|
const blobsNotFound = await extractNotFoundBlobNames(
|
|
243
242
|
typeReqData.attachments.map((att: IEmail_Attachment) => att.blobName),
|
|
244
243
|
)
|
|
245
|
-
console.log('blobsNotFound', blobsNotFound)
|
|
246
244
|
typeReqData.attachments = [
|
|
247
245
|
...typeReqData.attachments.filter(
|
|
248
246
|
(att: IEmail_Attachment) => !blobsNotFound.includes(att.blobName),
|