moved hooks to separate directories, added stories fallback

This commit is contained in:
Dmitriy Shishkov 2023-05-17 10:46:59 +03:00
parent e9b7a9e32a
commit dc6f8fe8f2
Signed by: dm1sh
GPG Key ID: 027994B0AA357688
6 changed files with 138 additions and 64 deletions

13
front/src/assets/puff.svg Normal file
View File

@ -0,0 +1,13 @@
<!-- By Sam Herbert (@sherb), for everyone. More @ http://goo.gl/7AJzbL -->
<svg width="44" height="44" viewBox="0 0 44 44" xmlns="http://www.w3.org/2000/svg" stroke="#fff">
<g fill="none" fill-rule="evenodd" stroke-width="2">
<circle cx="22" cy="22" r="1">
<animate attributeName="r" begin="0s" dur="1.8s" values="1; 20" calcMode="spline" keyTimes="0; 1" keySplines="0.165, 0.84, 0.44, 1" repeatCount="indefinite"/>
<animate attributeName="stroke-opacity" begin="0s" dur="1.8s" values="1; 0" calcMode="spline" keyTimes="0; 1" keySplines="0.3, 0.61, 0.355, 1" repeatCount="indefinite"/>
</circle>
<circle cx="22" cy="22" r="1">
<animate attributeName="r" begin="-0.9s" dur="1.8s" values="1; 20" calcMode="spline" keyTimes="0; 1" keySplines="0.165, 0.84, 0.44, 1" repeatCount="indefinite"/>
<animate attributeName="stroke-opacity" begin="-0.9s" dur="1.8s" values="1; 0" calcMode="spline" keyTimes="0; 1" keySplines="0.3, 0.61, 0.355, 1" repeatCount="indefinite"/>
</circle>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,5 @@
export { default as useHomeAnnouncementList } from './useHomeAnnouncementList'
export { default as useBook } from './useBook'
export { default as useAuth } from './useAuth'
export { default as useTrashboxes } from './useTrashboxes'
export { default as useAddAnnouncement } from './useAddAnnouncement'

View File

@ -0,0 +1,41 @@
import { useEffect, useState } from "react"
const useFetch = (url, params, initialData) => {
const [data, setData] = useState(initialData)
const [loading, setLoading] = useState(true)
const [error, setError] = useState("")
useEffect(() => {
fetch(url, params)
.then(res => {
if (!res.ok) {
switch (res.status) {
case 401: {
throw new Error("Ошибка авторизации")
}
case 404: {
new Error("Объект не найден")
}
break
default: {
throw new Error("Ошибка ответа от сервера")
}
}
}
return res.json()
})
.then(data => {
setData(data)
setLoading(false)
})
.catch(err => {
setError("Ошибка сети")
setLoading(false)
})
}, [url, params])
return { data, loading, error }
}
export default useFetch

View File

@ -0,0 +1,26 @@
import useFetch from './useFetch'
import { API_URL } from '../../config'
import { removeNull } from '../../utils'
const initialAnnouncements = { list_of_announcements: [], Success: true }
const useHomeAnnouncementList = (filters) => {
const { data, loading, error } = useFetch(
API_URL + '/announcements?' + new URLSearchParams(removeNull(filters)),
null,
initialAnnouncements
)
const annList = data.list_of_announcements
const res = annList.map(ann => ({
...ann,
lat: ann.latitude,
lng: ann.longtitude,
bestBy: ann.best_by
}))
return { data: error ? [] : res, loading, error }
}
export default useHomeAnnouncementList

View File

