diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx
index 75c2d97..958c299 100644
--- a/frontend/app/page.tsx
+++ b/frontend/app/page.tsx
@@ -20,8 +20,14 @@ import {
UmbrellasQuery,
} from "@/lib/gql/generated/graphql";
import { client } from "@/lib/graphClient";
-import { useEffect, useState } from "react";
-import { Check, ChevronsUpDown } from "lucide-react";
+import React, { useEffect, useState } from "react";
+import {
+ Check,
+ ChevronsUpDown,
+ Mail,
+ Building2,
+ ArrowDownToDot,
+} from "lucide-react";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
@@ -48,8 +54,12 @@ import {
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";
+import { Table, TableBody, TableCell, TableRow } from "@/components/ui/table";
+import {
+ HoverCard,
+ HoverCardTrigger,
+ HoverCardContent,
+} from "@/components/ui/hover-card";
type GroupedEvents = {
[week: number]: {
@@ -149,14 +159,6 @@ export default function Home() {
fetchData();
}, [filter, umbrella]);
- const handleFilterChange = (f: string) => {
- setFilter((prevSelected) =>
- prevSelected.includes(f)
- ? prevSelected.filter((t) => t !== f)
- : [...prevSelected, f]
- );
- };
-
const groupedEvents = groupEvents(events);
const calculateEventDurationInHours = (from: string, to: string) => {
@@ -219,45 +221,22 @@ export default function Home() {
-
-
-
- Thema |
-
- {topics.map((topic) => (
-
- ))}
- |
-
-
-
- Veranstaltungsart |
-
- {types.map((type) => (
-
- ))}
- |
-
-
-
+ {events.length > 0 && (
+
+ t.name)}
+ filter={filter}
+ setFilter={setFilter}
+ />
+ t.name)}
+ filter={filter}
+ setFilter={setFilter}
+ />
+
+ )}
{loading ? (
@@ -388,6 +367,43 @@ export default function Home() {
);
}
+function Filter({
+ title,
+ options,
+ filter,
+ setFilter,
+}: {
+ title: string;
+ options: string[];
+ filter: string[];
+ setFilter: React.Dispatch
>;
+}) {
+ const handleFilterChange = (f: string) => {
+ setFilter((prevSelected) =>
+ prevSelected.includes(f)
+ ? prevSelected.filter((t) => t !== f)
+ : [...prevSelected, f]
+ );
+ };
+
+ return (
+
+
{title}
+
+ {options.map((o) => (
+
+ ))}
+
+
+ );
+}
+
function EventDialog({ id }: { id: number }) {
const [loading, setLoading] = useState(true);
const [event, setEvent] = useState(
@@ -434,39 +450,131 @@ function EventDialog({ id }: { id: number }) {
{event?.description}
- {event?.topic.name}
- {event?.type.name}
+
+ {event?.topic.name}
+
+
+ {event?.type.name}
+
-
-
- {event?.tutorsAssigned?.map((e) => (
-
-
- {e.tutors?.map((t) => (
-
- ))}
-
-
-
-
- {e.registrations == null ? 0 : e.registrations}
- /
- {e.room?.capacity}
-
-
-
-
-
-
- ))}
-
-
+
+
+ {event?.tutorsAssigned?.map((e) => {
+ const registrations = e.registrations ?? 0;
+ const capacity = e.room?.capacity ?? 1;
+ const utilization = (registrations / capacity) * 100;
+
+ return (
+
+
+
+ {e.tutors?.map((t) => (
+
+
+
+ {t.fn + " " + t.sn[0] + "."}
+
+
+
+
+ {t.fn + " " + t.sn}
+
+
+
+
+ ))}
+
+
+
+
+
+
+ {e.room?.building.name}
+
+
+ {e.room?.name ? e.room.name : e.room?.number}
+
+
+
+
+
+
+
+
+
+ {e.room?.building.name}
+
+
+ {e.room?.building.street +
+ " " +
+ e.room?.building.number}
+
+
+
{e.room?.building.zip},
+
{e.room?.building.city}
+
+
+
+
+
+
+
+ {e.room?.name
+ ? e.room.name
+ : e.room?.number}
+
+
+ Ebene {e.room?.floor}
+
+
+
+
+
+
+
+
+
+
+ {registrations}
+ /
+ {e.room?.capacity}
+
+
+
+
+
+
+ );
+ })}
+
+
)}
diff --git a/frontend/components/ui/badge.tsx b/frontend/components/ui/badge.tsx
index 66cba29..e4ea960 100644
--- a/frontend/components/ui/badge.tsx
+++ b/frontend/components/ui/badge.tsx
@@ -2,6 +2,7 @@ import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils/tailwindUtils"
+import {calculateFontColor} from "@/lib/utils/colorUtils"
const badgeVariants = cva(
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
@@ -26,18 +27,17 @@ const badgeVariants = cva(
export interface BadgeProps
extends React.HTMLAttributes,
- VariantProps {}
+ VariantProps {
+ color?: string
+ }
-function Badge({ className, variant, ...props }: BadgeProps) {
+function Badge({ color, className, variant, ...props }: BadgeProps) {
return (
-
+
)
}
-function EventLabelBadge({ className, ...props }: BadgeProps) {
- return (
-
- )
-}
-
-export { EventLabelBadge, Badge, badgeVariants }
+export { Badge, badgeVariants }
diff --git a/frontend/components/ui/hover-card.tsx b/frontend/components/ui/hover-card.tsx
new file mode 100644
index 0000000..e54d91c
--- /dev/null
+++ b/frontend/components/ui/hover-card.tsx
@@ -0,0 +1,29 @@
+"use client"
+
+import * as React from "react"
+import * as HoverCardPrimitive from "@radix-ui/react-hover-card"
+
+import { cn } from "@/lib/utils"
+
+const HoverCard = HoverCardPrimitive.Root
+
+const HoverCardTrigger = HoverCardPrimitive.Trigger
+
+const HoverCardContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
+
+))
+HoverCardContent.displayName = HoverCardPrimitive.Content.displayName
+
+export { HoverCard, HoverCardTrigger, HoverCardContent }
diff --git a/frontend/lib/gql/generated/gql.ts b/frontend/lib/gql/generated/gql.ts
index 623fcb9..0e223b6 100644
--- a/frontend/lib/gql/generated/gql.ts
+++ b/frontend/lib/gql/generated/gql.ts
@@ -15,7 +15,7 @@ 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 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 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 city\n zip\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,
};
@@ -45,7 +45,7 @@ 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 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}"];
+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 city\n zip\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 city\n zip\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.
*/
diff --git a/frontend/lib/gql/generated/graphql.ts b/frontend/lib/gql/generated/graphql.ts
index c3a5900..c745c11 100644
--- a/frontend/lib/gql/generated/graphql.ts
+++ b/frontend/lib/gql/generated/graphql.ts
@@ -569,7 +569,7 @@ export type EventCloseupQueryVariables = Exact<{
}>;
-export type EventCloseupQuery = { __typename?: 'Query', events: Array<{ __typename?: 'Event', ID: number, title: string, description?: string | null, from: any, to: any, topic: { __typename?: 'Label', name: string, color?: any | null }, type: { __typename?: 'Label', name: string, color?: any | null }, tutorsAssigned?: Array<{ __typename?: 'EventTutorRoomPair', registrations?: number | null, tutors?: Array<{ __typename?: 'User', fn: string, sn: string, mail: string }> | null, room?: { __typename?: 'Room', capacity?: number | null, floor?: number | null, name?: string | null, number: string, building: { __typename?: 'Building', name: string, street: string, number: string, osm: string } } | null }> | null }> };
+export type EventCloseupQuery = { __typename?: 'Query', events: Array<{ __typename?: 'Event', ID: number, title: string, description?: string | null, from: any, to: any, topic: { __typename?: 'Label', name: string, color?: any | null }, type: { __typename?: 'Label', name: string, color?: any | null }, tutorsAssigned?: Array<{ __typename?: 'EventTutorRoomPair', registrations?: number | null, tutors?: Array<{ __typename?: 'User', fn: string, sn: string, mail: string }> | null, room?: { __typename?: 'Room', capacity?: number | null, floor?: number | null, name?: string | null, number: string, building: { __typename?: 'Building', name: string, street: string, number: string, city: string, zip: number, osm: string } } | null }> | null }> };
export type RegistrationFormQueryVariables = Exact<{
eventID: Scalars['Int']['input'];
@@ -588,6 +588,6 @@ export const AddStudentApplicationForEventDocument = {"kind":"Document","definit
export const AddTutorDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"addTutor"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"firstName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"lastName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"email"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventsAvailable"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"addTutor"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"tutor"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"fn"},"value":{"kind":"Variable","name":{"kind":"Name","value":"firstName"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"sn"},"value":{"kind":"Variable","name":{"kind":"Name","value":"lastName"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"mail"},"value":{"kind":"Variable","name":{"kind":"Name","value":"email"}}}]}},{"kind":"Argument","name":{"kind":"Name","value":"availability"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"userMail"},"value":{"kind":"Variable","name":{"kind":"Name","value":"email"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"eventID"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventsAvailable"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fn"}}]}}]}}]} as unknown as DocumentNode;
export const TutorFormEventsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"tutorFormEvents"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"needsTutors"},"value":{"kind":"BooleanValue","value":true}},{"kind":"Argument","name":{"kind":"Name","value":"onlyFuture"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"from"}},{"kind":"Field","name":{"kind":"Name","value":"to"}},{"kind":"Field","name":{"kind":"Name","value":"topic"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"type"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]}}]}}]} as unknown as DocumentNode;
export const PlannerEventsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"plannerEvents"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"umbrellaID"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"umbrellas"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"ListValue","values":[{"kind":"Variable","name":{"kind":"Name","value":"umbrellaID"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"typeLabels"},"name":{"kind":"Name","value":"labels"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"kind"},"value":{"kind":"EnumValue","value":"EVENT_TYPE"}},{"kind":"Argument","name":{"kind":"Name","value":"umbrellaID"},"value":{"kind":"ListValue","values":[{"kind":"Variable","name":{"kind":"Name","value":"umbrellaID"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"topicLabels"},"name":{"kind":"Name","value":"labels"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"kind"},"value":{"kind":"EnumValue","value":"TOPIC"}},{"kind":"Argument","name":{"kind":"Name","value":"umbrellaID"},"value":{"kind":"ListValue","values":[{"kind":"Variable","name":{"kind":"Name","value":"umbrellaID"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"umbrellaID"},"value":{"kind":"ListValue","values":[{"kind":"Variable","name":{"kind":"Name","value":"umbrellaID"}}]}},{"kind":"Argument","name":{"kind":"Name","value":"label"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"from"}},{"kind":"Field","name":{"kind":"Name","value":"to"}},{"kind":"Field","name":{"kind":"Name","value":"topic"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]}}]}}]} as unknown as DocumentNode;
-export const EventCloseupDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"eventCloseup"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"ListValue","values":[{"kind":"Variable","name":{"kind":"Name","value":"id"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"from"}},{"kind":"Field","name":{"kind":"Name","value":"to"}},{"kind":"Field","name":{"kind":"Name","value":"topic"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"type"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tutorsAssigned"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tutors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fn"}},{"kind":"Field","name":{"kind":"Name","value":"sn"}},{"kind":"Field","name":{"kind":"Name","value":"mail"}}]}},{"kind":"Field","name":{"kind":"Name","value":"room"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"capacity"}},{"kind":"Field","name":{"kind":"Name","value":"floor"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"number"}},{"kind":"Field","name":{"kind":"Name","value":"building"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"street"}},{"kind":"Field","name":{"kind":"Name","value":"number"}},{"kind":"Field","name":{"kind":"Name","value":"osm"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"registrations"}}]}}]}}]}}]} as unknown as DocumentNode;
+export const EventCloseupDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"eventCloseup"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"events"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"ListValue","values":[{"kind":"Variable","name":{"kind":"Name","value":"id"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"from"}},{"kind":"Field","name":{"kind":"Name","value":"to"}},{"kind":"Field","name":{"kind":"Name","value":"topic"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"type"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"tutorsAssigned"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tutors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fn"}},{"kind":"Field","name":{"kind":"Name","value":"sn"}},{"kind":"Field","name":{"kind":"Name","value":"mail"}}]}},{"kind":"Field","name":{"kind":"Name","value":"room"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"capacity"}},{"kind":"Field","name":{"kind":"Name","value":"floor"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"number"}},{"kind":"Field","name":{"kind":"Name","value":"building"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"street"}},{"kind":"Field","name":{"kind":"Name","value":"number"}},{"kind":"Field","name":{"kind":"Name","value":"city"}},{"kind":"Field","name":{"kind":"Name","value":"zip"}},{"kind":"Field","name":{"kind":"Name","value":"osm"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"registrations"}}]}}]}}]}}]} as unknown as DocumentNode;
export const RegistrationFormDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"registrationForm"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventID"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"forms"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"ListValue","values":[{"kind":"Variable","name":{"kind":"Name","value":"eventID"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"questions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"required"}},{"kind":"Field","name":{"kind":"Name","value":"answers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"points"}}]}}]}}]}}]}}]} as unknown as DocumentNode;
export const UmbrellasDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"umbrellas"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"umbrellas"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]}}]} as unknown as DocumentNode;
\ No newline at end of file
diff --git a/frontend/lib/gql/queries/events.graphql b/frontend/lib/gql/queries/events.graphql
index 005aac5..97dd852 100644
--- a/frontend/lib/gql/queries/events.graphql
+++ b/frontend/lib/gql/queries/events.graphql
@@ -66,6 +66,8 @@ query eventCloseup($id: Int!) {
name
street
number
+ city
+ zip
osm
}
}
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index a531be7..70aa41e 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -11,6 +11,7 @@
"@hookform/resolvers": "^3.9.0",
"@radix-ui/react-checkbox": "^1.1.1",
"@radix-ui/react-dialog": "^1.1.2",
+ "@radix-ui/react-hover-card": "^1.1.2",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-progress": "^1.1.0",
@@ -30,6 +31,7 @@
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.52.2",
+ "react-leaflet": "^4.2.1",
"shadcn-ui": "^0.9.2",
"sharp": "^0.33.4",
"sonner": "^1.5.0",
@@ -3704,6 +3706,127 @@
}
}
},
+ "node_modules/@radix-ui/react-hover-card": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.2.tgz",
+ "integrity": "sha512-Y5w0qGhysvmqsIy6nQxaPa6mXNKznfoGjOfBgzOjocLxr2XlSjqBMYQQL+FfyogsMuX+m8cZyQGYhJxvxUzO4w==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.0",
+ "@radix-ui/react-compose-refs": "1.1.0",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-dismissable-layer": "1.1.1",
+ "@radix-ui/react-popper": "1.2.0",
+ "@radix-ui/react-portal": "1.1.2",
+ "@radix-ui/react-presence": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.0",
+ "@radix-ui/react-use-controllable-state": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-context": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.1.tgz",
+ "integrity": "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.1.tgz",
+ "integrity": "sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.0",
+ "@radix-ui/react-compose-refs": "1.1.0",
+ "@radix-ui/react-primitive": "2.0.0",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-escape-keydown": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-portal": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.2.tgz",
+ "integrity": "sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.0",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-presence": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.1.tgz",
+ "integrity": "sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-id": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz",
@@ -4235,6 +4358,17 @@
"integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==",
"license": "MIT"
},
+ "node_modules/@react-leaflet/core": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz",
+ "integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==",
+ "license": "Hippocratic-2.1",
+ "peerDependencies": {
+ "leaflet": "^1.9.0",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0"
+ }
+ },
"node_modules/@repeaterjs/repeater": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.6.tgz",
@@ -8980,6 +9114,13 @@
"node": ">=0.10"
}
},
+ "node_modules/leaflet": {
+ "version": "1.9.4",
+ "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
+ "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==",
+ "license": "BSD-2-Clause",
+ "peer": true
+ },
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -10390,6 +10531,20 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/react-leaflet": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.2.1.tgz",
+ "integrity": "sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==",
+ "license": "Hippocratic-2.1",
+ "dependencies": {
+ "@react-leaflet/core": "^2.1.0"
+ },
+ "peerDependencies": {
+ "leaflet": "^1.9.0",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0"
+ }
+ },
"node_modules/react-remove-scroll": {
"version": "2.5.7",
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 1c20f75..1057acd 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -13,6 +13,7 @@
"@hookform/resolvers": "^3.9.0",
"@radix-ui/react-checkbox": "^1.1.1",
"@radix-ui/react-dialog": "^1.1.2",
+ "@radix-ui/react-hover-card": "^1.1.2",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-progress": "^1.1.0",
@@ -32,6 +33,7 @@
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.52.2",
+ "react-leaflet": "^4.2.1",
"shadcn-ui": "^0.9.2",
"sharp": "^0.33.4",
"sonner": "^1.5.0",