$validatedData = $request->validate([
'after' => 'nullable|date',
'before' => 'nullable|date',
+ 'event' => 'nullable|array',
+ 'event.*' => 'numeric',
]);
$after = isset($validatedData['after']) ? $validatedData['after'] : Carbon::now()->sub(2, 'hours');
$before = isset($validatedData['before']) ? $validatedData['before'] : Carbon::now()->add(1, 'days');
->where('events.visible', '=', true)
->orderBy('episodes.start')
->limit(1000);
+ if (!empty($validatedData['event'])) {
+ $episodes = $episodes->whereIn('episodes.event_id', $validatedData['event']);
+ }
if ($request->user() && $request->user()->isPrivileged()) {
$episodes = $episodes->with(['crew', 'crew.user']);
} else {
--- /dev/null
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+ /**
+ * Run the migrations.
+ *
+ * @return void
+ */
+ public function up()
+ {
+ Schema::table('events', function(Blueprint $table) {
+ $table->string('short')->default('');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('events', function(Blueprint $table) {
+ $table->dropColumn('short');
+ });
+ }
+};
before: moment().startOf('day').add(8, 'days').toISOString(),
},
}).then(response => {
- const newEvents = response.data || [];
+ const newEvents = (response.data || []).sort(
+ (a, b) => (a.short || a.title).localeCompare(b.short || b.title)
+ );
setEvents(newEvents);
}).catch(e => {
if (!axios.isCancel(e)) {
if (!events || !events.length) return null;
- return <div className="episode-filter">
+ return <div className="episode-filter button-bar text-end">
{events.map(event =>
<Button
active={isEventSelected(event)}
key={event.id}
onClick={() => toggleEvent(event)}
+ title={event.short ? event.title : null}
variant="outline-secondary"
>
- {event.title}
+ {event.short || event.title}
</Button>
)}
</div>;
import axios from 'axios';
import moment from 'moment';
import React from 'react';
-import { Container } from 'react-bootstrap';
+import { Alert, Container } from 'react-bootstrap';
import { Helmet } from 'react-helmet';
import { useTranslation } from 'react-i18next';
import List from '../episodes/List';
const Schedule = () => {
- const [ahead, setAhead] = React.useState(6);
+ const [ahead, setAhead] = React.useState(14);
const [behind, setBehind] = React.useState(0);
const [episodes, setEpisodes] = React.useState([]);
const [filter, setFilter] = React.useState({});
<meta name="description" content={t('schedule.description')} />
</Helmet>
<CanonicalLinks base="/schedule" />
- <h1>{t('schedule.heading')}</h1>
+ <div className="d-flex align-items-start justify-content-between">
+ <h1>{t('schedule.heading')}</h1>
+ <div className="mt-5">
+ <Filter filter={filter} setFilter={updateFilter} />
+ </div>
+ </div>
<ErrorBoundary>
- <Filter filter={filter} setFilter={updateFilter} />
- <List episodes={episodes} />
+ {episodes.length ?
+ <List episodes={episodes} />
+ :
+ <Alert variant="info">
+ {t('episodes.empty')}
+ </Alert>
+ }
</ErrorBoundary>
</Container>;
};
},
episodes: {
commentary: 'Kommentar',
+ empty: 'Keine anstehenden Termine.',
setup: 'Setup',
tracking: 'Tracking',
},
},
episodes: {
commentary: 'Commentary',
+ empty: 'No dates coming up.',
setup: 'Setup',
tracking: 'Tracking',
},