form-craft-package 1.8.2-dev.1 → 1.8.2-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 +1 -1
- package/src/components/common/custom-hooks/index.ts +1 -0
- package/src/components/common/custom-hooks/use-login-handler.ts +3 -3
- package/src/components/common/custom-hooks/use-node-condition.hook/use-disabled-elements.hook.ts +62 -22
- package/src/components/common/custom-hooks/use-node-condition.hook/use-hidden-elements.hook.ts +54 -42
- package/src/components/common/custom-hooks/use-set-persistent-domain.hook.ts +20 -0
- package/src/components/companies/3-config-provider/index.tsx +27 -2
- package/src/components/form/2-details/index.tsx +14 -5
- package/src/components/form/layout-renderer/1-row/index.tsx +5 -1
- package/src/components/form/layout-renderer/1-row/repeatable-render.tsx +69 -28
- package/src/components/form/layout-renderer/3-element/10-currency.tsx +4 -2
- package/src/components/form/layout-renderer/3-element/11-breadcrumb.tsx +4 -2
- package/src/components/form/layout-renderer/3-element/12-picker-field.tsx +4 -7
- package/src/components/form/layout-renderer/3-element/2-field-element.tsx +203 -225
- package/src/components/form/layout-renderer/3-element/3-read-field-data.tsx +4 -6
- package/src/components/form/layout-renderer/3-element/4-rich-text-editor.tsx +4 -1
- package/src/components/form/layout-renderer/3-element/5-re-captcha.tsx +4 -7
- package/src/components/form/layout-renderer/3-element/6-signature.tsx +4 -2
- package/src/components/form/layout-renderer/3-element/7-file-upload.tsx +78 -26
- package/src/components/form/layout-renderer/3-element/8-fields-with-options.tsx +4 -2
- package/src/components/form/layout-renderer/3-element/9-form-data-render.tsx +4 -2
- package/src/components/form/layout-renderer/3-element/index.tsx +125 -86
- package/src/enums/form.enum.ts +4 -0
- package/src/enums/index.ts +1 -0
- package/src/functions/companies/index.tsx +12 -0
- package/src/functions/companies/use-company-config.tsx +14 -10
- package/src/functions/forms/data-render-functions.tsx +0 -1
- package/src/functions/forms/get-element-props.ts +2 -2
- package/src/functions/forms/index.ts +3 -1
- package/src/types/companies/site-layout/authenticated/index.tsx +5 -2
- package/src/types/forms/index.ts +9 -4
- package/src/types/forms/layout-elements/button.ts +1 -1
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { useReducer, useState } from 'react'
|
|
2
2
|
import { useNavigate } from 'react-router-dom'
|
|
3
3
|
import client, { auth } from '../../../api/client'
|
|
4
|
-
import { LOCAL_STORAGE_KEYS_ENUM } from '../../../enums'
|
|
5
4
|
import { cookieHandler } from '../../../functions/cookie-handler'
|
|
6
5
|
import { message } from 'antd'
|
|
6
|
+
import { getLocalStorageDomain } from '../../../functions'
|
|
7
7
|
export function useLoginHandler() {
|
|
8
8
|
const navigate = useNavigate()
|
|
9
|
-
const domain =
|
|
9
|
+
const domain = getLocalStorageDomain()
|
|
10
10
|
const [loading, updateLoading] = useReducer((currState: any, updated: any) => ({ ...currState, ...updated }), {
|
|
11
11
|
login: false,
|
|
12
12
|
})
|
|
@@ -27,7 +27,7 @@ export function useLoginHandler() {
|
|
|
27
27
|
const { authRes, initialPath } = await auth(
|
|
28
28
|
values.email,
|
|
29
29
|
values.password,
|
|
30
|
-
|
|
30
|
+
getLocalStorageDomain(),
|
|
31
31
|
values.type || 'password',
|
|
32
32
|
)
|
|
33
33
|
if (authRes.status === 200) {
|
package/src/components/common/custom-hooks/use-node-condition.hook/use-disabled-elements.hook.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { useEffect
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
2
|
import useGetCurrentBreakpoint from '../use-window-width.hook'
|
|
3
3
|
import { DeviceBreakpointEnum, FormElementConditionalKeyEnum } from '../../../../enums'
|
|
4
4
|
import { disabledStore } from './visibility-store'
|
|
5
5
|
import { isValidationsMet } from './visibility-utils'
|
|
6
|
+
import { FormInstance } from 'antd'
|
|
6
7
|
import {
|
|
7
8
|
IDndLayoutElement,
|
|
8
9
|
IDndLayoutRow,
|
|
@@ -12,16 +13,64 @@ import {
|
|
|
12
13
|
|
|
13
14
|
export function useSetDisabledElements(
|
|
14
15
|
layoutConfig?: IDndLayoutStructure_Responsive,
|
|
15
|
-
|
|
16
|
+
formDataRef?: FormInstance,
|
|
16
17
|
formDataId?: string,
|
|
17
18
|
): void {
|
|
18
19
|
const currentBreakpoint = useGetCurrentBreakpoint()
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
// during the initial renders, handle the initially disabled fields
|
|
23
|
+
if (!formDataRef) return
|
|
24
|
+
|
|
25
|
+
const allValues = formDataRef.getFieldsValue()
|
|
26
|
+
|
|
27
|
+
const layout: IDndLayoutRow[] =
|
|
28
|
+
layoutConfig?.layouts?.[currentBreakpoint] || layoutConfig?.layouts?.[DeviceBreakpointEnum.Default] || []
|
|
29
|
+
const elementsMap: Record<string, IDndLayoutElement> = layoutConfig?.elements || {}
|
|
30
|
+
const configsPerElement: Record<string, IFormLayoutElementConditions> = Object.values(elementsMap).reduce(
|
|
31
|
+
(acc, el) => {
|
|
32
|
+
const elConditions = el.conditions?.[FormElementConditionalKeyEnum.EnableIf]
|
|
33
|
+
if (elConditions && Array.isArray(elConditions) && elConditions.length > 0) acc[el.key] = el.conditions!
|
|
34
|
+
|
|
35
|
+
return acc
|
|
36
|
+
},
|
|
37
|
+
{} as Record<string, IFormLayoutElementConditions>,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
const allInputsLoaded =
|
|
41
|
+
layout.length > 0 &&
|
|
42
|
+
Object.keys(elementsMap).length > 0 &&
|
|
43
|
+
Object.keys(configsPerElement).length > 0 &&
|
|
44
|
+
Object.values(allValues).filter(Boolean).length > 0
|
|
45
|
+
|
|
46
|
+
if (!allInputsLoaded) return
|
|
47
|
+
|
|
48
|
+
handleDisabledSet(allValues, currentBreakpoint, layoutConfig, formDataId)
|
|
49
|
+
}, [formDataRef, layoutConfig, currentBreakpoint, formDataId])
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function handleDisabledSet(
|
|
53
|
+
allValues: Record<string, any>,
|
|
54
|
+
currentBreakpoint: DeviceBreakpointEnum,
|
|
55
|
+
layoutConfig?: IDndLayoutStructure_Responsive,
|
|
56
|
+
formDataId?: string,
|
|
57
|
+
) {
|
|
58
|
+
const disabledSet = computeDisabledSet(allValues, currentBreakpoint, layoutConfig, formDataId)
|
|
59
|
+
disabledStore.setIds([...disabledSet])
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function computeDisabledSet(
|
|
63
|
+
allValues: Record<string, any>,
|
|
64
|
+
currentBreakpoint: DeviceBreakpointEnum,
|
|
65
|
+
layoutConfig?: IDndLayoutStructure_Responsive,
|
|
66
|
+
formDataId?: string,
|
|
67
|
+
): Set<string> {
|
|
19
68
|
const layout: IDndLayoutRow[] =
|
|
20
69
|
layoutConfig?.layouts?.[currentBreakpoint] || layoutConfig?.layouts?.[DeviceBreakpointEnum.Default] || []
|
|
21
70
|
|
|
22
71
|
const elementsMap: Record<string, IDndLayoutElement> = layoutConfig?.elements || {}
|
|
23
|
-
const dataValues: { [key: string]: any } = formValues && typeof formValues === 'object' ? formValues : {}
|
|
24
72
|
|
|
73
|
+
// Pull out only those elements which have EnableIf conditions
|
|
25
74
|
const configsPerElement: Record<string, IFormLayoutElementConditions> = Object.values(elementsMap).reduce(
|
|
26
75
|
(acc, el) => {
|
|
27
76
|
const elConditions = el.conditions?.[FormElementConditionalKeyEnum.EnableIf]
|
|
@@ -36,29 +85,20 @@ export function useSetDisabledElements(
|
|
|
36
85
|
layout.length > 0 &&
|
|
37
86
|
Object.keys(elementsMap).length > 0 &&
|
|
38
87
|
Object.keys(configsPerElement).length > 0 &&
|
|
39
|
-
Object.values(
|
|
88
|
+
Object.values(allValues).length > 0 &&
|
|
40
89
|
!!formDataId
|
|
41
90
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const elementConfigs = configsPerElement[key]
|
|
48
|
-
const shouldEnable = isValidationsMet(FormElementConditionalKeyEnum.EnableIf, dataValues, elementConfigs, {
|
|
91
|
+
const disabled = new Set<string>()
|
|
92
|
+
if (allInputsLoaded) {
|
|
93
|
+
for (const el of Object.values(elementsMap)) {
|
|
94
|
+
const conds = configsPerElement[el.key]
|
|
95
|
+
const shouldEnable = isValidationsMet(FormElementConditionalKeyEnum.EnableIf, allValues, conds, {
|
|
49
96
|
currentBreakpoint,
|
|
50
97
|
formDataId,
|
|
51
98
|
})
|
|
99
|
+
if (!shouldEnable) disabled.add(el.key)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
52
102
|
|
|
53
|
-
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
return disabledSet
|
|
57
|
-
}, [elementsMap, dataValues, configsPerElement, currentBreakpoint, formDataId, allInputsLoaded])
|
|
58
|
-
|
|
59
|
-
const individuallyDisabled = computeIndividuallyDisabled()
|
|
60
|
-
|
|
61
|
-
useEffect(() => {
|
|
62
|
-
if (allInputsLoaded) disabledStore.setIds([...individuallyDisabled])
|
|
63
|
-
}, [allInputsLoaded, individuallyDisabled])
|
|
103
|
+
return disabled
|
|
64
104
|
}
|
package/src/components/common/custom-hooks/use-node-condition.hook/use-hidden-elements.hook.ts
CHANGED
|
@@ -1,16 +1,49 @@
|
|
|
1
|
-
import { useEffect, useMemo, useCallback } from 'react'
|
|
2
|
-
import useGetCurrentBreakpoint from '../use-window-width.hook'
|
|
3
1
|
import { DeviceBreakpointEnum, FormElementConditionalKeyEnum } from '../../../../enums'
|
|
4
|
-
import { hiddenStore } from './visibility-store'
|
|
5
2
|
import { isValidationsMet } from './visibility-utils'
|
|
6
|
-
import {
|
|
3
|
+
import { useEffect } from 'react'
|
|
4
|
+
import useGetCurrentBreakpoint from '../use-window-width.hook'
|
|
5
|
+
import { FormInstance } from 'antd'
|
|
6
|
+
import { hiddenStore } from './visibility-store'
|
|
7
|
+
import type {
|
|
7
8
|
IDndLayoutCol,
|
|
8
|
-
IDndLayoutElement,
|
|
9
9
|
IDndLayoutRow,
|
|
10
10
|
IDndLayoutStructure_Responsive,
|
|
11
11
|
IFormLayoutElementConditions,
|
|
12
12
|
} from '../../../../types'
|
|
13
13
|
|
|
14
|
+
export function useSetHiddenNodes(
|
|
15
|
+
layoutConfig?: IDndLayoutStructure_Responsive,
|
|
16
|
+
formDataRef?: FormInstance,
|
|
17
|
+
formDataId?: string,
|
|
18
|
+
): void {
|
|
19
|
+
const currentBreakpoint = useGetCurrentBreakpoint()
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
// during the initial renders, handle the initially hidden nodes
|
|
23
|
+
if (!formDataRef) return
|
|
24
|
+
|
|
25
|
+
const allValues = formDataRef.getFieldsValue() || {}
|
|
26
|
+
const layout =
|
|
27
|
+
layoutConfig?.layouts?.[currentBreakpoint] || layoutConfig?.layouts?.[DeviceBreakpointEnum.Default] || []
|
|
28
|
+
|
|
29
|
+
const allInputsLoaded = layout.length > 0 && Object.values(allValues).filter(Boolean).length > 0 && !!formDataId
|
|
30
|
+
|
|
31
|
+
if (!allInputsLoaded) return
|
|
32
|
+
|
|
33
|
+
handleHiddenSet(allValues, currentBreakpoint, layoutConfig, formDataId)
|
|
34
|
+
}, [formDataRef, layoutConfig, currentBreakpoint, formDataId])
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function handleHiddenSet(
|
|
38
|
+
allValues: Record<string, any>,
|
|
39
|
+
currentBreakpoint: DeviceBreakpointEnum,
|
|
40
|
+
layoutConfig?: IDndLayoutStructure_Responsive,
|
|
41
|
+
formDataId?: string,
|
|
42
|
+
) {
|
|
43
|
+
const hiddenIds = computeHiddenIds(allValues, currentBreakpoint, layoutConfig, formDataId)
|
|
44
|
+
hiddenStore.setIds(hiddenIds)
|
|
45
|
+
}
|
|
46
|
+
|
|
14
47
|
function computeHiddenIdsRecursive(layout: IDndLayoutRow[], individuallyHidden: Set<string>): string[] {
|
|
15
48
|
const hiddenCols = new Set<string>()
|
|
16
49
|
const hiddenRows = new Set<string>()
|
|
@@ -54,16 +87,15 @@ function computeHiddenIdsRecursive(layout: IDndLayoutRow[], individuallyHidden:
|
|
|
54
87
|
return [...individuallyHidden, ...Array.from(hiddenCols), ...Array.from(hiddenRows)]
|
|
55
88
|
}
|
|
56
89
|
|
|
57
|
-
|
|
90
|
+
function computeHiddenIds(
|
|
91
|
+
allValues: Record<string, any>,
|
|
92
|
+
currentBreakpoint: DeviceBreakpointEnum,
|
|
58
93
|
layoutConfig?: IDndLayoutStructure_Responsive,
|
|
59
|
-
formValues?: { [key: string]: any },
|
|
60
94
|
formDataId?: string,
|
|
61
|
-
):
|
|
62
|
-
const
|
|
63
|
-
const layout: IDndLayoutRow[] =
|
|
95
|
+
): string[] {
|
|
96
|
+
const layout =
|
|
64
97
|
layoutConfig?.layouts?.[currentBreakpoint] || layoutConfig?.layouts?.[DeviceBreakpointEnum.Default] || []
|
|
65
|
-
const elementsMap
|
|
66
|
-
const dataValues: { [key: string]: any } = formValues && typeof formValues === 'object' ? formValues : {}
|
|
98
|
+
const elementsMap = layoutConfig?.elements || {}
|
|
67
99
|
const configsPerElement: Record<string, IFormLayoutElementConditions> = Object.values(elementsMap).reduce(
|
|
68
100
|
(curr, el) => {
|
|
69
101
|
const elConditions = el.conditions?.[FormElementConditionalKeyEnum.ShowIf]
|
|
@@ -72,40 +104,20 @@ export function useSetHiddenNodes(
|
|
|
72
104
|
|
|
73
105
|
return curr
|
|
74
106
|
},
|
|
75
|
-
{},
|
|
107
|
+
{} as any,
|
|
76
108
|
)
|
|
77
109
|
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
Object.keys(configsPerElement).length > 0 &&
|
|
82
|
-
!!formDataId
|
|
83
|
-
|
|
84
|
-
const computeIndividuallyHidden = useCallback((): Set<string> => {
|
|
85
|
-
if (!allInputsLoaded) return new Set()
|
|
110
|
+
const individuallyHidden = new Set<string>()
|
|
111
|
+
for (const el of Object.values(elementsMap)) {
|
|
112
|
+
const elementConfigs = configsPerElement[el.key]
|
|
86
113
|
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const elementConfigs = configsPerElement[key]
|
|
91
|
-
|
|
92
|
-
const shouldShow = isValidationsMet(FormElementConditionalKeyEnum.ShowIf, dataValues, elementConfigs, {
|
|
93
|
-
currentBreakpoint,
|
|
94
|
-
formDataId,
|
|
95
|
-
})
|
|
96
|
-
if (!shouldShow) hiddenSet.add(key)
|
|
114
|
+
const shouldShow = isValidationsMet(FormElementConditionalKeyEnum.ShowIf, allValues, elementConfigs, {
|
|
115
|
+
currentBreakpoint,
|
|
116
|
+
formDataId,
|
|
97
117
|
})
|
|
98
118
|
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const allHiddenArray = useMemo(() => {
|
|
103
|
-
const individuallyHidden = computeIndividuallyHidden()
|
|
104
|
-
|
|
105
|
-
return computeHiddenIdsRecursive(layout, individuallyHidden)
|
|
106
|
-
}, [layout, computeIndividuallyHidden])
|
|
119
|
+
if (!shouldShow) individuallyHidden.add(el.key)
|
|
120
|
+
}
|
|
107
121
|
|
|
108
|
-
|
|
109
|
-
if (allInputsLoaded) hiddenStore.setIds(allHiddenArray)
|
|
110
|
-
}, [allHiddenArray, allInputsLoaded])
|
|
122
|
+
return computeHiddenIdsRecursive(layout, individuallyHidden)
|
|
111
123
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useEffect } from 'react'
|
|
2
|
+
import { useLocation } from 'react-router-dom'
|
|
3
|
+
import { LOCAL_STORAGE_KEYS_ENUM } from '../../../enums'
|
|
4
|
+
|
|
5
|
+
export const useSetPeristentDomain = (domain: string) => {
|
|
6
|
+
const location = useLocation()
|
|
7
|
+
const isLogin = location.pathname === '/login'
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (!isLogin) return
|
|
11
|
+
|
|
12
|
+
if (typeof window === 'undefined') return
|
|
13
|
+
|
|
14
|
+
const current = window.localStorage.getItem(LOCAL_STORAGE_KEYS_ENUM.PersistDomain)
|
|
15
|
+
if (current !== domain) {
|
|
16
|
+
window.localStorage.setItem(LOCAL_STORAGE_KEYS_ENUM.PersistDomain, domain)
|
|
17
|
+
console.info(`[useSetCompanyDomain] "${LOCAL_STORAGE_KEYS_ENUM.PersistDomain}" set to "${domain}"`)
|
|
18
|
+
}
|
|
19
|
+
}, [isLogin])
|
|
20
|
+
}
|
|
@@ -3,14 +3,39 @@ import { ConfigProvider } from 'antd'
|
|
|
3
3
|
import { ConfigContext } from '../context'
|
|
4
4
|
import useSiteMetadata from '../../common/custom-hooks/use-site-meta-data'
|
|
5
5
|
import { ReactNode } from 'react'
|
|
6
|
+
import { Button_FillerPortal } from '../../common/button'
|
|
7
|
+
import { LOCAL_STORAGE_KEYS_ENUM } from '../../../enums'
|
|
8
|
+
import { useLocation, useNavigate } from 'react-router-dom'
|
|
6
9
|
|
|
7
10
|
export function ConfigProviderLayout({ children }: { children: ReactNode }): JSX.Element {
|
|
8
|
-
const
|
|
11
|
+
const navigate = useNavigate()
|
|
12
|
+
const location = useLocation()
|
|
13
|
+
const { config, theme, canSwitchDomain } = useCompanyConfig()
|
|
9
14
|
useSiteMetadata(config?.siteIdentity)
|
|
10
15
|
|
|
16
|
+
const showSwitchCompany =
|
|
17
|
+
canSwitchDomain &&
|
|
18
|
+
!localStorage.getItem(LOCAL_STORAGE_KEYS_ENUM.PersistDomain) &&
|
|
19
|
+
location.pathname.startsWith('/login')
|
|
20
|
+
|
|
11
21
|
return (
|
|
12
22
|
<ConfigContext.Provider value={{ config }}>
|
|
13
|
-
<ConfigProvider theme={theme}>
|
|
23
|
+
<ConfigProvider theme={theme}>
|
|
24
|
+
{showSwitchCompany && (
|
|
25
|
+
<div className="absolute top-2 right-2 z-20">
|
|
26
|
+
<Button_FillerPortal
|
|
27
|
+
outline
|
|
28
|
+
onClick={() => {
|
|
29
|
+
localStorage.removeItem(LOCAL_STORAGE_KEYS_ENUM.Domain)
|
|
30
|
+
navigate(0)
|
|
31
|
+
}}
|
|
32
|
+
>
|
|
33
|
+
Switch Project
|
|
34
|
+
</Button_FillerPortal>
|
|
35
|
+
</div>
|
|
36
|
+
)}
|
|
37
|
+
{children}
|
|
38
|
+
</ConfigProvider>
|
|
14
39
|
</ConfigContext.Provider>
|
|
15
40
|
)
|
|
16
41
|
}
|
|
@@ -12,8 +12,14 @@ import { useManyToManyConnector } from '../../common/custom-hooks/use-many-to-ma
|
|
|
12
12
|
import { PageViewTypEnum, DeviceBreakpointEnum, FormPreservedItemKeys, LOCAL_STORAGE_KEYS_ENUM } from '../../../enums'
|
|
13
13
|
import { UserAuth } from '../../../api/user'
|
|
14
14
|
import { useCacheFormLayoutConfig } from '../../common/custom-hooks/use-cache-form-layout-config.hook'
|
|
15
|
-
import {
|
|
16
|
-
|
|
15
|
+
import {
|
|
16
|
+
handleHiddenSet,
|
|
17
|
+
useSetHiddenNodes,
|
|
18
|
+
} from '../../common/custom-hooks/use-node-condition.hook/use-hidden-elements.hook'
|
|
19
|
+
import {
|
|
20
|
+
handleDisabledSet,
|
|
21
|
+
useSetDisabledElements,
|
|
22
|
+
} from '../../common/custom-hooks/use-node-condition.hook/use-disabled-elements.hook'
|
|
17
23
|
import { ELEMENTS_DEFAULT_CLASS } from '../../../constants'
|
|
18
24
|
import {
|
|
19
25
|
DynamicFormButtonRender,
|
|
@@ -50,10 +56,9 @@ export default function FormDataDetailsComponent({
|
|
|
50
56
|
const currentBreakpoint = useGetCurrentBreakpoint()
|
|
51
57
|
|
|
52
58
|
const { cachedConfig, isConfigLoading } = useCacheFormLayoutConfig(formId, formKey)
|
|
53
|
-
const detailsData = Form.useWatch([], formDataRef)
|
|
54
59
|
|
|
55
|
-
useSetHiddenNodes(cachedConfig?.detailsConfig,
|
|
56
|
-
useSetDisabledElements(cachedConfig?.detailsConfig,
|
|
60
|
+
useSetHiddenNodes(cachedConfig?.detailsConfig, formDataRef, formDataId)
|
|
61
|
+
useSetDisabledElements(cachedConfig?.detailsConfig, formDataRef, formDataId)
|
|
57
62
|
|
|
58
63
|
useEffect(() => {
|
|
59
64
|
// for public forms, setting the details form into localStorage, so that buttons work correctly
|
|
@@ -176,6 +181,10 @@ export default function FormDataDetailsComponent({
|
|
|
176
181
|
name="dynamic_form_data_form"
|
|
177
182
|
form={formDataRef}
|
|
178
183
|
className={ELEMENTS_DEFAULT_CLASS.DataDetailsForm}
|
|
184
|
+
onValuesChange={(_changed, allValues) => {
|
|
185
|
+
handleDisabledSet(allValues, currentBreakpoint, cachedConfig?.detailsConfig, formDataId)
|
|
186
|
+
handleHiddenSet(allValues, currentBreakpoint, cachedConfig?.detailsConfig, formDataId)
|
|
187
|
+
}}
|
|
179
188
|
>
|
|
180
189
|
{layout.map((row, rowIdx) => (
|
|
181
190
|
<LayoutRendererRow
|
|
@@ -28,7 +28,11 @@ export const LayoutRendererRow = memo(
|
|
|
28
28
|
className={ELEMENTS_DEFAULT_CLASS.LayoutRowContainer}
|
|
29
29
|
>
|
|
30
30
|
<LayoutRowConditionalHeaderRenderer header={rowData.props?.header}>
|
|
31
|
-
<LayoutRowRepeatableRenderer
|
|
31
|
+
<LayoutRowRepeatableRenderer
|
|
32
|
+
basePath={basePath}
|
|
33
|
+
formRef={formContext.formRef}
|
|
34
|
+
repeatingSection={rowData.props?.repeatingSection}
|
|
35
|
+
>
|
|
32
36
|
{(formListItemProps) => {
|
|
33
37
|
const style: { [key: string]: any } = { ...styleConfig, ...getGridContainerStyle(rowData.display) }
|
|
34
38
|
const hiddenColsIndices = rowData.children.reduce(
|
|
@@ -1,49 +1,90 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Form } from 'antd'
|
|
1
|
+
import { IButtonPropsBase, IRepeatingSectionConfig } from '../../../../types'
|
|
2
|
+
import { Form, FormInstance, Tabs } from 'antd'
|
|
3
3
|
import { Button_FillerPortal } from '../../../common/button'
|
|
4
4
|
import { FaTimes } from 'react-icons/fa'
|
|
5
5
|
import { FaPlus } from 'react-icons/fa6'
|
|
6
6
|
import { getButtonRenderProps } from '../../../../functions/forms/get-element-props'
|
|
7
|
+
import { useNotification } from '../../../common/custom-hooks'
|
|
8
|
+
import { RepeatingSectionTabTitleTypeEnum } from '../../../../enums'
|
|
7
9
|
|
|
8
10
|
/** This component return its children as function to feed the children with dynamic base path */
|
|
9
11
|
export const LayoutRowRepeatableRenderer = ({
|
|
10
12
|
children,
|
|
13
|
+
formRef,
|
|
11
14
|
basePath,
|
|
12
15
|
repeatingSection,
|
|
13
16
|
}: {
|
|
14
17
|
children: (props?: { updatedBasePath: (string | number)[]; removeButton: JSX.Element }) => JSX.Element
|
|
18
|
+
formRef?: FormInstance
|
|
15
19
|
basePath: (string | number)[]
|
|
16
20
|
repeatingSection: IRepeatingSectionConfig | undefined
|
|
17
21
|
}) => {
|
|
22
|
+
const { confirmModal } = useNotification()
|
|
23
|
+
|
|
18
24
|
if (!!repeatingSection?.name) {
|
|
19
25
|
return (
|
|
20
26
|
<Form.List name={[...basePath, repeatingSection.name]} initialValue={[{}]}>
|
|
21
|
-
{(
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
27
|
+
{(repeatItems, { add, remove }) => (
|
|
28
|
+
<Tabs
|
|
29
|
+
size="small"
|
|
30
|
+
defaultActiveKey="0"
|
|
31
|
+
tabBarStyle={{ paddingLeft: 20 }}
|
|
32
|
+
more={{ trigger: 'hover' }}
|
|
33
|
+
tabBarExtraContent={{
|
|
34
|
+
right: (repeatingSection.max ?? 1000) > repeatItems.length && (
|
|
35
|
+
<Button_FillerPortal
|
|
36
|
+
{...getButtonRenderProps(repeatingSection.addButton ?? ({} as IButtonPropsBase))}
|
|
37
|
+
onClick={() => add()}
|
|
38
|
+
>
|
|
39
|
+
{repeatingSection.addButton?.label ?? <FaPlus className="text-primary" />}
|
|
40
|
+
</Button_FillerPortal>
|
|
41
|
+
),
|
|
42
|
+
}}
|
|
43
|
+
items={repeatItems.map(({ name: itemName }) => {
|
|
44
|
+
const defaultTitle = `Group ${itemName + 1}`
|
|
45
|
+
const tabTitle =
|
|
46
|
+
!repeatingSection?.titleField?.type || !repeatingSection.titleField.value
|
|
47
|
+
? defaultTitle
|
|
48
|
+
: repeatingSection.titleField.type === RepeatingSectionTabTitleTypeEnum.Field
|
|
49
|
+
? formRef?.getFieldValue([
|
|
50
|
+
...basePath,
|
|
51
|
+
repeatingSection.name,
|
|
52
|
+
itemName,
|
|
53
|
+
repeatingSection.titleField.value,
|
|
54
|
+
]) ?? defaultTitle
|
|
55
|
+
: `${repeatingSection.titleField.value} ${itemName + 1}`
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
key: String(itemName),
|
|
59
|
+
label: tabTitle,
|
|
60
|
+
children: (
|
|
61
|
+
<div className="w-full" key={itemName}>
|
|
62
|
+
{children({
|
|
63
|
+
updatedBasePath: [...basePath, repeatingSection.name, itemName],
|
|
64
|
+
removeButton:
|
|
65
|
+
(repeatingSection.min ?? 0) < repeatItems.length ? (
|
|
66
|
+
<div className="flex justify-end">
|
|
67
|
+
<Button_FillerPortal
|
|
68
|
+
{...getButtonRenderProps(repeatingSection.removeButton ?? ({} as IButtonPropsBase))}
|
|
69
|
+
onClick={() =>
|
|
70
|
+
confirmModal({
|
|
71
|
+
content: 'Are you sure to remove this item?',
|
|
72
|
+
onOk: () => remove(itemName),
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
>
|
|
76
|
+
{repeatingSection.removeButton?.label || <FaTimes className="text-danger" />}
|
|
77
|
+
</Button_FillerPortal>
|
|
78
|
+
</div>
|
|
79
|
+
) : (
|
|
80
|
+
<></>
|
|
81
|
+
),
|
|
82
|
+
})}
|
|
83
|
+
</div>
|
|
84
|
+
),
|
|
85
|
+
}
|
|
86
|
+
})}
|
|
87
|
+
/>
|
|
47
88
|
)}
|
|
48
89
|
</Form.List>
|
|
49
90
|
)
|
|
@@ -4,10 +4,10 @@ import { ICurrencyInputElement } from '../../../../types'
|
|
|
4
4
|
import { IElementBaseProps } from '.'
|
|
5
5
|
import { getElementGeneralizedProps } from '../../../../functions/forms/get-element-props'
|
|
6
6
|
import { Form } from 'antd'
|
|
7
|
-
import { useEffect, useMemo } from 'react'
|
|
7
|
+
import { memo, useEffect, useMemo } from 'react'
|
|
8
8
|
import { evaluateValue } from '../../../../functions/forms/evaluate-value'
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
function LayoutRenderer_CurrencyField({
|
|
11
11
|
formContext,
|
|
12
12
|
formItem,
|
|
13
13
|
elementData,
|
|
@@ -43,6 +43,8 @@ export default function LayoutRenderer_CurrencyField({
|
|
|
43
43
|
)
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
export default memo(LayoutRenderer_CurrencyField)
|
|
47
|
+
|
|
46
48
|
type ILayoutRenderer_CurrencyField = {
|
|
47
49
|
formContext: IFormContext
|
|
48
50
|
elementData: ICurrencyInputElement
|
|
@@ -2,12 +2,12 @@ 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
|
+
import React, { memo } from 'react'
|
|
6
6
|
import { PageViewTypEnum } from '../../../../enums'
|
|
7
7
|
import { IBreadcrumbElementProps } from '../../../../types'
|
|
8
8
|
import { ELEMENTS_DEFAULT_CLASS } from '../../../../constants'
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
function LayoutRenderer_Breadcrumb({ elementProps }: { elementProps: IBreadcrumbElementProps }) {
|
|
11
11
|
const navigate = useNavigate()
|
|
12
12
|
const { breadcrumbs, sliceAt } = useBreadcrumb()
|
|
13
13
|
|
|
@@ -39,3 +39,5 @@ export default function LayoutRenderer_Breadcrumb({ elementProps }: { elementPro
|
|
|
39
39
|
</div>
|
|
40
40
|
)
|
|
41
41
|
}
|
|
42
|
+
|
|
43
|
+
export default memo(LayoutRenderer_Breadcrumb)
|
|
@@ -4,17 +4,12 @@ import { IPickerElement } from '../../../../types'
|
|
|
4
4
|
import { IElementBaseProps } from '.'
|
|
5
5
|
import { getElementGeneralizedProps } from '../../../../functions/forms/get-element-props'
|
|
6
6
|
import { ElementTypeEnum } from '../../../../enums'
|
|
7
|
-
import { useMemo } from 'react'
|
|
7
|
+
import { memo, useMemo } from 'react'
|
|
8
8
|
import { findMaxAndMinValues } from '../../../../functions'
|
|
9
9
|
import { VALIDATION_CURRENT_DATE_IDENTIFIER } from '../../../../constants'
|
|
10
10
|
import dayjs from 'dayjs'
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
formContext,
|
|
14
|
-
formItem,
|
|
15
|
-
elementData,
|
|
16
|
-
isDisabled,
|
|
17
|
-
}: ILayoutRenderer_PickerField) {
|
|
12
|
+
function LayoutRenderer_PickerField({ formContext, formItem, elementData, isDisabled }: ILayoutRenderer_PickerField) {
|
|
18
13
|
const props = getElementGeneralizedProps(elementData.props)
|
|
19
14
|
|
|
20
15
|
const placeholder =
|
|
@@ -47,6 +42,8 @@ export default function LayoutRenderer_PickerField({
|
|
|
47
42
|
)
|
|
48
43
|
}
|
|
49
44
|
|
|
45
|
+
export default memo(LayoutRenderer_PickerField)
|
|
46
|
+
|
|
50
47
|
type ILayoutRenderer_PickerField = {
|
|
51
48
|
formContext: IFormContext
|
|
52
49
|
elementData: IPickerElement
|