Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

[Feat]: filter options #1

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions frontend/components/ListRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,24 @@ 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<Event, 'people'> & { people: User[] };
export type Everything = { users: Record<string, User>, events: EventWithUsers[] };

type Props = Everything & { user?: string, filter: boolean };
type Props = Everything & { user?: string, filter: boolean, eventTypes?: string[] };
type Groups = { date: string, events: EventWithUsers[] }[];

export default function ListRenderer({ users, events, user, filter }: Props) {
export default function ListRenderer({ users, events, user, filter, eventTypes }: Props) {
const [groups, setGroups] = useState<Groups | undefined>();

useEffect(() => {
const groups = { };
for (const event of events) {
if (filter) {
if (!event.people.find(x => x._id === user)) 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();
Expand Down Expand Up @@ -49,7 +52,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, eventTypes]);

const groupCounts = useMemo(() => groups ? groups.map(x => x.events.length) : [], [ groups ]);

Expand Down
9 changes: 9 additions & 0 deletions frontend/components/Summary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
5 changes: 1 addition & 4 deletions frontend/pages/event/[id].tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -83,12 +83,9 @@ const IndexPage = ({ user, event }: Props) => {
</div>
);
};

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";

Expand Down
1 change: 1 addition & 0 deletions frontend/pages/global.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
html {
image-rendering: smooth;
background-color: rgb(47, 57, 68);
}

.skeleton {
Expand Down
70 changes: 62 additions & 8 deletions frontend/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Clinical: "Clinical",
Drop: "Drop in Session"
};

const IndexPage = ({ user }: AuthInterface) => {
const [data, setData] = useState<Everything | undefined>();
const [filter, setFilter] = useState(true);
const [preloader, setPreloader] = useState(false);
const [selectedEventTypes, setSelectedEventTypes] = useState<string[]>([]);

useEffect(() => {
if (typeof window !== 'undefined') {
Expand Down Expand Up @@ -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 (
<div className="select-none p-4 max-w-5xl mx-auto flex flex-col overflow-hidden h-screen">
<title>KCL Timetables</title>
Expand All @@ -50,18 +69,53 @@ const IndexPage = ({ user }: AuthInterface) => {

<Navbar user={user} />

<label className="block font-medium mb-1">Filter: </label>

<div className="flex items-center">
<input className="mr-1" type="checkbox" id="self" name="self" checked={filter} onChange={() => setFilter(!filter)} disabled={!user} />
<label htmlFor="self" className={user ? "hover:text-gray-900" : "text-gray-500"}>Filter my events.</label>
</div>
<div className="mr-2">
<input className="mr-1" type="checkbox" id="self" name="self" checked={filter} onChange={() => setFilter(!filter)} disabled={!user} />
<label htmlFor="self" className={user ? "hover:text-gray-900" : "text-gray-500"}>My Events</label>
</div>

{Object.keys(eventTypes).map(eventType => (
<div className="flex items-center"
key={eventType}>
<input
className="mr-1"
type="checkbox"
id={eventType}
name={eventType}
disabled={!user}
checked={selectedEventTypes.includes(eventTypes[eventType])}
onChange={() => toggleEventType(eventTypes[eventType])}
/>

<label
key={eventType}
htmlFor={eventType}
className={
user
? "hover:text-gray-900"
: "text-gray-500"
+ " mr-2"
}
>
{eventTypes[eventType]}
</label>
</div>
))}

{/*<div className="flex items-center">
<input className="mr-1" type="checkbox" id="prel" name="prel" checked={preloader} onChange={() => setPreloader(!preloader)} />
<label htmlFor="prel" className={"hover:text-gray-900"}>Appreciate the preloader.</label>
</div>*/}
</div>

{ (preloader || typeof data === 'undefined') && <Preloader /> }
{ !preloader && data && <ListRenderer {...data} filter={user && filter} user={user?._id} /> }
{!preloader && data && (
<ListRenderer
{...data}
filter={user && filter}
user={user?._id}
eventTypes={selectedEventTypes}
/>
)}
</div>
)
}
Expand Down