From: Daniel Karbach Date: Tue, 21 Feb 2023 16:44:22 +0000 (+0100) Subject: WIP event filter X-Git-Url: https://git.localhorst.tv/?a=commitdiff_plain;h=1555e7984ae682c7c7cddb5026275317742eaef3;p=alttp.git WIP event filter --- diff --git a/app/Http/Controllers/EventController.php b/app/Http/Controllers/EventController.php index eb74239..bfe9efd 100644 --- a/app/Http/Controllers/EventController.php +++ b/app/Http/Controllers/EventController.php @@ -3,13 +3,30 @@ namespace App\Http\Controllers; use App\Models\Event; +use Carbon\Carbon; use Illuminate\Http\Request; class EventController extends Controller { public function search(Request $request) { + $validatedData = $request->validate([ + 'after' => 'nullable|date', + 'before' => 'nullable|date', + ]); $events = Event::where('visible', '=', true); + if (isset($validatedData['before'])) { + $events = $events->where(function ($query) use ($validatedData) { + $query->whereNull('start'); + $query->orWhere('start', '<', $validatedData['before']); + }); + } + if (isset($validatedData['after'])) { + $events = $events->where(function ($query) use ($validatedData) { + $query->whereNull('end'); + $query->orWhere('end', '>', $validatedData['after']); + }); + } return $events->get()->toJson(); } diff --git a/resources/js/components/episodes/Filter.js b/resources/js/components/episodes/Filter.js new file mode 100644 index 0000000..4855a71 --- /dev/null +++ b/resources/js/components/episodes/Filter.js @@ -0,0 +1,80 @@ +import axios from 'axios'; +import moment from 'moment'; +import PropTypes from 'prop-types'; +import React from 'react'; +import { Button } from 'react-bootstrap'; + +const Filter = ({ filter, setFilter }) => { + const [events, setEvents] = React.useState([]); + + React.useEffect(() => { + const controller = new AbortController(); + axios.get(`/api/events`, { + signal: controller.signal, + params: { + after: moment().startOf('day').subtract(7, 'days').toISOString(), + before: moment().startOf('day').add(8, 'days').toISOString(), + }, + }).then(response => { + const newEvents = response.data || []; + setEvents(newEvents); + setFilter(filter => { + const eventFilter = filter.event || []; + return { + ...filter, + event: eventFilter.filter(newEvents.find(id => newEvents.includes(id))), + }; + }); + }).catch(e => { + if (!axios.isCancel(e)) { + console.error(e); + } + }); + return () => { + controller.abort(); + }; + }, [setEvents, setFilter]); + + const toggleEvent = React.useCallback(event => { + setFilter(filter => { + const eventFilter = filter.event || []; + if (!eventFilter.includes(event.id)) { + return { + ...filter, + event: [...eventFilter, event.id], + }; + } + return { + ...filter, + event: eventFilter.filter(id => id !== event.id), + }; + }); + }, [setFilter]); + + const isEventSelected = React.useCallback(event => { + const eventFilter = filter.event || []; + return eventFilter.includes(event.id); + }, [filter]); + + if (!events || !events.length) return null; + + return
+ {events.map(event => + + )} +
; +}; + +Filter.propTypes = { + filter: PropTypes.shape(), + setFilter: PropTypes.func, +}; + +export default Filter; diff --git a/resources/js/components/pages/Schedule.js b/resources/js/components/pages/Schedule.js index c27a384..2e97af9 100644 --- a/resources/js/components/pages/Schedule.js +++ b/resources/js/components/pages/Schedule.js @@ -7,21 +7,38 @@ import { useTranslation } from 'react-i18next'; import CanonicalLinks from '../common/CanonicalLinks'; import ErrorBoundary from '../common/ErrorBoundary'; +import Filter from '../episodes/Filter'; import List from '../episodes/List'; const Schedule = () => { const [ahead, setAhead] = React.useState(6); const [behind, setBehind] = React.useState(0); const [episodes, setEpisodes] = React.useState([]); + const [filter, setFilter] = React.useState({}); const { t } = useTranslation(); - const fetchEpisodes = React.useCallback((controller, ahead, behind) => { + React.useEffect(() => { + const savedFilter = localStorage.getItem('episodes.filter.schedule'); + if (savedFilter) { + setFilter(JSON.parse(savedFilter)); + } else { + setFilter(filter => filter ? {} : filter); + } + }, []); + + const updateFilter = React.useCallback(newFilter => { + localStorage.setItem('episodes.filter.schedule', JSON.stringify(newFilter)); + setFilter(newFilter); + }, [setFilter]); + + const fetchEpisodes = React.useCallback((controller, ahead, behind, filter) => { axios.get(`/api/episodes`, { signal: controller.signal, params: { after: moment().startOf('day').subtract(behind, 'days').toISOString(), before: moment().startOf('day').add(ahead + 1, 'days').toISOString(), + ...filter, }, }).then(response => { setEpisodes(response.data || []); @@ -34,15 +51,15 @@ const Schedule = () => { React.useEffect(() => { const controller = new AbortController(); - fetchEpisodes(controller, ahead, behind); + fetchEpisodes(controller, ahead, behind, filter); const timer = setInterval(() => { - fetchEpisodes(controller, ahead, behind); - }, 5 * 60 * 1000); + fetchEpisodes(controller, ahead, behind, filter); + }, 3 * 60 * 1000); return () => { controller.abort(); clearInterval(timer); }; - }, [ahead, behind, fetchEpisodes]); + }, [ahead, behind, fetchEpisodes, filter]); return @@ -52,6 +69,7 @@ const Schedule = () => {

{t('schedule.heading')}

+
;