Changeset View
Changeset View
Standalone View
Standalone View
web/modals/threads/gallery/thread-settings-media-gallery.react.js
// @flow | // @flow | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { fetchThreadMedia } from 'lib/actions/thread-actions.js'; | import { fetchThreadMedia } from 'lib/actions/thread-actions.js'; | ||||
import { useModalContext } from 'lib/components/modal-provider.react.js'; | |||||
import type { Media } from 'lib/types/media-types.js'; | |||||
import type { ThreadInfo } from 'lib/types/thread-types.js'; | import type { ThreadInfo } from 'lib/types/thread-types.js'; | ||||
import { useServerCall } from 'lib/utils/action-utils.js'; | import { useServerCall } from 'lib/utils/action-utils.js'; | ||||
import css from './thread-settings-media-gallery.css'; | import css from './thread-settings-media-gallery.css'; | ||||
import Tabs from '../../../components/tabs.react.js'; | import Tabs from '../../../components/tabs.react.js'; | ||||
import MultimediaModal from '../../../media/multimedia-modal.react.js'; | |||||
import Modal from '../../modal.react.js'; | import Modal from '../../modal.react.js'; | ||||
type MediaGalleryTab = 'All' | 'Images' | 'Videos'; | type MediaGalleryTab = 'All' | 'Images' | 'Videos'; | ||||
type ThreadSettingsMediaGalleryModalProps = { | type ThreadSettingsMediaGalleryModalProps = { | ||||
+onClose: () => void, | +onClose: () => void, | ||||
+parentThreadInfo: ThreadInfo, | +parentThreadInfo: ThreadInfo, | ||||
+limit: number, | +limit: number, | ||||
+activeTab: MediaGalleryTab, | +activeTab: MediaGalleryTab, | ||||
}; | }; | ||||
function ThreadSettingsMediaGalleryModal( | function ThreadSettingsMediaGalleryModal( | ||||
props: ThreadSettingsMediaGalleryModalProps, | props: ThreadSettingsMediaGalleryModalProps, | ||||
): React.Node { | ): React.Node { | ||||
const { pushModal } = useModalContext(); | |||||
const { onClose, parentThreadInfo, limit, activeTab } = props; | const { onClose, parentThreadInfo, limit, activeTab } = props; | ||||
const { id: threadID } = parentThreadInfo; | const { id: threadID } = parentThreadInfo; | ||||
const modalName = 'Media'; | const modalName = 'Media'; | ||||
const callFetchThreadMedia = useServerCall(fetchThreadMedia); | const callFetchThreadMedia = useServerCall(fetchThreadMedia); | ||||
const [mediaInfos, setMediaInfos] = React.useState([]); | const [mediaInfos, setMediaInfos] = React.useState([]); | ||||
const [tab, setTab] = React.useState<MediaGalleryTab>(activeTab); | const [tab, setTab] = React.useState<MediaGalleryTab>(activeTab); | ||||
React.useEffect(() => { | React.useEffect(() => { | ||||
const fetchData = async () => { | const fetchData = async () => { | ||||
const result = await callFetchThreadMedia({ | const result = await callFetchThreadMedia({ | ||||
threadID, | threadID, | ||||
limit, | limit, | ||||
offset: 0, | offset: 0, | ||||
}); | }); | ||||
setMediaInfos(result.media); | setMediaInfos(result.media); | ||||
}; | }; | ||||
fetchData(); | fetchData(); | ||||
}, [callFetchThreadMedia, threadID, limit]); | }, [callFetchThreadMedia, threadID, limit]); | ||||
const onClick = React.useCallback( | |||||
(media: Media) => { | |||||
pushModal(<MultimediaModal type={media.type} uri={media.uri} />); | |||||
}, | |||||
[pushModal], | |||||
); | |||||
const filteredMediaInfos = React.useMemo(() => { | const filteredMediaInfos = React.useMemo(() => { | ||||
if (tab === 'Images') { | if (tab === 'Images') { | ||||
return mediaInfos.filter(mediaInfo => mediaInfo.type === 'photo'); | return mediaInfos.filter(mediaInfo => mediaInfo.type === 'photo'); | ||||
} else if (tab === 'Videos') { | } else if (tab === 'Videos') { | ||||
return mediaInfos.filter(mediaInfo => mediaInfo.type === 'video'); | return mediaInfos.filter(mediaInfo => mediaInfo.type === 'video'); | ||||
} | } | ||||
return mediaInfos; | return mediaInfos; | ||||
}, [tab, mediaInfos]); | }, [tab, mediaInfos]); | ||||
const mediaCoverPhotos = React.useMemo( | const mediaCoverPhotos = React.useMemo( | ||||
() => filteredMediaInfos.map(media => media.thumbnailURI || media.uri), | () => filteredMediaInfos.map(media => media.thumbnailURI || media.uri), | ||||
[filteredMediaInfos], | [filteredMediaInfos], | ||||
); | ); | ||||
const mediaGalleryItems = React.useMemo( | const mediaGalleryItems = React.useMemo( | ||||
() => | () => | ||||
filteredMediaInfos.map((media, i) => ( | filteredMediaInfos.map((media, i) => ( | ||||
<div key={i} className={css.mediaContainer}> | <div | ||||
key={i} | |||||
onClick={() => onClick(media)} | |||||
className={css.mediaContainer} | |||||
> | |||||
<img src={mediaCoverPhotos[i]} className={css.media} /> | <img src={mediaCoverPhotos[i]} className={css.media} /> | ||||
</div> | </div> | ||||
)), | )), | ||||
[filteredMediaInfos, mediaCoverPhotos], | [filteredMediaInfos, onClick, mediaCoverPhotos], | ||||
); | ); | ||||
const handleScroll = React.useCallback( | const handleScroll = React.useCallback( | ||||
async event => { | async event => { | ||||
const container = event.target; | const container = event.target; | ||||
// Load more data when the user is within 1000 pixels of the end | // Load more data when the user is within 1000 pixels of the end | ||||
const buffer = 1000; | const buffer = 1000; | ||||
▲ Show 20 Lines • Show All 41 Lines • Show Last 20 Lines |