From 0021d5b2546b68739b32af61fb2ff540111bbfe6 Mon Sep 17 00:00:00 2001 From: Serge Alkhalil Date: Sat, 12 Aug 2023 14:04:39 +0100 Subject: [PATCH 1/9] chore: organise imports --- frontend/pages/event/[id].tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/frontend/pages/event/[id].tsx b/frontend/pages/event/[id].tsx index a6e4d15..6e7db7e 100644 --- a/frontend/pages/event/[id].tsx +++ b/frontend/pages/event/[id].tsx @@ -1,6 +1,6 @@ import Navbar from "../../components/Navbar"; import Avatar from "../../components/Avatar"; -import { AuthInterface } from "../../lib/auth"; +import { AuthInterface, getServerSideProps as getProps } from "../../lib/auth"; import { EventWithUsers } from "../../components/ListRenderer"; import Utterances from "@insertish/utterances"; @@ -83,12 +83,9 @@ const IndexPage = ({ user, event }: Props) => { ); }; - -import { getServerSideProps as getProps } from "../../lib/auth"; import { connectToDatabase } from "../../lib/mongodb"; import dayjs from "dayjs"; import { useState } from "react"; -import { EventEmitter } from "stream"; import Summary from "../../components/Summary"; import { TZ } from "../../lib/constants"; From 05ebba825cdf0a9678466fc331eb431b3eeca253 Mon Sep 17 00:00:00 2001 From: Serge Alkhalil Date: Sat, 12 Aug 2023 14:23:54 +0100 Subject: [PATCH 2/9] chore: add filterableOptions component --- frontend/components/FilterableOptions.tsx | 46 +++++++++++++++++++++++ frontend/pages/index.tsx | 3 ++ 2 files changed, 49 insertions(+) create mode 100644 frontend/components/FilterableOptions.tsx diff --git a/frontend/components/FilterableOptions.tsx b/frontend/components/FilterableOptions.tsx new file mode 100644 index 0000000..2870fad --- /dev/null +++ b/frontend/components/FilterableOptions.tsx @@ -0,0 +1,46 @@ +import React, { useState } from 'react'; + +export default function FilterableOptions ({ allOptions }) { + const [selectedOptions, setSelectedOptions] = useState([]); + const [filteredOptions, setFilteredOptions] = useState(allOptions); + + const handleOptionChange = (option) => { + const updatedOptions = selectedOptions.includes(option) + ? selectedOptions.filter((item) => item !== option) + : [...selectedOptions, option]; + + setSelectedOptions(updatedOptions); + + if (updatedOptions.length === 0) { + setFilteredOptions(allOptions); + } else { + const newFilteredOptions = allOptions.filter((item) => + updatedOptions.includes(item) + ); + setFilteredOptions(newFilteredOptions); + } + }; + + return ( +
+

Filter By:

+
+ {allOptions.map((option) => ( + + ))} +
+
    + {filteredOptions.map((option) => ( +
  • {option}
  • + ))} +
+
+ ); +}; \ No newline at end of file diff --git a/frontend/pages/index.tsx b/frontend/pages/index.tsx index 0695505..2082d9e 100644 --- a/frontend/pages/index.tsx +++ b/frontend/pages/index.tsx @@ -6,6 +6,7 @@ import { backOff } from "exponential-backoff"; import { Event, User } from "../lib/entities"; import Preloader from "../components/Preloader"; import ListRenderer, { Everything } from "../components/ListRenderer"; +import FilterableOptions from "../components/FilterableOptions"; const IndexPage = ({ user }: AuthInterface) => { const [data, setData] = useState(); @@ -60,6 +61,8 @@ const IndexPage = ({ user }: AuthInterface) => { */} + + { (preloader || typeof data === 'undefined') && } { !preloader && data && } From f829a4b7f199b7ceb129143d0b95d15d2c6ae638 Mon Sep 17 00:00:00 2001 From: Serge Alkhalil Date: Sat, 12 Aug 2023 22:48:19 +0100 Subject: [PATCH 3/9] chore: add eventType prop to ListRenderer component --- frontend/components/FilterableOptions.tsx | 46 ----------------------- frontend/components/ListRenderer.tsx | 8 ++-- frontend/pages/index.tsx | 5 +-- 3 files changed, 5 insertions(+), 54 deletions(-) delete mode 100644 frontend/components/FilterableOptions.tsx diff --git a/frontend/components/FilterableOptions.tsx b/frontend/components/FilterableOptions.tsx deleted file mode 100644 index 2870fad..0000000 --- a/frontend/components/FilterableOptions.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import React, { useState } from 'react'; - -export default function FilterableOptions ({ allOptions }) { - const [selectedOptions, setSelectedOptions] = useState([]); - const [filteredOptions, setFilteredOptions] = useState(allOptions); - - const handleOptionChange = (option) => { - const updatedOptions = selectedOptions.includes(option) - ? selectedOptions.filter((item) => item !== option) - : [...selectedOptions, option]; - - setSelectedOptions(updatedOptions); - - if (updatedOptions.length === 0) { - setFilteredOptions(allOptions); - } else { - const newFilteredOptions = allOptions.filter((item) => - updatedOptions.includes(item) - ); - setFilteredOptions(newFilteredOptions); - } - }; - - return ( -
-

Filter By:

-
- {allOptions.map((option) => ( - - ))} -
-
    - {filteredOptions.map((option) => ( -
  • {option}
  • - ))} -
-
- ); -}; \ No newline at end of file diff --git a/frontend/components/ListRenderer.tsx b/frontend/components/ListRenderer.tsx index 7fc7672..04b01f4 100644 --- a/frontend/components/ListRenderer.tsx +++ b/frontend/components/ListRenderer.tsx @@ -8,17 +8,17 @@ import Entry from "./Entry"; export type EventWithUsers = Omit & { people: User[] }; export type Everything = { users: Record, events: EventWithUsers[] }; -type Props = Everything & { user?: string, filter: boolean }; +type Props = Everything & { user?: string, filter: boolean, eventType?: string }; type Groups = { date: string, events: EventWithUsers[] }[]; -export default function ListRenderer({ users, events, user, filter }: Props) { +export default function ListRenderer({ users, events, user, filter, eventType }: Props) { const [groups, setGroups] = useState(); useEffect(() => { const groups = { }; for (const event of events) { if (filter) { - if (!event.people.find(x => x._id === user)) continue; + if (!event.people.find(x => x._id === user) || (eventType && event.description !== eventType)) continue; } const date = event.start.split('T').shift(); @@ -49,7 +49,7 @@ export default function ListRenderer({ users, events, user, filter }: Props) { .filter(x => new Date(x.date) > today) .sort((b, a) => +new Date(b.date) - +new Date(a.date)) ); - }, [users, events, filter]); + }, [users, events, filter, eventType]); const groupCounts = useMemo(() => groups ? groups.map(x => x.events.length) : [], [ groups ]); diff --git a/frontend/pages/index.tsx b/frontend/pages/index.tsx index 2082d9e..ada5655 100644 --- a/frontend/pages/index.tsx +++ b/frontend/pages/index.tsx @@ -6,7 +6,6 @@ import { backOff } from "exponential-backoff"; import { Event, User } from "../lib/entities"; import Preloader from "../components/Preloader"; import ListRenderer, { Everything } from "../components/ListRenderer"; -import FilterableOptions from "../components/FilterableOptions"; const IndexPage = ({ user }: AuthInterface) => { const [data, setData] = useState(); @@ -61,10 +60,8 @@ const IndexPage = ({ user }: AuthInterface) => { */} - - { (preloader || typeof data === 'undefined') && } - { !preloader && data && } + { !preloader && data && } ) } From b35995cc438c6e2366088462da9e90d7bc4a45e7 Mon Sep 17 00:00:00 2001 From: Serge Alkhalil Date: Sat, 12 Aug 2023 23:16:55 +0100 Subject: [PATCH 4/9] chore: integrate new filtering with existing codebase --- frontend/components/ListRenderer.tsx | 8 ++--- frontend/pages/index.tsx | 50 ++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/frontend/components/ListRenderer.tsx b/frontend/components/ListRenderer.tsx index 04b01f4..19b5339 100644 --- a/frontend/components/ListRenderer.tsx +++ b/frontend/components/ListRenderer.tsx @@ -8,17 +8,17 @@ import Entry from "./Entry"; export type EventWithUsers = Omit & { people: User[] }; export type Everything = { users: Record, events: EventWithUsers[] }; -type Props = Everything & { user?: string, filter: boolean, eventType?: string }; +type Props = Everything & { user?: string, filter: boolean, eventTypes?: string[] }; type Groups = { date: string, events: EventWithUsers[] }[]; -export default function ListRenderer({ users, events, user, filter, eventType }: Props) { +export default function ListRenderer({ users, events, user, filter, eventTypes }: Props) { const [groups, setGroups] = useState(); useEffect(() => { const groups = { }; for (const event of events) { if (filter) { - if (!event.people.find(x => x._id === user) || (eventType && event.description !== eventType)) continue; + if (!event.people.find(x => x._id === user) || (eventTypes && !eventTypes?.includes(event.description))) continue; } const date = event.start.split('T').shift(); @@ -49,7 +49,7 @@ export default function ListRenderer({ users, events, user, filter, eventType }: .filter(x => new Date(x.date) > today) .sort((b, a) => +new Date(b.date) - +new Date(a.date)) ); - }, [users, events, filter, eventType]); + }, [users, events, filter, eventTypes]); const groupCounts = useMemo(() => groups ? groups.map(x => x.events.length) : [], [ groups ]); diff --git a/frontend/pages/index.tsx b/frontend/pages/index.tsx index ada5655..176f844 100644 --- a/frontend/pages/index.tsx +++ b/frontend/pages/index.tsx @@ -7,10 +7,19 @@ import { Event, User } from "../lib/entities"; import Preloader from "../components/Preloader"; import ListRenderer, { Everything } from "../components/ListRenderer"; +export const eventTypes = { + Lecture: "Lecture", + SmallGroup: "Small Group", + Practical: "Practical", + MIS: "MIS", + Rev: "Rev", +}; + const IndexPage = ({ user }: AuthInterface) => { const [data, setData] = useState(); const [filter, setFilter] = useState(true); const [preloader, setPreloader] = useState(false); + const [selectedEventTypes, setSelectedEventTypes] = useState([]); useEffect(() => { if (typeof window !== 'undefined') { @@ -40,6 +49,16 @@ const IndexPage = ({ user }: AuthInterface) => { } }, []); + const toggleEventType = (eventType: string) => { + setSelectedEventTypes(prevSelectedEventTypes => { + if (prevSelectedEventTypes.includes(eventType)) { + return prevSelectedEventTypes.filter(type => type !== eventType); + } else { + return [...prevSelectedEventTypes, eventType]; + } + }); + }; + return (
KCL Timetables @@ -51,8 +70,28 @@ const IndexPage = ({ user }: AuthInterface) => {
+ + setFilter(!filter)} disabled={!user} /> - + + + {Object.keys(eventTypes).map(eventType => ( + + ))} +
{/*
@@ -61,7 +100,14 @@ const IndexPage = ({ user }: AuthInterface) => {
*/} { (preloader || typeof data === 'undefined') && } - { !preloader && data && } + {!preloader && data && ( + + )}
) } From 3083a54ba178e773950b8d4c1c3f69ba6655c683 Mon Sep 17 00:00:00 2001 From: Serge Alkhalil Date: Sat, 12 Aug 2023 23:39:44 +0100 Subject: [PATCH 5/9] styles: change bg-color because it's blinding me --- frontend/pages/global.css | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/pages/global.css b/frontend/pages/global.css index 02aee8c..7c740aa 100644 --- a/frontend/pages/global.css +++ b/frontend/pages/global.css @@ -1,5 +1,6 @@ html { image-rendering: smooth; + background-color: rgb(47, 57, 68); } .skeleton { From 2ebe5c3070e5803d0e3c9c8427ca2ee506fbeacd Mon Sep 17 00:00:00 2001 From: Serge Alkhalil Date: Sat, 12 Aug 2023 23:40:08 +0100 Subject: [PATCH 6/9] chore: tidy up code --- frontend/pages/index.tsx | 44 ++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/frontend/pages/index.tsx b/frontend/pages/index.tsx index 176f844..2104186 100644 --- a/frontend/pages/index.tsx +++ b/frontend/pages/index.tsx @@ -69,36 +69,44 @@ const IndexPage = ({ user }: AuthInterface) => { -
- + - setFilter(!filter)} disabled={!user} /> - +
+
+ setFilter(!filter)} disabled={!user} /> + +
{Object.keys(eventTypes).map(eventType => ( -
- {/*
- setPreloader(!preloader)} /> - -
*/} - { (preloader || typeof data === 'undefined') && } {!preloader && data && ( Date: Mon, 14 Aug 2023 19:33:21 +0100 Subject: [PATCH 7/9] chore: add extract type functionality --- frontend/components/Summary.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/frontend/components/Summary.tsx b/frontend/components/Summary.tsx index b9e2421..9a8531f 100644 --- a/frontend/components/Summary.tsx +++ b/frontend/components/Summary.tsx @@ -37,6 +37,15 @@ function typeToColor(type: string) { } } +export function extractType(title: string): string | null { + const match = title.match(TITLE_RE); + if (match) { + const [, , , type] = match; + return typeToEng(type); + } + return null; +} + export default function Summary({ title }: Props) { const v = title.match(TITLE_RE); if (v) { From b20fe48b024ce73ecb757b4cc8a747dea7a88020 Mon Sep 17 00:00:00 2001 From: Serge Alkhalil Date: Mon, 14 Aug 2023 19:33:33 +0100 Subject: [PATCH 8/9] chore: filter by type --- frontend/components/ListRenderer.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/components/ListRenderer.tsx b/frontend/components/ListRenderer.tsx index 19b5339..501b915 100644 --- a/frontend/components/ListRenderer.tsx +++ b/frontend/components/ListRenderer.tsx @@ -4,6 +4,7 @@ import { Event, User } from "../lib/entities"; import { GroupedVirtuoso } from "react-virtuoso"; import Category from "./Category"; import Entry from "./Entry"; +import { extractType } from "./Summary"; export type EventWithUsers = Omit & { people: User[] }; export type Everything = { users: Record, events: EventWithUsers[] }; @@ -17,8 +18,10 @@ export default function ListRenderer({ users, events, user, filter, eventTypes } useEffect(() => { const groups = { }; for (const event of events) { - if (filter) { - if (!event.people.find(x => x._id === user) || (eventTypes && !eventTypes?.includes(event.description))) continue; + if (filter || eventTypes) { + + if (!event.people.find(x => x._id === user) + || !eventTypes?.includes(extractType(event.summary))) continue; } const date = event.start.split('T').shift(); From 21d28a4d6a5ef6ea0d5b1ea6274ed1ce445bf462 Mon Sep 17 00:00:00 2001 From: Serge Alkhalil Date: Mon, 14 Aug 2023 19:33:55 +0100 Subject: [PATCH 9/9] chore: add types to filter by --- frontend/pages/index.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/frontend/pages/index.tsx b/frontend/pages/index.tsx index 2104186..507d7d5 100644 --- a/frontend/pages/index.tsx +++ b/frontend/pages/index.tsx @@ -8,11 +8,11 @@ import Preloader from "../components/Preloader"; import ListRenderer, { Everything } from "../components/ListRenderer"; export const eventTypes = { - Lecture: "Lecture", - SmallGroup: "Small Group", + Lecture: "Lecture", + SmallGroup: "Small Group", Practical: "Practical", - MIS: "MIS", - Rev: "Rev", + Clinical: "Clinical", + Drop: "Drop in Session" }; const IndexPage = ({ user }: AuthInterface) => { @@ -78,15 +78,16 @@ const IndexPage = ({ user }: AuthInterface) => {
{Object.keys(eventTypes).map(eventType => ( -
+
toggleEventType(eventType)} + checked={selectedEventTypes.includes(eventTypes[eventType])} + onChange={() => toggleEventType(eventTypes[eventType])} />