form-craft-package 1.11.9-dev.0 → 1.11.10

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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(xargs grep:*)"
5
+ ]
6
+ }
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "form-craft-package",
3
- "version": "1.11.9-dev.0",
3
+ "version": "1.11.10",
4
4
  "main": "index.ts",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -139,8 +139,12 @@ export const useSendNotificationAction = ({
139
139
  [formTemplateReports, formId, formDataId, companyKey],
140
140
  )
141
141
 
142
- const onSendNotification = useCallback(
143
- async (notifActionProps: IButtonProps_SendNotification, newFormDataId?: string) => {
142
+ const onSendNotification = useCallback(
143
+ async (
144
+ notifActionProps: IButtonProps_SendNotification,
145
+ newFormDataId?: string,
146
+ extraAttachments: IEmail_Attachment[] = [],
147
+ ) => {
144
148
  const { notificationId } = notifActionProps
145
149
 
146
150
  const { joins = [], notifications } = formNotifications
@@ -160,13 +164,14 @@ export const useSendNotificationAction = ({
160
164
 
161
165
  const hasAttachments = Array.isArray(formNotif.attachments) && formNotif.attachments.length > 0
162
166
 
163
- let formTemplateReportAttachments: IEmail_Attachment[] = []
164
- if (hasAttachments) {
165
- setDataLoadingType?.(FormLoadingModalTypeEnum.GeneratingReport)
166
- formTemplateReportAttachments = await handleTemplateReport(formNotif.attachments!, targetFormDataId)
167
- }
168
-
169
- setDataLoadingType?.(FormLoadingModalTypeEnum.SendingNotification)
167
+ let formTemplateReportAttachments: IEmail_Attachment[] = []
168
+ if (hasAttachments) {
169
+ setDataLoadingType?.(FormLoadingModalTypeEnum.GeneratingReport)
170
+ formTemplateReportAttachments = await handleTemplateReport(formNotif.attachments!, targetFormDataId)
171
+ }
172
+ const additionalEmailAttachments = [...formTemplateReportAttachments, ...extraAttachments]
173
+
174
+ setDataLoadingType?.(FormLoadingModalTypeEnum.SendingNotification)
170
175
 
171
176
  try {
172
177
  const notifConfigRes = await client.get(`/api/notificationconfig/${notificationId}/data`)
@@ -175,12 +180,12 @@ export const useSendNotificationAction = ({
175
180
  const notificationRequests = await buildNotificationRequests({
176
181
  notificationId: formNotif.id,
177
182
  notificationConfig: notifConfigRes.data.data,
178
- formNotification: formNotif,
179
- replacementData: formDataRes.data,
180
- formId,
181
- fileBaseUrl,
182
- additionalEmailAttachments: formTemplateReportAttachments,
183
- })
183
+ formNotification: formNotif,
184
+ replacementData: formDataRes.data,
185
+ formId,
186
+ fileBaseUrl,
187
+ additionalEmailAttachments,
188
+ })
184
189
 
185
190
  if (!notificationRequests.length) {
186
191
  onFinal()
@@ -224,13 +224,14 @@ function LayoutRenderer_Gallery({
224
224
  <Empty description={emptyDescription || 'No pictures uploaded'} />
225
225
  )}
226
226
  </Form.Item>
227
- <GalleryUploadModal
228
- isOpen={isUploadModalOpen}
229
- formContext={formContext}
230
- formItem={formItem}
231
- elementKey={elementKey}
232
- textConditions={textConditions}
233
- isDisabled={isDisabled}
227
+ <GalleryUploadModal
228
+ isOpen={isUploadModalOpen}
229
+ formContext={formContext}
230
+ formItem={formItem}
231
+ elementProps={elementProps}
232
+ elementKey={elementKey}
233
+ textConditions={textConditions}
234
+ isDisabled={isDisabled}
234
235
  onDiscardSuccess={() => setIsUploadModalOpen(false)}
235
236
  onSaveSuccess={(uploadedBlobNames) => {
236
237
  formRef?.setFieldValue(formItem.path, [
@@ -1,40 +1,56 @@
1
- import client from '../../../../../api/client'
2
- import { isNewFormDataPage, resolveConditionalText } from '../../../../../functions'
3
- import { saveFile } from '../../../../../functions/forms/form'
4
- import { TranslationTextSubTypeEnum, TranslationTextTypeEnum } from '../../../../../enums'
5
- import { RcFile, UploadFile, UploadProps } from 'antd/es/upload'
6
- import { Form, Modal, Spin, Upload } from 'antd'
7
- import { useCallback, useEffect, useMemo, useState } from 'react'
8
- import { FaUpload } from 'react-icons/fa6'
9
- import { Button_FillerPortal } from '../../../../common/button'
10
- import { useNotification, useTranslation } from '../../../../common/custom-hooks'
11
- import useGetCurrentBreakpoint from '../../../../common/custom-hooks/use-window-width.hook'
12
- import { IElementBaseProps } from '..'
13
- import { IFormContext } from '../../1-row'
14
-
15
- export default function GalleryUploadModal({
16
- isOpen,
17
- formContext,
18
- formItem,
19
- elementKey,
20
- textConditions,
21
- onDiscardSuccess,
22
- onSaveSuccess,
23
- }: {
24
- isOpen: boolean
25
- formContext: IFormContext
26
- onDiscardSuccess: () => void
27
- onSaveSuccess: (blobNames: string[]) => void
28
- } & IElementBaseProps) {
1
+ import client from '../../../../../api/client'
2
+ import { isNewFormDataPage, resolveConditionalText } from '../../../../../functions'
3
+ import { saveFile } from '../../../../../functions/forms/form'
4
+ import {
5
+ ButtonActionCategoryEnum,
6
+ EmailAttachmentTypeEnum,
7
+ TranslationTextSubTypeEnum,
8
+ TranslationTextTypeEnum,
9
+ } from '../../../../../enums'
10
+ import { RcFile, UploadFile, UploadProps } from 'antd/es/upload'
11
+ import { Form, Modal, Spin, Upload } from 'antd'
12
+ import { useCallback, useEffect, useMemo, useState } from 'react'
13
+ import { FaUpload } from 'react-icons/fa6'
14
+ import { useSendNotificationAction } from '../1-dynamic-button/use-send-notification.hook'
15
+ import { Button_FillerPortal } from '../../../../common/button'
16
+ import { useNotification, useTranslation } from '../../../../common/custom-hooks'
17
+ import useGetCurrentBreakpoint from '../../../../common/custom-hooks/use-window-width.hook'
18
+ import { IElementBaseProps } from '..'
19
+ import { IFormContext } from '../../1-row'
20
+ import { IEmail_Attachment, IGalleryElementProps } from '../../../../../types'
21
+
22
+ export default function GalleryUploadModal({
23
+ isOpen,
24
+ formContext,
25
+ formItem,
26
+ elementProps,
27
+ elementKey,
28
+ textConditions,
29
+ onDiscardSuccess,
30
+ onSaveSuccess,
31
+ }: {
32
+ isOpen: boolean
33
+ formContext: IFormContext
34
+ elementProps: IGalleryElementProps
35
+ onDiscardSuccess: () => void
36
+ onSaveSuccess: (blobNames: string[]) => void
37
+ } & IElementBaseProps) {
29
38
  const { formRef, formDataId, companyKey, formId } = formContext
30
39
  const { t } = useTranslation(formId)
31
40
  const currentBreakpoint = useGetCurrentBreakpoint()
32
41
  const { warningModal } = useNotification()
33
42
 
34
43
  const [uploadedFiles, setUploadedFiles] = useState<UploadFile[]>([])
35
- const [isUploadLoading, setIsUploadLoading] = useState(false)
36
- const [isSaving, setIsSaving] = useState(false)
37
- const [isDiscarding, setIsDiscarding] = useState(false)
44
+ const [isUploadLoading, setIsUploadLoading] = useState(false)
45
+ const [isSaving, setIsSaving] = useState(false)
46
+ const [isDiscarding, setIsDiscarding] = useState(false)
47
+ const [isSendingNotification, setIsSendingNotification] = useState(false)
48
+ const onSendNotification = useSendNotificationAction({
49
+ ...formContext,
50
+ onSuccess: () => {},
51
+ onError: () => {},
52
+ onFinal: () => {},
53
+ })
38
54
 
39
55
  const allValues = Form.useWatch([], { form: formRef, preserve: true })
40
56
 
@@ -123,11 +139,11 @@ export default function GalleryUploadModal({
123
139
  }
124
140
  }, [onDiscardSuccess, uploadedBlobNames])
125
141
 
126
- const saveUploadedFiles = useCallback(async () => {
127
- if (!formId || !formDataId || isNewFormDataPage(formDataId)) return
128
-
129
- setIsSaving(true)
130
- try {
142
+ const saveUploadedFiles = useCallback(async () => {
143
+ if (!formId || !formDataId || isNewFormDataPage(formDataId)) return
144
+
145
+ setIsSaving(true)
146
+ try {
131
147
  const formDataRes = await client.get(`/api/formdata/${formId}/${formDataId}`)
132
148
  const parsedData = JSON.parse(formDataRes.data.data)
133
149
  const fieldPath = Array.isArray(formItem.path) ? formItem.path : [formItem.path]
@@ -140,20 +156,65 @@ export default function GalleryUploadModal({
140
156
  ...(Array.isArray(existingBlobNames) ? existingBlobNames : []),
141
157
  ...uploadedBlobNames,
142
158
  ]
143
- const res = await client.put(`/api/formdata/${formId}/${formDataId}`, {
144
- name: formDataRes.data.name,
145
- version: formDataRes.data.version,
146
- private: formDataRes.data.private,
147
- data: JSON.stringify(parsedData),
148
- })
149
- if (res.status === 200) {
150
- setUploadedFiles([])
151
- onSaveSuccess(uploadedBlobNames)
152
- }
153
- } finally {
154
- setIsSaving(false)
155
- }
156
- }, [formDataId, formId, formItem.path, onSaveSuccess, uploadedBlobNames])
159
+ const res = await client.put(`/api/formdata/${formId}/${formDataId}`, {
160
+ name: formDataRes.data.name,
161
+ version: formDataRes.data.version,
162
+ private: formDataRes.data.private,
163
+ data: JSON.stringify(parsedData),
164
+ })
165
+ if (res.status === 200) {
166
+ const shouldSendNotification = elementProps.sendNotification && !!elementProps.notificationId
167
+ const savedBlobNames = [...uploadedBlobNames]
168
+
169
+ if (shouldSendNotification) {
170
+ const extraAttachments: IEmail_Attachment[] = uploadedFiles
171
+ .map((file) => {
172
+ const blobName =
173
+ typeof file.response === 'object' && file.response
174
+ ? (file.response as { blobName?: string }).blobName
175
+ : undefined
176
+ if (!blobName) return null
177
+
178
+ return {
179
+ blobName,
180
+ fileName: file.name,
181
+ type: EmailAttachmentTypeEnum.Image,
182
+ }
183
+ })
184
+ .filter((attachment): attachment is IEmail_Attachment => !!attachment)
185
+
186
+ setIsSendingNotification(true)
187
+ try {
188
+ await onSendNotification(
189
+ {
190
+ category: ButtonActionCategoryEnum.SendNotification,
191
+ notificationId: elementProps.notificationId!,
192
+ },
193
+ formDataId,
194
+ extraAttachments,
195
+ )
196
+ } finally {
197
+ setIsSendingNotification(false)
198
+ }
199
+ }
200
+
201
+ setUploadedFiles([])
202
+ onSaveSuccess(savedBlobNames)
203
+ }
204
+ } finally {
205
+ setIsSaving(false)
206
+ }
207
+ }, [
208
+ elementProps.notificationId,
209
+ elementProps.sendNotification,
210
+ formDataId,
211
+ formId,
212
+ formItem.path,
213
+ onSaveSuccess,
214
+ onSendNotification,
215
+ uploadedFiles,
216
+ uploadedBlobNames,
217
+ ])
157
218
 
158
219
  return (
159
220
  <Modal
@@ -164,24 +225,29 @@ export default function GalleryUploadModal({
164
225
  title={title || 'Upload pictures'}
165
226
  footer={
166
227
  <div className="flex justify-between">
167
- <Button_FillerPortal outline disabled={isUploadLoading} loading={isDiscarding} onClick={discardUploadedFiles}>
168
- {discardText || 'Discard & Close'}
169
- </Button_FillerPortal>
170
- <Button_FillerPortal
171
- primary
172
- disabled={isUploadLoading || isDiscarding}
173
- loading={isSaving}
174
- onClick={saveUploadedFiles}
175
- >
176
- {saveText || 'Save Pictures'}
177
- </Button_FillerPortal>
178
- </div>
179
- }
180
- >
181
- <Spin spinning={isUploadLoading}>
182
- <Upload.Dragger {...uploadProps} fileList={uploadedFiles}>
183
- <div className="flex flex-col items-center">
184
- <FaUpload size={24} className="text-primary" />
228
+ <Button_FillerPortal
229
+ outline
230
+ disabled={isUploadLoading || isSendingNotification}
231
+ loading={isDiscarding}
232
+ onClick={discardUploadedFiles}
233
+ >
234
+ {discardText || 'Discard & Close'}
235
+ </Button_FillerPortal>
236
+ <Button_FillerPortal
237
+ primary
238
+ disabled={isUploadLoading || isDiscarding || isSendingNotification}
239
+ loading={isSaving || isSendingNotification}
240
+ onClick={saveUploadedFiles}
241
+ >
242
+ {saveText || 'Save Pictures'}
243
+ </Button_FillerPortal>
244
+ </div>
245
+ }
246
+ >
247
+ <Spin spinning={isUploadLoading || isSendingNotification}>
248
+ <Upload.Dragger {...uploadProps} fileList={uploadedFiles}>
249
+ <div className="flex flex-col items-center">
250
+ <FaUpload size={24} className="text-primary" />
185
251
  <span className="font-semibold mt-2 text-secondary">
186
252
  {text || 'Click or drag image files to this area'}
187
253
  </span>
@@ -186,12 +186,14 @@ export interface IGalleryElement extends BaseFormLayoutElement {
186
186
  elementType: ElementTypeEnum.Gallery
187
187
  props: IGalleryElementProps
188
188
  }
189
- export interface IGalleryElementProps {
190
- hasNoLabel?: boolean
191
- grid?: Partial<Record<DeviceBreakpointEnum, IGalleryElementGridConfig | null>>
192
- uploadButtonConditions?: IFormLayoutElementConditions
193
- deleteButtonConditions?: IFormLayoutElementConditions
194
- }
189
+ export interface IGalleryElementProps {
190
+ hasNoLabel?: boolean
191
+ grid?: Partial<Record<DeviceBreakpointEnum, IGalleryElementGridConfig | null>>
192
+ uploadButtonConditions?: IFormLayoutElementConditions
193
+ deleteButtonConditions?: IFormLayoutElementConditions
194
+ sendNotification?: boolean
195
+ notificationId?: number
196
+ }
195
197
  export interface IGalleryElementGridConfig {
196
198
  count?: number | null
197
199
  row?: number | null