@ -1,18 +1,15 @@
import Stories from 'react-insta-stories'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import Stories from 'react-insta-stories'
import BottomNavBar from '../components/BottomNavBar' import BottomNavBar from '../components/BottomNavBar'
import useStoryDimensions from '../utils/useStoryDimensions' import useStoryDimensions from '../hooks/useStoryDimensions'
import { API_URL } from '../config'
import "./leafletStyles.css"
import 'leaflet/dist/leaflet.css'
import AnnouncementDetails from '../components/AnnouncementDetails' import AnnouncementDetails from '../components/AnnouncementDetails'
import { categoryGraphics } from '../assets/category'
import Filters from '../components/Filters' import Filters from '../components/Filters'
import { removeNull } from '../utils'
import { useHomeAnnouncementList } from '../hooks/api'
import puffSpinner from '../assets/puff.svg'
import { categoryGraphics } from '../assets/category'
function generateStories(announcements) { function generateStories(announcements) {
return announcements.map(announcement => { return announcements.map(announcement => {
@ -25,76 +22,68 @@ function generateStories(announcements) {
}) })
} }
const mock = [ function fallbackGenerateStories(announcementsFetch) {
{ const stories = generateStories(announcementsFetch.data)
id: 5,
name: "Огурец", if (announcementsFetch.loading)
category: "fruits_vegatables", return fallbackStory()
src: "https://upload.wikimedia.org/wikipedia/commons/thumb/2/24/Marketvegetables.jpg/800px-Marketvegetables.jpg",
bestBy: 10000, if (announcementsFetch.error)
description: "Очень вкусный огурец, прям, закачаешься", return fallbackStory(announcementsFetch.error)
lat: 59.9724,
lng: 30.3227, if (stories.length == 0)
address: "ул. Профессора Попова, дом 5 литера Ф", return fallbackStory("Здесь пока пусто")
metro: "Петроградская"
return stories
}
const fallbackStory = (text) => [{
content: ({ action }) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
useEffect(() => { action('pause') }, [action])
return (
<div style={{ margin: 'auto' }}>
{text || <img src={puffSpinner} />}
</div>
)
}, },
{ header: { heading: text }
id: 9, }]
name: "Арбуз",
category: "soup",
src: "/static/watermelon.mp4",
bestBy: 20000,
description: "Очень вкусный арбуз, прям, закачаешься",
lat: 60.9724,
lng: 30.3227,
address: "ул. Профессора Попова, дом 50 литера Ф",
metro: "Горьковская"
}
]
const defaultFilters = { userId: null, category: null, metro: null, bookedBy: null } const defaultFilters = { userId: null, category: null, metro: null, bookedBy: null }
const PROD = true
function HomePage() { function HomePage() {
const { height, width } = useStoryDimensions(16 / 10) const { height, width } = useStoryDimensions(16 / 10)
const [announcements, setAnnouncements] = useState([])
const [filterShown, setFilterShown] = useState(false) const [filterShown, setFilterShown] = useState(false)
const [filter, setFilter] = useState(defaultFilters) const [filter, setFilter] = useState(defaultFilters)
useEffect(() => { const announcementsFetch = useHomeAnnouncementList(filter)
(async () => {
try {
const res = PROD ? await fetch(API_URL + "/announcements?" + new URLSearchParams(removeNull(filter))) : null
const json = PROD ? (await res.json()).list_of_announcements : mock const stories = fallbackGenerateStories(announcementsFetch)
setAnnouncements(json)
}
catch (err) {
console.error(err)
}
})()
}, [filter])
const toggleFilters = (toggle) => setFilterShown(toggle)
return (<> return (<>
<Filters filter={filter} setFilter={setFilter} filterShown={filterShown} setFilterShown={setFilterShown} /> <Filters filter={filter} setFilter={setFilter} filterShown={filterShown} setFilterShown={setFilterShown} />
<div style={{ display: "flex", justifyContent: "center", backgroundColor: "rgb(17, 17, 17)" }}> <div style={{ display: "flex", justifyContent: "center", backgroundColor: "rgb(17, 17, 17)" }}>
{announcements.length && <Stories {announcementsFetch.error ?
stories={generateStories(announcements)} (
defaultInterval={11000} <div style={{ width, height, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
height={height} <p className='text-danger'>{announcementsFetch.error}</p>
width={width} </div>
loop={true} ) : (
keyboardNavigation={true} <Stories
/>} stories={stories}
defaultInterval={11000}
height={height}
width={width}
loop={true}
keyboardNavigation={true}
/>
)
}
</div> </div>
<BottomNavBar toggleFilters={toggleFilters} width={width} /> <BottomNavBar toggleFilters={setFilterShown} width={width} />
</>) </>)
} }