refactor(schedule): major ScheduleEntry type refactor
This commit is contained in:
parent
280a19865c
commit
ed5101c26c
@ -4,7 +4,7 @@ DegreeCourse json -- for which degree programmes this course is appropriate fo
|
|||||||
terms StudyTermsId
|
terms StudyTermsId
|
||||||
UniqueDegreeCourse course degree terms
|
UniqueDegreeCourse course degree terms
|
||||||
Course -- Information about a single course; contained info is always visible to all users
|
Course -- Information about a single course; contained info is always visible to all users
|
||||||
name (CI Text)
|
name CourseName
|
||||||
description Html Maybe -- user-defined large Html, ought to contain module description
|
description Html Maybe -- user-defined large Html, ought to contain module description
|
||||||
linkExternal Text Maybe -- arbitrary user-defined url for external course page
|
linkExternal Text Maybe -- arbitrary user-defined url for external course page
|
||||||
shorthand (CI Text) -- practical shorthand of course name, used for identification
|
shorthand (CI Text) -- practical shorthand of course name, used for identification
|
||||||
@ -29,9 +29,9 @@ Course -- Information about a single course; contained info is always visible
|
|||||||
TermSchoolCourseName term school name -- name must be unique within school and semester
|
TermSchoolCourseName term school name -- name must be unique within school and semester
|
||||||
deriving Generic
|
deriving Generic
|
||||||
CourseEvent
|
CourseEvent
|
||||||
type (CI Text)
|
type CourseEventType
|
||||||
course CourseId
|
course CourseId
|
||||||
room Text
|
room CourseEventRoom
|
||||||
time Occurrences
|
time Occurrences
|
||||||
note Html Maybe
|
note Html Maybe
|
||||||
lastChanged UTCTime default=now()
|
lastChanged UTCTime default=now()
|
||||||
|
|||||||
@ -29,7 +29,7 @@ ExamPart
|
|||||||
ExamOccurrence
|
ExamOccurrence
|
||||||
exam ExamId
|
exam ExamId
|
||||||
name ExamOccurrenceName
|
name ExamOccurrenceName
|
||||||
room Text
|
room ExamOccurrenceRoom
|
||||||
capacity Natural
|
capacity Natural
|
||||||
start UTCTime
|
start UTCTime
|
||||||
end UTCTime Maybe
|
end UTCTime Maybe
|
||||||
@ -66,4 +66,4 @@ ExamCorrector
|
|||||||
ExamPartCorrector
|
ExamPartCorrector
|
||||||
part ExamPartId
|
part ExamPartId
|
||||||
corrector ExamCorrectorId
|
corrector ExamCorrectorId
|
||||||
UniqueExamPartCorrector part corrector
|
UniqueExamPartCorrector part corrector
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
Tutorial json
|
Tutorial json
|
||||||
name TutorialName
|
name TutorialName
|
||||||
course CourseId
|
course CourseId
|
||||||
type (CI Text) -- "Tutorium", "Zentralübung", ...
|
type TutorialType -- "Tutorium", "Zentralübung", ...
|
||||||
capacity Int Maybe -- limit for enrolment in this tutorial
|
capacity Int Maybe -- limit for enrolment in this tutorial
|
||||||
room Text Maybe
|
room Text Maybe
|
||||||
time Occurrences
|
time Occurrences
|
||||||
@ -20,4 +20,4 @@ Tutor
|
|||||||
TutorialParticipant
|
TutorialParticipant
|
||||||
tutorial TutorialId
|
tutorial TutorialId
|
||||||
user UserId
|
user UserId
|
||||||
UniqueTutorialParticipant tutorial user
|
UniqueTutorialParticipant tutorial user
|
||||||
|
|||||||
@ -36,14 +36,18 @@ type SchoolName = CI Text
|
|||||||
type SchoolShorthand = CI Text
|
type SchoolShorthand = CI Text
|
||||||
type CourseName = CI Text
|
type CourseName = CI Text
|
||||||
type CourseShorthand = CI Text
|
type CourseShorthand = CI Text
|
||||||
|
type CourseEventType = CI Text
|
||||||
|
type CourseEventRoom = Text
|
||||||
type SheetName = CI Text
|
type SheetName = CI Text
|
||||||
type MaterialName = CI Text
|
type MaterialName = CI Text
|
||||||
type UserEmail = CI Email
|
type UserEmail = CI Email
|
||||||
type UserIdent = CI Text
|
type UserIdent = CI Text
|
||||||
type TutorialName = CI Text
|
type TutorialName = CI Text
|
||||||
|
type TutorialType = CI Text
|
||||||
type ExamName = CI Text
|
type ExamName = CI Text
|
||||||
type ExamPartName = CI Text
|
type ExamPartName = CI Text
|
||||||
type ExamOccurrenceName = CI Text
|
type ExamOccurrenceName = CI Text
|
||||||
|
type ExamOccurrenceRoom = Text
|
||||||
type AllocationName = CI Text
|
type AllocationName = CI Text
|
||||||
type AllocationShorthand = CI Text
|
type AllocationShorthand = CI Text
|
||||||
|
|
||||||
|
|||||||
@ -1,41 +1,28 @@
|
|||||||
module Utils.Schedule.Types
|
module Utils.Schedule.Types
|
||||||
( ScheduleEntry(..)
|
( ScheduleEntry(..)
|
||||||
, ScheduleEntryType(..)
|
|
||||||
, ScheduleEntryRoom
|
|
||||||
, ScheduleEntryOccurrence
|
|
||||||
, ScheduleEntryExamOccurrence(..)
|
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Import
|
import Import
|
||||||
|
|
||||||
|
|
||||||
data ScheduleEntry = ScheduleEntry
|
data ScheduleEntry = ScheduleCourseEvent
|
||||||
{ seCourse :: Entity Course -- TODO: just course?; TODO: Maybe?
|
{ sceCourse :: Entity Course -- TODO: just course?
|
||||||
, seType :: ScheduleEntryType
|
, sceType :: CourseEventType
|
||||||
, seRooms :: [ScheduleEntryRoom] -- multiple rooms in case of multiple parallel exam occurrences,
|
, sceRoom :: CourseEventRoom
|
||||||
-- no room in case of no room info (Nothing) for tutorials
|
, sceOccurrence :: Either OccurrenceException OccurrenceSchedule
|
||||||
-- TODO: encode in ScheduleEntryType instead
|
}
|
||||||
, seOccurrence :: ScheduleEntryOccurrence
|
| ScheduleTutorial
|
||||||
}
|
{ stCourse :: Entity Course
|
||||||
deriving (Generic, Typeable)
|
, stName :: TutorialName
|
||||||
|
, stType :: TutorialType
|
||||||
data ScheduleEntryType = SETCourseEvent { setceType :: CI Text
|
, stRoom :: Maybe Text -- TODO: introduce TutorialRoom type synonym
|
||||||
} -- TODO: CourseEventType not possible here (comes from data family instance)
|
, stOccurrence :: Either OccurrenceException OccurrenceSchedule
|
||||||
| SETTutorial { settType :: CI Text
|
}
|
||||||
, settName :: TutorialName
|
| ScheduleExamOccurrence
|
||||||
} -- TODO: TutorialType not possible here (comes from data family instance)
|
{ seoCourse :: Entity Course
|
||||||
| SETExamOccurrence { seteoExamName :: ExamName
|
, seoExamName :: ExamName
|
||||||
}
|
, seoRooms :: NonEmpty ExamOccurrenceRoom
|
||||||
deriving (Eq, Ord, Show, Read, Generic, Typeable)
|
, seoStart :: UTCTime
|
||||||
|
, seoEnd :: Maybe UTCTime
|
||||||
type ScheduleEntryRoom = Text
|
}
|
||||||
|
deriving (Generic, Typeable)
|
||||||
-- TODO: maybe introduce sum new type instead
|
|
||||||
type ScheduleEntryOccurrence = Either ScheduleEntryExamOccurrence (Either OccurrenceException OccurrenceSchedule)
|
|
||||||
|
|
||||||
-- Similar to OccurrenceException, but with Maybe as end
|
|
||||||
data ScheduleEntryExamOccurrence = ScheduleEntryExamOccurrence
|
|
||||||
{ seeoStart :: UTCTime
|
|
||||||
, seeoEnd :: Maybe UTCTime
|
|
||||||
}
|
|
||||||
deriving (Eq, Ord, Show, Read, Generic, Typeable)
|
|
||||||
|
|||||||
@ -26,6 +26,8 @@ weekSchedule uid dayOffset = do
|
|||||||
tz <- liftIO getCurrentTimeZone
|
tz <- liftIO getCurrentTimeZone
|
||||||
ata <- getSessionActiveAuthTags
|
ata <- getSessionActiveAuthTags
|
||||||
|
|
||||||
|
let dayNowOffset = fromMaybe 0 dayOffset `addDays` utctDay now
|
||||||
|
|
||||||
-- TODO: single runDB for all fetches below?
|
-- TODO: single runDB for all fetches below?
|
||||||
|
|
||||||
activeTerms <- liftHandler . runDB $ E.select $ E.from $ \term -> do
|
activeTerms <- liftHandler . runDB $ E.select $ E.from $ \term -> do
|
||||||
@ -59,7 +61,6 @@ weekSchedule uid dayOffset = do
|
|||||||
return (course, tutorial)
|
return (course, tutorial)
|
||||||
|
|
||||||
-- TODO: this makes the exam table partly redundant => maybe remove?
|
-- TODO: this makes the exam table partly redundant => maybe remove?
|
||||||
-- TODO: for lecturers, do not display one entry for each exam occurrences, but instead collect all occurrences happening at the same time in a list
|
|
||||||
examOccurrences <- liftHandler . runDB $ E.select $ E.from $ \(course `E.InnerJoin` exam `E.InnerJoin` examOccurrence) -> do
|
examOccurrences <- liftHandler . runDB $ E.select $ E.from $ \(course `E.InnerJoin` exam `E.InnerJoin` examOccurrence) -> do
|
||||||
E.on $ course E.^. CourseId E.==. exam E.^. ExamCourse
|
E.on $ course E.^. CourseId E.==. exam E.^. ExamCourse
|
||||||
E.on $ exam E.^. ExamId E.==. examOccurrence E.^. ExamOccurrenceExam
|
E.on $ exam E.^. ExamId E.==. examOccurrence E.^. ExamOccurrenceExam
|
||||||
@ -74,29 +75,25 @@ weekSchedule uid dayOffset = do
|
|||||||
|
|
||||||
let
|
let
|
||||||
courseEventToScheduleEntries :: (Entity Course, Entity CourseEvent) -> [ScheduleEntry]
|
courseEventToScheduleEntries :: (Entity Course, Entity CourseEvent) -> [ScheduleEntry]
|
||||||
courseEventToScheduleEntries (seCourse@(Entity _ Course{..}), Entity _ CourseEvent{courseEventType,courseEventRoom,courseEventTime=Occurrences{..}}) =
|
courseEventToScheduleEntries (sceCourse@(Entity _ Course{..}), Entity _ CourseEvent{courseEventType=sceType,courseEventRoom=sceRoom,courseEventTime=Occurrences{..}}) =
|
||||||
let seType = SETCourseEvent { setceType = courseEventType }
|
let scheduleds
|
||||||
seRooms = pure $ courseEventRoom
|
-- omit regular occurrences if the course term is not currently active
|
||||||
scheduleds
|
|
||||||
-- omit regular occurrences if the course's term is not currently active
|
|
||||||
| not (courseTerm `elem` (E.unValue <$> activeTerms)) = mempty
|
| not (courseTerm `elem` (E.unValue <$> activeTerms)) = mempty
|
||||||
| otherwise = Set.toList occurrencesScheduled <&> \scheduled ->
|
| otherwise = Set.toList occurrencesScheduled <&> \scheduled ->
|
||||||
let seOccurrence = Right (Right scheduled) in ScheduleEntry{..}
|
let sceOccurrence = Right scheduled in ScheduleCourseEvent{..}
|
||||||
exceptions = Set.toList occurrencesExceptions <&> \exception ->
|
exceptions = Set.toList occurrencesExceptions <&> \exception ->
|
||||||
let seOccurrence = Right (Left exception) in ScheduleEntry{..}
|
let sceOccurrence = Left exception in ScheduleCourseEvent{..}
|
||||||
in scheduleds <> exceptions
|
in scheduleds <> exceptions
|
||||||
|
|
||||||
tutorialToScheduleEntries :: (Entity Course, Entity Tutorial) -> [ScheduleEntry]
|
tutorialToScheduleEntries :: (Entity Course, Entity Tutorial) -> [ScheduleEntry]
|
||||||
tutorialToScheduleEntries (seCourse@(Entity _ Course{..}), Entity _ Tutorial{tutorialType,tutorialName,tutorialRoom,tutorialTime=Occurrences{..}}) =
|
tutorialToScheduleEntries (stCourse@(Entity _ Course{..}), Entity _ Tutorial{tutorialName=stName,tutorialType=stType,tutorialRoom=stRoom,tutorialTime=Occurrences{..}}) =
|
||||||
let seType = SETTutorial { settType = tutorialType, settName = tutorialName }
|
let scheduleds
|
||||||
seRooms = maybe mempty pure tutorialRoom
|
-- omit regular occurrences if the course term is not currently active
|
||||||
scheduleds
|
|
||||||
-- omit regular occurrences if the course's term is not currently active
|
|
||||||
| not (courseTerm `elem` (E.unValue <$> activeTerms)) = mempty
|
| not (courseTerm `elem` (E.unValue <$> activeTerms)) = mempty
|
||||||
| otherwise = Set.toList occurrencesScheduled <&> \scheduled ->
|
| otherwise = Set.toList occurrencesScheduled <&> \scheduled ->
|
||||||
let seOccurrence = Right (Right scheduled) in ScheduleEntry{..}
|
let stOccurrence = Right scheduled in ScheduleTutorial{..}
|
||||||
exceptions = Set.toList occurrencesExceptions <&> \exception ->
|
exceptions = Set.toList occurrencesExceptions <&> \exception ->
|
||||||
let seOccurrence = Right (Left exception) in ScheduleEntry{..}
|
let stOccurrence = Left exception in ScheduleTutorial{..}
|
||||||
in scheduleds <> exceptions
|
in scheduleds <> exceptions
|
||||||
|
|
||||||
-- TODO: introduce type synonym for (Entity Course, Entity Exam, Entity ExamOccurrence)?
|
-- TODO: introduce type synonym for (Entity Course, Entity Exam, Entity ExamOccurrence)?
|
||||||
@ -111,58 +108,68 @@ weekSchedule uid dayOffset = do
|
|||||||
&& examOccurrenceStart occ == examOccurrenceStart occ' && examOccurrenceEnd occ == examOccurrenceEnd occ'
|
&& examOccurrenceStart occ == examOccurrenceStart occ' && examOccurrenceEnd occ == examOccurrenceEnd occ'
|
||||||
|
|
||||||
examOccurrenceToScheduleEntry :: (Entity Course, Entity Exam, NonEmpty (Entity ExamOccurrence)) -> ScheduleEntry
|
examOccurrenceToScheduleEntry :: (Entity Course, Entity Exam, NonEmpty (Entity ExamOccurrence)) -> ScheduleEntry
|
||||||
examOccurrenceToScheduleEntry (seCourse@(Entity _ Course{}), Entity _ Exam{..}, examOccs@((Entity _ occ):|_)) =
|
examOccurrenceToScheduleEntry (seoCourse@(Entity _ Course{}), Entity _ Exam{examName=seoExamName}, examOccs@((Entity _ occ):|_)) =
|
||||||
let seType = SETExamOccurrence
|
let seoRooms = (examOccurrenceRoom . entityVal) <$> examOccs
|
||||||
{ seteoExamName = examName
|
seoStart = examOccurrenceStart occ -- multiple exam occurrences are joined on equality of start and end,
|
||||||
}
|
seoEnd = examOccurrenceEnd occ -- so taking the timestamps of the first occurrence suffices
|
||||||
seRooms = toList $ (examOccurrenceRoom . entityVal) <$> examOccs
|
in ScheduleExamOccurrence{..}
|
||||||
seOccurrence = Left $ ScheduleEntryExamOccurrence -- multiple exam occurrences are joined on equality
|
|
||||||
{ seeoStart = examOccurrenceStart occ -- of start and end, so taking the timstamps of the first
|
|
||||||
, seeoEnd = examOccurrenceEnd occ -- occurrence suffices
|
|
||||||
}
|
|
||||||
in ScheduleEntry{..}
|
|
||||||
|
|
||||||
seOccurrenceIsInSlot :: Day -> TimeSlot -> ScheduleEntryOccurrence -> Bool
|
seIsInSlot :: Day -> TimeSlot -> ScheduleEntry -> Bool
|
||||||
seOccurrenceIsInSlot day slot = \case
|
seIsInSlot day slot =
|
||||||
Right occurrence -> occDay == day && occTime `isInTimeSlot` slot where
|
let occurrenceIsInSlot occurrence = occDay == day && occTime `isInTimeSlot` slot where
|
||||||
(occDay,occTime) = case occurrence of
|
(occDay, occTime) = case occurrence of
|
||||||
Right ScheduleWeekly{..} -> (scheduleDayOfWeek `dayOfWeekToDayWith` now, scheduleStart)
|
Right ScheduleWeekly{..} -> (scheduleDayOfWeek `dayOfWeekToDayWith` dayNowOffset, scheduleStart)
|
||||||
Left ExceptOccur{..} -> (exceptDay, exceptStart)
|
Left ExceptOccur{..} -> (exceptDay, exceptStart)
|
||||||
Left ExceptNoOccur{exceptTime=LocalTime{..}} -> (localDay, localTimeOfDay)
|
Left ExceptNoOccur{exceptTime=LocalTime{..}} -> (localDay, localTimeOfDay)
|
||||||
Left ScheduleEntryExamOccurrence{..} -> let slotUTCTime = timeSlotToUTCTime tz day slot
|
in \case
|
||||||
nextSlotUTCTime = timeSlotToUTCTime tz day (slot+slotStep)
|
ScheduleCourseEvent{sceOccurrence} -> occurrenceIsInSlot sceOccurrence
|
||||||
in slotUTCTime <= seeoStart
|
ScheduleTutorial{stOccurrence} -> occurrenceIsInSlot stOccurrence
|
||||||
&& seeoStart < nextSlotUTCTime
|
ScheduleExamOccurrence{seoStart} -> let slotTime = timeSlotToUTCTime tz day slot
|
||||||
|
nextSlotTime = timeSlotToUTCTime tz day (slot+slotStep)
|
||||||
|
in slotTime <= seoStart
|
||||||
|
&& seoStart < nextSlotTime
|
||||||
|
|
||||||
events' :: Map Day (Map Int [ScheduleEntry])
|
events' :: Map Day (Map TimeSlot [ScheduleEntry])
|
||||||
events' = Map.fromList $ week <&> \day ->
|
events' = Map.fromList $ week <&> \day ->
|
||||||
( day
|
( day
|
||||||
, Map.fromList $ slotsToDisplay <&> \slot ->
|
, Map.fromList $ slotsToDisplay <&> \slot ->
|
||||||
( slot
|
( slot
|
||||||
, filter (seOccurrenceIsInSlot day slot . seOccurrence) $ join $
|
, filter (seIsInSlot day slot) $ join $
|
||||||
(courseEventToScheduleEntries <$> courseEvents)
|
(courseEventToScheduleEntries <$> courseEvents)
|
||||||
<> (tutorialToScheduleEntries <$> tutorials)
|
<> (tutorialToScheduleEntries <$> tutorials)
|
||||||
<> pure (examOccurrenceToScheduleEntry <$> (joinParallelExamOccurrences examOccurrences))
|
<> pure (examOccurrenceToScheduleEntry <$> (joinParallelExamOccurrences examOccurrences))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
events :: Map Day (Map Int [ScheduleEntry])
|
getRegulars :: [ScheduleEntry] -> [OccurrenceSchedule]
|
||||||
|
getRegulars = catMaybes . (goRegular <$>) where
|
||||||
|
goRegular ScheduleCourseEvent{sceOccurrence=Right schedule} = Just schedule
|
||||||
|
goRegular ScheduleTutorial{stOccurrence=Right schedule} = Just schedule
|
||||||
|
goRegular _ = Nothing
|
||||||
|
|
||||||
|
getNoOccurs :: [ScheduleEntry] -> [OccurrenceException]
|
||||||
|
getNoOccurs = catMaybes . (goNoOccur <$>) where
|
||||||
|
goNoOccur ScheduleCourseEvent{sceOccurrence=Left noOccur} = Just noOccur
|
||||||
|
goNoOccur ScheduleTutorial{stOccurrence=Left noOccur} = Just noOccur
|
||||||
|
goNoOccur _ = Nothing
|
||||||
|
|
||||||
|
events :: Map Day (Map TimeSlot [ScheduleEntry])
|
||||||
events = events' <&> \slotsPerDay -> slotsPerDay <&> \occurrencesInSlot ->
|
events = events' <&> \slotsPerDay -> slotsPerDay <&> \occurrencesInSlot ->
|
||||||
let
|
let
|
||||||
isRegularWithoutException :: ScheduleEntry -> Bool
|
isRegularWithoutException :: ScheduleEntry -> Bool
|
||||||
isRegularWithoutException = \case
|
isRegularWithoutException =
|
||||||
-- remove regular occurrences if there is a NoOccur exception for the occurrence of this week
|
let -- remove regular occurrences if there is a NoOccur exception for the occurrence of this week
|
||||||
ScheduleEntry{seOccurrence=Right (Right ScheduleWeekly{..})} ->
|
goPrune (Right ScheduleWeekly{..}) = not $ ExceptNoOccur (LocalTime (scheduleDayOfWeek `dayOfWeekToDayWith` dayNowOffset) scheduleStart) `elem` (getNoOccurs occurrencesInSlot)
|
||||||
not $ Right (Left $ ExceptNoOccur $ LocalTime (scheduleDayOfWeek `dayOfWeekToDayWith` now) scheduleStart)
|
-- remove NoOccur exceptions if there is no regular occurrence to override
|
||||||
`elem` (seOccurrence <$> occurrencesInSlot)
|
goPrune (Left ExceptNoOccur{exceptTime=LocalTime{..}}) =
|
||||||
-- remove NoOccur exceptions if there is no regular occurrence to override
|
any (\ScheduleWeekly{..} -> scheduleDayOfWeek `dayOfWeekToDayWith` dayNowOffset == localDay
|
||||||
ScheduleEntry{seOccurrence=Right (Left ExceptNoOccur{exceptTime=LocalTime{..}})} ->
|
&& scheduleStart == localTimeOfDay
|
||||||
any (\case
|
) (getRegulars occurrencesInSlot)
|
||||||
Right (Right ScheduleWeekly{..}) -> scheduleDayOfWeek `dayOfWeekToDayWith` now == localDay
|
goPrune _ = True -- TODO: maybe filter NoOccur exceptions in general? (Should NoOccur exceptions be displayed?)
|
||||||
&& scheduleStart == localTimeOfDay
|
in \case
|
||||||
_ -> False
|
ScheduleCourseEvent{sceOccurrence} -> goPrune sceOccurrence
|
||||||
) (seOccurrence <$> occurrencesInSlot)
|
ScheduleTutorial{stOccurrence} -> goPrune stOccurrence
|
||||||
_ -> True -- TODO: maybe filter out ExceptNoOccurs? (Should NoOccurs be displayed or not?)
|
_ -> True
|
||||||
in filter isRegularWithoutException occurrencesInSlot
|
in filter isRegularWithoutException occurrencesInSlot
|
||||||
|
|
||||||
-- TODO: Internationalize default week start (and/or make configurable)
|
-- TODO: Internationalize default week start (and/or make configurable)
|
||||||
@ -181,27 +188,26 @@ weekSchedule uid dayOffset = do
|
|||||||
|
|
||||||
-- | To which route should each schedule entry link to?
|
-- | To which route should each schedule entry link to?
|
||||||
scheduleEntryToHref :: ScheduleEntry -> Route UniWorX
|
scheduleEntryToHref :: ScheduleEntry -> Route UniWorX
|
||||||
scheduleEntryToHref ScheduleEntry{seCourse=Entity _ Course{..},seType} = case seType of
|
scheduleEntryToHref = \case
|
||||||
SETCourseEvent{} -> CourseR courseTerm courseSchool courseShorthand CShowR -- TODO: link to events table? (TODO currently has no id)
|
ScheduleCourseEvent{sceCourse=(Entity _ Course{..})} -> CourseR courseTerm courseSchool courseShorthand CShowR -- TODO: link to events table? (currently has no id)
|
||||||
SETTutorial{} -> CourseR courseTerm courseSchool courseShorthand CShowR -- TODO: link to table with id "tutorials"?
|
ScheduleTutorial{stCourse=(Entity _ Course{..})} -> CourseR courseTerm courseSchool courseShorthand CShowR -- TODO: link to table with id "tutorials"?
|
||||||
SETExamOccurrence{..} -> CExamR courseTerm courseSchool courseShorthand seteoExamName EShowR
|
ScheduleExamOccurrence{seoCourse=(Entity _ Course{..}),seoExamName} -> CExamR courseTerm courseSchool courseShorthand seoExamName EShowR
|
||||||
|
|
||||||
-- | Calls formatTimeRangeW with the correct arguments and prepends an occurrence descriptor based on the occurrence type
|
-- | Calls formatTimeRangeW with the correct arguments and prepends an occurrence descriptor based on the occurrence type
|
||||||
formatOccurrenceW :: ScheduleEntryOccurrence -> Widget
|
formatEitherOccurrenceW :: Either OccurrenceException OccurrenceSchedule -> Widget
|
||||||
formatOccurrenceW = \case
|
formatEitherOccurrenceW = \case
|
||||||
Right (Right ScheduleWeekly{..}) -> [whamlet| _{MsgScheduleTime}: |] <> formatTimeRangeW SelFormatTime scheduleStart (Just scheduleEnd)
|
Right ScheduleWeekly{..} -> [whamlet| _{MsgScheduleTime}: |] <> formatTimeRangeW SelFormatTime scheduleStart (Just scheduleEnd)
|
||||||
Right (Left ExceptOccur{..}) -> [whamlet| _{MsgScheduleOccur}: |] <> formatTimeRangeW SelFormatTime (LocalTime exceptDay exceptStart) (Just $ LocalTime exceptDay exceptEnd)
|
Left ExceptOccur{..} -> [whamlet| _{MsgScheduleOccur}: |] <> formatTimeRangeW SelFormatTime (LocalTime exceptDay exceptStart) (Just $ LocalTime exceptDay exceptEnd)
|
||||||
Right (Left ExceptNoOccur{}) -> [whamlet| _{MsgScheduleNoOccur} |] -- <> formatTimeW SelFormatDateTime exceptTime
|
Left ExceptNoOccur{} -> [whamlet| _{MsgScheduleNoOccur} |] -- <> formatTimeW SelFormatDateTime exceptTime
|
||||||
Left ScheduleEntryExamOccurrence{..} -> [whamlet| _{MsgScheduleOccur}: |] <> formatTimeRangeW selFormat seeoStart seeoEnd
|
|
||||||
where selFormat = bool SelFormatDateTime SelFormatTime $ maybe True ((utctDay seeoStart ==) . utctDay) seeoEnd
|
|
||||||
-- | Uniquely identify each day as table head
|
-- | Uniquely identify each day as table head
|
||||||
-- | This avoids constantly hiding e.g. some DayOfWeek (which would interfere with day offsets)
|
-- | This avoids constantly hiding e.g. some DayOfWeek (which would interfere with day offsets)
|
||||||
dayTableHeadIdent :: Day -> Text
|
dayTableHeadIdent :: Day -> Text
|
||||||
dayTableHeadIdent = tshow . toModifiedJulianDay
|
dayTableHeadIdent = tshow . toModifiedJulianDay
|
||||||
|
|
||||||
-- | Convert from DayOfWeek to Day of this week using the current time (as UTCTime)
|
-- | Convert from DayOfWeek to Day of this week using the current day
|
||||||
dayOfWeekToDayWith :: DayOfWeek -> UTCTime -> Day
|
dayOfWeekToDayWith :: DayOfWeek -> Day -> Day
|
||||||
dayOfWeekToDayWith weekDay = go . utctDay where
|
dayOfWeekToDayWith weekDay = go where
|
||||||
go day | weekDay' == weekDay = day
|
go day | weekDay' == weekDay = day
|
||||||
| weekDay' > weekDay = go $ pred day
|
| weekDay' > weekDay = go $ pred day
|
||||||
| otherwise = go $ succ day
|
| otherwise = go $ succ day
|
||||||
|
|||||||
@ -18,26 +18,28 @@ $newline never
|
|||||||
<div .table__td-content>
|
<div .table__td-content>
|
||||||
$maybe dayEvents <- Map.lookup day events
|
$maybe dayEvents <- Map.lookup day events
|
||||||
$maybe slotEvents <- Map.lookup slot dayEvents
|
$maybe slotEvents <- Map.lookup slot dayEvents
|
||||||
$forall se@ScheduleEntry{seCourse=Entity _ Course{courseName},seType,seRooms,seOccurrence} <- slotEvents
|
$forall scheduleEntry <- slotEvents
|
||||||
<a href=@{scheduleEntryToHref se} .schedule--entry-link>
|
<a href=@{scheduleEntryToHref scheduleEntry} .schedule--entry-link>
|
||||||
<div .schedule--entry>
|
<div .schedule--entry>
|
||||||
#{CI.original courseName}: #
|
$case scheduleEntry
|
||||||
$case seType
|
$of ScheduleCourseEvent{sceCourse=Entity _ Course{courseName},sceType,sceRoom,sceOccurrence}
|
||||||
$of SETCourseEvent{..}
|
#{CI.original courseName}: #{CI.original sceType} <br/>
|
||||||
#{CI.original setceType}
|
_{MsgScheduleRoom}: #{sceRoom} <br/>
|
||||||
$of SETTutorial{..}
|
^{formatEitherOccurrenceW sceOccurrence}
|
||||||
#{settName} #
|
$of ScheduleTutorial{stCourse=Entity _ Course{courseName},stName,stType,stRoom,stOccurrence}
|
||||||
(#{CI.original settType})
|
#{CI.original courseName}: #{stName} (#{CI.original stType}) <br/>
|
||||||
$of SETExamOccurrence{..}
|
_{MsgScheduleRoom}: #{stRoom} <br/>
|
||||||
#{seteoExamName} #
|
^{formatEitherOccurrenceW stOccurrence}
|
||||||
<br>
|
$of ScheduleExamOccurrence{seoCourse=Entity _ Course{courseName},seoExamName,seoRooms,seoStart,seoEnd}
|
||||||
|
#{CI.original courseName}: #{seoExamName} <br/>
|
||||||
$case seRooms
|
$case toList seoRooms
|
||||||
$of []
|
$of [room]
|
||||||
$of [room]
|
_{MsgScheduleRoom}: #{room}
|
||||||
_{MsgScheduleRoom}: #{room}
|
$of more
|
||||||
$of rooms
|
_{MsgScheduleRooms}: #{intercalate ", " more}
|
||||||
_{MsgScheduleRooms}: #{intercalate ", " rooms}
|
<br>
|
||||||
<br>
|
_{MsgScheduleOccur}: #
|
||||||
|
$if Just (utctDay seoStart) == fmap utctDay seoEnd
|
||||||
^{formatOccurrenceW seOccurrence}
|
^{formatTimeRangeW SelFormatTime seoStart seoEnd}
|
||||||
|
$else
|
||||||
|
^{formatTimeRangeW SelFormatDateTime seoStart seoEnd}
|
||||||
|
|||||||
Reference in New Issue
Block a user