@pega/react-sdk-overrides 0.23.26 → 0.23.27

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 (238) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +17 -0
  3. package/SECURITY.md +10 -0
  4. package/lib/designSystemExtension/AlertBanner/AlertBanner.tsx +39 -0
  5. package/lib/designSystemExtension/AlertBanner/index.tsx +1 -0
  6. package/lib/designSystemExtension/Banner/Banner.tsx +21 -7
  7. package/lib/designSystemExtension/CaseSummaryFields/CaseSummaryFields.css +0 -1
  8. package/lib/designSystemExtension/CaseSummaryFields/CaseSummaryFields.tsx +36 -26
  9. package/lib/designSystemExtension/DetailsFields/DetailsFields.tsx +21 -28
  10. package/lib/designSystemExtension/DetailsFields/index.tsx +1 -1
  11. package/lib/designSystemExtension/FieldGroup/FieldGroup.tsx +50 -18
  12. package/lib/designSystemExtension/FieldGroupList/FieldGroupList.tsx +13 -12
  13. package/lib/designSystemExtension/FieldValueList/FieldValueList.tsx +18 -27
  14. package/lib/designSystemExtension/Operator/Operator.tsx +106 -87
  15. package/lib/designSystemExtension/Pulse/Pulse.tsx +21 -19
  16. package/lib/designSystemExtension/RichTextEditor/RichTextEditor.tsx +122 -0
  17. package/lib/designSystemExtension/RichTextEditor/index.tsx +1 -0
  18. package/lib/designSystemExtension/WssQuickCreate/WssQuickCreate.tsx +21 -12
  19. package/lib/field/AutoComplete/AutoComplete.tsx +33 -16
  20. package/lib/field/AutoComplete/config-ext.json +2 -3
  21. package/lib/field/CancelAlert/CancelAlert.tsx +21 -15
  22. package/lib/field/CancelAlert/index.tsx +1 -1
  23. package/lib/field/Checkbox/Checkbox.tsx +29 -19
  24. package/lib/field/Checkbox/config-ext.json +2 -3
  25. package/lib/field/Currency/Currency.tsx +27 -38
  26. package/lib/field/Currency/config-ext.json +2 -3
  27. package/lib/field/Currency/currency-utils.ts +10 -18
  28. package/lib/field/Date/Date.tsx +33 -15
  29. package/lib/field/Date/config-ext.json +2 -3
  30. package/lib/field/DateTime/DateTime.tsx +22 -11
  31. package/lib/field/DateTime/config-ext.json +1 -2
  32. package/lib/field/Decimal/Decimal.tsx +64 -17
  33. package/lib/field/Decimal/config-ext.json +1 -2
  34. package/lib/field/Decimal/index.tsx +1 -1
  35. package/lib/field/Dropdown/Dropdown.tsx +154 -18
  36. package/lib/field/Dropdown/config-ext.json +1 -2
  37. package/lib/field/Email/Email.tsx +16 -7
  38. package/lib/field/Email/config-ext.json +1 -2
  39. package/lib/field/Email/index.tsx +1 -1
  40. package/lib/field/Group/Group.tsx +37 -0
  41. package/lib/field/Group/config-ext.json +7 -0
  42. package/lib/field/Group/index.tsx +1 -0
  43. package/lib/field/Integer/Integer.tsx +15 -6
  44. package/lib/field/Integer/config-ext.json +1 -2
  45. package/lib/field/Percentage/Percentage.tsx +14 -6
  46. package/lib/field/Percentage/config-ext.json +1 -2
  47. package/lib/field/Phone/Phone.tsx +17 -7
  48. package/lib/field/Phone/index.tsx +1 -1
  49. package/lib/field/RadioButtons/RadioButtons.tsx +55 -24
  50. package/lib/field/RadioButtons/config-ext.json +1 -2
  51. package/lib/field/RichText/RichText.tsx +96 -0
  52. package/lib/field/RichText/index.tsx +1 -0
  53. package/lib/field/ScalarList/ScalarList.tsx +63 -0
  54. package/lib/field/ScalarList/config-ext.json +7 -0
  55. package/lib/field/ScalarList/index.tsx +1 -0
  56. package/lib/field/SemanticLink/SemanticLink.tsx +26 -25
  57. package/lib/field/SemanticLink/config-ext.json +1 -2
  58. package/lib/field/SemanticLink/utils.ts +8 -10
  59. package/lib/field/TextArea/TextArea.tsx +15 -5
  60. package/lib/field/TextArea/config-ext.json +1 -2
  61. package/lib/field/TextContent/TextContent.tsx +9 -2
  62. package/lib/field/TextContent/config-ext.json +1 -2
  63. package/lib/field/TextInput/TextInput.tsx +41 -10
  64. package/lib/field/TextInput/config-ext.json +1 -2
  65. package/lib/field/TextInput/index.tsx +1 -1
  66. package/lib/field/Time/Time.tsx +21 -18
  67. package/lib/field/Time/config-ext.json +1 -2
  68. package/lib/field/URL/URL.tsx +23 -6
  69. package/lib/field/URL/config-ext.json +1 -2
  70. package/lib/field/URL/index.tsx +1 -1
  71. package/lib/field/UserReference/UserReference.tsx +52 -58
  72. package/lib/field/UserReference/UserReferenceUtils.ts +2 -2
  73. package/lib/field/UserReference/config-ext.json +1 -2
  74. package/lib/helpers/{attachmentHelpers.js → attachmentHelpers.ts} +16 -11
  75. package/lib/helpers/case-utils.tsx +99 -0
  76. package/lib/helpers/common-utils.ts +8 -0
  77. package/lib/helpers/data_page.ts +3 -6
  78. package/lib/helpers/date-format-utils.ts +29 -19
  79. package/lib/helpers/{event-utils.js → event-utils.ts} +4 -4
  80. package/lib/helpers/{field-group-utils.js → field-group-utils.ts} +9 -10
  81. package/lib/helpers/formatters/Boolean.ts +21 -0
  82. package/lib/helpers/formatters/{Currency.js → Currency.ts} +22 -27
  83. package/lib/helpers/formatters/CurrencyMap.ts +915 -0
  84. package/lib/helpers/formatters/{Date.js → Date.ts} +20 -26
  85. package/lib/helpers/formatters/{common.js → common.ts} +3 -4
  86. package/lib/helpers/formatters/{index.js → index.ts} +22 -22
  87. package/lib/helpers/{reactContextHelpers.js → reactContextHelpers.ts} +2 -2
  88. package/lib/helpers/simpleTableHelpers.ts +65 -85
  89. package/lib/helpers/state-utils.tsx +43 -0
  90. package/lib/helpers/template-utils.ts +4 -8
  91. package/lib/helpers/utils.ts +16 -8
  92. package/lib/helpers/versionHelpers.ts +1 -5
  93. package/lib/infra/ActionButtons/ActionButtons.tsx +46 -42
  94. package/lib/infra/ActionButtons/index.tsx +1 -1
  95. package/lib/infra/Assignment/Assignment.tsx +99 -84
  96. package/lib/infra/Assignment/index.tsx +1 -1
  97. package/lib/infra/AssignmentCard/AssignmentCard.tsx +19 -26
  98. package/lib/infra/AssignmentCard/index.tsx +1 -1
  99. package/lib/infra/Containers/FlowContainer/FlowContainer.tsx +98 -232
  100. package/lib/infra/Containers/FlowContainer/helpers.ts +138 -0
  101. package/lib/infra/Containers/FlowContainer/index.tsx +1 -1
  102. package/lib/infra/Containers/ModalViewContainer/ListViewActionButtons/ListViewActionButtons.tsx +66 -0
  103. package/lib/infra/Containers/ModalViewContainer/ListViewActionButtons/index.tsx +1 -0
  104. package/lib/infra/Containers/ModalViewContainer/ModalViewContainer.tsx +105 -70
  105. package/lib/infra/Containers/ModalViewContainer/index.tsx +1 -1
  106. package/lib/infra/Containers/SimpleView/SimpleView.tsx +48 -0
  107. package/lib/infra/Containers/SimpleView/helper.ts +125 -0
  108. package/lib/infra/Containers/SimpleView/index.tsx +1 -0
  109. package/lib/infra/Containers/ViewContainer/ViewContainer.tsx +49 -64
  110. package/lib/infra/Containers/helpers.ts +6 -0
  111. package/lib/infra/DashboardFilter/DashboardFilter.tsx +26 -51
  112. package/lib/infra/DashboardFilter/filterUtils.tsx +12 -40
  113. package/lib/infra/DeferLoad/DeferLoad.tsx +22 -31
  114. package/lib/infra/DeferLoad/index.tsx +1 -1
  115. package/lib/infra/ErrorBoundary/ErrorBoundary.tsx +25 -38
  116. package/lib/infra/MultiStep/MultiStep.css +11 -15
  117. package/lib/infra/MultiStep/MultiStep.tsx +180 -216
  118. package/lib/infra/MultiStep/index.tsx +1 -1
  119. package/lib/infra/NavBar/NavBar.css +103 -105
  120. package/lib/infra/NavBar/NavBar.tsx +28 -43
  121. package/lib/infra/Reference/Reference.tsx +16 -22
  122. package/lib/infra/Region/Region.tsx +9 -9
  123. package/lib/infra/RootContainer/RootContainer.tsx +82 -125
  124. package/lib/infra/RootContainer/index.tsx +1 -1
  125. package/lib/infra/Stages/Stages.tsx +38 -39
  126. package/lib/infra/VerticalTabs/LeftAlignVerticalTabs/LeftAlignVerticalTabs.tsx +17 -10
  127. package/lib/infra/VerticalTabs/VerticalTabs/VerticalTabs.tsx +29 -36
  128. package/lib/infra/View/View.tsx +32 -63
  129. package/lib/template/AppShell/AppShell.css +22 -23
  130. package/lib/template/AppShell/AppShell.tsx +51 -69
  131. package/lib/template/BannerPage/BannerPage.tsx +26 -33
  132. package/lib/template/CaseSummary/CaseSummary.tsx +23 -18
  133. package/lib/template/CaseSummary/config-ext.json +1 -2
  134. package/lib/template/CaseView/CaseView.tsx +122 -114
  135. package/lib/template/CaseView/config-ext.json +1 -2
  136. package/lib/template/CaseViewActionsMenu/CaseViewActionsMenu.tsx +46 -35
  137. package/lib/template/Confirmation/Confirmation.tsx +25 -53
  138. package/lib/template/Confirmation/config-ext.json +1 -2
  139. package/lib/template/DataReference/DataReference.tsx +112 -140
  140. package/lib/template/DataReference/config-ext.json +1 -2
  141. package/lib/template/DefaultForm/DefaultForm.css +7 -3
  142. package/lib/template/DefaultForm/DefaultForm.tsx +26 -20
  143. package/lib/template/DefaultForm/config-ext.json +1 -2
  144. package/lib/template/DefaultForm/utils/index.ts +33 -0
  145. package/lib/template/Details/Details/Details.tsx +24 -28
  146. package/lib/template/Details/DetailsSubTabs/DetailsSubTabs.tsx +15 -22
  147. package/lib/template/Details/DetailsSubTabs/config-ext.json +1 -2
  148. package/lib/template/Details/DetailsThreeColumn/DetailsThreeColumn.tsx +25 -29
  149. package/lib/template/Details/DetailsThreeColumn/config-ext.json +1 -2
  150. package/lib/template/Details/DetailsTwoColumn/DetailsTwoColumn.tsx +25 -29
  151. package/lib/template/Details/DetailsTwoColumn/config-ext.json +1 -2
  152. package/lib/template/Details/DetailsTwoColumn/index.tsx +1 -1
  153. package/lib/template/Details/DynamicTabs/DynamicTabs.tsx +79 -0
  154. package/lib/template/Details/DynamicTabs/config.json +36 -0
  155. package/lib/template/Details/DynamicTabs/index.tsx +1 -0
  156. package/lib/template/FieldGroupTemplate/FieldGroupTemplate.tsx +24 -34
  157. package/lib/template/InlineDashboard/InlineDashboard.tsx +16 -14
  158. package/lib/template/InlineDashboardPage/InlineDashboardPage.tsx +19 -21
  159. package/lib/template/ListPage/ListPage.tsx +12 -16
  160. package/lib/template/ListPage/config-ext.json +1 -2
  161. package/lib/template/ListView/{DefaultViewMeta.js → DefaultViewMeta.ts} +1 -3
  162. package/lib/template/ListView/ListView.tsx +245 -306
  163. package/lib/template/ListView/config-ext.json +1 -2
  164. package/lib/template/ListView/{hooks.js → hooks.ts} +24 -24
  165. package/lib/template/ListView/{utils.js → utils.ts} +202 -91
  166. package/lib/template/MultiReferenceReadOnly/MultiReferenceReadOnly.tsx +25 -30
  167. package/lib/template/NarrowWide/NarrowWide/NarrowWide.css +0 -2
  168. package/lib/template/NarrowWide/NarrowWide/NarrowWide.tsx +31 -29
  169. package/lib/template/NarrowWide/NarrowWideDetails/NarrowWideDetails.tsx +27 -31
  170. package/lib/template/NarrowWide/NarrowWideDetails/config-ext.json +1 -2
  171. package/lib/template/NarrowWide/NarrowWideForm/NarrowWideForm.css +0 -2
  172. package/lib/template/NarrowWide/NarrowWideForm/NarrowWideForm.tsx +17 -19
  173. package/lib/template/NarrowWide/NarrowWideForm/config-ext.json +1 -2
  174. package/lib/template/NarrowWide/NarrowWidePage/NarrowWidePage.tsx +16 -26
  175. package/lib/template/NarrowWide/NarrowWidePage/config-ext.json +1 -2
  176. package/lib/template/OneColumn/OneColumn/OneColumn.tsx +17 -17
  177. package/lib/template/OneColumn/OneColumn/config-ext.json +1 -2
  178. package/lib/template/OneColumn/OneColumnPage/OneColumnPage.tsx +9 -16
  179. package/lib/template/OneColumn/OneColumnPage/config-ext.json +1 -2
  180. package/lib/template/OneColumn/OneColumnTab/OneColumnTab.tsx +8 -14
  181. package/lib/template/OneColumn/OneColumnTab/config-ext.json +1 -2
  182. package/lib/template/PromotedFilters/PromotedFilters.css +1 -1
  183. package/lib/template/PromotedFilters/PromotedFilters.tsx +44 -34
  184. package/lib/template/SimpleTable/SimpleTable/SimpleTable.tsx +115 -14
  185. package/lib/template/SimpleTable/SimpleTable/config-ext.json +1 -2
  186. package/lib/template/SimpleTable/SimpleTableManual/SimpleTableManual.tsx +171 -100
  187. package/lib/template/SimpleTable/SimpleTableSelect/SimpleTableSelect.tsx +34 -40
  188. package/lib/template/SingleReferenceReadOnly/SingleReferenceReadOnly.tsx +45 -48
  189. package/lib/template/SubTabs/SubTabs.tsx +26 -45
  190. package/lib/template/SubTabs/config-ext.json +1 -2
  191. package/lib/template/SubTabs/tabUtils.ts +2 -7
  192. package/lib/template/TwoColumn/TwoColumn/TwoColumn.css +0 -1
  193. package/lib/template/TwoColumn/TwoColumn/TwoColumn.tsx +33 -36
  194. package/lib/template/TwoColumn/TwoColumn/config-ext.json +1 -2
  195. package/lib/template/TwoColumn/TwoColumnPage/TwoColumnPage.tsx +9 -16
  196. package/lib/template/TwoColumn/TwoColumnPage/config-ext.json +1 -2
  197. package/lib/template/TwoColumn/TwoColumnTab/TwoColumnTab.tsx +33 -33
  198. package/lib/template/TwoColumn/TwoColumnTab/config-ext.json +1 -2
  199. package/lib/template/WideNarrow/WideNarrow/WideNarrow.css +0 -2
  200. package/lib/template/WideNarrow/WideNarrow/WideNarrow.tsx +29 -27
  201. package/lib/template/WideNarrow/WideNarrowDetails/WideNarrowDetails.tsx +39 -33
  202. package/lib/template/WideNarrow/WideNarrowDetails/config-ext.json +1 -2
  203. package/lib/template/WideNarrow/WideNarrowForm/WideNarrowForm.css +0 -2
  204. package/lib/template/WideNarrow/WideNarrowForm/WideNarrowForm.tsx +16 -18
  205. package/lib/template/WideNarrow/WideNarrowForm/config-ext.json +1 -2
  206. package/lib/template/WideNarrow/WideNarrowPage/WideNarrowPage.tsx +15 -25
  207. package/lib/template/WideNarrow/WideNarrowPage/config-ext.json +1 -2
  208. package/lib/template/WideNarrow/WideNarrowPage/index.tsx +1 -1
  209. package/lib/template/WssNavBar/WssNavBar.tsx +20 -9
  210. package/lib/widget/AppAnnouncement/AppAnnouncement.tsx +34 -41
  211. package/lib/widget/AppAnnouncement/config-ext.json +1 -2
  212. package/lib/widget/Attachment/Attachment.css +75 -4
  213. package/lib/widget/Attachment/Attachment.tsx +370 -388
  214. package/lib/widget/Attachment/index.tsx +1 -1
  215. package/lib/widget/CaseHistory/CaseHistory.tsx +67 -67
  216. package/lib/widget/CaseHistory/config-ext.json +1 -2
  217. package/lib/widget/CaseHistory/index.tsx +1 -1
  218. package/lib/widget/FileUtility/ActionButtonsForFileUtil/ActionButtonsForFileUtil.tsx +19 -9
  219. package/lib/widget/FileUtility/FileUtility/FileUtility.css +2 -2
  220. package/lib/widget/FileUtility/FileUtility/FileUtility.tsx +324 -246
  221. package/lib/widget/FileUtility/FileUtility/config-ext.json +1 -2
  222. package/lib/widget/Followers/Followers.tsx +27 -25
  223. package/lib/widget/Followers/config-ext.json +1 -2
  224. package/lib/widget/QuickCreate/QuickCreate.tsx +24 -16
  225. package/lib/widget/SummaryItem/SummaryItem.css +9 -9
  226. package/lib/widget/SummaryItem/SummaryItem.tsx +62 -54
  227. package/lib/widget/SummaryItem/index.tsx +1 -1
  228. package/lib/widget/SummaryList/SummaryList.tsx +15 -4
  229. package/lib/widget/ToDo/ToDo.css +4 -4
  230. package/lib/widget/ToDo/ToDo.tsx +80 -116
  231. package/lib/widget/ToDo/config-ext.json +1 -2
  232. package/package.json +5 -2
  233. package/lib/helpers/auth.js +0 -483
  234. package/lib/helpers/authManager.js +0 -631
  235. package/lib/helpers/config_access.js +0 -268
  236. package/lib/helpers/formatters/Boolean.js +0 -38
  237. package/lib/helpers/formatters/CurrencyMap.js +0 -908
  238. package/lib/infra/Containers/FlowContainer/helpers.js +0 -147
