]> git.localhorst.tv Git - alttp.git/blob - resources/js/components/pages/Schedule.js
schedule event filter
[alttp.git] / resources / js / components / pages / Schedule.js
1 import axios from 'axios';
2 import moment from 'moment';
3 import React from 'react';
4 import { Alert, Container } from 'react-bootstrap';
5 import { Helmet } from 'react-helmet';
6 import { useTranslation } from 'react-i18next';
7
8 import CanonicalLinks from '../common/CanonicalLinks';
9 import ErrorBoundary from '../common/ErrorBoundary';
10 import Filter from '../episodes/Filter';
11 import List from '../episodes/List';
12
13 const Schedule = () => {
14         const [ahead, setAhead] = React.useState(14);
15         const [behind, setBehind] = React.useState(0);
16         const [episodes, setEpisodes] = React.useState([]);
17         const [filter, setFilter] = React.useState({});
18
19         const { t } = useTranslation();
20
21         React.useEffect(() => {
22                 const savedFilter = localStorage.getItem('episodes.filter.schedule');
23                 if (savedFilter) {
24                         setFilter(JSON.parse(savedFilter));
25                 } else {
26                         setFilter(filter => filter ? {} : filter);
27                 }
28         }, []);
29
30         const updateFilter = React.useCallback(newFilter => {
31                 localStorage.setItem('episodes.filter.schedule', JSON.stringify(newFilter));
32                 setFilter(newFilter);
33         }, []);
34
35         const fetchEpisodes = React.useCallback((controller, ahead, behind, filter) => {
36                 axios.get(`/api/episodes`, {
37                         signal: controller.signal,
38                         params: {
39                                 after: moment().startOf('day').subtract(behind, 'days').toISOString(),
40                                 before: moment().startOf('day').add(ahead + 1, 'days').toISOString(),
41                                 ...filter,
42                         },
43                 }).then(response => {
44                         setEpisodes(response.data || []);
45                 }).catch(e => {
46                         if (!axios.isCancel(e)) {
47                                 console.error(e);
48                         }
49                 });
50         }, []);
51
52         React.useEffect(() => {
53                 const controller = new AbortController();
54                 fetchEpisodes(controller, ahead, behind, filter);
55                 const timer = setInterval(() => {
56                         fetchEpisodes(controller, ahead, behind, filter);
57                 }, 3 * 60 * 1000);
58                 return () => {
59                         controller.abort();
60                         clearInterval(timer);
61                 };
62         }, [ahead, behind, fetchEpisodes, filter]);
63
64         return <Container>
65                 <Helmet>
66                         <title>{t('schedule.heading')}</title>
67                         <meta name="description" content={t('schedule.description')} />
68                 </Helmet>
69                 <CanonicalLinks base="/schedule" />
70                 <div className="d-flex align-items-start justify-content-between">
71                         <h1>{t('schedule.heading')}</h1>
72                         <div className="mt-5">
73                                 <Filter filter={filter} setFilter={updateFilter} />
74                         </div>
75                 </div>
76                 <ErrorBoundary>
77                         {episodes.length ?
78                                 <List episodes={episodes} />
79                         :
80                                 <Alert variant="info">
81                                         {t('episodes.empty')}
82                                 </Alert>
83                         }
84                 </ErrorBoundary>
85         </Container>;
86 };
87
88 export default Schedule;