form-craft-package 1.10.2 → 1.10.3-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.
Files changed (32) hide show
  1. package/.env.production +1 -1
  2. package/package.json +1 -1
  3. package/src/components/common/custom-hooks/use-node-condition.hook/visibility-utils.ts +18 -138
  4. package/src/components/common/custom-hooks/use-preserved-form-items.hook.ts +2 -0
  5. package/src/components/form/1-list/table-header.tsx +15 -4
  6. package/src/components/form/2-details/index.tsx +12 -1
  7. package/src/components/form/layout-renderer/1-row/index.tsx +5 -3
  8. package/src/components/form/layout-renderer/2-col/index.tsx +6 -3
  9. package/src/components/form/layout-renderer/3-element/1-dynamic-button/use-create-data.hook.ts +127 -66
  10. package/src/components/form/layout-renderer/3-element/10-currency.tsx +1 -1
  11. package/src/components/form/layout-renderer/3-element/12-picker-field.tsx +9 -2
  12. package/src/components/form/layout-renderer/3-element/14-auto-complete.tsx +107 -88
  13. package/src/components/form/layout-renderer/3-element/{15-form-submission-pdf/index.tsx → 15-form-submission-pdf.tsx} +8 -8
  14. package/src/components/form/layout-renderer/3-element/16-user-role.tsx +60 -0
  15. package/src/components/form/layout-renderer/3-element/17-custom-component.tsx +21 -0
  16. package/src/components/form/layout-renderer/3-element/2-field-element.tsx +74 -10
  17. package/src/components/form/layout-renderer/3-element/4-rich-text-editor.tsx +31 -13
  18. package/src/components/form/layout-renderer/3-element/6-signature.tsx +21 -1
  19. package/src/components/form/layout-renderer/3-element/8-fields-with-options.tsx +1 -1
  20. package/src/components/form/layout-renderer/3-element/9-form-data-render.tsx +9 -11
  21. package/src/components/form/layout-renderer/3-element/index.tsx +46 -10
  22. package/src/constants.ts +3 -2
  23. package/src/enums/form.enum.ts +14 -0
  24. package/src/enums/index.ts +6 -2
  25. package/src/functions/companies/use-company-config.tsx +2 -0
  26. package/src/functions/forms/conditional-rule.utils.ts +165 -0
  27. package/src/functions/forms/create-form-rules.ts +20 -4
  28. package/src/types/companies/index.ts +206 -206
  29. package/src/types/companies/roles.ts +14 -14
  30. package/src/types/forms/layout-elements/index.ts +37 -7
  31. package/src/types/forms/layout-elements/validation.ts +3 -1
  32. package/src/types/index.ts +6 -0
package/.env.production CHANGED
@@ -1,5 +1,5 @@
1
1
  # .env
2
- VITE_API_BASE_URL=https://formcraftmaster-backend-ecgtewb6cag8faeq.centralus-01.azurewebsites.net/
2
+ VITE_API_BASE_URL=https://formcraftmaster-backend-ecgtewb6cag8faeq.centralus-01.azurewebsites.net
3
3
  VITE_LOG_LEVEL=error
4
4
  VITE_COOKIE_DOMAIN=localhost
5
5
  VITE_ENV=production
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "form-craft-package",
3
- "version": "1.10.2",
3
+ "version": "1.10.3-dev.0",
4
4
  "main": "index.ts",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -1,139 +1,19 @@
