Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ddf325c03 | ||
|
|
973acad17a | ||
|
|
c8172ad88a | ||
|
|
c0b2894c22 | ||
|
|
fd0440465c | ||
|
|
32dc9a6104 | ||
|
|
af41177561 |
+2
-1
@@ -16,7 +16,8 @@
|
|||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"preact": "^10.10.6",
|
"preact": "^10.10.6",
|
||||||
"sass": "^1.54.8",
|
"sass": "^1.54.8",
|
||||||
"vite": "^3.0.9"
|
"vite": "^3.0.9",
|
||||||
|
"yaml": "^2.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.18.13",
|
"@babel/core": "^7.18.13",
|
||||||
|
|||||||
Generated
+8
@@ -23,6 +23,9 @@ dependencies:
|
|||||||
vite:
|
vite:
|
||||||
specifier: ^3.0.9
|
specifier: ^3.0.9
|
||||||
version: 3.0.9(sass@1.54.8)
|
version: 3.0.9(sass@1.54.8)
|
||||||
|
yaml:
|
||||||
|
specifier: ^2.3.2
|
||||||
|
version: 2.3.2
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@babel/core':
|
'@babel/core':
|
||||||
@@ -937,3 +940,8 @@ packages:
|
|||||||
sass: 1.54.8
|
sass: 1.54.8
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.2
|
fsevents: 2.3.2
|
||||||
|
|
||||||
|
/yaml@2.3.2:
|
||||||
|
resolution: {integrity: sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==}
|
||||||
|
engines: {node: '>= 14'}
|
||||||
|
dev: false
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { useRef } from 'preact/hooks'
|
||||||
|
import { Icon } from './Icon.jsx'
|
||||||
|
|
||||||
|
export const DatePicker = ({ date, setDate }) => {
|
||||||
|
const input = useRef()
|
||||||
|
|
||||||
|
const [year, month, day] = date.split('T')[0].split('-')
|
||||||
|
return (
|
||||||
|
<div class="date-picker" onClick={() => input.current.showPicker()}>
|
||||||
|
<input
|
||||||
|
ref={input}
|
||||||
|
type="date"
|
||||||
|
value={`${year}-${month}-${day}`}
|
||||||
|
onChange={e => setDate(new Date(e.target.value).toISOString())}
|
||||||
|
/>
|
||||||
|
<div class="date-picker-render">
|
||||||
|
<div class="date">
|
||||||
|
{day}/{month}/{year}
|
||||||
|
</div>
|
||||||
|
<div class="calendar">
|
||||||
|
<Icon name="calendar_month" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,27 +1,17 @@
|
|||||||
import { ComboBox } from './ComboBox.jsx'
|
import { ComboBox } from './ComboBox.jsx'
|
||||||
import { MODE_COURSES, MODE_SCHEDULE, MODE_WORKWEEK, MODE_WORKWEEK_GRID } from './EventsView.jsx'
|
import {
|
||||||
|
MODE_COURSES,
|
||||||
|
MODE_SCHEDULE,
|
||||||
|
MODE_WORKWEEK,
|
||||||
|
MODE_WORKWEEK_GRID,
|
||||||
|
} from './EventsView.jsx'
|
||||||
|
import { DatePicker } from './DatePicker.jsx'
|
||||||
import { Help } from './Help.jsx'
|
import { Help } from './Help.jsx'
|
||||||
import { Icon } from './Icon.jsx'
|
import { Icon } from './Icon.jsx'
|
||||||
|
|
||||||
export const HamburgerMenu = ({ onClose, theme, setTheme }) => {
|
export const HamburgerMenu = ({ date, setDate, onClose, theme, setTheme }) => {
|
||||||
return (
|
return (
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
<div class="header">
|
|
||||||
<div class="option-group">
|
|
||||||
<button class="flat icon" onClick={onClose}>
|
|
||||||
<Icon name="close" />
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="icon"
|
|
||||||
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
|
|
||||||
>
|
|
||||||
<Icon name={theme === 'dark' ? 'dark_mode' : 'light_mode'} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="item logo">
|
|
||||||
<img src="logo-circuit-board.svg" alt="logo" /> / <span>Orario</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="help">
|
<div class="help">
|
||||||
<h2>
|
<h2>
|
||||||
<Icon name="info" />
|
<Icon name="info" />
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ export const Help = ({}) => (
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Una volta compiuta la selezione, è possibile vedere la tabella delle
|
Una volta compiuta la selezione, è possibile vedere la tabella delle
|
||||||
lezioni andando nella visualizzazione Orario
|
lezioni andando nella visualizzazione Orario (
|
||||||
|
<Icon name="calendar_view_month" />)
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Per via di eventuali preferenze personali, è possibile cambiare
|
Per via di eventuali preferenze personali, è possibile cambiare
|
||||||
@@ -20,6 +21,11 @@ export const Help = ({}) => (
|
|||||||
pulsante Trasponi (
|
pulsante Trasponi (
|
||||||
<Icon name="switch_left" style="transform: rotate(-45deg)" />)
|
<Icon name="switch_left" style="transform: rotate(-45deg)" />)
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
È anche possibile visualizzare in uno specchietto riassuntivo
|
||||||
|
soltanto i corsi selezionati, andando nella visualizzazione Lista (
|
||||||
|
<Icon name="list" />)
|
||||||
|
</p>
|
||||||
<h3>Stampa</h3>
|
<h3>Stampa</h3>
|
||||||
<p>
|
<p>
|
||||||
Da desktop puoi stampare l'orario attualmente visibile con il
|
Da desktop puoi stampare l'orario attualmente visibile con il
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { CompoundButton } from './CompoundButton.jsx'
|
import { CompoundButton } from './CompoundButton.jsx'
|
||||||
import { Icon } from './Icon.jsx'
|
import { Icon } from './Icon.jsx'
|
||||||
|
|
||||||
export const OptionBar = ({ source, setSource }) => {
|
export const OptionBar = ({ view, setView }) => {
|
||||||
return (
|
return (
|
||||||
<div class="option-bar">
|
<div class="option-bar">
|
||||||
<div class="option-group">
|
<div class="option-group">
|
||||||
@@ -14,20 +14,25 @@ export const OptionBar = ({ source, setSource }) => {
|
|||||||
{ value: 'magistrale', label: 'M' },
|
{ value: 'magistrale', label: 'M' },
|
||||||
{ value: 'tutti', label: 'Tutti' },
|
{ value: 'tutti', label: 'Tutti' },
|
||||||
]}
|
]}
|
||||||
value={source}
|
value={view}
|
||||||
setValue={setSource}
|
setValue={setView}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<CompoundButton
|
<CompoundButton
|
||||||
options={[
|
options={[
|
||||||
{
|
{
|
||||||
value: 'orario',
|
value: 'orario',
|
||||||
label: <Icon name="calendar_month" />,
|
label: <Icon name="calendar_view_month" />,
|
||||||
|
icon: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'lista',
|
||||||
|
label: <Icon name="list" />,
|
||||||
icon: true,
|
icon: true,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
value={source}
|
value={view}
|
||||||
setValue={setSource}
|
setValue={setView}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { DatePicker } from './DatePicker.jsx'
|
||||||
|
import { Icon } from './Icon.jsx'
|
||||||
|
|
||||||
|
export const SettingsBar = ({ theme, setTheme, date, setDate }) => {
|
||||||
|
return (
|
||||||
|
<div class="settings-bar">
|
||||||
|
<div class="settings-group">
|
||||||
|
<button
|
||||||
|
class="icon"
|
||||||
|
onClick={() =>
|
||||||
|
setTheme(theme === 'dark' ? 'light' : 'dark')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
name={theme === 'dark' ? 'dark_mode' : 'light_mode'}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="icon"
|
||||||
|
onClick={() =>
|
||||||
|
setTheme(theme === 'dark' ? 'light' : 'dark')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
name="add"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<DatePicker date={date} setDate={setDate} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
import { CompoundButton } from './CompoundButton.jsx'
|
import { CompoundButton } from './CompoundButton.jsx'
|
||||||
|
import { DatePicker } from './DatePicker.jsx'
|
||||||
import { Icon } from './Icon.jsx'
|
import { Icon } from './Icon.jsx'
|
||||||
|
|
||||||
export const Toolbar = ({
|
export const Toolbar = ({
|
||||||
source,
|
source,
|
||||||
setSource,
|
setSource,
|
||||||
onShowMenu,
|
date,
|
||||||
|
setDate,
|
||||||
|
showMobileMenu,
|
||||||
|
setShowMobileMenu,
|
||||||
onHelp,
|
onHelp,
|
||||||
theme,
|
theme,
|
||||||
setTheme,
|
setTheme,
|
||||||
@@ -12,8 +16,11 @@ export const Toolbar = ({
|
|||||||
return (
|
return (
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<div class="mobile">
|
<div class="mobile">
|
||||||
<button class="flat icon" onClick={onShowMenu}>
|
<button
|
||||||
<Icon name="menu" />
|
class="flat icon"
|
||||||
|
onClick={() => setShowMobileMenu(!showMobileMenu)}
|
||||||
|
>
|
||||||
|
<Icon name={`${showMobileMenu ? 'close' : 'menu'}`} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="item logo">
|
<div class="item logo">
|
||||||
@@ -29,6 +36,7 @@ export const Toolbar = ({
|
|||||||
{ value: 'anno-3', label: 'III' },
|
{ value: 'anno-3', label: 'III' },
|
||||||
{ value: 'magistrale', label: 'Magistrale' },
|
{ value: 'magistrale', label: 'Magistrale' },
|
||||||
{ value: 'tutti', label: 'Tutti' },
|
{ value: 'tutti', label: 'Tutti' },
|
||||||
|
{ value: 'custom', label: 'Custom' },
|
||||||
]}
|
]}
|
||||||
value={source}
|
value={source}
|
||||||
setValue={setSource}
|
setValue={setSource}
|
||||||
@@ -38,11 +46,16 @@ export const Toolbar = ({
|
|||||||
<CompoundButton
|
<CompoundButton
|
||||||
options={[
|
options={[
|
||||||
{ value: 'orario', label: 'Orario' },
|
{ value: 'orario', label: 'Orario' },
|
||||||
|
{ value: 'lista', label: 'Lista' },
|
||||||
]}
|
]}
|
||||||
value={source}
|
value={source}
|
||||||
setValue={setSource}
|
setValue={setSource}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="empty"></div>
|
||||||
|
<div class="item option">
|
||||||
|
<DatePicker date={date} setDate={setDate} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="option-group">
|
<div class="option-group">
|
||||||
<div class="item option">
|
<div class="item option">
|
||||||
|
|||||||
@@ -2,13 +2,29 @@ import { format } from 'date-fns'
|
|||||||
|
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { useEffect, useRef, useState } from 'preact/hooks'
|
import { useEffect, useRef, useState } from 'preact/hooks'
|
||||||
import { prettyCourseName, WEEK_DAYS } from '../../utils.jsx'
|
import { parseCustomEvents, prettyCourseName, WEEK_DAYS } from '../../utils.jsx'
|
||||||
|
import { Icon } from '../Icon.jsx'
|
||||||
|
|
||||||
export const Courses = ({ source, timetables, selection, setSelection }) => {
|
export const Courses = ({
|
||||||
const events = timetables[source]
|
source,
|
||||||
|
timetables,
|
||||||
|
selection,
|
||||||
|
setSelection,
|
||||||
|
custom,
|
||||||
|
isRestrictedList,
|
||||||
|
}) => {
|
||||||
|
const events = isRestrictedList ? timetables['tutti'] : timetables[source]
|
||||||
const selectionSet = new Set(selection)
|
const selectionSet = new Set(selection)
|
||||||
|
|
||||||
const eventsByCourse = _.groupBy(_.sortBy(events, 'id'), 'id')
|
console.log(events)
|
||||||
|
|
||||||
|
const visibleEvents = isRestrictedList
|
||||||
|
? events
|
||||||
|
.filter(e => selectionSet.has(e.id))
|
||||||
|
.concat(parseCustomEvents(custom))
|
||||||
|
: events
|
||||||
|
|
||||||
|
const eventsByCourse = _.groupBy(_.sortBy(visibleEvents, 'id'), 'id')
|
||||||
|
|
||||||
const profsPerCourse = _.mapValues(eventsByCourse, events =>
|
const profsPerCourse = _.mapValues(eventsByCourse, events =>
|
||||||
_.uniq(events.flatMap(event => event.docenti))
|
_.uniq(events.flatMap(event => event.docenti))
|
||||||
@@ -42,28 +58,53 @@ export const Courses = ({ source, timetables, selection, setSelection }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="course-view" ref={element}>
|
<div class="course-view" ref={element}>
|
||||||
|
{isRestrictedList && selection.length === 0 && (
|
||||||
|
<div class="warning">
|
||||||
|
<p>Non hai ancora selezionato nessun corso.</p>
|
||||||
|
<p>
|
||||||
|
Clicca sui corsi nelle altre visuali per selezionarli e
|
||||||
|
visualizzarli nella lista
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div class="wrap-container">
|
<div class="wrap-container">
|
||||||
{Object.entries(eventsByCourse).map(([id, courseEvents]) => (
|
{Object.entries(eventsByCourse).map(([id, courseEvents]) => (
|
||||||
<div
|
<div
|
||||||
class={
|
class={
|
||||||
'course' +
|
'course' +
|
||||||
(currentlyHovered === id ? ' highlight' : '') +
|
(currentlyHovered === id && !isRestrictedList
|
||||||
(selectionSet.has(id) ? ' selected' : '')
|
? ' highlight'
|
||||||
|
: '') +
|
||||||
|
(selectionSet.has(id) && !isRestrictedList
|
||||||
|
? ' selected'
|
||||||
|
: '')
|
||||||
}
|
}
|
||||||
data-course-id={id}
|
data-course-id={id}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!selectionSet.has(id)) setSelection([...selection, id])
|
if (isRestrictedList) return
|
||||||
else setSelection(selection.filter(selId => selId !== id))
|
if (!selectionSet.has(id))
|
||||||
|
setSelection([...selection, id])
|
||||||
|
else
|
||||||
|
setSelection(
|
||||||
|
selection.filter(selId => selId !== id)
|
||||||
|
)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="title">{prettyCourseName(courseEvents[0].name)}</div>
|
<div class="title">
|
||||||
<div class="docenti">{profsPerCourse[id].join(', ')}</div>
|
{prettyCourseName(courseEvents[0].name)}
|
||||||
|
</div>
|
||||||
|
<div class="docenti">
|
||||||
|
{profsPerCourse[id].join(', ')}
|
||||||
|
</div>
|
||||||
<div class="events">
|
<div class="events">
|
||||||
{courseEvents.map(course => (
|
{courseEvents.map(course => (
|
||||||
<div>
|
<div>
|
||||||
{WEEK_DAYS[course.start.getDay()]}{' '}
|
{WEEK_DAYS[course.day]} {course.start / 60}:
|
||||||
{format(course.start, 'H:mm')}–
|
{String(course.start % 60).padStart(2, '0')}
|
||||||
{format(course.end, 'H:mm')} {course.aule.join(', ')}
|
–
|
||||||
|
{course.end / 60}:
|
||||||
|
{String(course.end % 60).padStart(2, '0')}{' '}
|
||||||
|
{course.aule.join(', ')}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { useEffect, useRef, useState } from 'preact/hooks'
|
import { useEffect, useRef, useState } from 'preact/hooks'
|
||||||
|
|
||||||
import _ from 'lodash'
|
import _, { parseInt } from 'lodash'
|
||||||
import { differenceInMinutes, startOfDay } from 'date-fns'
|
import { differenceInMinutes, startOfDay } from 'date-fns'
|
||||||
|
import { parse } from 'yaml'
|
||||||
|
import { parseCustomEvents } from '../../utils.jsx'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
WEEK_DAYS_SHORT,
|
WEEK_DAYS_SHORT,
|
||||||
@@ -46,7 +48,7 @@ const TransposePopup = ({ onClose }) => {
|
|||||||
|
|
||||||
const NoCourseWarning = () => {
|
const NoCourseWarning = () => {
|
||||||
return (
|
return (
|
||||||
<div class="no-courses-warning">
|
<div class="warning">
|
||||||
<p>Non hai ancora selezionato nessun corso.</p>
|
<p>Non hai ancora selezionato nessun corso.</p>
|
||||||
<p>
|
<p>
|
||||||
Clicca sui corsi nelle altre visuali per selezionarli e
|
Clicca sui corsi nelle altre visuali per selezionarli e
|
||||||
@@ -57,7 +59,6 @@ const NoCourseWarning = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Layout = ({ layout, day, colors }) => {
|
const Layout = ({ layout, day, colors }) => {
|
||||||
console.log(layout)
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{layout.map(block => (
|
{layout.map(block => (
|
||||||
@@ -211,7 +212,7 @@ const ScheduleCard = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Schedule = ({ timetables, selection, setSelection }) => {
|
export const Schedule = ({ timetables, selection, custom }) => {
|
||||||
const [hasSeenTranspose, setHasSeenTranspose] = usePersistentState(
|
const [hasSeenTranspose, setHasSeenTranspose] = usePersistentState(
|
||||||
'transpose_info',
|
'transpose_info',
|
||||||
'false'
|
'false'
|
||||||
@@ -233,14 +234,8 @@ export const Schedule = ({ timetables, selection, setSelection }) => {
|
|||||||
|
|
||||||
const allEvents = timetables['tutti']
|
const allEvents = timetables['tutti']
|
||||||
const selectionSet = new Set(selection)
|
const selectionSet = new Set(selection)
|
||||||
const events = allEvents
|
const events = allEvents.filter(e => selectionSet.has(e.id))
|
||||||
.filter(e => selectionSet.has(e.id))
|
parseCustomEvents(custom).forEach(event => events.push(event))
|
||||||
.map(e => ({
|
|
||||||
...e,
|
|
||||||
day: e.start.getDay(),
|
|
||||||
start: differenceInMinutes(e.start, startOfDay(e.start)),
|
|
||||||
end: differenceInMinutes(e.end, startOfDay(e.start)),
|
|
||||||
}))
|
|
||||||
|
|
||||||
const weekStart = Math.min(...events.map(e => e.start), 9 * 60) / 30
|
const weekStart = Math.min(...events.map(e => e.start), 9 * 60) / 30
|
||||||
const weekEnd = Math.max(...events.map(e => e.end), 18 * 60) / 30
|
const weekEnd = Math.max(...events.map(e => e.end), 18 * 60) / 30
|
||||||
|
|||||||
+161
-80
@@ -1,6 +1,7 @@
|
|||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { render } from 'preact'
|
import { render } from 'preact'
|
||||||
import { useEffect, useState } from 'preact/hooks'
|
import { useEffect, useState } from 'preact/hooks'
|
||||||
|
import { differenceInMinutes, startOfDay } from 'date-fns'
|
||||||
|
|
||||||
// import { ToolOverlay } from './components/ToolOverlay.jsx'
|
// import { ToolOverlay } from './components/ToolOverlay.jsx'
|
||||||
//
|
//
|
||||||
@@ -18,12 +19,8 @@ import { Icon } from './components/Icon.jsx'
|
|||||||
import { Popup } from './components/Popup.jsx'
|
import { Popup } from './components/Popup.jsx'
|
||||||
import { Toolbar } from './components/Toolbar.jsx'
|
import { Toolbar } from './components/Toolbar.jsx'
|
||||||
import { OptionBar } from './components/OptionBar.jsx'
|
import { OptionBar } from './components/OptionBar.jsx'
|
||||||
import {
|
import { prettyAulaName, prettyProfName, usePersistentState } from './utils.jsx'
|
||||||
prettyAulaName,
|
import { SettingsBar } from './components/SettingsBar.jsx'
|
||||||
prettyProfName,
|
|
||||||
clearOldPersistentStates,
|
|
||||||
usePersistentState,
|
|
||||||
} from './utils.jsx'
|
|
||||||
|
|
||||||
// Che fanno queste due righe?
|
// Che fanno queste due righe?
|
||||||
window._ = _
|
window._ = _
|
||||||
@@ -36,17 +33,17 @@ const TIMETABLE_IDS = {
|
|||||||
'magistrale': '64a7c7091ab813002c5d9ede',
|
'magistrale': '64a7c7091ab813002c5d9ede',
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_DATE_RANGE = {
|
// const DEFAULT_DATE_RANGE = {
|
||||||
from: '2023-10-09T00:00:00.000Z',
|
// from: '2023-10-09T00:00:00.000Z',
|
||||||
to: '2023-10-14T00:00:00.000Z',
|
// to: '2023-10-14T00:00:00.000Z',
|
||||||
}
|
// }
|
||||||
|
|
||||||
const DATE_RANGES = {
|
// const DATE_RANGES = {
|
||||||
'64a7c1c651f079001d52e9c8': DEFAULT_DATE_RANGE,
|
// '64a7c1c651f079001d52e9c8': DEFAULT_DATE_RANGE,
|
||||||
'6308e2dc09352a0208fefdd9': DEFAULT_DATE_RANGE,
|
// '6308e2dc09352a0208fefdd9': DEFAULT_DATE_RANGE,
|
||||||
'6308e42a1df5cb026699ced4': DEFAULT_DATE_RANGE,
|
// '6308e42a1df5cb026699ced4': DEFAULT_DATE_RANGE,
|
||||||
'64a7c7091ab813002c5d9ede': DEFAULT_DATE_RANGE,
|
// '64a7c7091ab813002c5d9ede': DEFAULT_DATE_RANGE,
|
||||||
}
|
// }
|
||||||
|
|
||||||
function specialEventPatches(eventi) {
|
function specialEventPatches(eventi) {
|
||||||
// Il laboratorio del primo anno in realtà è in due canali separati
|
// Il laboratorio del primo anno in realtà è in due canali separati
|
||||||
@@ -66,11 +63,14 @@ function specialEventPatches(eventi) {
|
|||||||
|
|
||||||
function formatEvents(timetable) {
|
function formatEvents(timetable) {
|
||||||
return timetable.map(({ nome, dataInizio, dataFine, docenti, aule }) => {
|
return timetable.map(({ nome, dataInizio, dataFine, docenti, aule }) => {
|
||||||
|
const start = new Date(dataInizio)
|
||||||
|
const end = new Date(dataFine)
|
||||||
return {
|
return {
|
||||||
id: nome,
|
id: nome,
|
||||||
name: _.split(nome, '-', 1)[0].trim(),
|
name: _.split(nome, '-', 1)[0].trim(),
|
||||||
start: new Date(dataInizio),
|
day: start.getDay(),
|
||||||
end: new Date(dataFine),
|
start: differenceInMinutes(start, startOfDay(start)),
|
||||||
|
end: differenceInMinutes(end, startOfDay(start)),
|
||||||
docenti: docenti.map(({ nome, cognome }) =>
|
docenti: docenti.map(({ nome, cognome }) =>
|
||||||
prettyProfName(nome, cognome)
|
prettyProfName(nome, cognome)
|
||||||
),
|
),
|
||||||
@@ -79,7 +79,18 @@ function formatEvents(timetable) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadCalendari() {
|
async function loadCalendari(date) {
|
||||||
|
function getMonday(d) {
|
||||||
|
const day = d.getDay()
|
||||||
|
const diff = d.getDate() - day + (day === 0 ? -6 : 1)
|
||||||
|
const monday = new Date(d.setDate(diff))
|
||||||
|
monday.setUTCHours(0, 0, 0, 0)
|
||||||
|
return monday
|
||||||
|
}
|
||||||
|
const monday = getMonday(date)
|
||||||
|
const saturday = new Date(monday)
|
||||||
|
saturday.setDate(monday.getDate() + 5)
|
||||||
|
|
||||||
async function req(id) {
|
async function req(id) {
|
||||||
// Almost directly copy-pasted from Chrome Dev Tools
|
// Almost directly copy-pasted from Chrome Dev Tools
|
||||||
const req = await fetch(
|
const req = await fetch(
|
||||||
@@ -97,8 +108,8 @@ async function loadCalendari() {
|
|||||||
linkCalendarioId: id,
|
linkCalendarioId: id,
|
||||||
clienteId: '628de8b9b63679f193b87046',
|
clienteId: '628de8b9b63679f193b87046',
|
||||||
pianificazioneTemplate: false,
|
pianificazioneTemplate: false,
|
||||||
dataInizio: DATE_RANGES[id].from,
|
dataInizio: monday.toISOString(),
|
||||||
dataFine: DATE_RANGES[id].to,
|
dataFine: saturday.toISOString(),
|
||||||
}),
|
}),
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
mode: 'cors',
|
mode: 'cors',
|
||||||
@@ -130,23 +141,78 @@ async function loadCalendari() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const View = ({
|
||||||
|
view,
|
||||||
|
selection,
|
||||||
|
setSelection,
|
||||||
|
timetables,
|
||||||
|
custom,
|
||||||
|
setCustom,
|
||||||
|
}) => {
|
||||||
|
if (view === 'orario') {
|
||||||
|
return (
|
||||||
|
<Schedule
|
||||||
|
selection={selection}
|
||||||
|
timetables={timetables}
|
||||||
|
custom={custom}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
} else if (view === 'lista') {
|
||||||
|
return (
|
||||||
|
<Courses
|
||||||
|
selection={selection}
|
||||||
|
setSelection={setSelection}
|
||||||
|
timetables={timetables}
|
||||||
|
custom={custom}
|
||||||
|
isRestrictedList={true}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
} else if (view === 'custom') {
|
||||||
|
return (
|
||||||
|
<div class="custom-events-view">
|
||||||
|
<textarea
|
||||||
|
value={custom}
|
||||||
|
onChange={e => setCustom(e.target.value)}
|
||||||
|
/>
|
||||||
|
<p>Esempio di evento personalizzato</p>
|
||||||
|
<p>
|
||||||
|
Nome evento [label globale]:
|
||||||
|
<br />
|
||||||
|
- Lun 9-11
|
||||||
|
<br />
|
||||||
|
- Mar 9:00-11:00
|
||||||
|
<br />- Gio 8:00-12:00 [label locale]
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<Courses
|
||||||
|
selection={selection}
|
||||||
|
setSelection={setSelection}
|
||||||
|
source={view}
|
||||||
|
timetables={timetables}
|
||||||
|
isRestrictedList={false}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
const App = ({}) => {
|
const App = ({}) => {
|
||||||
// Clear persistent states unless state_token corresponds to the one passed
|
// Clear persistent states unless state_token corresponds to the one passed
|
||||||
// as the argument. Useful with breaking updates. Change this token if your
|
// as the argument. Useful with breaking updates. Change this token if your
|
||||||
// (breaking) update needs a reset of persistent states to avoid crashes.
|
// (breaking) update needs a reset of persistent states to avoid crashes.
|
||||||
//
|
//
|
||||||
// Use any random string of your choice
|
// Use any random string of your choice
|
||||||
clearOldPersistentStates('e73cba02')
|
// clearOldPersistentStates('e73cba02')
|
||||||
|
|
||||||
|
const [date, setDate] = useState(new Date().toISOString())
|
||||||
|
|
||||||
// Data Sources
|
// Data Sources
|
||||||
const [source, setSource] = usePersistentState('source', 'magistrale')
|
const [view, setView] = usePersistentState('view', 'magistrale')
|
||||||
const [timetables, setTimetables] = useState(null)
|
const [timetables, setTimetables] = useState(null)
|
||||||
useEffect(async () => {
|
useEffect(async () => {
|
||||||
setTimetables(await loadCalendari())
|
setTimetables(await loadCalendari(new Date(date)))
|
||||||
}, [])
|
}, [date])
|
||||||
|
|
||||||
// View Modes
|
|
||||||
// const [mode, setMode] = usePersistentState('orario.mode', MODE_COURSES)
|
|
||||||
|
|
||||||
// Selection
|
// Selection
|
||||||
const [selectedCourses, setSelectedCourses] = usePersistentState(
|
const [selectedCourses, setSelectedCourses] = usePersistentState(
|
||||||
@@ -154,6 +220,9 @@ const App = ({}) => {
|
|||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Custom Events
|
||||||
|
const [custom, setCustom] = usePersistentState('custom', [])
|
||||||
|
|
||||||
// Menus
|
// Menus
|
||||||
const [helpVisible, setHelpVisible] = useState(false)
|
const [helpVisible, setHelpVisible] = useState(false)
|
||||||
const [showMobileMenu, setShowMobileMenu] = useState(false)
|
const [showMobileMenu, setShowMobileMenu] = useState(false)
|
||||||
@@ -175,69 +244,81 @@ const App = ({}) => {
|
|||||||
<>
|
<>
|
||||||
<Toolbar
|
<Toolbar
|
||||||
{...{
|
{...{
|
||||||
source,
|
source: view,
|
||||||
setSource,
|
setSource: setView,
|
||||||
onShowMenu: () => setShowMobileMenu(true),
|
date: date,
|
||||||
|
setDate: setDate,
|
||||||
|
showMobileMenu: showMobileMenu,
|
||||||
|
setShowMobileMenu: setShowMobileMenu,
|
||||||
onHelp: () => setHelpVisible(true),
|
onHelp: () => setHelpVisible(true),
|
||||||
theme,
|
theme,
|
||||||
setTheme,
|
setTheme,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<OptionBar
|
{showMobileMenu ? (
|
||||||
{...{
|
<SettingsBar
|
||||||
source,
|
|
||||||
setSource,
|
|
||||||
onHelp: () => setHelpVisible(true),
|
|
||||||
}}
|
|
||||||
orizzontale
|
|
||||||
/>
|
|
||||||
|
|
||||||
{timetables && (
|
|
||||||
<div class="content">
|
|
||||||
{source === 'orario' ? (
|
|
||||||
<Schedule
|
|
||||||
selection={selectedCourses}
|
|
||||||
setSelection={setSelectedCourses}
|
|
||||||
start={new Date(2022, 10, 3)}
|
|
||||||
source={source}
|
|
||||||
timetables={timetables}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Courses
|
|
||||||
selection={selectedCourses}
|
|
||||||
setSelection={setSelectedCourses}
|
|
||||||
start={new Date(2022, 10, 3)}
|
|
||||||
source={source}
|
|
||||||
timetables={timetables}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{/* toolOverlayVisible && (
|
|
||||||
<ToolOverlay
|
|
||||||
mode={mode}
|
|
||||||
toggleMode={() =>
|
|
||||||
setMode(
|
|
||||||
mode === MODE_COURSES ? MODE_SCHEDULE : MODE_COURSES
|
|
||||||
)
|
|
||||||
}
|
|
||||||
onClose={() => {
|
|
||||||
setSelectedCourses([])
|
|
||||||
setMode(MODE_COURSES)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) */}
|
|
||||||
{showMobileMenu && (
|
|
||||||
<HamburgerMenu
|
|
||||||
{...{
|
{...{
|
||||||
theme,
|
theme,
|
||||||
setTheme,
|
setTheme,
|
||||||
onClose: () => {
|
date,
|
||||||
setShowMobileMenu(false)
|
setDate,
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<OptionBar
|
||||||
|
{...{
|
||||||
|
view: view,
|
||||||
|
setView: setView,
|
||||||
|
onHelp: () => setHelpVisible(true),
|
||||||
|
}}
|
||||||
|
orizzontale
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
{timetables &&
|
||||||
|
(showMobileMenu ? (
|
||||||
|
<HamburgerMenu
|
||||||
|
{...{
|
||||||
|
date,
|
||||||
|
setDate,
|
||||||
|
theme,
|
||||||
|
setTheme,
|
||||||
|
onClose: () => {
|
||||||
|
setShowMobileMenu(false)
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : timetables['tutti'].length === 0 ? (
|
||||||
|
<div class="warning">
|
||||||
|
<p>
|
||||||
|
Non esistono corsi per la settimana selezionata:
|
||||||
|
buone vacanze! 🎉
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Per cambiare settimana puoi usare il widget
|
||||||
|
Calendario (
|
||||||
|
<Icon name="calendar_month" />) in alto a destra
|
||||||
|
<br />
|
||||||
|
In versione mobile, il widget Calendario è
|
||||||
|
situato dentro il Menu (
|
||||||
|
<Icon name="menu" />)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<View
|
||||||
|
selection={selectedCourses}
|
||||||
|
setSelection={setSelectedCourses}
|
||||||
|
view={view}
|
||||||
|
timetables={timetables}
|
||||||
|
custom={custom}
|
||||||
|
setCustom={setCustom}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* showMobileMenu && (
|
||||||
|
) */}
|
||||||
{helpVisible && (
|
{helpVisible && (
|
||||||
<Popup
|
<Popup
|
||||||
title={
|
title={
|
||||||
|
|||||||
+167
-83
@@ -374,6 +374,47 @@ button,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.date-picker {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
// align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
height: 2.5rem;
|
||||||
|
padding-left: 0.75rem;
|
||||||
|
padding-right: 0.75rem;
|
||||||
|
|
||||||
|
background: var(--bg-500);
|
||||||
|
border: 2px solid var(--border-400);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
|
||||||
|
font-weight: 400;
|
||||||
|
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
input {
|
||||||
|
z-index: -1;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-picker-render {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
.material-symbols-outlined {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Extension Classes
|
// Extension Classes
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
@@ -444,7 +485,8 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.option-bar {
|
.option-bar,
|
||||||
|
.settings-bar {
|
||||||
@extend .panel;
|
@extend .panel;
|
||||||
|
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
@@ -469,30 +511,60 @@ body {
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.option-group {
|
.option-group,
|
||||||
|
.settings-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-bar {
|
||||||
|
@media screen and (max-width: $device-s-width), (pointer: coarse) {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
height: calc(100vh - 4rem);
|
height: calc(100dvh - 4rem);
|
||||||
@media screen and (max-width: $device-s-width), (pointer: coarse) {
|
@media screen and (max-width: $device-s-width), (pointer: coarse) {
|
||||||
height: calc(100vh - 8rem);
|
height: calc(100dvh - 8rem);
|
||||||
|
}
|
||||||
|
overflow-y: scroll;
|
||||||
|
|
||||||
|
padding: 1rem 0rem;
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
@extend .text-block;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
p {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-view {
|
.course-view {
|
||||||
padding: 1rem;
|
padding: 0rem 1rem;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
height: 100%;
|
min-height: 100%;
|
||||||
|
|
||||||
overflow-y: scroll;
|
text-align: center;
|
||||||
|
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
.wrap-container {
|
.wrap-container {
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -550,30 +622,18 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.schedule-view {
|
.schedule-view {
|
||||||
height: 100%;
|
min-height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 57rem;
|
max-width: 55rem;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
|
||||||
padding: 1rem 0.5rem;
|
padding: 0rem 0.5rem;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
|
|
||||||
.no-courses-warning {
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1rem;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
p {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.schedule-card {
|
.schedule-card {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
@@ -773,6 +833,91 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.menu {
|
||||||
|
// position: absolute;
|
||||||
|
// top: 0;
|
||||||
|
// left: 0;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
|
||||||
|
background: var(--bg-500);
|
||||||
|
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
height: 4rem;
|
||||||
|
|
||||||
|
padding: 0.75rem 1rem 0.75rem 0.75rem;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
border-bottom: 1px solid var(--border-500);
|
||||||
|
|
||||||
|
.option-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
padding: 1rem;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
width: calc(100% - 2rem);
|
||||||
|
height: 1px;
|
||||||
|
left: 1rem;
|
||||||
|
|
||||||
|
background: var(--border-500);
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help {
|
||||||
|
@extend .text-block;
|
||||||
|
|
||||||
|
padding: 1rem 1rem 2.5rem;
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-events-view {
|
||||||
|
min-height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 30rem;
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
padding: 1rem 1rem;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 20rem;
|
||||||
|
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.overlay {
|
.overlay {
|
||||||
@@ -808,67 +953,6 @@ body {
|
|||||||
animation: fade-in 150ms ease-in forwards;
|
animation: fade-in 150ms ease-in forwards;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
|
|
||||||
background: var(--bg-500);
|
|
||||||
|
|
||||||
z-index: 10;
|
|
||||||
|
|
||||||
.header {
|
|
||||||
height: 4rem;
|
|
||||||
|
|
||||||
padding: 0.75rem 1rem 0.75rem 0.75rem;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
border-bottom: 1px solid var(--border-500);
|
|
||||||
|
|
||||||
.option-group {
|
|
||||||
display: flex;
|
|
||||||
gap: 0.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.options {
|
|
||||||
padding: 1rem;
|
|
||||||
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: auto 1fr;
|
|
||||||
|
|
||||||
gap: 1rem;
|
|
||||||
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.label {
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
width: calc(100% - 2rem);
|
|
||||||
height: 1px;
|
|
||||||
left: 1rem;
|
|
||||||
|
|
||||||
background: var(--border-500);
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.help {
|
|
||||||
@extend .text-block;
|
|
||||||
|
|
||||||
padding: 1rem 1rem 2.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// not on mobile
|
// not on mobile
|
||||||
|
|
||||||
@media screen and (min-width: $device-s-width) and (pointer: fine) {
|
@media screen and (min-width: $device-s-width) and (pointer: fine) {
|
||||||
|
|||||||
+60
-11
@@ -1,6 +1,7 @@
|
|||||||
// Calendar
|
|
||||||
|
|
||||||
import { useEffect, useState } from 'preact/hooks'
|
import { useEffect, useState } from 'preact/hooks'
|
||||||
|
import { parse } from 'yaml'
|
||||||
|
|
||||||
|
// Calendar
|
||||||
|
|
||||||
export const WEEK_DAYS = [
|
export const WEEK_DAYS = [
|
||||||
'Domenica',
|
'Domenica',
|
||||||
@@ -12,15 +13,7 @@ export const WEEK_DAYS = [
|
|||||||
'Sabato',
|
'Sabato',
|
||||||
]
|
]
|
||||||
|
|
||||||
export const WEEK_DAYS_SHORT = [
|
export const WEEK_DAYS_SHORT = ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab']
|
||||||
'Dom',
|
|
||||||
'Lun',
|
|
||||||
'Mar',
|
|
||||||
'Mer',
|
|
||||||
'Gio',
|
|
||||||
'Ven',
|
|
||||||
'Sab'
|
|
||||||
]
|
|
||||||
|
|
||||||
// Hashing
|
// Hashing
|
||||||
|
|
||||||
@@ -77,6 +70,62 @@ export function prettyProfName(nome, cognome) {
|
|||||||
.join('')
|
.join('')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Custom events
|
||||||
|
|
||||||
|
export function parseCustomEvents(customEventsString) {
|
||||||
|
try {
|
||||||
|
const customEvents = []
|
||||||
|
const parsedEvents = parse(customEventsString)
|
||||||
|
for (const customCourse in parsedEvents) {
|
||||||
|
const [_, name, teachers] = /([^\[]*)(?:\[(.*)\])?/.exec(
|
||||||
|
customCourse
|
||||||
|
)
|
||||||
|
const docenti = teachers ? teachers.split(',') : []
|
||||||
|
for (const customEvent of parsedEvents[customCourse]) {
|
||||||
|
const [_b, day, startH, startM, endH, endM, label] =
|
||||||
|
/(lun|lunedì|mar|martedì|mer|mercoledì|gio|giovedì|ven|venerdì)\s*(\d{1,2})(?:\:(\d\d))?\s*-\s*(\d{1,2})(?:\:(\d\d))?\s*(.*)?/i.exec(
|
||||||
|
customEvent
|
||||||
|
)
|
||||||
|
const dayNumber = {
|
||||||
|
lun: 1,
|
||||||
|
lunedì: 1,
|
||||||
|
mar: 2,
|
||||||
|
martedì: 2,
|
||||||
|
mer: 3,
|
||||||
|
mercoledì: 3,
|
||||||
|
gio: 4,
|
||||||
|
giovedì: 4,
|
||||||
|
ven: 5,
|
||||||
|
venerdì: 5,
|
||||||
|
}[day.toLowerCase()]
|
||||||
|
|
||||||
|
const start = startM
|
||||||
|
? parseInt(startH) * 60 + parseInt(startM)
|
||||||
|
: parseInt(startH) * 60
|
||||||
|
const end = endM
|
||||||
|
? parseInt(endH) * 60 + parseInt(endM)
|
||||||
|
: parseInt(endH) * 60
|
||||||
|
|
||||||
|
const aule = label ? label.split(',') : []
|
||||||
|
|
||||||
|
customEvents.push({
|
||||||
|
id: name,
|
||||||
|
name,
|
||||||
|
docenti,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
day: dayNumber,
|
||||||
|
aule,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return customEvents
|
||||||
|
} catch (e) {
|
||||||
|
console.log('ehi', e)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// JSX
|
// JSX
|
||||||
|
|
||||||
export const withClasses = classes =>
|
export const withClasses = classes =>
|
||||||
|
|||||||
Reference in New Issue
Block a user