@@ -1,42 +1,63 @@
1
1
  /* eslint-disable react/jsx-boolean-value */
2
+ /* eslint-disable react/no-array-index-key */
3
+ import { useState, useEffect, useCallback } from 'react';
4
+ import { CircularProgress, IconButton, Menu, MenuItem, Button } from '@material-ui/core';
5
+ import MoreVertIcon from '@material-ui/icons/MoreVert';
6
+ import download from 'downloadjs';
2
7
 
3
- import { Button } from '@material-ui/core';
4
- import React, { useState, useEffect } from 'react';
5
- import { buildFilePropsFromResponse, getIconFromFileType, validateMaxSize, getIconForAttachment } from '@pega/react-sdk-components/lib/components/helpers/attachmentHelpers';
6
- import './Attachment.css';
7
- import SummaryList from '@pega/react-sdk-components/lib/components/widget/SummaryList'
8
- import { CircularProgress } from "@material-ui/core";
9
- import download from "downloadjs";
8
+ import { buildFilePropsFromResponse, getIconFromFileType, validateMaxSize } from '@pega/react-sdk-components/lib/components/helpers/attachmentHelpers';
9
+ import { Utils } from '@pega/react-sdk-components/lib/components/helpers/utils';
10
+ import { isInfinity23OrHigher } from '@pega/react-sdk-components/lib/components/helpers/common-utils';
11
+ import { PConnFieldProps } from '@pega/react-sdk-components/lib/types/PConnProps';
10
12
 
