form-craft-package 1.10.13-dev.2 → 1.10.13-dev.4
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/use-find-dynamic-form.hook.ts +10 -2
- package/src/components/form/1-list/table.tsx +9 -1
- package/src/components/form/2-details/index.tsx +6 -3
- package/src/components/form/layout-renderer/3-element/11-breadcrumb/index.tsx +131 -126
- package/src/components/form/layout-renderer/3-element/3-read-field-data.tsx +35 -7
- package/src/enums/form.enum.ts +3 -1
- package/src/functions/forms/data-render-functions.tsx +3 -2
- package/src/functions/forms/get-data-list-option-value.ts +12 -3
- package/src/functions/forms/index.ts +16 -9
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState, useEffect, useCallback } from 'react'
|
|
1
|
+
import { useState, useEffect, useCallback, useRef, useMemo } from 'react'
|
|
2
2
|
import { useParams } from 'react-router-dom'
|
|
3
3
|
import { IDynamicForm } from '../../../types'
|
|
4
4
|
import { LOCAL_STORAGE_KEYS_ENUM } from '../../../enums'
|
|
@@ -6,6 +6,7 @@ import { LOCAL_STORAGE_KEYS_ENUM } from '../../../enums'
|
|
|
6
6
|
export const useFindDynamiForm = () => {
|
|
7
7
|
const { formName: formSlug } = useParams<{ formName: string }>()
|
|
8
8
|
const [foundItem, setFoundItem] = useState<IDynamicForm | null | undefined>(undefined)
|
|
9
|
+
const lastResolvedRef = useRef<{ slug?: string; id?: number | null }>({})
|
|
9
10
|
|
|
10
11
|
useEffect(() => {
|
|
11
12
|
if (!formSlug) return
|
|
@@ -16,8 +17,15 @@ export const useFindDynamiForm = () => {
|
|
|
16
17
|
const list: IDynamicForm[] = JSON.parse(stored)
|
|
17
18
|
let match = list.find((entry) => entry.slug === formSlug)
|
|
18
19
|
if (!match) match = list.find((entry) => entry.name.split(' ').join('-').toLowerCase() === formSlug)
|
|
20
|
+
|
|
21
|
+
const nextId = match?.id ?? null
|
|
22
|
+
if (lastResolvedRef.current.slug === formSlug && lastResolvedRef.current.id === nextId) return
|
|
23
|
+
lastResolvedRef.current = { slug: formSlug, id: nextId }
|
|
24
|
+
|
|
19
25
|
setFoundItem(match ?? null)
|
|
20
26
|
} else {
|
|
27
|
+
if (lastResolvedRef.current.slug === formSlug && lastResolvedRef.current.id === null) return
|
|
28
|
+
lastResolvedRef.current = { slug: formSlug, id: null }
|
|
21
29
|
setFoundItem(null)
|
|
22
30
|
}
|
|
23
31
|
} catch (err) {
|
|
@@ -41,5 +49,5 @@ export const useFindDynamiForm = () => {
|
|
|
41
49
|
}
|
|
42
50
|
}, [])
|
|
43
51
|
|
|
44
|
-
return { formInfo: foundItem, getFormById }
|
|
52
|
+
return useMemo(() => ({ formInfo: foundItem, getFormById }), [foundItem, getFormById])
|
|
45
53
|
}
|
|
@@ -83,7 +83,15 @@ export default function FormDataListTableComponent({
|
|
|
83
83
|
processOptions(layoutsConfigs.dataListConfig.columns).then((optionValues) => {
|
|
84
84
|
setTableColumns((curr) =>
|
|
85
85
|
curr.map((col) => {
|
|
86
|
-
if ('optionFieldPath' in col)
|
|
86
|
+
if ('optionFieldPath' in col)
|
|
87
|
+
return {
|
|
88
|
+
...col,
|
|
89
|
+
render: (optionKey) => {
|
|
90
|
+
if (Array.isArray(optionKey)) return optionKey.map((k) => optionValues[k]).join(', ') ?? '-'
|
|
91
|
+
|
|
92
|
+
return optionValues[optionKey] ?? '-'
|
|
93
|
+
},
|
|
94
|
+
}
|
|
87
95
|
return col
|
|
88
96
|
}),
|
|
89
97
|
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Form, Spin } from 'antd'
|
|
2
|
-
import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'
|
|
2
|
+
import { memo, useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'
|
|
3
3
|
import { IDndLayoutStructure_Responsive, IFormDataDetailsFetchConfig } from '../../../types'
|
|
4
4
|
import { LayoutRendererRow } from '../layout-renderer/1-row'
|
|
5
5
|
import FormDataListSkeleton_Details from '../../common/loading-skeletons/details'
|
|
@@ -49,13 +49,15 @@ import {
|
|
|
49
49
|
queryParamsToObject,
|
|
50
50
|
} from '../../../functions/forms'
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
const FormDataDetailsComponent = memo(function FormDataDetailsComponent(props: IFormDataDetailsComponent) {
|
|
53
53
|
return (
|
|
54
54
|
<BlurEventBusProvider>
|
|
55
55
|
<FormDataDetailsComponentChild {...props} />
|
|
56
56
|
</BlurEventBusProvider>
|
|
57
57
|
)
|
|
58
|
-
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
export default FormDataDetailsComponent
|
|
59
61
|
|
|
60
62
|
function FormDataDetailsComponentChild({
|
|
61
63
|
isPublic,
|
|
@@ -441,3 +443,4 @@ interface IDataDetailsPrivateProps {
|
|
|
441
443
|
formId: number
|
|
442
444
|
formKey?: string
|
|
443
445
|
}
|
|
446
|
+
|
|
@@ -1,127 +1,132 @@
|
|
|
1
|
-
import { IBreadcrumb, useBreadcrumb } from '../../../../common/custom-hooks/use-breadcrumb.hook'
|
|
2
|
-
import { Button_FillerPortal } from '../../../../common/button'
|
|
3
|
-
import { useNavigate } from 'react-router-dom'
|
|
4
|
-
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa6'
|
|
5
|
-
import React, { memo, useMemo, useSyncExternalStore } from 'react'
|
|
6
|
-
import { ELEMENTS_DEFAULT_CLASS } from '../../../../../constants'
|
|
7
|
-
import { IElementBaseProps } from '../'
|
|
8
|
-
import useGetCurrentBreakpoint from '../../../../common/custom-hooks/use-window-width.hook'
|
|
9
|
-
import { Select } from 'antd'
|
|
10
|
-
import { CountryEnum, DeviceBreakpointEnum, PageViewTypEnum } from '../../../../../enums'
|
|
11
|
-
import { useConfigContext } from '../../../../companies/context'
|
|
12
|
-
import { buildBreadcrumbTranslationKey } from '../../../../../functions'
|
|
13
|
-
import { translationStore } from '../../../../common/custom-hooks/use-translation.hook/store'
|
|
14
|
-
|
|
15
|
-
import './index.scss'
|
|
16
|
-
|
|
17
|
-
function LayoutRenderer_Breadcrumb(_: { formId?: number } & IElementBaseProps) {
|
|
18
|
-
const currentBreakpoint = useGetCurrentBreakpoint()
|
|
19
|
-
const navigate = useNavigate()
|
|
20
|
-
const { breadcrumbs, sliceCrumbAt } = useBreadcrumb()
|
|
21
|
-
const { config } = useConfigContext()
|
|
22
|
-
const { selectedLanguage } = useSyncExternalStore(
|
|
23
|
-
translationStore.subscribe.bind(translationStore),
|
|
24
|
-
translationStore.getSnapshot.bind(translationStore),
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
const translations = config?.translations
|
|
28
|
-
const fallbackTexts = { Detail: 'detail', List: 'list', New: 'New' }
|
|
29
|
-
const getTranslation = useMemo(
|
|
30
|
-
() => (key: string) => (selectedLanguage ? translations?.[key]?.[selectedLanguage as CountryEnum] ?? '' : ''),
|
|
31
|
-
[selectedLanguage, translations],
|
|
32
|
-
)
|
|
33
|
-
const getFormName = useMemo(
|
|
34
|
-
() =>
|
|
35
|
-
(bc: IBreadcrumb) =>
|
|
36
|
-
bc.formId
|
|
37
|
-
? getTranslation(buildBreadcrumbTranslationKey(bc.formId,
|
|
38
|
-
: bc.label,
|
|
39
|
-
[getTranslation],
|
|
40
|
-
)
|
|
41
|
-
const getBreadcrumbText = useMemo(
|
|
42
|
-
() =>
|
|
43
|
-
(
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
1
|
+
import { IBreadcrumb, useBreadcrumb } from '../../../../common/custom-hooks/use-breadcrumb.hook'
|
|
2
|
+
import { Button_FillerPortal } from '../../../../common/button'
|
|
3
|
+
import { useNavigate } from 'react-router-dom'
|
|
4
|
+
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa6'
|
|
5
|
+
import React, { memo, useMemo, useSyncExternalStore } from 'react'
|
|
6
|
+
import { ELEMENTS_DEFAULT_CLASS } from '../../../../../constants'
|
|
7
|
+
import { IElementBaseProps } from '../'
|
|
8
|
+
import useGetCurrentBreakpoint from '../../../../common/custom-hooks/use-window-width.hook'
|
|
9
|
+
import { Select } from 'antd'
|
|
10
|
+
import { CountryEnum, DeviceBreakpointEnum, PageViewTypEnum } from '../../../../../enums'
|
|
11
|
+
import { useConfigContext } from '../../../../companies/context'
|
|
12
|
+
import { buildBreadcrumbTranslationKey } from '../../../../../functions'
|
|
13
|
+
import { translationStore } from '../../../../common/custom-hooks/use-translation.hook/store'
|
|
14
|
+
|
|
15
|
+
import './index.scss'
|
|
16
|
+
|
|
17
|
+
function LayoutRenderer_Breadcrumb(_: { formId?: number } & IElementBaseProps) {
|
|
18
|
+
const currentBreakpoint = useGetCurrentBreakpoint()
|
|
19
|
+
const navigate = useNavigate()
|
|
20
|
+
const { breadcrumbs, sliceCrumbAt } = useBreadcrumb()
|
|
21
|
+
const { config } = useConfigContext()
|
|
22
|
+
const { selectedLanguage } = useSyncExternalStore(
|
|
23
|
+
translationStore.subscribe.bind(translationStore),
|
|
24
|
+
translationStore.getSnapshot.bind(translationStore),
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
const translations = config?.translations
|
|
28
|
+
const fallbackTexts = { Detail: 'detail', List: 'list', New: 'New' }
|
|
29
|
+
const getTranslation = useMemo(
|
|
30
|
+
() => (key: string) => (selectedLanguage ? translations?.[key]?.[selectedLanguage as CountryEnum] ?? '' : ''),
|
|
31
|
+
[selectedLanguage, translations],
|
|
32
|
+
)
|
|
33
|
+
const getFormName = useMemo(
|
|
34
|
+
() =>
|
|
35
|
+
(bc: IBreadcrumb, field: 'Detail' | 'List' | 'New') =>
|
|
36
|
+
bc.formId
|
|
37
|
+
? getTranslation(buildBreadcrumbTranslationKey(bc.formId, field)) || bc.formName?.split(' ')?.[0] || bc.label
|
|
38
|
+
: bc.label,
|
|
39
|
+
[getTranslation],
|
|
40
|
+
)
|
|
41
|
+
const getBreadcrumbText = useMemo(
|
|
42
|
+
() =>
|
|
43
|
+
(field: 'Detail' | 'List' | 'New') => {
|
|
44
|
+
const defaultText = getTranslation(buildBreadcrumbTranslationKey('Default', field))
|
|
45
|
+
return defaultText || fallbackTexts[field]
|
|
46
|
+
},
|
|
47
|
+
[getTranslation],
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
const showAsSelect = useMemo(
|
|
51
|
+
() =>
|
|
52
|
+
([DeviceBreakpointEnum.Mobile, DeviceBreakpointEnum.TabletPortrait].includes(currentBreakpoint) &&
|
|
53
|
+
breadcrumbs.length > 1) ||
|
|
54
|
+
breadcrumbs.length > 3,
|
|
55
|
+
[currentBreakpoint, breadcrumbs],
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
if (showAsSelect)
|
|
59
|
+
return (
|
|
60
|
+
<Select
|
|
61
|
+
suffixIcon={null}
|
|
62
|
+
value={breadcrumbs[breadcrumbs.length - 1].href}
|
|
63
|
+
optionFilterProp="label"
|
|
64
|
+
allowClear={false}
|
|
65
|
+
className={`${ELEMENTS_DEFAULT_CLASS.Breadcrumb} responsive max-w-[250px]`}
|
|
66
|
+
onChange={(bc) => {
|
|
67
|
+
const decodedUri = decodeURIComponent(bc)
|
|
68
|
+
const bcIdx = breadcrumbs.findIndex((bc) => bc.href === decodedUri)
|
|
69
|
+
|
|
70
|
+
sliceCrumbAt(bcIdx)
|
|
71
|
+
navigate(decodedUri)
|
|
72
|
+
}}
|
|
73
|
+
options={breadcrumbs.map((bc) => ({
|
|
74
|
+
value: bc.href,
|
|
75
|
+
label: (
|
|
76
|
+
<div className="flex gap-2 items-center">
|
|
77
|
+
<FaChevronLeft className="text-primary" size={10} />
|
|
78
|
+
{renderText(bc, getFormName, getBreadcrumbText)}
|
|
79
|
+
</div>
|
|
80
|
+
),
|
|
81
|
+
}))}
|
|
82
|
+
/>
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<div className={`${ELEMENTS_DEFAULT_CLASS.Breadcrumb} flex items-center text-12`}>
|
|
87
|
+
{breadcrumbs.map((bc, bcIdx) => (
|
|
88
|
+
<React.Fragment key={bcIdx}>
|
|
89
|
+
<Button_FillerPortal
|
|
90
|
+
link
|
|
91
|
+
disabled={breadcrumbs.length - 1 === bcIdx}
|
|
92
|
+
onClick={() => {
|
|
93
|
+
sliceCrumbAt(bcIdx)
|
|
94
|
+
navigate(bc.href)
|
|
95
|
+
}}
|
|
96
|
+
>
|
|
97
|
+
{renderText(bc, getFormName, getBreadcrumbText)}
|
|
98
|
+
</Button_FillerPortal>
|
|
99
|
+
{breadcrumbs.length - 1 !== bcIdx && <FaChevronRight className="text-primary" />}
|
|
100
|
+
</React.Fragment>
|
|
101
|
+
))}
|
|
102
|
+
</div>
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export default memo(LayoutRenderer_Breadcrumb)
|
|
107
|
+
|
|
108
|
+
const renderText = (
|
|
109
|
+
bc: IBreadcrumb,
|
|
110
|
+
getFormName: (bc: IBreadcrumb, field: 'Detail' | 'List' | 'New') => string,
|
|
111
|
+
getBreadcrumbText: (field: 'Detail' | 'List' | 'New') => string,
|
|
112
|
+
) => {
|
|
113
|
+
const label =
|
|
114
|
+
bc.type === PageViewTypEnum.Details
|
|
115
|
+
? getFormName(bc, 'Detail')
|
|
116
|
+
: bc.type === PageViewTypEnum.List
|
|
117
|
+
? getFormName(bc, 'List')
|
|
118
|
+
: bc.type === PageViewTypEnum.New
|
|
119
|
+
? getFormName(bc, 'New')
|
|
120
|
+
: bc.label
|
|
121
|
+
const detailText = getBreadcrumbText('Detail')
|
|
122
|
+
const listText = getBreadcrumbText('List')
|
|
123
|
+
const newText = getBreadcrumbText('New')
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<span className="font-normal italic">
|
|
127
|
+
{bc.type === PageViewTypEnum.New ? `${newText} ` : ''}
|
|
128
|
+
{label}
|
|
129
|
+
{bc.type === PageViewTypEnum.Details ? ` ${detailText}` : bc.type === PageViewTypEnum.List ? ` ${listText}` : ''}
|
|
130
|
+
</span>
|
|
131
|
+
)
|
|
105
132
|
}
|
|
106
|
-
|
|
107
|
-
export default memo(LayoutRenderer_Breadcrumb)
|
|
108
|
-
|
|
109
|
-
const renderText = (
|
|
110
|
-
bc: IBreadcrumb,
|
|
111
|
-
getFormName: (bc: IBreadcrumb) => string,
|
|
112
|
-
getBreadcrumbText: (bc: IBreadcrumb, field: 'Detail' | 'List' | 'New') => string,
|
|
113
|
-
) => {
|
|
114
|
-
const label = getFormName(bc)
|
|
115
|
-
const detailText = getBreadcrumbText(bc, 'Detail')
|
|
116
|
-
const listText = getBreadcrumbText(bc, 'List')
|
|
117
|
-
const newText = getBreadcrumbText(bc, 'New')
|
|
118
|
-
|
|
119
|
-
return (
|
|
120
|
-
<span className="font-normal italic">
|
|
121
|
-
{bc.type === PageViewTypEnum.New ? `${newText} ` : ''}
|
|
122
|
-
{label}
|
|
123
|
-
{bc.type === PageViewTypEnum.Details ? ` ${detailText}` : bc.type === PageViewTypEnum.List ? ` ${listText}` : ''}
|
|
124
|
-
</span>
|
|
125
|
-
)
|
|
126
|
-
}
|
|
127
|
-
|
|
@@ -2,8 +2,14 @@ import { Form } from 'antd'
|
|
|
2
2
|
import { renderData, resolveConditionalText } from '../../../../functions/forms'
|
|
3
3
|
import { useFormPreservedItemValues } from '../../../common/custom-hooks/use-preserved-form-items.hook'
|
|
4
4
|
import { memo, useMemo } from 'react'
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
DataRenderTypeEnum,
|
|
7
|
+
LOCAL_STORAGE_KEYS_ENUM,
|
|
8
|
+
ReadFieldDataValueTypeEnum,
|
|
9
|
+
TranslationTextTypeEnum,
|
|
10
|
+
UserFormPlaceholders,
|
|
11
|
+
} from '../../../../enums'
|
|
12
|
+
import { IReadFieldDataElementProps, ISystemRole } from '../../../../types'
|
|
7
13
|
import { IFormContext } from '../1-row'
|
|
8
14
|
import { evaluateValue } from '../../../../functions/forms/evaluate-value'
|
|
9
15
|
import { ELEMENTS_DEFAULT_CLASS } from '../../../../constants'
|
|
@@ -59,6 +65,27 @@ function LayoutRenderer_ReadFieldData({
|
|
|
59
65
|
[elementKey, textConditions, t, formValues, formContext.formDataId, currentBreakpoint],
|
|
60
66
|
)
|
|
61
67
|
|
|
68
|
+
const roles = useMemo(() => {
|
|
69
|
+
if (
|
|
70
|
+
elementProps.valueType !== ReadFieldDataValueTypeEnum.Evaluated &&
|
|
71
|
+
elementProps.field === UserFormPlaceholders.LoginUserFieldKey_Roles &&
|
|
72
|
+
Array.isArray(fieldValue)
|
|
73
|
+
) {
|
|
74
|
+
const storageRoles: ISystemRole[] = localStorage.getItem(LOCAL_STORAGE_KEYS_ENUM.UserRoles)
|
|
75
|
+
? (JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEYS_ENUM.UserRoles) as string) ?? [])
|
|
76
|
+
: []
|
|
77
|
+
|
|
78
|
+
return fieldValue
|
|
79
|
+
.map((selectedR) => {
|
|
80
|
+
const rInfo = storageRoles.find((r) => r.id === selectedR)?.name
|
|
81
|
+
return rInfo
|
|
82
|
+
})
|
|
83
|
+
.filter(Boolean)
|
|
84
|
+
.join(', ')
|
|
85
|
+
}
|
|
86
|
+
return null
|
|
87
|
+
}, [elementProps])
|
|
88
|
+
|
|
62
89
|
return (
|
|
63
90
|
<div className={`${ELEMENTS_DEFAULT_CLASS.ReadFieldData} flex items-center gap-2`}>
|
|
64
91
|
{label && <span>{label}: </span>}
|
|
@@ -67,10 +94,12 @@ function LayoutRenderer_ReadFieldData({
|
|
|
67
94
|
elementProps.renderConfig?.type === DataRenderTypeEnum.Image
|
|
68
95
|
? attachmentUrl
|
|
69
96
|
: elementProps.renderConfig?.type === DataRenderTypeEnum.Conditional
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
97
|
+
? formValues
|
|
98
|
+
: elementProps.valueType === ReadFieldDataValueTypeEnum.Evaluated
|
|
99
|
+
? evaluatedValue
|
|
100
|
+
: roles
|
|
101
|
+
? roles
|
|
102
|
+
: fieldValue,
|
|
74
103
|
elementProps.renderConfig ?? { type: DataRenderTypeEnum.Default },
|
|
75
104
|
) ?? 'N/A'}
|
|
76
105
|
</span>
|
|
@@ -85,4 +114,3 @@ type ILayoutRenderer_ReadFieldData = {
|
|
|
85
114
|
elementProps: IReadFieldDataElementProps
|
|
86
115
|
style?: { [key: string]: any }
|
|
87
116
|
} & IElementBaseProps
|
|
88
|
-
|
package/src/enums/form.enum.ts
CHANGED
|
@@ -80,6 +80,7 @@ export enum FieldElementOptionSourceEnum {
|
|
|
80
80
|
Static = 'Static',
|
|
81
81
|
DynamicForm = 'DynamicForm',
|
|
82
82
|
ReadFromDetails = 'ReadFromDetails', // used in data list header
|
|
83
|
+
Roles = 'Roles',
|
|
83
84
|
}
|
|
84
85
|
export enum FormDataListViewTypeEnum {
|
|
85
86
|
Table = 'Table',
|
|
@@ -207,7 +208,8 @@ export enum PatternPlacholdersEnum {
|
|
|
207
208
|
CyrillicLowercase = 'c',
|
|
208
209
|
Digit = 'D',
|
|
209
210
|
}
|
|
210
|
-
export enum TemplateDataReplacementFieldTypesEnum {
|
|
211
|
+
export enum TemplateDataReplacementFieldTypesEnum {
|
|
212
|
+
// used for /api/template/{key}/{blobName}
|
|
211
213
|
Text = 1,
|
|
212
214
|
Html,
|
|
213
215
|
Image,
|
|
@@ -70,8 +70,8 @@ export const renderTableColumns = (
|
|
|
70
70
|
colRaw.align === AlignTypeEnum.Center
|
|
71
71
|
? 'justify-center'
|
|
72
72
|
: colRaw.align === AlignTypeEnum.Right
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
? 'justify-end'
|
|
74
|
+
: ''
|
|
75
75
|
}`}
|
|
76
76
|
onClick={(e) => e.stopPropagation()}
|
|
77
77
|
>
|
|
@@ -144,6 +144,7 @@ export const renderData = (data?: any, renderConfig?: IDataRenderConfig): ReactN
|
|
|
144
144
|
case DataRenderTypeEnum.Conditional:
|
|
145
145
|
return renderConditionalData(data, renderConfig)
|
|
146
146
|
case DataRenderTypeEnum.Default:
|
|
147
|
+
return data
|
|
147
148
|
case DataRenderTypeEnum.Buttons:
|
|
148
149
|
default:
|
|
149
150
|
return data
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fetchFormDataAsLookup } from '.'
|
|
2
|
-
import { FieldElementOptionSourceEnum, TranslationTextTypeEnum } from '../../enums'
|
|
3
|
-
import { IFormDataListColumn } from '../../types'
|
|
2
|
+
import { FieldElementOptionSourceEnum, LOCAL_STORAGE_KEYS_ENUM, TranslationTextTypeEnum } from '../../enums'
|
|
3
|
+
import { IFormDataListColumn, ISystemRole } from '../../types'
|
|
4
4
|
import client from '../../api/client'
|
|
5
5
|
import { REACT_QUERY_CLIENT } from '../../constants'
|
|
6
6
|
import { translationStore } from '../../components/common/custom-hooks/use-translation.hook/store'
|
|
@@ -27,7 +27,8 @@ export async function processOptions(options: IFormDataListColumn[]): Promise<{
|
|
|
27
27
|
groupedRequests.forEach((paths, formId) => {
|
|
28
28
|
const cachedConfig = REACT_QUERY_CLIENT.getQueryData(['layoutConfig', String(formId)])
|
|
29
29
|
|
|
30
|
-
if (cachedConfig)
|
|
30
|
+
if (cachedConfig)
|
|
31
|
+
apiCallPromises.push(Promise.resolve({ _id: formId, Data: extractByDotPaths(paths, cachedConfig) }))
|
|
31
32
|
else
|
|
32
33
|
apiCallPromises.push(
|
|
33
34
|
client.post(`/api/form/${formId}`, { project: JSON.stringify(paths) }).then((res) => res.data),
|
|
@@ -74,6 +75,14 @@ export async function processOptions(options: IFormDataListColumn[]): Promise<{
|
|
|
74
75
|
})
|
|
75
76
|
}),
|
|
76
77
|
)
|
|
78
|
+
} else if (optionSource.type === FieldElementOptionSourceEnum.Roles) {
|
|
79
|
+
const storageRoles: ISystemRole[] = localStorage.getItem(LOCAL_STORAGE_KEYS_ENUM.UserRoles)
|
|
80
|
+
? (JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEYS_ENUM.UserRoles) as string) ?? [])
|
|
81
|
+
: []
|
|
82
|
+
|
|
83
|
+
storageRoles.forEach((r) => {
|
|
84
|
+
finalResult[r.id as string] = r.name
|
|
85
|
+
})
|
|
77
86
|
}
|
|
78
87
|
})
|
|
79
88
|
})
|
|
@@ -58,10 +58,10 @@ export const extractFiltersFromLayout = (elements: { [key: string]: IDndLayoutEl
|
|
|
58
58
|
bsonDataType: el.key.includes(BSON_DATA_IDENTIFIER_PREFIXES.ObjectId)
|
|
59
59
|
? BSON_DATA_IDENTIFIER_PREFIXES.ObjectId
|
|
60
60
|
: el.key.includes(BSON_DATA_IDENTIFIER_PREFIXES.Number)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
? BSON_DATA_IDENTIFIER_PREFIXES.Number
|
|
62
|
+
: el.key.includes(BSON_DATA_IDENTIFIER_PREFIXES.Date)
|
|
63
|
+
? BSON_DATA_IDENTIFIER_PREFIXES.Date
|
|
64
|
+
: undefined,
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
})
|
|
@@ -153,11 +153,14 @@ export const queryParamsToObject = (query: string): Record<string, string | unde
|
|
|
153
153
|
return query
|
|
154
154
|
.replace(/^\?/, '') // Remove leading "?" if present
|
|
155
155
|
.split('&')
|
|
156
|
-
.reduce(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
156
|
+
.reduce(
|
|
157
|
+
(acc, param) => {
|
|
158
|
+
const [key, value] = param.split('=').map(decodeURIComponent) // Decode and split by "="
|
|
159
|
+
if (key) acc[key] = !['null', 'undefined'].includes(value) ? value : undefined // Add key-value to the object
|
|
160
|
+
return acc
|
|
161
|
+
},
|
|
162
|
+
{} as Record<string, string | undefined>,
|
|
163
|
+
)
|
|
161
164
|
}
|
|
162
165
|
|
|
163
166
|
/** --------------------------------------------------------------------------------------------------------- */
|
|
@@ -284,6 +287,10 @@ export const replaceAndGetFileBlob = async (
|
|
|
284
287
|
}
|
|
285
288
|
|
|
286
289
|
if (rep.type === TemplateDataReplacementFieldTypesEnum.Image) {
|
|
290
|
+
const isEmpty = typeof repValue !== 'string' || repValue.length === 0
|
|
291
|
+
if (isEmpty)
|
|
292
|
+
return { placeholder: rep.placeholder, value: '-', type: TemplateDataReplacementFieldTypesEnum.Text }
|
|
293
|
+
|
|
287
294
|
const imageRenderConfig = rep.renderConfig.type === DataRenderTypeEnum.Image ? rep.renderConfig : undefined
|
|
288
295
|
const imageRenderOptions: { imageWidth?: number; imageHeight?: number } = {
|
|
289
296
|
imageWidth: 624, // Page width minus margins
|