form-craft-package 1.1.2 → 1.1.3

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "form-craft-package",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "main": "index.ts",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -1,7 +1,7 @@
1
1
  import { useState, useEffect } from 'react'
2
2
  import { useParams } from 'react-router-dom'
3
- import { LOCAL_STORAGE_KEYS_ENUM } from '../../../constants'
4
3
  import { IDynamicForm } from '../../../types'
4
+ import { LOCAL_STORAGE_KEYS_ENUM } from '../../../enums'
5
5
 
6
6
  export const useFindDynamiForm = () => {
7
7
  const { formName } = useParams<{ formName: string }>()
@@ -9,6 +9,7 @@ import { DynamicFormButtonRender, ICustomFunctionCall } from '../layout-renderer
9
9
  import FormDataListSkeleton_Details from '../../common/loading-skeletons/details'
10
10
  import { useLocation } from 'react-router-dom'
11
11
  import { queryParamsToObject } from '../../../functions'
12
+ import { FormPreservedItemKeys } from '../../../enums'
12
13
 
13
14
  export default function FormDataDetailsComponent({
14
15
  isPublic,
@@ -28,7 +29,7 @@ export default function FormDataDetailsComponent({
28
29
  // this is for converting the screen to PDF
29
30
  if (isPublic && location.search) {
30
31
  const formValues = queryParamsToObject(location.search)
31
- formDataRef.setFieldsValue(formValues)
32
+ formDataRef.setFieldsValue({ ...formValues, [FormPreservedItemKeys.IsGeneratingPDF]: true })
32
33
  }
33
34
  }, [isPublic, location, formDataRef])
34
35
 
@@ -66,10 +67,11 @@ export default function FormDataDetailsComponent({
66
67
  if (res.status === 200) {
67
68
  const parsedData: IFormSchema | null = parseJSON(res.data.data)
68
69
  if (parsedData) {
70
+ console.log({parsedData})
69
71
  const { layout, migrationRules, convertScreenToPdf = false } = parsedData.detailsConfig
70
72
 
71
73
  if (isPublic) {
72
- formDataRef.setFieldValue('convertScreenToPdf', convertScreenToPdf)
74
+ formDataRef.setFieldValue(FormPreservedItemKeys.ConvertScreenToPDF, convertScreenToPdf)
73
75
  setLoadings((c) => ({ ...c, data: false }))
74
76
  } else fetchFormData(formId, migrationRules)
75
77
  setLayout(layout)
@@ -3,15 +3,16 @@ import { useLocation, useNavigate } from 'react-router-dom'
3
3
  import { Form, FormInstance } from 'antd'
4
4
  import { getButtonRenderProps } from '../../../../functions/get-element-props'
5
5
  import { stringifyJSON } from '../../../../functions/json-handlers'
6
- import { ButtonActionCategoryEnum, FormLoadingModalTypeEnum } from '../../../../enums'
6
+ import { ButtonActionCategoryEnum, FormLoadingModalTypeEnum, FormPreservedItemKeys } from '../../../../enums'
7
7
  import { IDataRender_ButtonProps, IFormLayoutElementConditions } from '../../../../types'
8
8
  import { NEW_FORM_DATA_IDENTIFIER } from '../../../../constants'
9
9
  import { Button_FillerPortal } from '../../../common/button'
10
- import { extractDynamicFormHref, objectToQueryParams } from '../../../../functions'
10
+ import { base64ToBlob, extractDynamicFormHref, objectToQueryParams } from '../../../../functions'
11
11
  import { useNotification } from '../../../common/custom-hooks/use-notification.hook'
12
12
  import client from '../../../../functions/axios-handler'
13
13
  import { useLazyModalOpener } from '../../../common/custom-hooks/use-lazy-modal-opener.hook'
14
14
  import WarningIcon from '../../../common/warning-icon'
15
+ import { saveFile } from '../../../../functions/form'
15
16
 
16
17
  const FormDataLoadingIndicatorModal = lazy(() => import('../../../modals/form-data-loading.modal'))
17
18
 
@@ -34,9 +35,12 @@ export const DynamicFormButtonRender = memo(
34
35
  const [dataLoadingType, setDataLoadingType] = useState<FormLoadingModalTypeEnum | undefined>()
35
36
 
36
37
  const formValues = Form.useWatch([], { form: formRef, preserve: true })
37
- const formId = Form.useWatch('formId', { form: formRef, preserve: true }) // for public use
38
- const formKey = Form.useWatch('formKey', { form: formRef, preserve: true }) // for public use
39
- const convertScreenToPdf = Form.useWatch('convertScreenToPdf', { form: formRef, preserve: true }) // for public use
38
+ const formId = Form.useWatch(FormPreservedItemKeys.FormId, { form: formRef, preserve: true }) // for public use
39
+ const formKey = Form.useWatch(FormPreservedItemKeys.FormKey, { form: formRef, preserve: true }) // for public use
40
+ const convertScreenToPdf = Form.useWatch(FormPreservedItemKeys.ConvertScreenToPDF, {
41
+ form: formRef,
42
+ preserve: true,
43
+ }) // for public use
40
44
 
41
45
  const baseDynamicUrl = useMemo(() => extractDynamicFormHref(location.pathname), [location.pathname])
42
46
 
@@ -133,7 +137,7 @@ export const DynamicFormButtonRender = memo(
133
137
  if (isPublic) reqData.private = true // TODO: figure out what this is
134
138
  else reqData.version = 1
135
139
 
136
- const endpoint = isPublic ? `/api/formdata/${formId}` : `/api/site/${formKey}`
140
+ const endpoint = isPublic ? `/api/site/${formKey}` : `/api/formdata/${formId}`
137
141
 
138
142
  client
139
143
  .post(endpoint, reqData)
@@ -156,13 +160,21 @@ export const DynamicFormButtonRender = memo(
156
160
  const generatePdfProof = useCallback(() => {
157
161
  formRef?.validateFields().then((values) => {
158
162
  const queryParams = objectToQueryParams(values)
163
+ console.log(queryParams)
159
164
  const fullUrl = `${location.pathname}?${queryParams}`
160
165
  console.log(fullUrl)
161
- // TODO: call api
162
- const generatedPdfBlobName = ''
163
- onCreateNewData(generatedPdfBlobName)
166
+ const blobName = 'abc'
167
+ client
168
+ .post(`/api/attachment/pdf/${formKey}/${fullUrl}/${blobName}`)
169
+ .then((res) => {
170
+ if (res.status < 300) {
171
+ console.log(res.data)
172
+ onCreateNewData(res.data)
173
+ }
174
+ })
175
+ .catch(() => error({ message: 'Error occured while generating PDF!' }))
164
176
  })
165
- }, [formRef, location.pathname])
177
+ }, [formRef, location.pathname, formKey])
166
178
 
167
179
  const onSaveExistingData = useCallback(() => {
168
180
  formRef!.validateFields().then((values) => {
@@ -191,7 +203,7 @@ export const DynamicFormButtonRender = memo(
191
203
  })
192
204
  }, [formRef, formId, formDataId])
193
205
 
194
- const onButtonClick = useCallback(() => {
206
+ const onButtonClick = useCallback(async () => {
195
207
  switch (btnProps.category) {
196
208
  case ButtonActionCategoryEnum.CreateNewData:
197
209
  navigate(`${baseDynamicUrl}/${NEW_FORM_DATA_IDENTIFIER}`)
@@ -214,6 +226,16 @@ export const DynamicFormButtonRender = memo(
214
226
  break
215
227
  case ButtonActionCategoryEnum.SaveDataChanges:
216
228
  if (formRef) {
229
+ const signatureField = formRef.getFieldValue(FormPreservedItemKeys.HasSignature)
230
+ if (!!signatureField) {
231
+ setDataLoadingType(FormLoadingModalTypeEnum.GeneratingPdf)
232
+
233
+ const signatureBase64 = formRef.getFieldValue(signatureField)
234
+ const blobName = await saveFile(base64ToBlob(signatureBase64), 'signature')
235
+
236
+ if (!!blobName) formRef.setFieldValue(signatureField, blobName)
237
+ }
238
+
217
239
  if (formDataId === NEW_FORM_DATA_IDENTIFIER) {
218
240
  if (convertScreenToPdf) generatePdfProof()
219
241
  else onCreateNewData()
@@ -2,10 +2,11 @@ import { Form, FormInstance } from 'antd'
2
2
  import { useCallback, useState } from 'react'
3
3
  import ReCAPTCHA from 'react-google-recaptcha'
4
4
  import client from '../../../../functions/axios-handler'
5
+ import { FormPreservedItemKeys } from '../../../../enums'
5
6
 
6
7
  export default function LayoutRenderer_ReCaptcha({ formRef, fieldKey, elementProps }: ILayoutRenderer_RichEditor) {
7
8
  const [tokenVerificationFailed, setTokenVerificationFailed] = useState(false)
8
- const formKey = Form.useWatch('formKey', { form: formRef, preserve: true })
9
+ const formKey = Form.useWatch(FormPreservedItemKeys.FormKey, { form: formRef, preserve: true })
9
10
 
10
11
  const verifyReCaptcha = useCallback(
11
12
  (token: string | null) => {
@@ -1,71 +1,21 @@
1
1
  import { Form, FormInstance } from 'antd'
2
- import { useCallback, useRef, useState } from 'react'
2
+ import { useRef } from 'react'
3
3
  import SignatureCanvas from 'react-signature-canvas'
4
- import { Button_FillerPortal } from '../../../common/button'
5
- import client from '../../../../functions/axios-handler'
6
- import { base64ToBlob } from '../../../../functions'
7
4
  import { NEW_FORM_DATA_IDENTIFIER } from '../../../../constants'
5
+ import { FormPreservedItemKeys } from '../../../../enums'
8
6
 
9
7
  export default function LayoutRenderer_Signature({ formRef, fieldKey, elementProps }: ILayoutRenderer_Signature) {
10
- const [loading, setLoading] = useState(false)
11
8
  const sigCanvasRef = useRef<SignatureCanvas>(null)
12
9
  const savedSignatureBlobName = Form.useWatch(fieldKey, formRef)
13
- const formDataId = Form.useWatch('formDataId', { form: formRef, preserve: true })
14
- const baseServerUrl = Form.useWatch('baseServerUrl', { form: formRef, preserve: true })
15
- const companyKey = Form.useWatch('companyKey', { form: formRef, preserve: true })
16
-
17
- const saveSignature = useCallback(
18
- (signatureBase64: string) => {
19
- setLoading(true)
20
- const formData = new FormData()
21
- formData.append('file', base64ToBlob(signatureBase64), 'signature.jpg')
22
- client
23
- .post('/api/attachment', formData)
24
- .then((res) => {
25
- if (res.status < 300 && res.data) formRef.setFieldValue(fieldKey, res.data)
26
- })
27
- .finally(() => setLoading(false))
28
- },
29
- [fieldKey],
30
- )
31
-
32
- const deleteSavedSignature = useCallback((blobName: string) => {
33
- setLoading(true)
34
- client
35
- .delete(`/api/attachment/${blobName}`)
36
- .then((res) => {
37
- if (res.status < 300) {
38
- formRef.setFieldValue(fieldKey, null)
39
- sigCanvasRef.current?.clear()
40
- }
41
- })
42
- .finally(() => setLoading(false))
43
- }, [])
10
+ const formDataId = Form.useWatch(FormPreservedItemKeys.FormDataId, { form: formRef, preserve: true })
11
+ const baseServerUrl = Form.useWatch(FormPreservedItemKeys.BaseServerUrl, { form: formRef, preserve: true })
12
+ const companyKey = Form.useWatch(FormPreservedItemKeys.CompanyKey, { form: formRef, preserve: true })
13
+ const isGeneratingPdf = Form.useWatch(FormPreservedItemKeys.IsGeneratingPDF, { form: formRef, preserve: true })
44
14
 
45
15
  return (
46
- <Form.Item
47
- name={fieldKey}
48
- label={
49
- <>
50
- <span>{elementProps.hasNoLabel ? '' : elementProps.label}</span>
51
- {formDataId === NEW_FORM_DATA_IDENTIFIER && (
52
- <Button_FillerPortal
53
- link
54
- loading={loading}
55
- onClick={() => {
56
- if (savedSignatureBlobName) deleteSavedSignature(savedSignatureBlobName)
57
- else sigCanvasRef.current?.clear()
58
- }}
59
- >
60
- <span className="underline">Clear field</span>
61
- </Button_FillerPortal>
62
- )}
63
- </>
64
- }
65
- labelAlign="left"
66
- >
67
- {formDataId !== NEW_FORM_DATA_IDENTIFIER ? (
68
- <div className="h-[300px] rounded-md">
16
+ <Form.Item name={fieldKey} label={elementProps.hasNoLabel ? '' : elementProps.label} labelAlign="left">
17
+ {formDataId !== NEW_FORM_DATA_IDENTIFIER || isGeneratingPdf ? (
18
+ <div className="h-[300px] rounded-md border-2 border-[#f0f0f0]">
69
19
  <img alt="signature" src={`${baseServerUrl}/api/attachment/${companyKey}/${savedSignatureBlobName}`} />
70
20
  </div>
71
21
  ) : (
@@ -78,7 +28,9 @@ export default function LayoutRenderer_Signature({ formRef, fieldKey, elementPro
78
28
  }}
79
29
  onEnd={() => {
80
30
  const sigBase64 = sigCanvasRef.current?.toDataURL()
81
- if (sigBase64) saveSignature(sigBase64)
31
+ if (sigBase64)
32
+ formRef.setFieldsValue({ [fieldKey]: sigBase64, [FormPreservedItemKeys.HasSignature]: fieldKey })
33
+ // saveSignature(sigBase64)
82
34
  }}
83
35
  />
84
36
  )}
@@ -6,6 +6,7 @@ import { FaFile, FaUpload } from 'react-icons/fa6'
6
6
  import { IFileUploadElementRules } from '../../../../types'
7
7
  import { useNotification } from '../../../common/custom-hooks'
8
8
  import { FaTrashAlt } from 'react-icons/fa'
9
+ import { saveFile } from '../../../../functions/form'
9
10
 
10
11
  export default function LayoutRenderer_FileUpload({
11
12
  formRef,
@@ -17,21 +18,6 @@ export default function LayoutRenderer_FileUpload({
17
18
  const [loading, setLoading] = useState(false)
18
19
  const savedSignatureBlobName = Form.useWatch(fieldKey, formRef)
19
20
 
20
- const saveFile = useCallback(
21
- (file: any) => {
22
- setLoading(true)
23
- const formData = new FormData()
24
- formData.append('file', file.originFileObj, file.name)
25
- client
26
- .post('/api/attachment', formData)
27
- .then((res) => {
28
- if (res.status < 300 && res.data) formRef.setFieldValue(fieldKey, res.data)
29
- })
30
- .finally(() => setLoading(false))
31
- },
32
- [fieldKey],
33
- )
34
-
35
21
  const deleteSavedFile = useCallback((blobName: string) => {
36
22
  setLoading(true)
37
23
  client
@@ -48,8 +34,13 @@ export default function LayoutRenderer_FileUpload({
48
34
  customRequest: ({ file, onSuccess }: any): void => {
49
35
  setTimeout(() => onSuccess('ok', file), 100)
50
36
  },
51
- onChange: (fileInfo: any) => {
52
- if (fileInfo.file.status === 'done') saveFile(fileInfo.file)
37
+ onChange: async (fileInfo: any) => {
38
+ if (fileInfo.file.status === 'done') {
39
+ setLoading(true)
40
+ const blobName = await saveFile(fileInfo.file.originFileObj, fileInfo.file.name)
41
+ if (blobName) formRef.setFieldValue(fieldKey, blobName)
42
+ setLoading(false)
43
+ }
53
44
  },
54
45
  }
55
46
 
package/src/constants.ts CHANGED
@@ -10,6 +10,3 @@ export const DEFAULT_FLEX_CONFIG = {
10
10
  Item: { flexBasis: '0', flexGrow: 1, display: CSSLayoutType.Flex, flexDirection: FlexDirection.Col, gap: '10px' },
11
11
  }
12
12
  export const NEW_FORM_DATA_IDENTIFIER = 'new'
13
- export enum LOCAL_STORAGE_KEYS_ENUM {
14
- DynamicForms = '38be231fe41c169037ed04c267ebe070',
15
- }
package/src/enums.ts CHANGED
@@ -1,3 +1,6 @@
1
+ export enum LOCAL_STORAGE_KEYS_ENUM {
2
+ DynamicForms = '38be231fe41c169037ed04c267ebe070',
3
+ }
1
4
  export enum ElementTypeEnum {
2
5
  ShortInput = 'Short Input',
3
6
  LongInput = 'Long Input',
@@ -163,6 +166,7 @@ export enum ResponsivenessDeviceEnum {
163
166
  Mobile = 'xs',
164
167
  }
165
168
  export enum FormLoadingModalTypeEnum {
169
+ GeneratingPdf,
166
170
  SavingChanges,
167
171
  ErrorOccured,
168
172
  }
@@ -181,4 +185,14 @@ export enum FileTypeEnum {
181
185
  EXCEL = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
182
186
  CSV = 'text/csv',
183
187
  DOCX = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
184
- }
188
+ }
189
+ export enum FormPreservedItemKeys {
190
+ FormId = 'formId',
191
+ FormKey = 'formKey',
192
+ FormDataId = 'formDataId',
193
+ BaseServerUrl = 'baseServerUrl',
194
+ CompanyKey = 'companyKey',
195
+ ConvertScreenToPDF = 'convertScreenToPdf',
196
+ IsGeneratingPDF = 'isGeneratingPdf',
197
+ HasSignature = 'hasSignature',
198
+ }
@@ -0,0 +1,15 @@
1
+ import client from './axios-handler'
2
+
3
+ export const saveFile = async (file: any, fileName: string): Promise<string | null> => {
4
+ try {
5
+ const formData = new FormData()
6
+ formData.append('file', file, fileName)
7
+ const response = await client.post('/api/attachment', formData)
8
+ if (response.status < 300) return response.data
9
+
10
+ return null
11
+ } catch (error: any) {
12
+ console.error(error.response)
13
+ return null
14
+ }
15
+ }