11
- declare const PCore: any;
13
+ import './Attachment.css';
12
14
 
13
- function getCurrentAttachmentsList(context) {
14
- return PCore.getStoreValue('.attachmentsList', 'context_data', context) || [];
15
+ interface AttachmentProps extends Omit<PConnFieldProps, 'value'> {
16
+ // If any, enter additional props that only exist on this component
17
+ value: any;
18
+ allowMultiple: string;
19
+ extensions: string;
15
20
  }
16
21
 
17
- export default function Attachment(props) {
18
- const {value, getPConnect, label} = props;
22
+ const getAttachmentKey = (name = '') => (name ? `attachmentsList.${name}` : 'attachmentsList');
23
+
24
+ const getCurrentAttachmentsList = (key, context) => {
25
+ return PCore.getStoreValue(`.${key}`, 'context_data', context) || [];
26
+ };
27
+
28
+ const updateAttachmentState = (pConn, key, attachments) => {
29
+ PCore.getStateUtils().updateState(pConn.getContextName(), key, attachments, {
30
+ pageReference: 'context_data',
31
+ isArrayDeepMerge: false
32
+ });
33
+ };
34
+
35
+ export default function Attachment(props: AttachmentProps) {
36
+ const { value, getPConnect, label, validatemessage, allowMultiple, extensions, displayMode } = props;
19
37
  /* this is a temporary fix because required is supposed to be passed as a boolean and NOT as a string */
20
38
  let { required, disabled } = props;
21
- [required, disabled] = [required, disabled].map(
22
- prop => prop === true || (typeof prop === 'string' && prop === 'true')
23
- );
24
- let arFileList$: Array<any> = [];
39
+ [required, disabled] = [required, disabled].map(prop => prop === true || (typeof prop === 'string' && prop === 'true'));
25
40
  const pConn = getPConnect();
26
41
  const caseID = PCore.getStoreValue('.pyID', 'caseInfo.content', pConn.getContextName());
27
- let fileTemp: any = {};
28
42
 
29
43
  let categoryName = '';
30
44
  if (value && value.pyCategoryName) {
31
45
  categoryName = value.pyCategoryName;
32
46
  }
33
-
34
- let valueRef = pConn.getStateProps().value;
47
+ const deleteIcon = Utils.getImageSrc('trash', Utils.getSDKStaticConentUrl());
48
+ const srcImg = Utils.getImageSrc('document-doc', Utils.getSDKStaticConentUrl());
49
+ let valueRef = (pConn.getStateProps() as any).value;
35
50
  valueRef = valueRef.indexOf('.') === 0 ? valueRef.substring(1) : valueRef;
36
- const [file, setFile] = useState(fileTemp);
51
+ const [anchorEl, setAnchorEl] = useState(null);
52
+ const open = Boolean(anchorEl);
53
+ const [files, setFiles] = useState<any[]>(() =>
54
+ value?.pxResults && +value.pyCount > 0 ? value.pxResults.map(f => buildFilePropsFromResponse(f)) : []
55
+ );
56
+ const [filesWithError, setFilesWithError] = useState<any[]>([]);
57
+ const [toggleUploadBegin, setToggleUploadBegin] = useState(false);
37
58
 
38
59
  const resetAttachmentStoredState = () => {
39
- PCore.getStateUtils().updateState(pConn.getContextName(), 'attachmentsList', undefined, {
60
+ PCore.getStateUtils().updateState(pConn.getContextName(), getAttachmentKey(isInfinity23OrHigher() ? valueRef : ''), undefined, {
40
61
  pageReference: 'context_data',
41
62
  isArrayDeepMerge: false
42
63
  });
@@ -47,426 +68,387 @@ export default function Attachment(props) {
47
68
  download(atob(data), fileData);
48
69
  };
49
70
 
50
- function _downloadFileFromList(fileObj: any) {
71
+ const downloadFile = (fileObj: any) => {
72
+ setAnchorEl(null);
51
73
  PCore.getAttachmentUtils()
74
+ // @ts-ignore - 3rd parameter "responseEncoding" should be optional
52
75
  .downloadAttachment(fileObj.pzInsKey, pConn.getContextName())
53
- .then((content) => {
54
- const extension = fileObj.pyAttachName.split(".").pop();
76
+ .then((content: any) => {
77
+ const extension = fileObj.pyAttachName.split('.').pop();
55
78
  fileDownload(content.data, fileObj.pyFileName, extension);
56
79
  })
57
80
  .catch(() => {});
58
- }
59
-
60
- function setNewFiles(arFiles) {
61
- let index = 0;
62
- for (const item of arFiles) {
63
- if (!validateMaxSize(item, 5)) {
64
- item.error = true;
65
- item.meta = "File is too big. Max allowed size is 5MB.";
66
- }
67
- item.mimeType = item.type;
68
- item.icon = getIconFromFileType(item.type);
69
- item.ID = `${new Date().getTime()}I${index}`;
70
- index+=1;
71
- }
72
- return arFiles;
73
- }
74
-
75
- function getFiles(arFiles: Array<any>) {
76
- return setNewFiles(arFiles);
77
- }
81
+ };
78
82
 
79
- function getNewListUtilityItemProps({
80
- att,
81
- cancelFile,
82
- downloadFile,
83
- deleteFile,
84
- removeFile
85
- }) {
86
- let actions;
87
- if (att.progress && att.progress !== 100) {
88
- actions = [
89
- {
90
- id: `Cancel-${att.ID}`,
91
- text: "Cancel",
92
- icon: "times",
93
- onClick: cancelFile
94
- }
95
- ];
96
- } else if (att.links) {
97
- const isFile = att.type === "FILE";
98
- const ID = att.ID.replace(/\s/gi, "");
99
- const actionsMap = new Map([
100
- [
101
- "download",
102
- {
103
- id: `download-${ID}`,
104
- text: isFile ? "Download" : "Open",
105
- icon: isFile ? "download" : "open",
106
- onClick: downloadFile
83
+ const deleteFile = useCallback(
84
+ file => {
85
+ setAnchorEl(null);
86
+ let attachmentsList: any[] = [];
87
+ let currentAttachmentList = getCurrentAttachmentsList(getAttachmentKey(valueRef), pConn.getContextName());
88
+
89
+ // If file to be deleted is the one added in previous stage i.e. for which a file instance is created in server
90
+ // no need to filter currentAttachmentList as we will get another entry of file in redux with delete & label
91
+ // eslint-disable-next-line no-unsafe-optional-chaining
92
+ if (value && value?.pxResults && +value?.pyCount > 0 && file.responseProps && file?.responseProps?.pzInsKey !== 'temp') {
93
+ const updatedAttachments = files.map(f => {
94
+ if (f.responseProps && f.responseProps.pzInsKey === file.responseProps.pzInsKey) {
95
+ return { ...f, delete: true, label: valueRef };
107
96
  }
108
- ],
109
- [
110
- "delete",
111
- {
112
- id: `Delete-${ID}`,
113
- text: "Delete",
114
- icon: "trash",
115
- onClick: deleteFile
116
- }
117
- ]
118
- ]);
119
- actions = [];
120
- actionsMap.forEach((action, actionKey) => {
121
- if (att.links[actionKey]) {
122
- actions.push(action);
97
+ return f;
98
+ });
99
+
100
+ // updating the redux store to help form-handler in passing the data to delete the file from server
101
+ updateAttachmentState(pConn, getAttachmentKey(valueRef), [...updatedAttachments]);
102
+ setFiles(current => {
103
+ const newlyAddedFiles = current.filter(f => !!f.ID);
104
+ const filesPostDelete = current.filter(
105
+ f => f.responseProps?.pzInsKey !== 'temp' && f.responseProps?.pzInsKey !== file.responseProps?.pzInsKey
106
+ );
107
+ attachmentsList = [...filesPostDelete, ...newlyAddedFiles];
108
+ return attachmentsList;
109
+ });
110
+ } // if the file being deleted is the added in this stage i.e. whose data is not yet created in server
111
+ else {
112
+ // filter newly added files in this stage, later the updated current stage files will be added to redux once files state is updated in below setFiles()
113
+ currentAttachmentList = currentAttachmentList.filter(f => f.label !== valueRef);
114
+ setFiles(current => {
115
+ attachmentsList = current.filter(f => f.ID !== file.ID);
116
+ return attachmentsList;
117
+ });
118
+ updateAttachmentState(pConn, getAttachmentKey(valueRef), [...currentAttachmentList, ...attachmentsList]);
119
+ if (file.inProgress) {
120
+ // @ts-ignore - 3rd parameter "responseEncoding" should be optional
121
+ PCore.getAttachmentUtils().cancelRequest(file.ID, pConn.getContextName());
123
122
  }
123
+ }
124
+
125
+ setToggleUploadBegin(false);
126
+ setFilesWithError(prevFilesWithError => {
127
+ return prevFilesWithError.filter(f => f.ID !== file.ID);
124
128
  });
125
- } else if (att.error) {
126
- actions = [
127
- {
128
- id: `Remove-${att.ID}`,
129
- text: "Remove",
130
- icon: "trash",
131
- onClick: removeFile
129
+ },
130
+ [pConn, value, valueRef, filesWithError]
131
+ );
132
+
133
+ const onUploadProgress = () => {};
134
+
135
+ const errorHandler = (isFetchCanceled, attachedFile) => {
136
+ return error => {
137
+ if (!isFetchCanceled(error)) {
138
+ let uploadFailMsg = pConn.getLocalizedValue('Something went wrong', '', '');
139
+ if (error.response && error.response.data && error.response.data.errorDetails) {
140
+ uploadFailMsg = pConn.getLocalizedValue(error.response.data.errorDetails[0].localizedValue, '', '');
132
141
  }
133
- ];
134
- }
135
- return {
136
- id: att.ID,
137
- visual: {
138
- icon: getIconForAttachment(att),
139
- progress: att.progress === 100 ? undefined: att.progress,
140
- },
141
- primary: {
142
- type: att.type,
143
- name: att.error ? att.fileName : att.name,
144
- icon: "trash",
145
- click: removeFile,
146
- },
147
- secondary: {
148
- text: att.meta,
149
- error: att.error
150
- },
151
- actions
142
+ setFiles(current => {
143
+ return current.map(f => {
144
+ if (f.ID === attachedFile.ID) {
145
+ f.props.meta = uploadFailMsg;
146
+ f.props.error = true;
147
+ f.props.onDelete = () => deleteFile(f);
148
+ f.props.icon = getIconFromFileType(f.type);
149
+ f.props.name = pConn.getLocalizedValue('Unable to upload file', '', '');
150
+ f.inProgress = false;
151
+ const fieldName = (pConn.getStateProps() as any).value;
152
+ const context = pConn.getContextName();
153
+ // set errors to property to block submit even on errors in file upload
154
+ PCore.getMessageManager().addMessages({
155
+ // @ts-ignore
156
+ messages: [
157
+ {
158
+ type: 'error',
159
+ message: pConn.getLocalizedValue('Error with one or more files', '', '')
160
+ }
161
+ ],
162
+ property: fieldName,
163
+ pageReference: pConn.getPageReference(),
164
+ context
165
+ });
166
+ delete f.props.progress;
167
+ }
168
+ return f;
169
+ });
170
+ });
171
+ }
172
+ throw error;
152
173
  };
153
174
  };
154
175
 
155
- const onFileAdded = (event) => {
156
- const addedFile = event.target.files[0];
157
- setFile({
158
- props: {
159
- name: addedFile.name,
160
- icon: getIconFromFileType(addedFile.type),
161
- },
162
- inProgress: true
163
- });
164
- const arFiles$ = getFiles(event.target.files);
165
- const myFiles: any = Array.from(arFiles$);
166
-
167
- const onUploadProgress = () => {};
176
+ const validateFileExtension = (fileObj, allowedExtensions) => {
177
+ if (!allowedExtensions) {
178
+ return true;
179
+ }
180
+ const allowedExtensionList = allowedExtensions
181
+ .toLowerCase()
182
+ .split(',')
183
+ .map(item => item.replaceAll('.', '').trim());
184
+ const extension = fileObj.name.split('.').pop().toLowerCase();
185
+ return allowedExtensionList.includes(extension);
186
+ };
168
187
 
169
- const errorHandler = (isFetchCanceled) => {
170
- return (error) => {
171
- if (!isFetchCanceled(error)) {
172
- let uploadFailMsg = pConn.getLocalizedValue('Something went wrong');
173
- if (error.response && error.response.data && error.response.data.errorDetails) {
174
- uploadFailMsg = pConn.getLocalizedValue(error.response.data.errorDetails[0].localizedValue);
175
- }
176
- myFiles[0].meta = uploadFailMsg;
177
- myFiles[0].error = true;
178
- myFiles[0].fileName = pConn.getLocalizedValue('Unable to upload file');
179
- arFileList$ = myFiles.map((att) => {
180
- return getNewListUtilityItemProps({
181
- att,
182
- downloadFile: null,
183
- cancelFile: null,
184
- deleteFile: null,
185
- removeFile: null
186
- });
187
- });
188
- setFile((current) => {
189
- return {
190
- ...current,
191
- props: {
192
- ...current.props,
193
- arFileList$
194
- },
195
- inProgress: false,
196
- attachmentUploaded: true,
197
- showMenuIcon: false
198
- };
199
- });
200
- }
201
- throw error;
202
- };
203
- };
188
+ const clearFieldErrorMessages = () => {
189
+ const fieldName = (pConn.getStateProps() as any).value;
190
+ const context = pConn.getContextName();
191
+ // @ts-ignore
192
+ PCore.getMessageManager().clearMessages({
193
+ type: PCore.getConstants().MESSAGES.MESSAGES_TYPE_ERROR,
194
+ property: fieldName,
195
+ pageReference: pConn.getPageReference(),
196
+ context
197
+ });
198
+ };
204
199
 
205
- PCore.getAttachmentUtils()
206
- .uploadAttachment(
207
- myFiles[0],
208
- onUploadProgress,
209
- errorHandler,
210
- pConn.getContextName()
211
- )
212
- .then((fileRes) => {
213
- let reqObj;
214
- if (PCore.getPCoreVersion()?.includes('8.7')) {
215
- reqObj = {
216
- type: "File",
217
- attachmentFieldName: valueRef,
218
- category: categoryName,
219
- ID: fileRes.ID
220
- };
221
- pConn.attachmentsInfo = reqObj;
222
- } else {
223
- reqObj = {
224
- type: "File",
225
- label: valueRef,
226
- category: categoryName,
227
- handle: fileRes.ID,
228
- ID: fileRes.clientFileID
229
- };
230
- const currentAttachmentList = getCurrentAttachmentsList(pConn.getContextName()).filter(
231
- (f) => f.label !== valueRef
232
- );
233
- PCore.getStateUtils().updateState(
234
- pConn.getContextName(),
235
- 'attachmentsList',
236
- [...currentAttachmentList, reqObj],
237
- {
238
- pageReference: 'context_data',
239
- isArrayDeepMerge: false
240
- }
241
- );
200
+ const onFileAdded = event => {
201
+ let addedFiles = Array.from(event.target.files);
202
+ addedFiles = allowMultiple === 'true' ? addedFiles : [addedFiles[0]];
203
+ const maxAttachmentSize = PCore.getEnvironmentInfo().getMaxAttachmentSize() || '5';
204
+ const tempFilesToBeUploaded = [
205
+ ...addedFiles.map((f: any, index) => {
206
+ f.ID = `${new Date().getTime()}I${index}`;
207
+ f.inProgress = true;
208
+ f.props = {
209
+ type: f.type,
210
+ name: f.name,
211
+ icon: getIconFromFileType(f.type),
212
+ onDelete: () => deleteFile(f)
213
+ };
214
+ if (!validateMaxSize(f, maxAttachmentSize)) {
215
+ f.props.error = true;
216
+ f.props.meta = pConn.getLocalizedValue(`File is too big. Max allowed size is ${maxAttachmentSize}MB.`, '', '');
217
+ } else if (!validateFileExtension(f, extensions)) {
218
+ f.props.error = true;
219
+ f.props.meta = `${pConn.getLocalizedValue('File has invalid extension. Allowed extensions are:', '', '')} ${extensions.replaceAll(
220
+ '.',
221
+ ''
222
+ )}`;
242
223
  }
243
- const fieldName = pConn.getStateProps().value;
244
- const context = pConn.getContextName();
245
-
246
- PCore.getMessageManager().clearMessages({
247
- type: PCore.getConstants().MESSAGES.MESSAGES_TYPE_ERROR,
248
- property: fieldName,
249
- pageReference: pConn.getPageReference(),
250
- context
251
- });
252
- myFiles[0].meta = "Uploaded Successfully";
253
-
254
- arFileList$ = myFiles.map((att) => {
255
- return getNewListUtilityItemProps({
256
- att,
257
- downloadFile: null,
258
- cancelFile: null,
259
- deleteFile: null,
260
- removeFile: null
224
+ if (f.props.error) {
225
+ const fieldName = (pConn.getStateProps() as any).value;
226
+ const context = pConn.getContextName();
227
+ PCore.getMessageManager().addMessages({
228
+ // @ts-ignore
229
+ messages: [
230
+ {
231
+ type: 'error',
232
+ message: pConn.getLocalizedValue('Error with one or more files', '', '')
233
+ }
234
+ ],
235
+ property: fieldName,
236
+ pageReference: pConn.getPageReference(),
237
+ context
261
238
  });
262
- });
263
- setFile((current) => {
264
- return {
265
- ...current,
266
- props: {
267
- ...current.props,
268
- arFileList$
269
- },
270
- inProgress: false,
271
- attachmentUploaded: true,
272
- showMenuIcon: false
273
- };
274
- });
239
+ }
240
+ return f;
275
241
  })
276
-
277
- .catch(() => {
278
- // just catching the rethrown error at uploadAttachment
279
- // to handle Unhandled rejections
280
- });
242
+ ];
243
+ const tempFilesWithError = tempFilesToBeUploaded.filter(f => f.props.error);
244
+ if (tempFilesWithError.length > 0) {
245
+ setFilesWithError(tempFilesWithError);
246
+ }
247
+ setFiles(current => (allowMultiple !== 'true' ? [...tempFilesToBeUploaded] : [...current, ...tempFilesToBeUploaded]));
248
+ setToggleUploadBegin(true);
281
249
  };
282
250
 
283
- function _removeFileFromList(item: any, list) {
284
- const arFileList = file.props ? file.props.arFileList$ : list;
285
- const fileIndex = arFileList.findIndex(element => element?.id === item?.id);
286
- if (PCore.getPCoreVersion()?.includes('8.7')) {
287
- if (value) {
288
- pConn.attachmentsInfo = {
289
- type: "File",
290
- attachmentFieldName: valueRef,
291
- delete: true
292
- };
293
- }
294
- if (fileIndex > -1) { arFileList.splice(parseInt(fileIndex, 10), 1) };
295
- setFile((current) => {
296
- return {
297
- ...current,
298
- props: {
299
- ...current.props,
300
- arFileList
251
+ const uploadFiles = useCallback(() => {
252
+ const filesToBeUploaded = files
253
+ .filter(e => {
254
+ const isFileUploaded = e.props && e.props.progress === 100;
255
+ const fileHasError = e.props && e.props.error;
256
+ const isFileUploadedinLastStep = e.responseProps && e.responseProps.pzInsKey;
257
+ return !isFileUploaded && !fileHasError && !isFileUploadedinLastStep;
258
+ })
259
+ .map(f =>
260
+ window.PCore.getAttachmentUtils().uploadAttachment(
261
+ f,
262
+ () => {
263
+ onUploadProgress();
301
264
  },
302
- };
303
- });
304
- } else {
305
- const attachmentsList = [];
306
- const currentAttachmentList = getCurrentAttachmentsList(pConn.getContextName()).filter(
307
- (f) => f.label !== valueRef
308
- );
309
- if (value && value.pxResults && +value.pyCount > 0) {
310
- const deletedFile = {
311
- type: "File",
312
- label: valueRef,
313
- delete: true,
314
- responseProps: {
315
- pzInsKey: arFileList[fileIndex].id
265
+ isFetchCanceled => {
266
+ return errorHandler(isFetchCanceled, f);
316
267
  },
317
- };
318
- // updating the redux store to help form-handler in passing the data to delete the file from server
319
- PCore.getStateUtils().updateState(
320
- pConn.getContextName(),
321
- 'attachmentsList',
322
- [...currentAttachmentList, deletedFile],
323
- {
324
- pageReference: 'context_data',
325
- isArrayDeepMerge: false
326
- }
327
- );
328
- } else {
329
- PCore.getStateUtils().updateState(
330
- pConn.getContextName(),
331
- 'attachmentsList',
332
- [...currentAttachmentList, ...attachmentsList],
333
- {
334
- pageReference: 'context_data',
335
- isArrayDeepMerge: false
268
+ pConn.getContextName()
269
+ )
270
+ );
271
+ Promise.allSettled(filesToBeUploaded)
272
+ .then((fileResponses: any) => {
273
+ fileResponses = fileResponses.filter(fr => fr.status !== 'rejected'); // in case of deleting an in progress file, promise gets cancelled but still enters then block
274
+ if (fileResponses.length > 0) {
275
+ setFiles(current => {
276
+ const tempFilesUploaded = [...current];
277
+ tempFilesUploaded.forEach(f => {
278
+ const index = fileResponses.findIndex((fr: any) => fr.value.clientFileID === f.ID);
279
+ if (index >= 0) {
280
+ f.props.meta = pConn.getLocalizedValue('Uploaded successfully', '', '');
281
+ f.props.progress = 100;
282
+ f.inProgress = false;
283
+ f.handle = fileResponses[index].value.ID;
284
+ f.label = valueRef;
285
+ f.category = categoryName;
286
+ f.responseProps = {
287
+ pzInsKey: 'temp',
288
+ pyAttachName: f.props.name
289
+ };
290
+ }
291
+ });
292
+ return tempFilesUploaded;
293
+ });
294
+
295
+ if (filesWithError.length === 0) {
296
+ clearFieldErrorMessages();
336
297
  }
337
- );
338
- }
339
- if (fileIndex > -1) { arFileList.splice(parseInt(fileIndex, 10), 1) };
340
- setFile((current) => {
341
- return {
342
- ...current,
343
- props: {
344
- ...current.props,
345
- arFileList
346
- },
347
- };
298
+ }
299
+ setToggleUploadBegin(false);
300
+ })
301
+ .catch(error => {
302
+ // eslint-disable-next-line no-console
303
+ console.log(error);
304
+ setToggleUploadBegin(false);
348
305
  });
349
- }
350
- }
306
+ }, [files, filesWithError]);
351
307
 
352
308
  useEffect(() => {
353
- if (value && value.pxResults && +value.pyCount > 0) {
354
- fileTemp = buildFilePropsFromResponse(value.pxResults[0]);
355
-
356
- if (fileTemp.responseProps) {
357
- if (!pConn.attachmentsInfo) {
358
- pConn.attachmentsInfo = {
359
- type: "File",
360
- attachmentFieldName: valueRef,
361
- category: categoryName
362
- };
363
- }
309
+ if (toggleUploadBegin && files.length > 0) {
310
+ uploadFiles();
311
+ }
312
+ }, [toggleUploadBegin]);
364
313
 
365
- if (fileTemp.responseProps.pzInsKey && !fileTemp.responseProps.pzInsKey.includes("temp")) {
366
-
367
- fileTemp.props.type = fileTemp.responseProps.pyMimeFileExtension;
368
- fileTemp.props.mimeType = fileTemp.responseProps.pyMimeFileExtension;
369
- fileTemp.props.ID = fileTemp.responseProps.pzInsKey;
370
- // create the actions for the "more" menu on the attachment
371
- const arMenuList: Array<any> = [];
372
- let oMenu: any = {};
373
-
374
- oMenu.icon = "download";
375
- oMenu.text = "Download";
376
- oMenu.onClick = () => { _downloadFileFromList(value.pxResults[0])}
377
- arMenuList.push(oMenu);
378
- oMenu = {};
379
- oMenu.icon = "trash";
380
- oMenu.text = "Delete";
381
- oMenu.onClick = () => { _removeFileFromList(arFileList$[0], arFileList$)}
382
- arMenuList.push(oMenu);
383
-
384
- arFileList$.push(getNewListUtilityItemProps({
385
- att: fileTemp.props,
386
- downloadFile: null,
387
- cancelFile: null,
388
- deleteFile: null,
389
- removeFile: null
390
- }));
391
- arFileList$[0].actions = arMenuList;
392
-
393
- setFile((current) => {
394
- return {
395
- ...current,
396
- props: {
397
- ...current.props,
398
- arFileList$
399
- },
400
- inProgress: false,
401
- attachmentUploaded: true,
402
- showMenuIcon: true
403
- };
404
- });
405
- }
314
+ useEffect(() => {
315
+ if (files.length > 0 && displayMode !== 'DISPLAY_ONLY') {
316
+ const currentAttachmentList = getCurrentAttachmentsList(getAttachmentKey(valueRef), pConn.getContextName());
317
+ // block duplicate files to redux store when added 1 after another to prevent multiple duplicates being added to the case on submit
318
+ const tempFiles = files.filter(f => currentAttachmentList.findIndex(fr => fr.ID === f.ID) === -1 && !f.inProgress && f.responseProps);
406
319
 
407
- if (fileTemp) {
408
- const currentAttachmentList = getCurrentAttachmentsList(pConn.getContextName());
409
- const index = currentAttachmentList.findIndex(element => element.props.ID === fileTemp.props.ID);
410
- let tempFiles: any = [];
411
- if (index < 0) {
412
- tempFiles = [fileTemp];
413
- }
414
- PCore.getStateUtils().updateState(
415
- pConn.getContextName(),
416
- 'attachmentsList',
417
- [...currentAttachmentList, ...tempFiles],
418
- {
419
- pageReference: 'context_data',
420
- isArrayDeepMerge: false
421
- }
422
- );
423
- }
320
+ const updatedAttList = [...currentAttachmentList, ...tempFiles];
321
+ updateAttachmentState(pConn, getAttachmentKey(valueRef), updatedAttList);
424
322
  }
323
+ }, [files]);
324
+
325
+ useEffect(() => {
326
+ if (filesWithError.length === 0) {
327
+ clearFieldErrorMessages();
425
328
  }
426
- PCore.getPubSubUtils().subscribe(
427
- PCore.getConstants().PUB_SUB_EVENTS.CASE_EVENTS.ASSIGNMENT_SUBMISSION,
428
- resetAttachmentStoredState,
429
- caseID
430
- );
329
+ }, [filesWithError]);
330
+
331
+ useEffect(() => {
332
+ let tempUploadedFiles = getCurrentAttachmentsList(getAttachmentKey(valueRef), pConn.getContextName());
333
+ tempUploadedFiles = tempUploadedFiles.filter(f => f.label === valueRef);
334
+ setFiles(current => {
335
+ return [
336
+ ...current.map(f => {
337
+ return f.responseProps.pzInsKey && !f.responseProps.pzInsKey.includes('temp')
338
+ ? {
339
+ ...f,
340
+ props: {
341
+ ...f.props,
342
+ onDelete: () => deleteFile(f)
343
+ }
344
+ }
345
+ : { ...f };
346
+ }),
347
+ ...tempUploadedFiles
348
+ ];
349
+ });
350
+ PCore.getPubSubUtils().subscribe(PCore.getConstants().PUB_SUB_EVENTS.CASE_EVENTS.ASSIGNMENT_SUBMISSION, resetAttachmentStoredState, caseID);
431
351
  return () => {
432
352
  PCore.getPubSubUtils().unsubscribe(PCore.getConstants().PUB_SUB_EVENTS.CASE_EVENTS.ASSIGNMENT_SUBMISSION, caseID);
433
353
  };
434
354
  }, []);
435
355
 
436
- let content = (
437
- <div className='file-div'>
438
- {file.inProgress && (<div className="progress-div"><CircularProgress /></div>)}
439
- <div hidden={true} id="attachment-ID">{valueRef}</div>
356
+ const handleClick = event => {
357
+ setAnchorEl(event.currentTarget);
358
+ };
359
+
360
+ const handleClose = () => {
361
+ setAnchorEl(null);
362
+ };
363
+
364
+ const content = (
365
+ <div style={{ marginBottom: '8px' }}>
366
+ <div className={`${disabled ? 'file-disabled' : ''} ${validatemessage === '' ? 'file-div' : 'file-div-error'}`}>
367
+ <div hidden={true} id='attachment-ID'>
368
+ {valueRef}
369
+ </div>
440
370
  <label htmlFor={valueRef}>
441
371
  <input
442
372
  style={{ display: 'none' }}
443
373
  id={valueRef}
444
374
  name='upload-photo'
445
375
  type='file'
376
+ multiple={allowMultiple === 'true'}
446
377
  required={required}
378
+ disabled={disabled}
447
379
  onChange={onFileAdded}
448
380
  />
449
- <Button variant='outlined' color='primary' component="span">
450
- Upload file
381
+ <Button style={{ textTransform: 'none' }} variant='outlined' color='primary' component='span'>
382
+ {allowMultiple === 'true' ? 'Upload files' : 'Upload a file'}
451
383
  </Button>
452
384
  </label>
385
+ </div>
453
386
  </div>
454
387
  );
455
388
 
456
- if (file && file.attachmentUploaded && file.props.arFileList$ && file.props.arFileList$.length > 0) {
457
- content = (
458
- <div>
459
- {file.showMenuIcon && (<SummaryList arItems$={file.props.arFileList$} menuIconOverrideAction$={_removeFileFromList}></SummaryList>)}
460
- {!file.showMenuIcon && (<SummaryList menuIconOverride$='trash' arItems$={file.props.arFileList$} menuIconOverrideAction$={_removeFileFromList}></SummaryList>)}
461
- </div>
462
-
463
- );
464
- }
389
+ const fileDisplay = (
390
+ <div>
391
+ {files &&
392
+ files.length > 0 &&
393
+ files.map((item, index) => {
394
+ return (
395
+ <div key={index} className='psdk-utility-card'>
396
+ <div className='psdk-utility-card-icon'>
397
+ {!item.inProgress && <img className='psdk-utility-card-svg-icon' src={srcImg} />}
398
+ {item.inProgress && (
399
+ <div>
400
+ <CircularProgress />
401
+ </div>
402
+ )}
403
+ </div>
404
+ <div className='psdk-utility-card-main'>
405
+ <div className='psdk-utility-card-main-primary-label'>{item.props.name}</div>
406
+ {item.props.meta && <div style={{ color: item.props.error ? 'red' : undefined }}>{item.props.meta}</div>}
407
+ </div>
408
+ <div className='psdk-utility-action'>
409
+ {item.ID && (
410
+ <button type='button' className='psdk-utility-button' aria-label='Delete Attachment' onClick={() => deleteFile(item)}>
411
+ <img className='psdk-utility-card-action-svg-icon' src={deleteIcon} />
412
+ </button>
413
+ )}
414
+ {!item.ID && (
415
+ <div>
416
+ <IconButton
417
+ id='setting-button'
418
+ aria-controls={open ? 'file-menu' : undefined}
419
+ aria-expanded={open ? 'true' : undefined}
420
+ aria-haspopup='true'
421
+ onClick={handleClick}
422
+ >
423
+ <MoreVertIcon />
424
+ </IconButton>
425
+ <Menu style={{ marginTop: '3rem' }} id='file-menu' anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose}>
426
+ <MenuItem
427
+ style={{ fontSize: '14px' }}
428
+ key='download'
429
+ onClick={() => downloadFile(item.responseProps ? item.responseProps : {})}
430
+ >
431
+ Download
432
+ </MenuItem>
433
+ <MenuItem style={{ fontSize: '14px' }} key='delete' onClick={() => deleteFile(item)}>
434
+ Delete
435
+ </MenuItem>
436
+ </Menu>
437
+ </div>
438
+ )}
439
+ </div>
440
+ </div>
441
+ );
442
+ })}
443
+ </div>
444
+ );
465
445
 
466
446
  return (
467
447
  <div className='file-upload-container'>
468
448
  <span className={`label ${required ? 'file-label' : ''}`}>{label}</span>
469
- <section>{content}</section>
449
+ {((files.length === 0 && allowMultiple !== 'true') || allowMultiple === 'true') && <section>{content}</section>}
450
+ {validatemessage !== '' ? <span className='file-error'>{validatemessage}</span> : ''}
451
+ {files && files.length > 0 && <section>{fileDisplay}</section>}
470
452
  </div>
471
453
  );
472
454
  }