Skip to content

Commit

Permalink
event popup
Browse files Browse the repository at this point in the history
  • Loading branch information
dheidemann committed Oct 5, 2024
1 parent 69c817d commit 094e83e
Show file tree
Hide file tree
Showing 8 changed files with 386 additions and 72 deletions.
231 changes: 177 additions & 54 deletions frontend/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import {
} from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import {
EventCloseupDocument,
EventCloseupQuery,
EventCloseupQueryVariables,
PlannerEventsDocument,
PlannerEventsQuery,
PlannerEventsQueryVariables,
UmbrellasDocument,
UmbrellasQuery,
UmbrellasQueryVariables,
} from "@/lib/gql/generated/graphql";
import { client } from "@/lib/graphClient";
import { useEffect, useState } from "react";
Expand All @@ -37,6 +39,17 @@ import {
PopoverTrigger,
} from "@/components/ui/popover";
import { Skeleton } from "@/components/ui/skeleton";
import {
Dialog,
DialogHeader,
DialogContent,
DialogDescription,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Badge } from "@/components/ui/badge";
import { Table, TableBody, TableCaption, TableCell, TableRow } from "@/components/ui/table";
import {Progress} from "@/components/ui/progress";

type GroupedEvents = {
[week: number]: {
Expand Down Expand Up @@ -92,6 +105,7 @@ export default function Home() {
const [loading, setLoading] = useState(true);
const [filter, setFilter] = useState<string[]>([]);
const [umbrellaSelectionOpen, setUmbrellaSelectionOpen] = useState(false);
const [popupId, setPopupId] = useState(0);

useEffect(() => {
const fetchData = async () => {
Expand Down Expand Up @@ -154,7 +168,7 @@ export default function Home() {

return (
<main>
<Header></Header>
<Header />

<div className="space-y-6 min-h-screen flex-col p-8">
<Popover
Expand Down Expand Up @@ -205,35 +219,51 @@ export default function Home() {
</PopoverContent>
</Popover>

<div className="flex flex-row space-x-4">
{topics.map((topic) => (
<label key={topic.name} className="flex items-center space-x-2">
<Checkbox
checked={filter.includes(topic.name)}
onCheckedChange={() => handleFilterChange(topic.name)}
/>
<span>{topic.name}</span>
</label>
))}
</div>
<table className="table-auto">
<tbody>
<tr>
<td className="font-bold">Thema</td>
<td className="flex flex-row space-x-4 ml-4">
{topics.map((topic) => (
<label
key={topic.name}
className="flex items-center space-x-2"
>
<Checkbox
checked={filter.includes(topic.name)}
onCheckedChange={() => handleFilterChange(topic.name)}
/>
<p>{topic.name}</p>
</label>
))}
</td>
</tr>

<div className="flex flex-row space-x-4">
{types.map((type) => (
<label key={type.name} className="flex items-center space-x-2">
<Checkbox
checked={filter.includes(type.name)}
onCheckedChange={() => handleFilterChange(type.name)}
/>
<span>{type.name}</span>
</label>
))}
</div>
<tr>
<td className="font-bold">Veranstaltungsart</td>
<td className="flex flex-row space-x-4 ml-4">
{types.map((type) => (
<label
key={type.name}
className="flex items-center space-x-2"
>
<Checkbox
checked={filter.includes(type.name)}
onCheckedChange={() => handleFilterChange(type.name)}
/>
<p>{type.name}</p>
</label>
))}
</td>
</tr>
</tbody>
</table>

{loading ? (
<div className="flex flex-col space-y-3">
<Skeleton className="h-5 w-[200px]" />
<Skeleton className="h-5 w-[80px]" />
<Skeleton className="h-[125px] w-[400px] rounded-xl" />
<Skeleton className="h-[125px] w-full rounded-xl" />
</div>
) : (
<div className="flex flex-row space-x-4">
Expand Down Expand Up @@ -305,35 +335,42 @@ export default function Home() {
className="bg-transparent"
style={{ height: `${gap * 100}px` }}
></div>
<li
key={event.ID}
className={`rounded-lg p-4 text-white cursor-pointer hover:opacity-90 transition-opacity`}
style={{
backgroundColor: event.topic.color,
height: `${eventDurationHours * 100}px`,
}}
role="button"
tabIndex={0}
onClick={() => alert(event.title)}
>
<p className="text-sm font-bold">
{event.title}
</p>
<p className="text-sm">
{new Date(event.from).toLocaleTimeString(
[],
{
hour: "2-digit",
minute: "2-digit",
}
)}{" "}
-{" "}
{new Date(event.to).toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
})}
</p>
</li>
<Dialog>
<DialogTrigger asChild>
<li
key={event.ID}
className={`rounded-lg p-4 text-white cursor-pointer hover:opacity-90 transition-opacity`}
style={{
backgroundColor: event.topic.color,
height: `${eventDurationHours * 100}px`,
}}
role="button"
tabIndex={0}
onClick={() => setPopupId(event.ID)}
>
<p className="text-sm font-bold">
{event.title}
</p>
<p className="text-sm">
{new Date(
event.from
).toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
})}{" "}
-{" "}
{new Date(event.to).toLocaleTimeString(
[],
{
hour: "2-digit",
minute: "2-digit",
}
)}
</p>
</li>
</DialogTrigger>
<EventDialog id={popupId} />
</Dialog>
</div>
);
})}
Expand All @@ -350,3 +387,89 @@ export default function Home() {
</main>
);
}

function EventDialog({ id }: { id: number }) {
const [loading, setLoading] = useState(true);
const [event, setEvent] = useState<EventCloseupQuery["events"][0] | null>(
null
);

useEffect(() => {
if (!id) return;
const fetchData = async () => {
setLoading(true);

const vars: EventCloseupQueryVariables = {
id: id,
};

await new Promise((resolve) => setTimeout(resolve, 250));

const eventData = await client.request<EventCloseupQuery>(
EventCloseupDocument,
vars
);

if (eventData.events.length) {
setEvent(eventData.events[0]);
setLoading(false);
}
};

fetchData();
}, [id]);

return (
<DialogContent className="sm:max-w-[550px]">
{loading ? (
<div className="flex flex-col space-y-3">
<Skeleton className="h-5 w-[80px]" />
<Skeleton className="h-3 w-[200px]" />
<Skeleton className="h-[125px] w-full rounded-xl" />
</div>
) : (
<div className="space-y-4">
<DialogHeader>
<DialogTitle>{event?.title}</DialogTitle>
<DialogDescription>
{event?.description}
<div className="space-x-2 mt-2">
<Badge color={event?.topic.color}>{event?.topic.name}</Badge>
<Badge color={event?.type.color}>{event?.type.name}</Badge>
</div>
</DialogDescription>
</DialogHeader>
<div className="rounded-md border">
<Table>
<TableBody>
{event?.tutorsAssigned?.map((e) => (
<TableRow key={e.room?.number}>
<TableCell>
{e.tutors?.map((t) => (
<div key={t.mail} className="space-x-1 flex flex-row">
<p>{t.fn}</p>
<p>{t.sn}</p>
</div>
))}
</TableCell>
<TableCell>
<Progress value={e.registrations == null ? 0 : e.registrations} className="w-[200px]" />
<div className="text-xs text-muted-foreground">
<span>{e.registrations == null ? 0 : e.registrations}</span>
<span>/</span>
<span>{e.room?.capacity}</span>
</div>
</TableCell>
<TableCell>
<Button variant="outline">Eintragen</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</div>
)}
</DialogContent>
);
}
9 changes: 7 additions & 2 deletions frontend/lib/gql/generated/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/
const documents = {
"mutation addStudentApplicationForEvent($application: NewUserToEventApplication!) {\n addStudentApplicationForEvent(application: $application) {\n fn\n }\n}": types.AddStudentApplicationForEventDocument,
"mutation addTutor($firstName: String!, $lastName: String!, $email: String!, $eventsAvailable: [Int!]!) {\n addTutor(\n tutor: {fn: $firstName, sn: $lastName, mail: $email}\n availability: {userMail: $email, eventID: $eventsAvailable}\n ) {\n fn\n }\n}": types.AddTutorDocument,
"query tutorFormEvents {\n events(needsTutors: true, onlyFuture: true) {\n ID\n title\n from\n to\n topic {\n name\n color\n }\n type {\n name\n color\n }\n }\n}\n\nquery plannerEvents($umbrellaID: Int!, $filter: [String!]) {\n umbrellas(id: [$umbrellaID]) {\n title\n }\n typeLabels: labels(kind: EVENT_TYPE, umbrellaID: [$umbrellaID]) {\n name\n }\n topicLabels: labels(kind: TOPIC, umbrellaID: [$umbrellaID]) {\n name\n }\n events(umbrellaID: [$umbrellaID], label: $filter) {\n ID\n title\n from\n to\n topic {\n color\n }\n }\n}\n\nquery umbrellas {\n umbrellas {\n ID\n title\n }\n}": types.TutorFormEventsDocument,
"query tutorFormEvents {\n events(needsTutors: true, onlyFuture: true) {\n ID\n title\n from\n to\n topic {\n name\n color\n }\n type {\n name\n color\n }\n }\n}\n\nquery plannerEvents($umbrellaID: Int!, $filter: [String!]) {\n umbrellas(id: [$umbrellaID]) {\n title\n }\n typeLabels: labels(kind: EVENT_TYPE, umbrellaID: [$umbrellaID]) {\n name\n }\n topicLabels: labels(kind: TOPIC, umbrellaID: [$umbrellaID]) {\n name\n }\n events(umbrellaID: [$umbrellaID], label: $filter) {\n ID\n title\n from\n to\n topic {\n color\n }\n }\n}\n\nquery eventCloseup($id: Int!) {\n events(id: [$id]) {\n ID\n title\n description\n from\n to\n topic {\n name\n color\n }\n type {\n name\n color\n }\n tutorsAssigned {\n tutors {\n fn\n sn\n mail\n }\n room {\n capacity\n floor\n name\n number\n building {\n name\n street\n number\n osm\n }\n }\n registrations\n }\n }\n}": types.TutorFormEventsDocument,
"query registrationForm($eventID: Int!) {\n forms(id: [$eventID]) {\n title\n description\n questions {\n ID\n title\n type\n required\n answers {\n ID\n title\n points\n }\n }\n }\n}": types.RegistrationFormDocument,
"query umbrellas {\n umbrellas {\n ID\n title\n }\n}": types.UmbrellasDocument,
};

/**
Expand Down Expand Up @@ -44,11 +45,15 @@ export function graphql(source: "mutation addTutor($firstName: String!, $lastNam
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "query tutorFormEvents {\n events(needsTutors: true, onlyFuture: true) {\n ID\n title\n from\n to\n topic {\n name\n color\n }\n type {\n name\n color\n }\n }\n}\n\nquery plannerEvents($umbrellaID: Int!, $filter: [String!]) {\n umbrellas(id: [$umbrellaID]) {\n title\n }\n typeLabels: labels(kind: EVENT_TYPE, umbrellaID: [$umbrellaID]) {\n name\n }\n topicLabels: labels(kind: TOPIC, umbrellaID: [$umbrellaID]) {\n name\n }\n events(umbrellaID: [$umbrellaID], label: $filter) {\n ID\n title\n from\n to\n topic {\n color\n }\n }\n}\n\nquery umbrellas {\n umbrellas {\n ID\n title\n }\n}"): (typeof documents)["query tutorFormEvents {\n events(needsTutors: true, onlyFuture: true) {\n ID\n title\n from\n to\n topic {\n name\n color\n }\n type {\n name\n color\n }\n }\n}\n\nquery plannerEvents($umbrellaID: Int!, $filter: [String!]) {\n umbrellas(id: [$umbrellaID]) {\n title\n }\n typeLabels: labels(kind: EVENT_TYPE, umbrellaID: [$umbrellaID]) {\n name\n }\n topicLabels: labels(kind: TOPIC, umbrellaID: [$umbrellaID]) {\n name\n }\n events(umbrellaID: [$umbrellaID], label: $filter) {\n ID\n title\n from\n to\n topic {\n color\n }\n }\n}\n\nquery umbrellas {\n umbrellas {\n ID\n title\n }\n}"];
export function graphql(source: "query tutorFormEvents {\n events(needsTutors: true, onlyFuture: true) {\n ID\n title\n from\n to\n topic {\n name\n color\n }\n type {\n name\n color\n }\n }\n}\n\nquery plannerEvents($umbrellaID: Int!, $filter: [String!]) {\n umbrellas(id: [$umbrellaID]) {\n title\n }\n typeLabels: labels(kind: EVENT_TYPE, umbrellaID: [$umbrellaID]) {\n name\n }\n topicLabels: labels(kind: TOPIC, umbrellaID: [$umbrellaID]) {\n name\n }\n events(umbrellaID: [$umbrellaID], label: $filter) {\n ID\n title\n from\n to\n topic {\n color\n }\n }\n}\n\nquery eventCloseup($id: Int!) {\n events(id: [$id]) {\n ID\n title\n description\n from\n to\n topic {\n name\n color\n }\n type {\n name\n color\n }\n tutorsAssigned {\n tutors {\n fn\n sn\n mail\n }\n room {\n capacity\n floor\n name\n number\n building {\n name\n street\n number\n osm\n }\n }\n registrations\n }\n }\n}"): (typeof documents)["query tutorFormEvents {\n events(needsTutors: true, onlyFuture: true) {\n ID\n title\n from\n to\n topic {\n name\n color\n }\n type {\n name\n color\n }\n }\n}\n\nquery plannerEvents($umbrellaID: Int!, $filter: [String!]) {\n umbrellas(id: [$umbrellaID]) {\n title\n }\n typeLabels: labels(kind: EVENT_TYPE, umbrellaID: [$umbrellaID]) {\n name\n }\n topicLabels: labels(kind: TOPIC, umbrellaID: [$umbrellaID]) {\n name\n }\n events(umbrellaID: [$umbrellaID], label: $filter) {\n ID\n title\n from\n to\n topic {\n color\n }\n }\n}\n\nquery eventCloseup($id: Int!) {\n events(id: [$id]) {\n ID\n title\n description\n from\n to\n topic {\n name\n color\n }\n type {\n name\n color\n }\n tutorsAssigned {\n tutors {\n fn\n sn\n mail\n }\n room {\n capacity\n floor\n name\n number\n building {\n name\n street\n number\n osm\n }\n }\n registrations\n }\n }\n}"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "query registrationForm($eventID: Int!) {\n forms(id: [$eventID]) {\n title\n description\n questions {\n ID\n title\n type\n required\n answers {\n ID\n title\n points\n }\n }\n }\n}"): (typeof documents)["query registrationForm($eventID: Int!) {\n forms(id: [$eventID]) {\n title\n description\n questions {\n ID\n title\n type\n required\n answers {\n ID\n title\n points\n }\n }\n }\n}"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "query umbrellas {\n umbrellas {\n ID\n title\n }\n}"): (typeof documents)["query umbrellas {\n umbrellas {\n ID\n title\n }\n}"];

export function graphql(source: string) {
return (documents as any)[source] ?? {};
Expand Down
Loading

0 comments on commit 094e83e

Please sign in to comment.