1
- import { NEW_FORM_DATA_IDENTIFIER, REGEX_PATTERNS } from '../../../../constants'
2
- import { IFormContext } from '../../../form/layout-renderer/1-row'
3
- import { isNewFormDataPage } from '../../../../functions'
4
- import {
5
- ConditionDependencyTypeEnum,
6
- DeviceBreakpointEnum,
7
- FieldValidationEnum,
8
- FormElementConditionalKeyEnum,
9
- FormStateEnum,
10
- } from '../../../../enums'
11
- import {
12
- IConditionalValidation,
13
- IConditionalValidation_AuthUser,
14
- IConditionalValidation_Field,
15
- IConditionalValidation_FormState,
16
- IFormLayoutElementConditions,
17
- } from '../../../../types'
18
-
19
- const getValidationConfigs = (validationConfigs: IConditionalValidation[]) =>
20
- validationConfigs.reduce<{
21
- fieldValidations: IConditionalValidation_Field[]
22
- authUserValidations: IConditionalValidation_AuthUser[]
23
- hasDataIdValidation: IConditionalValidation_FormState | undefined
24
- alwaysDisabled: boolean
25
- hideScreens: DeviceBreakpointEnum[]
26
- }>(
27
- (curr, v) => {
28
- if (v.dependentType === ConditionDependencyTypeEnum.Field)
29
- return { ...curr, fieldValidations: [...curr.fieldValidations, v] }
30
- else if (v.dependentType === ConditionDependencyTypeEnum.AuthUser)
31
- return { ...curr, authUserValidations: [...curr.authUserValidations, v] }
32
- else if (v.dependentType === ConditionDependencyTypeEnum.FormState) return { ...curr, hasDataIdValidation: v }
33
- else if (v.dependentType === ConditionDependencyTypeEnum.AlwaysFalse) return { ...curr, alwaysDisabled: true }
34
- else if (v.dependentType === ConditionDependencyTypeEnum.Screen) return { ...curr, hideScreens: v.hideScreens }
35
-
36
- return curr
37
- },
38
- {
39
- fieldValidations: [],
40
- authUserValidations: [],
41
- hasDataIdValidation: undefined,
42
- alwaysDisabled: false,
43
- hideScreens: [],
44
- },
45
- )
46
-
47
- /** If any of the validations fails, the function returns false */
48
- const validateConditions = (validations: IConditionalValidation_Field[], data: Record<string, any>): boolean => {
49
- return validations.every((validation) => {
50
- const { field, rule, value: configuredValue } = validation
51
- const formValue = data[field]
52
-
53
- switch (rule) {
54
- case FieldValidationEnum.Required:
55
- if (!!formValue) return true
56
- return false
57
-
58
- case FieldValidationEnum.DataLength:
59
- return (
60
- typeof formValue === 'string' && typeof configuredValue === 'number' && formValue.length === configuredValue
61
- )
62
-
63
- case FieldValidationEnum.MaxDataLength:
64
- return (
65
- typeof formValue === 'string' && typeof configuredValue === 'number' && formValue.length <= configuredValue
66
- )
67
-
68
- case FieldValidationEnum.MinDataLength:
69
- return (
70
- typeof formValue === 'string' && typeof configuredValue === 'number' && formValue.length >= configuredValue
71
- )
72
-
73
- case FieldValidationEnum.MinValue:
74
- return typeof formValue === 'number' && typeof configuredValue === 'number' && formValue >= configuredValue
75
-
76
- case FieldValidationEnum.MaxValue:
77
- return typeof formValue === 'number' && typeof configuredValue === 'number' && formValue <= configuredValue
78
-
79
- case FieldValidationEnum.Regex:
80
- return (
81
- typeof formValue === 'string' &&
82
- typeof configuredValue === 'string' &&
83
- new RegExp(configuredValue).test(formValue)
84
- )
85
-
86
- case FieldValidationEnum.Email:
87
- return typeof formValue === 'string' && REGEX_PATTERNS.Email.test(formValue)
88
-
89
- case FieldValidationEnum.StrictlyEquals:
90
- if (!configuredValue)
91
- // equals no value
92
- return !formValue || [null, undefined, ''].includes(formValue)
93
-
94
- return Array.isArray(formValue) ? formValue.includes(configuredValue) : formValue === configuredValue
95
-
96
- default:
97
- return false
98
- }
99
- })
100
- }
101
-
102
- export const isValidationsMet = (
103
- type: FormElementConditionalKeyEnum,
104
- dataValues: { [key: string]: any },
105
- configs?: IFormLayoutElementConditions,
106
- contextValues: { currentBreakpoint?: DeviceBreakpointEnum } & IFormContext = {},
107
- ) => {
108
- const validations = configs?.[type] ?? []
109
-
110
- if (validations.length === 0) return true
111
-
112
- const { fieldValidations, authUserValidations, hasDataIdValidation, alwaysDisabled, hideScreens } =
113
- getValidationConfigs(validations)
114
-
115
- if (alwaysDisabled) return false
116
-
117
- // Dependent on other fields
118
- const isFieldsConditionsMet =
119
- dataValues && typeof dataValues === 'object' && fieldValidations.length > 0
120
- ? validateConditions(fieldValidations as IConditionalValidation_Field[], dataValues)
121
- : true
122
-
123
- // Dependent on auth user
124
- const isAuthUserConditionsMet = authUserValidations.length > 0 ? false : true
125
-
126
- // Dependent on data id
127
- const isDataIdConditionsMet = hasDataIdValidation
128
- ? hasDataIdValidation.state === FormStateEnum.New
129
- ? isNewFormDataPage(contextValues.formDataId)
130
- : contextValues.formDataId !== NEW_FORM_DATA_IDENTIFIER
131
- : true
132
-
133
- // Dependent on screen
134
- const isScreenConditionsMet = contextValues?.currentBreakpoint
135
- ? !hideScreens.includes(contextValues.currentBreakpoint)
136
- : true
137
-
138
- return isFieldsConditionsMet && isAuthUserConditionsMet && isDataIdConditionsMet && isScreenConditionsMet
1
+ import { IFormContext } from '../../../form/layout-renderer/1-row'
2
+ import { DeviceBreakpointEnum, FormElementConditionalKeyEnum } from '../../../../enums'
3
+ import { IConditionalValidation, IFormLayoutElementConditions } from '../../../../types'
4
+ import { areConditionalRulesMet } from '../../../../functions/forms/conditional-rule.utils'
5
+
6
+ export const isValidationsMet = (
7
+ type: FormElementConditionalKeyEnum,
8
+ dataValues: { [key: string]: any },
9
+ configs?: IFormLayoutElementConditions,
10
+ contextValues: { currentBreakpoint?: DeviceBreakpointEnum } & IFormContext = {},
11
+ ) => {
12
+ const validations: IConditionalValidation[] = configs?.[type] ?? []
13
+
14
+ return areConditionalRulesMet(validations, {
15
+ fieldValues: dataValues,
16
+ currentBreakpoint: contextValues.currentBreakpoint,
17
+ formDataId: contextValues.formDataId,
18
+ })
139
19
  }
@@ -7,6 +7,7 @@ export const useFormPreservedItemValues = (formRef?: FormInstance): IFormValues
7
7
  const signatureFields = Form.useWatch(FormPreservedItemKeys.SignatureFields, { form: formRef, preserve: true })
8
8
  const isPublic = Form.useWatch(FormPreservedItemKeys.IsPublic, { form: formRef, preserve: true })
9
9
  const formNotifications = Form.useWatch(FormPreservedItemKeys.FormNotifications, { form: formRef, preserve: true })
10
+ const isUserForm = Form.useWatch(FormPreservedItemKeys.IsUserForm, { form: formRef, preserve: true })
10
11
  const formTemplateReports = Form.useWatch(FormPreservedItemKeys.FormTemplateReports, {
11
12
  form: formRef,
12
13
  preserve: true,
@@ -35,6 +36,7 @@ export const useFormPreservedItemValues = (formRef?: FormInstance): IFormValues
35
36
  [FormPreservedItemKeys.DuplicateDataFound]:
36
37
  duplicateDataMatches && Object.values(duplicateDataMatches).some((result) => result),
37
38
  [FormPreservedItemKeys.DuplicateCheckPending]: isDuplicateCheckPending,
39
+ [FormPreservedItemKeys.IsUserForm]: isUserForm,
38
40
  }
39
41
  }
40
42
 
@@ -36,6 +36,7 @@ export default function FormDataListHeaderComponent({
36
36
  const { formId, detailPageFormId, parentFormJoins, formDataId, manyToManyRelInfo, onCustomFunctionCall } =
37
37
  headerLayoutContext
38
38
  const isInitialFetchRef = useRef(true)
39
+ const lastSerializedFiltersRef = useRef<string | null>(null)
39
40
 
40
41
  const currentBreakpoint = useGetCurrentBreakpoint()
41
42
 
@@ -95,12 +96,22 @@ export default function FormDataListHeaderComponent({
95
96
  [filterConfigs],
96
97
  )
97
98
 
99
+
98
100
  useEffect(() => {
99
- if (filterValues) {
100
- if (!isInitialFetchRef.current) organizeFilterData(filterValues)
101
- else isInitialFetchRef.current = false
101
+ if (!filterValues) return
102
+
103
+ const serialized = JSON.stringify(filterValues)
104
+ if (lastSerializedFiltersRef.current === serialized) return
105
+
106
+ lastSerializedFiltersRef.current = serialized
107
+
108
+ if (isInitialFetchRef.current) {
109
+ isInitialFetchRef.current = false
110
+ return
102
111
  }
103
- }, [filterValues])
112
+
113
+ organizeFilterData(filterValues)
114
+ }, [filterValues, organizeFilterData])
104
115
 
105
116
  const formContext = useMemo(
106
117
  () => ({
@@ -35,6 +35,7 @@ import {
35
35
  isValidMongoDbId,
36
36
  queryParamsToObject,
37
37
  } from '../../../functions/forms'
38
+ import { ICustomComponents } from '../layout-renderer/3-element'
38
39
 
39
40
  export default function FormDataDetailsComponent(props: IFormDataDetailsComponent) {
40
41
  return (
@@ -53,6 +54,7 @@ function FormDataDetailsComponentChild({
53
54
  baseServerUrl,
54
55
  initialValues,
55
56
  companyKey,
57
+ customComponents,
56
58
  onCustomFunctionCall,
57
59
  }: IFormDataDetailsComponent) {
58
60
  const { pushCrumb, breadcrumbs } = useBreadcrumb()
@@ -176,6 +178,7 @@ function FormDataDetailsComponentChild({
176
178
  }
177
179
  } else setIsNotFound(true)
178
180
  })
181
+ .catch(() => setIsNotFound(true))
179
182
  }
180
183
  },
181
184
  [formDataId, formDataRef, breadcrumbs],
@@ -206,6 +209,12 @@ function FormDataDetailsComponentChild({
206
209
  translationStore.setTranslations(cachedConfig.id, cachedConfig.translations)
207
210
  }, [cachedConfig])
208
211
 
212
+ useEffect(() => {
213
+ if (!cachedConfig) return
214
+
215
+ formDataRef.setFieldValue(FormPreservedItemKeys.IsUserForm, true)
216
+ }, [cachedConfig])
217
+
209
218
  useEffect(() => {
210
219
  if (!cachedConfig?.detailsConfig) return
211
220
 
@@ -269,6 +278,7 @@ function FormDataDetailsComponentChild({
269
278
  formRef: formDataRef,
270
279
  companyKey,
271
280
  }}
281
+ customComponents={customComponents}
272
282
  elements={cachedConfig.detailsConfig.elements}
273
283
  renderButton={(btnProps) => (
274
284
  <DynamicFormButtonRender
@@ -298,7 +308,8 @@ type IFormDataDetailsComponent = {
298
308
  formName?: string
299
309
  initialValues?: Record<string, any>
300
310
  } & (IDataDetailsPublicProps | IDataDetailsPrivateProps) &
301
- ICustomFunctionCall
311
+ ICustomFunctionCall &
312
+ ICustomComponents
302
313
 
303
314
  interface IDataDetailsPublicProps {
304
315
  isPublic: true
@@ -9,6 +9,7 @@ import { IDynamicButton_DisplayStateProps } from '../3-element/1-dynamic-button'
9
9
  import { ELEMENTS_DEFAULT_CLASS } from '../../../../constants'
10
10
  import { useHiddenIds } from '../../../common/custom-hooks/use-node-condition.hook/use-node-condition.hook'
11
11
  import FormDataListSkeleton_Details from '../../../common/loading-skeletons/details'
12
+ import { ICustomComponents } from '../3-element'
12
13
 
13
14
  export const LayoutRendererRow = memo(
14
15
  ({
@@ -18,6 +19,7 @@ export const LayoutRendererRow = memo(
18
19
  formContext,
19
20
  elements,
20
21
  isTopLevel = false,
22
+ customComponents,
21
23
  renderButton,
22
24
  }: ILayoutRendererRow) => {
23
25
  const hiddenIds = useHiddenIds()
@@ -83,6 +85,7 @@ export const LayoutRendererRow = memo(
83
85
  formContext={formContext}
84
86
  colStyle={getColumnStyle(colIdx, rowData.display)}
85
87
  renderButton={renderButton}
88
+ customComponents={customComponents}
86
89
  />
87
90
  ))}
88
91
  {formListItemProps?.removeButton}
@@ -95,7 +98,7 @@ export const LayoutRendererRow = memo(
95
98
  },
96
99
  )
97
100
 
98
- interface ILayoutRendererRow {
101
+ type ILayoutRendererRow = {
99
102
  basePath?: (string | number)[]
100
103
  rowData: IDndLayoutRow
101
104
  isTopLevel?: boolean
@@ -103,8 +106,7 @@ interface ILayoutRendererRow {
103
106
  formContext: IFormContext
104
107
  elements: { [key: string]: IDndLayoutElement }
105
108
  renderButton?: (btnProps: IDynamicButton_DisplayStateProps) => ReactElement
106
- hideCol?: (bool: boolean) => void
107
- }
109
+ } & ICustomComponents
108
110
 
109
111
  export interface IFormContext {
110
112
  formDataId?: string
@@ -1,7 +1,7 @@
1
1
  import { memo, ReactElement } from 'react'
2
2
  import { IFormContext, LayoutRendererRow } from '../1-row'
3
3
  import { DndLayoutNodeEnum } from '../../../../enums'
4
- import LayoutRendererElementWrapper from '../3-element'
4
+ import LayoutRendererElementWrapper, { ICustomComponents } from '../3-element'
5
5
  import { useIsNodeHidden } from '../../../common/custom-hooks/use-node-condition.hook/use-node-condition.hook'
6
6
  import { IDndLayoutCol, IDndLayoutElement, IDndLayoutRow } from '../../../../types'
7
7
  import { IDynamicButton_DisplayStateProps } from '../3-element/1-dynamic-button'
@@ -14,6 +14,7 @@ function LayoutRendererCol({
14
14
  elements,
15
15
  formContext,
16
16
  colStyle,
17
+ customComponents,
17
18
  renderButton,
18
19
  }: ILayoutRendererCol) {
19
20
  const isHidden = useIsNodeHidden(colData.id)
@@ -33,6 +34,7 @@ function LayoutRendererCol({
33
34
  formContext={formContext}
34
35
  dataCount={dataCount}
35
36
  elements={elements}
37
+ customComponents={customComponents}
36
38
  renderButton={renderButton}
37
39
  />
38
40
  ) : (
@@ -43,6 +45,7 @@ function LayoutRendererCol({
43
45
  formContext={formContext}
44
46
  dataCount={dataCount}
45
47
  renderButton={renderButton}
48
+ customComponents={customComponents}
46
49
  />
47
50
  ),
48
51
  )}
@@ -51,7 +54,7 @@ function LayoutRendererCol({
51
54
  }
52
55
 
53
56
  export default memo(LayoutRendererCol)
54
- interface ILayoutRendererCol {
57
+ type ILayoutRendererCol = {
55
58
  basePath: (string | number)[]
56
59
  colData: IDndLayoutCol
57
60
  dataCount?: 'pending' | number
@@ -59,4 +62,4 @@ interface ILayoutRendererCol {
59
62
  formContext: IFormContext
60
63
  colStyle: { [key: string]: number | string }
61
64
  renderButton?: (btnProps: IDynamicButton_DisplayStateProps) => ReactElement
62
- }
65
+ } & ICustomComponents
@@ -1,5 +1,4 @@
1
1
  import { useCallback } from 'react'
2
- import { FormLoadingModalTypeEnum, TranslationTextTypeEnum } from '../../../../../enums'
3
2
  import { useFormPreservedItemValues } from '../../../../common/custom-hooks/use-preserved-form-items.hook'
4
3
  import { toMongoDbExtendedJSON } from '../../../../../functions/forms/extended-json-handlers'
5
4
  import client from '../../../../../api/client'
@@ -8,9 +7,15 @@ import { useNotification, useTranslation } from '../../../../common/custom-hooks
8
7
  import { useNavigate } from 'react-router-dom'
9
8
  import { IFormContext } from '../../1-row'
10
9
  import { IOnSuccessFunctions } from '.'
11
- import { IFormTemplateReport } from '../../../../../types'
10
+ import { IFormTemplateReport, ISystemRole, SystemRolePermissionEnum } from '../../../../../types'
12
11
  import { useBreadcrumb } from '../../../../common/custom-hooks/use-breadcrumb.hook'
13
12
  import { FORM_SUBMISSION_PDF_KEY } from '../../../../../constants'
13
+ import {
14
+ FormLoadingModalTypeEnum,
15
+ LOCAL_STORAGE_KEYS_ENUM,
16
+ TranslationTextTypeEnum,
17
+ UserFormPlaceholders,
18
+ } from '../../../../../enums'
14
19
 
15
20
  /* --------------------------------------------------------------------------
16
21
  - Creates new form data.
@@ -33,83 +38,132 @@ export const useCreateDataWithPdfActions = ({
33
38
  const { t } = useTranslation(formId)
34
39
  const navigate = useNavigate()
35
40
  const { errorModal, warning } = useNotification()
36
- const { baseServerUrl, submissionTemplateReportConfig, formTemplateReports, isPublic } =
41
+ const { baseServerUrl, submissionTemplateReportConfig, formTemplateReports, isPublic, isUserForm } =
37
42
  useFormPreservedItemValues(formRef)
38
43
  const { breadcrumbs } = useBreadcrumb()
39
44
 
40
45
  const onCreateNewData = useCallback(
41
- (generatedPdfBlobName?: string) => {
46
+ async (generatedPdfBlobName?: string) => {
42
47
  try {
43
- formRef
44
- ?.validateFields()
45
- .then(async (values) => {
46
- setDataLoadingType(FormLoadingModalTypeEnum.SavingChanges)
47
- const submissionValues = { ...values }
48
-
49
- const shouldGenerateSubmissionPdf =
50
- isNewFormDataPage(formDataId) &&
51
- submissionTemplateReportConfig?.enabled &&
52
- submissionTemplateReportConfig.template &&
53
- formId &&
54
- (isPublic ? !!companyKey : true)
55
-
56
- if (shouldGenerateSubmissionPdf) {
57
- const templateReportsForForm = formTemplateReports?.[formId]
58
- const templateInfo = Array.isArray(templateReportsForForm?.templates)
59
- ? (templateReportsForForm?.templates.find(
60
- (report: IFormTemplateReport) => report.fileBlobName === submissionTemplateReportConfig.template,
61
- ) as IFormTemplateReport | undefined)
62
- : undefined
63
-
64
- if (templateInfo) {
65
- const generatedTemplate = await replaceTemplateReportAndUpload({
66
- templateInfo,
67
- formData: { Data: submissionValues },
68
- companyKey,
69
- formId,
70
- isPublic,
71
- fileNameHint: submissionTemplateReportConfig.fileName || 'SubmissionProofPdf.pdf',
72
- })
73
-
74
- if (generatedTemplate?.blobName) submissionValues[FORM_SUBMISSION_PDF_KEY] = generatedTemplate.blobName
75
- }
48
+ if (!formRef) return
49
+
50
+ const values = await formRef.validateFields()
51
+ let submissionValues = { ...values }
52
+
53
+ if (isUserForm) {
54
+ setDataLoadingType(FormLoadingModalTypeEnum.CreatingUserAccount)
55
+
56
+ const systemRoles = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEYS_ENUM.UserRoles) || '[]') || []
57
+ const selectedRoles = values?.[UserFormPlaceholders.ROLES_FIELD_KEY] || []
58
+ const selectedPermissions = systemRoles.reduce(
59
+ (accR: SystemRolePermissionEnum[], r: ISystemRole) =>
60
+ selectedRoles.includes(r.name) ? [...accR, ...r.permissions] : accR,
61
+ [],
62
+ )
63
+ const userPayload = {
64
+ email: values?.[UserFormPlaceholders.EMAIL_FIELD_KEY],
65
+ phone: values?.[UserFormPlaceholders.PHONE_NUMBER_FIELD_KEY],
66
+ enable2FA: values?.[UserFormPlaceholders.ENABLE_2FA] || false,
67
+ password: values?.[UserFormPlaceholders.PASSWORD_FIELD_KEY],
68
+ roles: [...new Set(selectedPermissions)],
69
+ notification: null,
70
+ }
71
+
72
+ try {
73
+ const userResponse = await client.post('/api/user', userPayload)
74
+
75
+ if (userResponse.status >= 300 || !userResponse.data) {
76
+ setDataLoadingType(FormLoadingModalTypeEnum.ErrorOccured)
77
+ errorModal({
78
+ title: 'User account creation failed',
79
+ content: 'An error occurred while creating the user account.',
80
+ })
81
+ onCreateError()
82
+ return
76
83
  }
77
84
 
78
- const reqData = {
79
- name: '', // TODO: maybe later, make it dynamic
80
- data: JSON.stringify(toMongoDbExtendedJSON({ ...submissionValues, generatedPdfBlobName })),
81
- ...(isPublic ? { private: false } : { version: 1 }),
85
+ submissionValues = {
86
+ ...submissionValues,
87
+ [UserFormPlaceholders.AspUserId]: userResponse.data,
82
88
  }
89
+ } catch (_error) {
90
+ setDataLoadingType(FormLoadingModalTypeEnum.ErrorOccured)
91
+ errorModal({
92
+ title: 'User account creation failed',
93
+ content: 'An error occurred while creating the user account.',
94
+ })
95
+ onCreateError()
96
+ return
97
+ }
98
+ }
99
+
100
+ setDataLoadingType(FormLoadingModalTypeEnum.SavingChanges)
101
+
102
+ const shouldGenerateSubmissionPdf =
103
+ isNewFormDataPage(formDataId) &&
104
+ submissionTemplateReportConfig?.enabled &&
105
+ submissionTemplateReportConfig.template &&
106
+ formId &&
107
+ (isPublic ? !!companyKey : true)
108
+
109
+ if (shouldGenerateSubmissionPdf) {
110
+ const templateReportsForForm = formTemplateReports?.[formId]
111
+ const templateInfo = Array.isArray(templateReportsForForm?.templates)
112
+ ? (templateReportsForForm?.templates.find(
113
+ (report: IFormTemplateReport) => report.fileBlobName === submissionTemplateReportConfig.template,
114
+ ) as IFormTemplateReport | undefined)
115
+ : undefined
116
+
117
+ if (templateInfo) {
118
+ const generatedTemplate = await replaceTemplateReportAndUpload({
119
+ templateInfo,
120
+ formData: { Data: submissionValues },
121
+ companyKey,
122
+ formId,
123
+ isPublic,
124
+ fileNameHint: submissionTemplateReportConfig.fileName || 'SubmissionProofPdf.pdf',
125
+ })
83
126
 
84
- const endpoint = isPublic ? `/api/site/${formKey}` : `/api/formdata/${formId}`
85
- const res = await client.post(endpoint, reqData)
86
-
87
- if (res.status === 200) onCreateSuccess(res.data)
127
+ if (generatedTemplate?.blobName) submissionValues[FORM_SUBMISSION_PDF_KEY] = generatedTemplate.blobName
128
+ }
129
+ }
130
+
131
+ const reqData = {
132
+ name: '', // TODO: maybe later, make it dynamic
133
+ data: JSON.stringify(toMongoDbExtendedJSON({ ...submissionValues, generatedPdfBlobName })),
134
+ ...(isPublic ? { private: false } : { version: 1 }),
135
+ }
136
+
137
+ const endpoint = isPublic ? `/api/site/${formKey}` : `/api/formdata/${formId}`
138
+ const res = await client.post(endpoint, reqData)
139
+
140
+ if (res.status === 200) onCreateSuccess(res.data)
141
+ } catch (err: any) {
142
+ if (err?.errorFields) {
143
+ const firstErrorField = Array.isArray(err.errorFields) && err.errorFields.length > 0 && err.errorFields[0]
144
+ const labels = firstErrorField
145
+ ? (t(
146
+ err.errorFields
147
+ .filter((f: { name?: string[] }) => Array.isArray(f.name) && f.name.length === 1)
148
+ .map((f: { name: string[] }) => ({ key: f.name[0], type: TranslationTextTypeEnum.Label })),
149
+ ) as string[])
150
+ : []
151
+
152
+ warning({
153
+ message: 'Please fill out all the required fields!',
154
+ description: labels.length > 5 ? `${labels.length} required fields are missing.` : labels.join(', '),
88
155
  })
89
- .catch((err) => {
90
- const firstErrorField = Array.isArray(err?.errorFields) && err.errorFields.length > 0 && err.errorFields[0]
91
- const labels = firstErrorField
92
- ? (t(
93
- err.errorFields
94
- .filter((f: { name?: string[] }) => Array.isArray(f.name) && f.name.length === 1)
95
- .map((f: { name: string[] }) => ({ key: f.name[0], type: TranslationTextTypeEnum.Label })),
96
- ) as string[])
97
- : []
98
-
99
- warning({
100
- message: 'Please fill out all the required fields!',
101
- description: labels.length > 5 ? `${labels.length} required fields are missing.` : labels.join(', '),
102
- })
103
156
 
104
- const firstFieldName =
105
- Array.isArray(firstErrorField?.name) && firstErrorField.name.length > 0 && firstErrorField?.name[0]
157
+ const firstFieldName =
158
+ Array.isArray(firstErrorField?.name) && firstErrorField.name.length > 0 && firstErrorField?.name[0]
106
159
 
107
- if (!firstFieldName) return
160
+ if (!firstFieldName) return
161
+
162
+ const element = document.getElementById(firstFieldName)
163
+ if (element) element.scrollIntoView({ behavior: 'smooth', block: 'start' })
164
+ return
165
+ }
108
166
 
109
- const element = document.getElementById(firstFieldName)
110
- if (element) element.scrollIntoView({ behavior: 'smooth', block: 'start' })
111
- })
112
- } catch (err) {
113
167
  onCreateError()
114
168
  } finally {
115
169
  onCreateFinal()
@@ -125,10 +179,17 @@ export const useCreateDataWithPdfActions = ({
125
179
  formTemplateReports,
126
180
  submissionTemplateReportConfig,
127
181
  isPublic,
182
+ isUserForm,
128
183
  baseServerUrl,
129
184
  companyKey,
130
185
  navigate,
131
186
  errorModal,
187
+ setDataLoadingType,
188
+ onCreateSuccess,
189
+ onCreateError,
190
+ onCreateFinal,
191
+ t,
192
+ warning,
132
193
  ],
133
194
  )
134
195
 
@@ -44,7 +44,7 @@ function LayoutRenderer_CurrencyField({
44
44
  )
45
45
 
46
46
  return (
47
- <LayoutRenderer_FieldElement formRef={formRef} elementKey={elementData.key} formId={formContext.formId}>
47
+ <LayoutRenderer_FieldElement formRef={formRef} elementKey={elementData.key} formId={formContext.formId} formContext={formContext}>
48
48
  {() => ({
49
49
  ...props,
50
50
  label,
@@ -9,6 +9,7 @@ import { findMaxAndMinValues } from '../../../../functions'
9
9
  import { VALIDATION_CURRENT_DATE_IDENTIFIER } from '../../../../constants'
10
10
  import dayjs from 'dayjs'
11
11
  import { useTranslation } from '../../../common/custom-hooks/use-translation.hook/hook'
12
+ import useGetCurrentBreakpoint from '../../../common/custom-hooks/use-window-width.hook'
12
13
 
13
14
  function LayoutRenderer_PickerField({ formContext, formItem, elementData, isDisabled }: ILayoutRenderer_PickerField) {
14
15
  const { t } = useTranslation(formContext.formId)
@@ -32,10 +33,15 @@ function LayoutRenderer_PickerField({ formContext, formItem, elementData, isDisa
32
33
  ? [placeholder1, placeholder2]
33
34
  : placeholder1
34
35
 
35
- let { maxValue, minValue } = useMemo(() => findMaxAndMinValues(elementData.validations), [elementData.validations])
36
+ const currentBreakpoint = useGetCurrentBreakpoint()
37
+ let { maxValue, minValue } = findMaxAndMinValues(elementData.validations, {
38
+ fieldValues: (formContext.formRef?.getFieldsValue(true) ?? {}) as Record<string, any>,
39
+ formDataId: formContext.formDataId,
40
+ currentBreakpoint,
41
+ })
36
42
 
37
43
  return (
38
- <LayoutRenderer_FieldElement formRef={formContext.formRef} elementKey={elementData.key} formId={formContext.formId}>
44
+ <LayoutRenderer_FieldElement formRef={formContext.formRef} elementKey={elementData.key} formId={formContext.formId} formContext={formContext}>
39
45
  {() => ({
40
46
  ...props,
41
47
  label,
@@ -65,3 +71,4 @@ type ILayoutRenderer_PickerField = {
65
71
  elementData: IPickerElement
66
72
  } & IElementBaseProps
67
73
 
74
+