11/* eslint-disable react/jsx-boolean-value */
22/* eslint-disable react/no-array-index-key */
33/* eslint-disable no-nested-ternary */
4- import { useState , useEffect , useCallback } from 'react' ;
4+ import { useState , useEffect , useCallback , useMemo , useRef } from 'react' ;
55import { CircularProgress , IconButton , Menu , MenuItem , Button } from '@mui/material' ;
66import MoreVertIcon from '@mui/icons-material/MoreVert' ;
7- import download from 'downloadjs' ;
87
9- import { buildFilePropsFromResponse , getIconFromFileType , validateMaxSize } from '../../helpers/attachmentHelpers' ;
8+ import { getIconFromFileType , isFileUploadedToServer , useFileDownload , validateMaxSize } from '../../helpers/attachmentHelpers' ;
9+
1010import { Utils } from '../../helpers/utils' ;
1111import { PConnFieldProps } from '../../../types/PConnProps' ;
1212
@@ -19,7 +19,9 @@ interface AttachmentProps extends Omit<PConnFieldProps, 'value'> {
1919 extensions : string ;
2020}
2121
22- const getAttachmentKey = ( name = '' ) => ( name ? `attachmentsList.${ name } ` : 'attachmentsList' ) ;
22+ const getAttachmentKey = ( name , embeddedReference ) => {
23+ return `attachmentsList${ embeddedReference } .${ name } ` ;
24+ } ;
2325
2426const getCurrentAttachmentsList = ( key , context ) => {
2527 return PCore . getStoreValue ( `.${ key } ` , 'context_data' , context ) || [ ] ;
@@ -38,61 +40,65 @@ export default function Attachment(props: AttachmentProps) {
3840 let { required, disabled } = props ;
3941 [ required , disabled ] = [ required , disabled ] . map ( prop => prop === true || ( typeof prop === 'string' && prop === 'true' ) ) ;
4042 const pConn = getPConnect ( ) ;
43+
44+ const actionSequencer = useMemo ( ( ) => PCore . getActionsSequencer ( ) , [ ] ) ;
4145 const caseID = PCore . getStoreValue ( '.pyID' , 'caseInfo.content' , pConn . getContextName ( ) ) ;
4246 const localizedVal = PCore . getLocaleUtils ( ) . getLocaleValue ;
4347 const localeCategory = 'CosmosFields' ;
4448 const uploadMultipleFilesLabel = localizedVal ( 'file_upload_text_multiple' , localeCategory ) ;
4549 const uploadSingleFileLabel = localizedVal ( 'file_upload_text_one' , localeCategory ) ;
46- let categoryName = '' ;
47- if ( value && value . pyCategoryName ) {
48- categoryName = value . pyCategoryName ;
49- }
5050 const deleteIcon = Utils . getImageSrc ( 'trash' , Utils . getSDKStaticConentUrl ( ) ) ;
5151 const srcImg = Utils . getImageSrc ( 'document-doc' , Utils . getSDKStaticConentUrl ( ) ) ;
5252 let valueRef = ( pConn . getStateProps ( ) as any ) . value ;
5353 valueRef = valueRef . indexOf ( '.' ) === 0 ? valueRef . substring ( 1 ) : valueRef ;
5454 const [ anchorEl , setAnchorEl ] = useState ( null ) ;
5555 const open = Boolean ( anchorEl ) ;
56- const [ files , setFiles ] = useState < any [ ] > ( ( ) =>
57- value ?. pxResults && + value . pyCount > 0 ? value . pxResults . map ( f => buildFilePropsFromResponse ( f ) ) : [ ]
58- ) ;
56+
57+ const rawValue = pConn . getComponentConfig ( ) . value ;
58+ const isAttachmentAnnotationPresent = typeof rawValue === 'object' ? false : rawValue ?. includes ( '@ATTACHMENT' ) ;
59+ const { hasUploadedFiles, attachments, categoryName } = isAttachmentAnnotationPresent
60+ ? value
61+ : PCore . getAttachmentUtils ( ) . prepareAttachmentData ( value ) ;
62+
63+ const fileInputRef = useRef < HTMLInputElement > ( null ) ;
64+ const [ files , setFiles ] = useState < any [ ] > ( attachments ) ;
5965 const [ filesWithError , setFilesWithError ] = useState < any [ ] > ( [ ] ) ;
6066 const [ toggleUploadBegin , setToggleUploadBegin ] = useState ( false ) ;
6167
68+ const context = pConn . getContextName ( ) ;
69+ const onFileDownload = useFileDownload ( context ) ;
70+
71+ let embeddedProperty = pConn
72+ . getPageReference ( )
73+ . replace ( PCore . getConstants ( ) . CASE_INFO . CASE_INFO_CONTENT , '' )
74+ . replace ( PCore . getConstants ( ) . DATA_INFO . DATA_INFO_CONTENT , '' ) ;
75+
76+ if ( valueRef ?. indexOf ( '.' ) > 0 ) {
77+ embeddedProperty = valueRef . substring ( 0 , valueRef . indexOf ( '.' ) + 1 ) ;
78+ }
79+
6280 const resetAttachmentStoredState = ( ) => {
63- PCore . getStateUtils ( ) . updateState ( pConn . getContextName ( ) , getAttachmentKey ( valueRef ) , undefined , {
81+ PCore . getStateUtils ( ) . updateState ( pConn . getContextName ( ) , getAttachmentKey ( valueRef , embeddedProperty ) , undefined , {
6482 pageReference : 'context_data' ,
6583 isArrayDeepMerge : false
6684 } ) ;
6785 } ;
6886
69- const fileDownload = ( data , fileName , ext ) => {
70- const fileData = ext ? `${ fileName } .${ ext } ` : fileName ;
71- download ( atob ( data ) , fileData ) ;
72- } ;
73-
74- const downloadFile = ( fileObj : any ) => {
75- setAnchorEl ( null ) ;
76- PCore . getAttachmentUtils ( )
77- // @ts -ignore - 3rd parameter "responseEncoding" should be optional
78- . downloadAttachment ( fileObj . pzInsKey , pConn . getContextName ( ) )
79- . then ( ( content : any ) => {
80- const extension = fileObj . pyAttachName . split ( '.' ) . pop ( ) ;
81- fileDownload ( content . data , fileObj . pyFileName , extension ) ;
82- } )
83- . catch ( ( ) => { } ) ;
84- } ;
85-
8687 const deleteFile = useCallback (
8788 file => {
8889 setAnchorEl ( null ) ;
90+
91+ // reset the file input so that it will allow re-uploading the same file after deletion
92+ if ( fileInputRef . current ) {
93+ fileInputRef . current . value = '' ; // Reset the input
94+ }
95+
8996 let attachmentsList : any [ ] = [ ] ;
90- let currentAttachmentList = getCurrentAttachmentsList ( getAttachmentKey ( valueRef ) , pConn . getContextName ( ) ) ;
97+ let currentAttachmentList = getCurrentAttachmentsList ( getAttachmentKey ( valueRef , embeddedProperty ) , pConn . getContextName ( ) ) ;
9198
9299 // If file to be deleted is the one added in previous stage i.e. for which a file instance is created in server
93100 // no need to filter currentAttachmentList as we will get another entry of file in redux with delete & label
94- // eslint-disable-next-line no-unsafe-optional-chaining
95- if ( value && value ?. pxResults && + value ?. pyCount > 0 && file . responseProps && file ?. responseProps ?. pzInsKey !== 'temp' ) {
101+ if ( hasUploadedFiles && isFileUploadedToServer ( file ) ) {
96102 const updatedAttachments = files . map ( f => {
97103 if ( f . responseProps && f . responseProps . pzInsKey === file . responseProps . pzInsKey ) {
98104 return { ...f , delete : true , label : valueRef } ;
@@ -101,27 +107,26 @@ export default function Attachment(props: AttachmentProps) {
101107 } ) ;
102108
103109 // updating the redux store to help form-handler in passing the data to delete the file from server
104- updateAttachmentState ( pConn , getAttachmentKey ( valueRef ) , [ ...updatedAttachments ] ) ;
110+ updateAttachmentState ( pConn , getAttachmentKey ( valueRef , embeddedProperty ) , [ ...updatedAttachments ] ) ;
105111 setFiles ( current => {
106112 const newlyAddedFiles = current . filter ( f => ! ! f . ID ) ;
107- const filesPostDelete = current . filter (
108- f => f . responseProps ?. pzInsKey !== 'temp' && f . responseProps ?. pzInsKey !== file . responseProps ?. pzInsKey
109- ) ;
113+ const filesPostDelete = current . filter ( f => isFileUploadedToServer ( f ) && f . responseProps ?. ID !== file . responseProps ?. ID ) ;
110114 attachmentsList = [ ...filesPostDelete , ...newlyAddedFiles ] ;
111115 return attachmentsList ;
112116 } ) ;
113117 } // if the file being deleted is the added in this stage i.e. whose data is not yet created in server
114118 else {
115119 // 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()
116- currentAttachmentList = currentAttachmentList . filter ( f => f . label !== valueRef ) ;
117- setFiles ( current => {
118- attachmentsList = current . filter ( f => f . ID !== file . ID ) ;
119- return attachmentsList ;
120- } ) ;
121- updateAttachmentState ( pConn , getAttachmentKey ( valueRef ) , [ ...currentAttachmentList , ...attachmentsList ] ) ;
120+ currentAttachmentList = currentAttachmentList . filter ( f => ! f . props . error && ( f . delete || f . label !== valueRef ) ) ;
121+ setFiles ( current => current . filter ( f => f . ID !== file . ID ) ) ;
122+ updateAttachmentState ( pConn , getAttachmentKey ( valueRef , embeddedProperty ) , [ ...currentAttachmentList , ...attachmentsList ] ) ;
122123 if ( file . inProgress ) {
123124 // @ts -ignore - 3rd parameter "responseEncoding" should be optional
124125 PCore . getAttachmentUtils ( ) . cancelRequest ( file . ID , pConn . getContextName ( ) ) ;
126+ actionSequencer . deRegisterBlockingAction ( pConn . getContextName ( ) ) . catch ( error => {
127+ // eslint-disable-next-line no-console
128+ console . log ( error ) ;
129+ } ) ;
125130 }
126131 }
127132
@@ -130,7 +135,7 @@ export default function Attachment(props: AttachmentProps) {
130135 return prevFilesWithError . filter ( f => f . ID !== file . ID ) ;
131136 } ) ;
132137 } ,
133- [ pConn , value , valueRef , filesWithError ]
138+ [ valueRef , pConn , hasUploadedFiles , filesWithError , hasUploadedFiles , actionSequencer ]
134139 ) ;
135140
136141 const onUploadProgress = ( ) => { } ;
@@ -152,7 +157,6 @@ export default function Attachment(props: AttachmentProps) {
152157 f . props . name = pConn . getLocalizedValue ( 'Unable to upload file' , '' , '' ) ;
153158 f . inProgress = false ;
154159 const fieldName = ( pConn . getStateProps ( ) as any ) . value ;
155- const context = pConn . getContextName ( ) ;
156160 // set errors to property to block submit even on errors in file upload
157161 PCore . getMessageManager ( ) . addMessages ( {
158162 messages : [
@@ -189,7 +193,6 @@ export default function Attachment(props: AttachmentProps) {
189193
190194 const clearFieldErrorMessages = ( ) => {
191195 const fieldName = ( pConn . getStateProps ( ) as any ) . value ;
192- const context = pConn . getContextName ( ) ;
193196 PCore . getMessageManager ( ) . clearMessages ( {
194197 type : PCore . getConstants ( ) . MESSAGES . MESSAGES_TYPE_ERROR ,
195198 property : fieldName ,
@@ -226,7 +229,6 @@ export default function Attachment(props: AttachmentProps) {
226229 }
227230 if ( f . props . error ) {
228231 const fieldName = ( pConn . getStateProps ( ) as any ) . value ;
229- const context = pConn . getContextName ( ) ;
230232 PCore . getMessageManager ( ) . addMessages ( {
231233 messages : [
232234 {
@@ -315,12 +317,12 @@ export default function Attachment(props: AttachmentProps) {
315317
316318 useEffect ( ( ) => {
317319 if ( files . length > 0 && displayMode !== 'DISPLAY_ONLY' ) {
318- const currentAttachmentList = getCurrentAttachmentsList ( getAttachmentKey ( valueRef ) , pConn . getContextName ( ) ) ;
320+ const currentAttachmentList = getCurrentAttachmentsList ( getAttachmentKey ( valueRef , embeddedProperty ) , pConn . getContextName ( ) ) ;
319321 // block duplicate files to redux store when added 1 after another to prevent multiple duplicates being added to the case on submit
320322 const tempFiles = files . filter ( f => currentAttachmentList . findIndex ( fr => fr . ID === f . ID ) === - 1 && ! f . inProgress && f . responseProps ) ;
321323
322324 const updatedAttList = [ ...currentAttachmentList , ...tempFiles ] ;
323- updateAttachmentState ( pConn , getAttachmentKey ( valueRef ) , updatedAttList ) ;
325+ updateAttachmentState ( pConn , getAttachmentKey ( valueRef , embeddedProperty ) , updatedAttList ) ;
324326 }
325327 } , [ files ] ) ;
326328
@@ -331,7 +333,7 @@ export default function Attachment(props: AttachmentProps) {
331333 } , [ filesWithError ] ) ;
332334
333335 useEffect ( ( ) => {
334- let tempUploadedFiles = getCurrentAttachmentsList ( getAttachmentKey ( valueRef ) , pConn . getContextName ( ) ) ;
336+ let tempUploadedFiles = getCurrentAttachmentsList ( getAttachmentKey ( valueRef , embeddedProperty ) , pConn . getContextName ( ) ) ;
335337 tempUploadedFiles = tempUploadedFiles . filter ( f => f . label === valueRef ) ;
336338 setFiles ( current => {
337339 return [
@@ -349,9 +351,13 @@ export default function Attachment(props: AttachmentProps) {
349351 ...tempUploadedFiles
350352 ] ;
351353 } ) ;
352- PCore . getPubSubUtils ( ) . subscribe ( PCore . getConstants ( ) . PUB_SUB_EVENTS . CASE_EVENTS . ASSIGNMENT_SUBMISSION , resetAttachmentStoredState , caseID ) ;
354+ if ( displayMode !== 'DISPLAY_ONLY' ) {
355+ PCore . getPubSubUtils ( ) . subscribe ( PCore . getConstants ( ) . PUB_SUB_EVENTS . CASE_EVENTS . ASSIGNMENT_SUBMISSION , resetAttachmentStoredState , caseID ) ;
356+ }
353357 return ( ) => {
354- PCore . getPubSubUtils ( ) . unsubscribe ( PCore . getConstants ( ) . PUB_SUB_EVENTS . CASE_EVENTS . ASSIGNMENT_SUBMISSION , caseID ) ;
358+ if ( displayMode !== 'DISPLAY_ONLY' ) {
359+ PCore . getPubSubUtils ( ) . unsubscribe ( PCore . getConstants ( ) . PUB_SUB_EVENTS . CASE_EVENTS . ASSIGNMENT_SUBMISSION , caseID ) ;
360+ }
355361 } ;
356362 } , [ ] ) ;
357363
@@ -435,7 +441,10 @@ export default function Attachment(props: AttachmentProps) {
435441 < MenuItem
436442 style = { { fontSize : '14px' } }
437443 key = 'download'
438- onClick = { ( ) => downloadFile ( item . responseProps ? item . responseProps : { } ) }
444+ onClick = { ( ) => {
445+ setAnchorEl ( null ) ;
446+ onFileDownload ( item . responseProps ? item . responseProps : { } ) ;
447+ } }
439448 >
440449 Download
441450 </ MenuItem >
0 commit comments