@@ -128,7 +128,12 @@ class MessageInput extends PureComponent {
128128 props . editing ,
129129 props . initialValue ,
130130 ) ;
131- this . state = { ...state , sending : false } ;
131+ this . state = {
132+ ...state ,
133+ asyncIds : Immutable ( [ ] ) , // saves data for images that resolve after hitting send
134+ asyncUploads : Immutable ( { } ) , // saves data for images that resolve after hitting send
135+ } ;
136+ this . sending = false ;
132137 }
133138
134139 static themePath = 'messageInput' ;
@@ -223,12 +228,17 @@ class MessageInput extends PureComponent {
223228 ] ) ,
224229 /** Disables the child MessageInput component */
225230 disabled : PropTypes . bool ,
231+ /**
232+ * For images still in uploading state when user hits send, send text immediately and send image as follow-up message once uploaded
233+ */
234+ sendImageAsync : PropTypes . bool ,
226235 } ;
227236
228237 static defaultProps = {
229238 hasImagePicker : true ,
230239 hasFilePicker : true ,
231240 disabled : false ,
241+ sendImageAsync : false ,
232242 SendButton,
233243 AttachButton,
234244 } ;
@@ -328,6 +338,16 @@ class MessageInput extends PureComponent {
328338 }
329339
330340 componentDidUpdate ( prevProps ) {
341+ if ( Object . keys ( this . state . asyncUploads ) . length ) {
342+ /**
343+ * When successful image upload response occurs after hitting send,
344+ * send a follow up message with the image
345+ */
346+ this . sending = true ;
347+ this . state . asyncIds . forEach ( ( id ) => this . sendMessageAsync ( id ) ) ;
348+ this . sending = false ;
349+ }
350+
331351 if ( this . props . editing ) this . inputBox . focus ( ) ;
332352 if (
333353 this . props . editing &&
@@ -405,29 +425,78 @@ class MessageInput extends PureComponent {
405425 return false ;
406426 } ;
407427
428+ sendMessageAsync = ( id ) => {
429+ const image = this . state . asyncUploads [ id ] ;
430+ if ( ! image || image . state === FileState . UPLOAD_FAILED ) return ;
431+
432+ if ( image . state === FileState . UPLOADED ) {
433+ const attachments = [
434+ {
435+ type : 'image' ,
436+ image_url : image . url ,
437+ } ,
438+ ] ;
439+
440+ try {
441+ this . props . sendMessage ( {
442+ text : '' ,
443+ parent : this . props . parent ,
444+ mentioned_users : [ ] ,
445+ attachments,
446+ } ) ;
447+
448+ this . setState ( ( prevState ) => ( {
449+ numberOfUploads : prevState . numberOfUploads - 1 ,
450+ asyncIds : prevState . asyncIds . splice (
451+ prevState . asyncIds . indexOf ( id ) ,
452+ 1 ,
453+ ) ,
454+ asyncUploads : prevState . asyncUploads . without ( [ id ] ) ,
455+ } ) ) ;
456+ } catch ( err ) {
457+ console . log ( 'Failed' ) ;
458+ }
459+ }
460+ } ;
461+
408462 sendMessage = async ( ) => {
409- if ( this . state . sending ) return ;
463+ if ( this . sending ) return ;
464+ this . sending = true ;
410465
411466 const { text } = this . state ;
412- await this . setState ( { sending : true , text : '' } , ( ) =>
413- this . inputBox . clear ( ) ,
414- ) ;
467+ await this . setState ( { text : '' } , ( ) => this . inputBox . clear ( ) ) ;
415468
416469 const attachments = [ ] ;
417470 for ( const id of this . state . imageOrder ) {
418471 const image = this . state . imageUploads [ id ] ;
472+
419473 if ( ! image || image . state === FileState . UPLOAD_FAILED ) {
420474 continue ;
421475 }
476+
422477 if ( image . state === FileState . UPLOADING ) {
423478 // TODO: show error to user that they should wait until image is uploaded
424- return this . setState ( { sending : false } ) ;
479+ if ( this . props . sendImageAsync ) {
480+ /**
481+ * If user hit send before image uploaded, push ID into a queue to later
482+ * be matched with the successful CDN response
483+ */
484+ this . setState ( ( prevState ) => ( {
485+ asyncIds : [ ...prevState . asyncIds , id ] ,
486+ } ) ) ;
487+ } else {
488+ this . sending = false ;
489+ return this . setState ( { text } ) ;
490+ }
491+ }
492+
493+ if ( image . state === FileState . UPLOADED ) {
494+ attachments . push ( {
495+ type : 'image' ,
496+ image_url : image . url ,
497+ fallback : image . file . name ,
498+ } ) ;
425499 }
426- attachments . push ( {
427- type : 'image' ,
428- image_url : image . url ,
429- fallback : image . file . name ,
430- } ) ;
431500 }
432501
433502 for ( const id of this . state . fileOrder ) {
@@ -437,20 +506,22 @@ class MessageInput extends PureComponent {
437506 }
438507 if ( upload . state === FileState . UPLOADING ) {
439508 // TODO: show error to user that they should wait until image is uploaded
440- return this . setState ( { sending : false } ) ;
509+ return ( this . sending = false ) ;
510+ }
511+ if ( upload . state === FileState . UPLOADED ) {
512+ attachments . push ( {
513+ type : 'file' ,
514+ asset_url : upload . url ,
515+ title : upload . file . name ,
516+ mime_type : upload . file . type ,
517+ file_size : upload . file . size ,
518+ } ) ;
441519 }
442- attachments . push ( {
443- type : 'file' ,
444- asset_url : upload . url ,
445- title : upload . file . name ,
446- mime_type : upload . file . type ,
447- file_size : upload . file . size ,
448- } ) ;
449520 }
450521
451522 // Disallow sending message if its empty.
452523 if ( ! text && attachments . length === 0 ) {
453- return this . setState ( { sending : false } ) ;
524+ return ( this . sending = false ) ;
454525 }
455526
456527 if ( this . props . editing ) {
@@ -469,7 +540,7 @@ class MessageInput extends PureComponent {
469540 . then ( this . props . clearEditingState ) ;
470541 logChatPromiseExecution ( updateMessagePromise , 'update message' ) ;
471542
472- this . setState ( { sending : false } ) ;
543+ this . sending = false ;
473544 } else {
474545 try {
475546 this . props . sendMessage ( {
@@ -479,17 +550,19 @@ class MessageInput extends PureComponent {
479550 attachments,
480551 } ) ;
481552
482- this . setState ( {
553+ this . sending = false ;
554+ this . setState ( ( prevState ) => ( {
483555 text : '' ,
484556 imageUploads : Immutable ( { } ) ,
485557 imageOrder : Immutable ( [ ] ) ,
486558 fileUploads : Immutable ( { } ) ,
487559 fileOrder : Immutable ( [ ] ) ,
488560 mentioned_users : [ ] ,
489- sending : false ,
490- } ) ;
561+ numberOfUploads : prevState . numberOfUploads - attachments . length ,
562+ } ) ) ;
491563 } catch ( err ) {
492- this . setState ( { sending : false , text } ) ;
564+ this . sending = false ;
565+ this . setState ( { text } ) ;
493566 console . log ( 'Failed' ) ;
494567 }
495568 }
@@ -669,21 +742,12 @@ class MessageInput extends PureComponent {
669742 } ;
670743
671744 _uploadImage = async ( id ) => {
672- const img = this . state . imageUploads [ id ] ;
673- if ( ! img ) {
745+ const { file } = this . state . imageUploads [ id ] ;
746+ if ( ! file ) {
674747 return ;
675748 }
676- const { file } = img ;
677749
678- await this . setState ( ( prevState ) => ( {
679- imageUploads : prevState . imageUploads . setIn (
680- [ id , 'state' ] ,
681- FileState . UPLOADING ,
682- ) ,
683- } ) ) ;
684-
685- let response = { } ;
686- response = { } ;
750+ let response ;
687751
688752 const filename = ( file . name || file . uri ) . replace (
689753 / ^ ( f i l e : \/ \/ | c o n t e n t : \/ \/ ) / ,
@@ -697,13 +761,40 @@ class MessageInput extends PureComponent {
697761 file ,
698762 this . props . channel ,
699763 ) ;
764+ } else if ( this . props . sendImageAsync ) {
765+ this . props . channel
766+ . sendImage ( file . uri , null , contentType )
767+ . then ( ( res ) => {
768+ if ( this . state . asyncIds . includes ( id ) ) {
769+ // Evaluates to true if user hit send before image successfully uploaded
770+ this . setState ( ( prevState ) => ( {
771+ asyncUploads : prevState . asyncUploads
772+ . setIn ( [ id , 'state' ] , FileState . UPLOADED )
773+ . setIn ( [ id , 'url' ] , res . file ) ,
774+ } ) ) ;
775+ } else {
776+ this . setState ( ( prevState ) => ( {
777+ imageUploads : prevState . imageUploads
778+ . setIn ( [ id , 'state' ] , FileState . UPLOADED )
779+ . setIn ( [ id , 'url' ] , res . file ) ,
780+ } ) ) ;
781+ }
782+ } ) ;
700783 } else {
701784 response = await this . props . channel . sendImage (
702785 file . uri ,
703786 null ,
704787 contentType ,
705788 ) ;
706789 }
790+
791+ if ( response ) {
792+ this . setState ( ( prevState ) => ( {
793+ imageUploads : prevState . imageUploads
794+ . setIn ( [ id , 'state' ] , FileState . UPLOADED )
795+ . setIn ( [ id , 'url' ] , response . file ) ,
796+ } ) ) ;
797+ }
707798 } catch ( e ) {
708799 console . warn ( e ) ;
709800 await this . setState ( ( prevState ) => {
@@ -725,15 +816,10 @@ class MessageInput extends PureComponent {
725816
726817 return ;
727818 }
728- this . setState ( ( prevState ) => ( {
729- imageUploads : prevState . imageUploads
730- . setIn ( [ id , 'state' ] , FileState . UPLOADED )
731- . setIn ( [ id , 'url' ] , response . file ) ,
732- } ) ) ;
733819 } ;
734820
735821 onChangeText = ( text ) => {
736- if ( this . state . sending ) return ;
822+ if ( this . sending ) return ;
737823 this . setState ( { text } ) ;
738824
739825 if ( text ) {
@@ -913,9 +999,7 @@ class MessageInput extends PureComponent {
913999 title = { t ( 'Send message' ) }
9141000 sendMessage = { this . sendMessage }
9151001 editing = { this . props . editing }
916- disabled = {
917- disabled || this . state . sending || ! this . isValidMessage ( )
918- }
1002+ disabled = { disabled || this . sending || ! this . isValidMessage ( ) }
9191003 />
9201004 </ >
9211005 ) }
0 commit comments