You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			110 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			TypeScript
		
	
		
		
			
		
	
	
			110 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			TypeScript
		
	
| 
											8 years ago
										 | /** | ||
|  |  * @prettier | ||
|  |  */ | ||
| 
											4 years ago
										 | import React, { useCallback, useEffect, useState } from 'react'; | ||
| 
											8 years ago
										 | 
 | ||
|  | import { Lightbox } from './Lightbox'; | ||
|  | 
 | ||
| 
											5 years ago
										 | // tslint:disable-next-line: no-submodule-imports
 | ||
| 
											5 years ago
										 | import useKey from 'react-use/lib/useKey'; | ||
| 
											4 years ago
										 | import { AttachmentTypeWithPath } from '../../types/Attachment'; | ||
| 
											4 years ago
										 | import { useDispatch, useSelector } from 'react-redux'; | ||
| 
											4 years ago
										 | import { showLightBox } from '../../state/ducks/conversations'; | ||
|  | import { getSelectedConversationKey } from '../../state/selectors/conversations'; | ||
|  | import { MIME } from '../../types'; | ||
|  | import { saveAttachmentToDisk } from '../../util/attachmentsUtil'; | ||
| 
											8 years ago
										 | 
 | ||
| 
											7 years ago
										 | export interface MediaItemType { | ||
| 
											8 years ago
										 |   objectURL?: string; | ||
| 
											7 years ago
										 |   thumbnailObjectUrl?: string; | ||
| 
											5 years ago
										 |   contentType: MIME.MIMEType; | ||
| 
											7 years ago
										 |   index: number; | ||
| 
											4 years ago
										 |   attachment: AttachmentTypeWithPath; | ||
| 
											4 years ago
										 |   messageTimestamp: number; | ||
|  |   messageSender: string; | ||
| 
											4 years ago
										 |   messageId: string; | ||
| 
											8 years ago
										 | } | ||
|  | 
 | ||
| 
											5 years ago
										 | type Props = { | ||
| 
											7 years ago
										 |   media: Array<MediaItemType>; | ||
| 
											8 years ago
										 |   selectedIndex: number; | ||
| 
											5 years ago
										 | }; | ||
|  | 
 | ||
|  | export const LightboxGallery = (props: Props) => { | ||
| 
											4 years ago
										 |   const { media } = props; | ||
| 
											4 years ago
										 |   const [currentIndex, setCurrentIndex] = useState(-1); | ||
| 
											4 years ago
										 |   const selectedConversation = useSelector(getSelectedConversationKey) as string; | ||
| 
											5 years ago
										 | 
 | ||
| 
											4 years ago
										 |   const dispatch = useDispatch(); | ||
|  | 
 | ||
| 
											5 years ago
										 |   // just run once, when the component is mounted. It's to show the lightbox on the specified index at start.
 | ||
|  |   useEffect(() => { | ||
|  |     setCurrentIndex(props.selectedIndex); | ||
|  |   }, []); | ||
|  | 
 | ||
|  |   const selectedMedia = media[currentIndex]; | ||
|  |   const firstIndex = 0; | ||
|  |   const lastIndex = media.length - 1; | ||
| 
											4 years ago
										 | 
 | ||
|  |   const hasPrevious = currentIndex > firstIndex; | ||
|  |   const hasNext = currentIndex < lastIndex; | ||
|  | 
 | ||
|  |   const onPrevious = useCallback(() => { | ||
|  |     setCurrentIndex(Math.max(currentIndex - 1, 0)); | ||
|  |   }, [currentIndex]); | ||
|  | 
 | ||
|  |   const onNext = useCallback(() => { | ||
|  |     setCurrentIndex(Math.min(currentIndex + 1, lastIndex)); | ||
|  |   }, [currentIndex, lastIndex]); | ||
|  | 
 | ||
|  |   const handleSave = useCallback(() => { | ||
| 
											5 years ago
										 |     const mediaItem = media[currentIndex]; | ||
| 
											4 years ago
										 |     void saveAttachmentToDisk({ ...mediaItem, conversationId: selectedConversation }); | ||
| 
											4 years ago
										 |   }, [currentIndex, media]); | ||
| 
											5 years ago
										 | 
 | ||
|  |   useKey( | ||
|  |     'ArrowRight', | ||
|  |     () => { | ||
|  |       onNext?.(); | ||
|  |     }, | ||
|  |     undefined, | ||
|  |     [currentIndex] | ||
|  |   ); | ||
|  |   useKey( | ||
|  |     'ArrowLeft', | ||
|  |     () => { | ||
|  |       onPrevious?.(); | ||
|  |     }, | ||
|  |     undefined, | ||
|  |     [currentIndex] | ||
|  |   ); | ||
|  | 
 | ||
| 
											4 years ago
										 |   useKey( | ||
|  |     'Escape', | ||
|  |     () => { | ||
|  |       dispatch(showLightBox(undefined)); | ||
|  |     }, | ||
|  |     undefined, | ||
|  |     [currentIndex] | ||
|  |   ); | ||
|  |   // just to avoid to render the first element during the first render when the user selected another item
 | ||
|  |   if (currentIndex === -1) { | ||
|  |     return null; | ||
|  |   } | ||
|  |   const objectURL = selectedMedia?.objectURL || 'images/alert-outline.svg'; | ||
|  |   const { attachment } = selectedMedia; | ||
| 
											5 years ago
										 | 
 | ||
| 
											4 years ago
										 |   const caption = attachment?.caption; | ||
| 
											5 years ago
										 |   return ( | ||
| 
											4 years ago
										 |     // tslint:disable: use-simple-attributes
 | ||
| 
											5 years ago
										 |     <Lightbox | ||
| 
											4 years ago
										 |       onPrevious={hasPrevious ? onPrevious : undefined} | ||
|  |       onNext={hasNext ? onNext : undefined} | ||
| 
											4 years ago
										 |       onSave={handleSave} | ||
| 
											5 years ago
										 |       objectURL={objectURL} | ||
| 
											4 years ago
										 |       caption={caption} | ||
| 
											5 years ago
										 |       contentType={selectedMedia.contentType} | ||
|  |     /> | ||
|  |   ); | ||
|  | }; |