forked from phc/orario
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
105 lines
4.7 KiB
JavaScript
105 lines
4.7 KiB
JavaScript
import { useEffect, useRef } from 'preact/hooks'
|
|
|
|
import _ from 'lodash'
|
|
import { differenceInMinutes, startOfDay } from 'date-fns'
|
|
|
|
import { hashString, normalizeCourseName, WEEK_DAYS } from '../../utils.jsx'
|
|
import { layoutIntervals } from '../../interval-layout.js'
|
|
|
|
export const WorkWeekTranspose = ({ events }) => {
|
|
const eventsByWeekday = _.groupBy(events, event => event.start.getDay())
|
|
|
|
// For each weekday compute the interval layout
|
|
const rowLayouts = _.mapValues(eventsByWeekday, events =>
|
|
layoutIntervals(
|
|
events.map(e => ({
|
|
start: differenceInMinutes(e.start, startOfDay(e.start)),
|
|
end: differenceInMinutes(e.end, startOfDay(e.start)),
|
|
data: e,
|
|
}))
|
|
)
|
|
)
|
|
|
|
return (
|
|
<div class="work-week-h-view">
|
|
<div class="week">
|
|
{WEEK_DAYS.slice(1, 6).map((label, index) => (
|
|
<div class="day" style={{ '--size': rowLayouts[index + 1]?.length ?? 0 }}>
|
|
{label}
|
|
</div>
|
|
))}
|
|
</div>
|
|
<div class="events">
|
|
<div class="header">
|
|
<div class="label" style={{ 'grid-column': '2 / span 2' }}>
|
|
9:00 – 11:00
|
|
</div>
|
|
<div class="label" style={{ 'grid-column': '4 / span 2' }}>
|
|
11:00 – 13:00
|
|
</div>
|
|
<div class="label" style={{ 'grid-column': '7 / span 2' }}>
|
|
14:00 – 16:00
|
|
</div>
|
|
<div class="label" style={{ 'grid-column': '9 / span 2' }}>
|
|
16:00 – 18:00
|
|
</div>
|
|
</div>
|
|
<div class="days">
|
|
{Object.values(rowLayouts).map(layout => (
|
|
<div class="day" style={{ '--size': layout.length }}>
|
|
{layout.map((events, rowIndex) =>
|
|
events.map(event => {
|
|
const Local = () => {
|
|
const eventRef = useRef()
|
|
|
|
const updateMinWidth = () => {
|
|
eventRef.current.style.minWidth =
|
|
eventRef.current.offsetWidth + 'px'
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (eventRef.current) {
|
|
setTimeout(updateMinWidth, 100)
|
|
window.addEventListener('resize', updateMinWidth)
|
|
|
|
return () => {
|
|
window.removeEventListener(
|
|
'resize',
|
|
updateMinWidth
|
|
)
|
|
}
|
|
}
|
|
}, [eventRef.current])
|
|
|
|
return (
|
|
<div
|
|
class="event"
|
|
style={{
|
|
'--row': rowIndex + 1,
|
|
'--start': event.start / 60 - 7,
|
|
'--size': (event.end - event.start) / 60,
|
|
'--hue':
|
|
(Math.abs(
|
|
hashString('seed3' + event.data.id)
|
|
) %
|
|
360) +
|
|
'deg',
|
|
}}
|
|
ref={eventRef}
|
|
>
|
|
{normalizeCourseName(event.data.name)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return <Local />
|
|
})
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|