Schedule view

compressed-week-view
Antonio De Lucreziis 2 years ago
parent 0f0bc1c52a
commit c0340c3407

@ -1,15 +1,18 @@
import { Course } from './view/Course.jsx' import { Course } from './view/Course.jsx'
import { Schedule } from './view/Schedule.jsx'
import { WorkWeek } from './view/WorkWeek.jsx' import { WorkWeek } from './view/WorkWeek.jsx'
import { WorkWeekTranspose } from './view/WorkWeekTranspose.jsx' import { WorkWeekTranspose } from './view/WorkWeekTranspose.jsx'
export const MODE_COURSE = 'course' export const MODE_COURSE = 'course'
export const MODE_WORKWEEK = 'work-week' export const MODE_WORKWEEK = 'work-week'
export const MODE_SCHEDULE = 'schedule'
export const MODE_WORKWEEK_TRANSPOSE = 'work-week-transpose' export const MODE_WORKWEEK_TRANSPOSE = 'work-week-transpose'
const viewModeMap = { const viewModeMap = {
[MODE_COURSE]: Course, [MODE_COURSE]: Course,
[MODE_WORKWEEK]: WorkWeek, [MODE_WORKWEEK]: WorkWeek,
[MODE_WORKWEEK_TRANSPOSE]: WorkWeekTranspose, [MODE_WORKWEEK_TRANSPOSE]: WorkWeekTranspose,
[MODE_SCHEDULE]: Schedule,
} }
export const EventsView = ({ mode, ...viewProps }) => { export const EventsView = ({ mode, ...viewProps }) => {

@ -1,5 +1,5 @@
import { ComboBox } from './ComboBox.jsx' import { ComboBox } from './ComboBox.jsx'
import { MODE_COURSE, MODE_WORKWEEK } from './EventsView.jsx' import { MODE_COURSE, MODE_SCHEDULE, MODE_WORKWEEK } from './EventsView.jsx'
import { Help } from './Help.jsx' import { Help } from './Help.jsx'
import { Icon } from './Icon.jsx' import { Icon } from './Icon.jsx'
@ -41,6 +41,7 @@ export const HamburgerMenu = ({ onClose, mode, setMode, source, setSource, theme
setValue={setMode} setValue={setMode}
options={[ options={[
{ value: MODE_COURSE, label: 'Corsi' }, { value: MODE_COURSE, label: 'Corsi' },
{ value: MODE_SCHEDULE, label: 'Giornaliera' },
{ value: MODE_WORKWEEK, label: 'Settimana' }, { value: MODE_WORKWEEK, label: 'Settimana' },
]} ]}
/> />

@ -1,5 +1,5 @@
import { CompoundButton } from './CompoundButton.jsx' import { CompoundButton } from './CompoundButton.jsx'
import { MODE_COURSE, MODE_WORKWEEK } from './EventsView.jsx' import { MODE_COURSE, MODE_SCHEDULE, MODE_WORKWEEK } from './EventsView.jsx'
import { Icon } from './Icon.jsx' import { Icon } from './Icon.jsx'
export const Toolbar = ({ export const Toolbar = ({
@ -43,6 +43,7 @@ export const Toolbar = ({
options={[ options={[
{ value: MODE_COURSE, label: 'Corsi' }, { value: MODE_COURSE, label: 'Corsi' },
{ value: MODE_WORKWEEK, label: 'Settimana' }, { value: MODE_WORKWEEK, label: 'Settimana' },
{ value: MODE_SCHEDULE, label: 'Giorno' },
]} ]}
value={mode} value={mode}
setValue={setMode} setValue={setMode}

@ -0,0 +1,54 @@
import { format } from 'date-fns'
import _ from 'lodash'
import { normalizeCourseName, WEEK_DAYS, withClasses } from '../../utils.jsx'
export const Schedule = ({ events, selection, setSelection, hideOtherCourses }) => {
const selectionSet = new Set(selection)
const visibleEvents = !hideOtherCourses ? events : events.filter(e => selectionSet.has(e.id))
const eventsByWeekday = _.mapValues(
_.groupBy(visibleEvents, e => e.start.getDay()),
dailyEvents => _.groupBy(dailyEvents, e => e.start.getHours())
)
return (
<div class="schedule-view">
{Object.entries(eventsByWeekday).map(([index, dailyEvents]) => (
<>
<div class="header giorno">
<div class="inner">{WEEK_DAYS[index]}</div>
</div>
{Object.values(dailyEvents).map(events => (
<>
<div class="header orario">{format(events[0].start, 'H:mm')}</div>
{events.map(event => (
<div
class={withClasses([
'event',
selectionSet.has(event.id) && 'selected',
])}
onClick={() => {
if (!selectionSet.has(event.id))
setSelection([...selection, event.id])
else
setSelection(
selection.filter(selId => selId !== event.id)
)
}}
>
<div class="title">{normalizeCourseName(event.name)}</div>
<div class="orario">
{format(event.start, 'H:mm')} &ndash;{' '}
{format(event.end, 'H:mm')}
</div>
<div class="aula">{event.aula}</div>
</div>
))}
</>
))}
</>
))}
</div>
)
}

@ -3,7 +3,7 @@ import { render } from 'preact'
import { useEffect, useState } from 'preact/hooks' import { useEffect, useState } from 'preact/hooks'
import { ToolOverlay } from './components/CourseVisibility.jsx' import { ToolOverlay } from './components/CourseVisibility.jsx'
import { EventsView } from './components/EventsView.jsx' import { EventsView, MODE_SCHEDULE } from './components/EventsView.jsx'
import { HamburgerMenu } from './components/HamburgerMenu.jsx' import { HamburgerMenu } from './components/HamburgerMenu.jsx'
import { Help } from './components/Help.jsx' import { Help } from './components/Help.jsx'
import { Icon } from './components/Icon.jsx' import { Icon } from './components/Icon.jsx'
@ -73,7 +73,7 @@ const App = ({}) => {
const [eventi, setEventi] = useState([]) const [eventi, setEventi] = useState([])
// View Modes // View Modes
const [mode, setMode] = useState('course') const [mode, setMode] = useState(MODE_SCHEDULE)
// Selection // Selection
const [selectedCourses, setSelectedCourses] = useState([]) const [selectedCourses, setSelectedCourses] = useState([])

@ -810,6 +810,85 @@ body {
} }
} }
} }
.schedule-view {
padding: 1rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
overflow-y: scroll;
height: 100%;
& > * {
max-width: 50rem;
}
.header {
position: relative;
width: 100%;
display: grid;
place-content: center;
&.giorno {
font-size: 24px;
font-weight: 400;
.inner {
background: var(--bg-500);
padding: 0 0.5rem;
}
&::before {
position: absolute;
content: '';
top: 50%;
left: 0;
right: 0;
height: 1px;
background: var(--border-600);
z-index: -1;
}
}
&.orario {
font-size: 18px;
font-weight: 300;
}
}
.event {
@extend .panel;
width: 100%;
.title {
font-size: 22px;
}
position: relative;
&.selected {
background: var(--bg-selected-500);
&::after {
content: '';
position: absolute;
inset: -1px;
border-radius: 1rem;
border: 3px solid var(--border-selected-500);
}
}
}
}
} }
.overlay { .overlay {

Loading…
Cancel
Save