porridger/front/src/pages/HomePage.tsx

100 lines
3.2 KiB
TypeScript

import { CSSProperties, useEffect, useMemo, useState } from 'react'
import Stories from 'react-insta-stories'
import { Story } from 'react-insta-stories/dist/interfaces'
import { BottomNavBar, AnnouncementDetails, Filters } from '../components'
import { useStoryDimensions } from '../hooks'
import { useAnnouncements } from '../hooks/api'
import { defaultFilters } from '../utils/filters'
import { Announcement } from '../api/announcement/types'
import { categoryGraphics } from '../assets/category'
import puffSpinner from '../assets/puff.svg'
import { UseFetchReturn, gotError } from '../hooks/useFetch'
import useStoryIndex from '../hooks/useStoryIndex'
function generateStories(announcements: Announcement[]): Story[] {
return announcements.map(announcement => {
return ({
id: announcement.id,
url: announcement.src || categoryGraphics[announcement.category],
type: announcement.src?.endsWith('mp4') ? 'video' : undefined,
seeMore: ({ close }: { close: () => void }) => <AnnouncementDetails close={close} announcement={announcement} />
})
})
}
function fallbackGenerateStories(announcements: UseFetchReturn<Announcement[]>) {
if (announcements.loading)
return fallbackStory()
if (gotError(announcements))
return fallbackStory(announcements.error, true)
const stories = generateStories(announcements.data)
if (stories.length === 0)
return fallbackStory('Здесь пока пусто')
return stories
}
const fallbackStory = (text = '', isError = false): Story[] => [{
content: ({ action }) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
useEffect(() => { action('pause') }, [action])
return (
<div style={styles.center} className={isError ? 'text-danger' : ''}>
{text || <img src={puffSpinner} />}
</div>
)
},
}]
const styles = {
container: {
display: 'flex',
justifyContent: 'center',
backgroundColor: 'rgb(17, 17, 17)',
} as CSSProperties,
center: {
margin: 'auto'
} as CSSProperties,
}
function HomePage() {
const { height, width } = useStoryDimensions(16 / 9)
const [filterShown, setFilterShown] = useState(false)
const [filter, setFilter] = useState(defaultFilters)
const announcements = useAnnouncements(filter)
const stories = useMemo(() => fallbackGenerateStories(announcements), [announcements])
const index = useStoryIndex(announcements.data?.length)
return (<>
<Filters filter={filter} setFilter={index.withReset(setFilter)} filterShown={filterShown} setFilterShown={setFilterShown} />
<div style={styles.container}>
<Stories
currentIndex={index.n}
onStoryEnd={index.increment}
onNext={index.increment}
onPrevious={index.decrement}
stories={stories}
defaultInterval={11000}
height={height}
width={width}
loop={true}
keyboardNavigation={true}
/>
</div>
<BottomNavBar toggleFilters={setFilterShown} width={width} />
</>)
}
export default HomePage