Skip to content
Closed
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,8 @@ next-env.d.ts
*storybook.log
/.env

public/speakers2
.env

public/speakers2
.env
187 changes: 144 additions & 43 deletions app/agenda/agenda.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,40 @@ import * as Select from "@/components/select/Select";
import { Session as SessionComponent } from "@/components/session";
import { Text } from "@/components/text";
import { Toggle } from "@/components/toggle";
import { Session, Stages, Tracks } from "@/model/session";
// import { Session, Stages, Tracks } from "@/model/session";
import * as Separator from "@radix-ui/react-separator";
import classNames from "classnames";
import React, { useState } from "react";
import {
Session,
Stages,
Tracks,
Speaker,
} from "@/components/service/contentStrapi_static";

type AgendaProps = { sessions: Session[] };
type AgendaProps = { sessions: Session[]; speakers: Speaker[] };

export const Agenda: React.FC<AgendaProps> = ({ sessions }) => {
export const Agenda: React.FC<AgendaProps> = ({ sessions, speakers }) => {
const [titleFilter, setTitleFilter] = useState<string>("");
const [dayFilter, setDayFilter] = useState<Date>();
const [trackFilter, setTrackFilter] = useState<Session["track"] & "all">();
const [stageFilter, setStageFilter] = useState<Session["room"] & "all">();

const stageDisplayNames: Record<string, string> = {
"Stage 1": "Turing Stage",
"Stage 2": "Hopper Stage",
"Stage 3": "Nakamoto Stage",
"Workshop Room": "Lovelace Room",
};

const STAGE_PRIORITY: Record<string, number> = {
"Stage 3": 0, // Nakamoto — highest priority
"Stage 1": 1, // Turing
"Stage 2": 2, // Hopper
"Workshop Room": 3, // Lovelace
};
const SAME_TIME_WINDOW_MS = 0 * 60 * 1000; // 5 minutes

function isSameDay(d1: Date, d2: Date) {
return (
d1.getFullYear() === d2.getFullYear() &&
Expand All @@ -27,12 +49,41 @@ export const Agenda: React.FC<AgendaProps> = ({ sessions }) => {
let filteredSessions = null;

if (sessions) {
filteredSessions = sessions.filter(
(item) =>
(!dayFilter || isSameDay(dayFilter, new Date(item.startTime))) &&
(trackFilter === "all" || !trackFilter || trackFilter === item.track) &&
(stageFilter === "all" || !stageFilter || stageFilter === item.room),
);
filteredSessions = sessions.filter((item) => {
const matchesDay =
!dayFilter || isSameDay(dayFilter, new Date(item.startTime));
const matchesTrack =
trackFilter === "all" || !trackFilter || trackFilter === item.track;
const matchesStage =
stageFilter === "all" || !stageFilter || stageFilter === item.room;
const matchesTitle =
!titleFilter.trim() ||
item.title.toLowerCase().includes(titleFilter.trim().toLowerCase());

return matchesDay && matchesTrack && matchesStage && matchesTitle;
});

filteredSessions.sort((a, b) => {
const ta = new Date(a.startTime).getTime();
const tb = new Date(b.startTime).getTime();

if (ta !== tb) {
// If they're close in time, apply stage priority
if (Math.abs(ta - tb) <= SAME_TIME_WINDOW_MS) {
const pa = STAGE_PRIORITY[a.room] ?? 99;
const pb = STAGE_PRIORITY[b.room] ?? 99;
if (pa !== pb) return pa - pb;
}
return ta - tb;
}

const pa = STAGE_PRIORITY[a.room] ?? 99;
const pb = STAGE_PRIORITY[b.room] ?? 99;
if (pa !== pb) return pa - pb;

if (a.room !== b.room) return a.room.localeCompare(b.room);
return a.title.localeCompare(b.title);
});
}

return (
Expand All @@ -44,6 +95,18 @@ export const Agenda: React.FC<AgendaProps> = ({ sessions }) => {
<Text textType={"sub_title"} className="text-left" as="p">
Filter
</Text>
<div className="flex flex-col gap-2">
<Text textType={"paragraph"} className="font-bold text-left" as="p">
Title
</Text>
<input
type="text"
value={titleFilter}
onChange={(e) => setTitleFilter(e.target.value)}
placeholder="Search agenda titles..."
className="w-full rounded-lg text-white border py-2 px-3 bg-black placeholder-gray-500"
/>
</div>
<div className="flex flex-col gap-3 h-fit">
<Text textType={"paragraph"} className="font-bold text-left" as="p">
Days
Expand Down Expand Up @@ -106,7 +169,7 @@ export const Agenda: React.FC<AgendaProps> = ({ sessions }) => {
<Select.Item value={"all"}>Any Stage</Select.Item>
{Stages.map((stage, index) => (
<Select.Item value={stage} key={index}>
{stage}
{stageDisplayNames[stage] || stage}
</Select.Item>
))}
</Select.Content>
Expand All @@ -129,7 +192,9 @@ export const Agenda: React.FC<AgendaProps> = ({ sessions }) => {
/>
<Select.Content>
<Select.Item value="all">Any Track</Select.Item>
{Tracks.map((track, index) => (
{Tracks.filter(
(track) => track !== "TUM Blockchain Club",
).map((track, index) => (
<Select.Item
value={track}
key={index}
Expand All @@ -138,12 +203,12 @@ export const Agenda: React.FC<AgendaProps> = ({ sessions }) => {
<span
className={classNames(
"inline-block w-3 h-3 rounded-full mr-2",
track === "Education Track" && "bg-green-400",
track === "Research Track" && "bg-yellow-400",
track === "Ecosystem Track" && "bg-blue-400",
track === "Regulation Track" && "bg-red-400",
track === "Academic Track" && "bg-purple-400",
track === "Application Track" && "bg-teal-400",
track === "Education" && "bg-green-400",
track === "Research" && "bg-yellow-400",
track === "Ecosystem" && "bg-blue-400",
track === "Regulation" && "bg-red-400",
track === "Workshop" && "bg-purple-400",
track === "Application" && "bg-teal-400",
)}
/>
{track}
Expand All @@ -157,32 +222,68 @@ export const Agenda: React.FC<AgendaProps> = ({ sessions }) => {
</div>
<div id="sessions" className="flex w-full flex-col gap-y-4">
<div className="flex w-full flex-col items-center md:items-start">
{filteredSessions?.map((item, index) => (
<>
{
// Add divider when there is they change
index > 0 &&
new Date(filteredSessions[index - 1].startTime).getDate() <
new Date(item.startTime).getDate() && (
<Separator.Root
attr-text={new Date(item.startTime).toLocaleDateString(
"en-DE",
{
weekday: "long",
timeZone: "Europe/Berlin",
},
)}
className={classNames(
"h-px my-16 bg-gradient-tbc w-full text-center overflow-visible",
"after:bg-black after:px-4 after:relative after:-top-[0.75em]",
"after:content-[attr(attr-text)]",
)}
/>
)
}
<SessionComponent session={item} key={index} />
</>
))}
{filteredSessions?.map((item, index) => {
// --- Warnings if Strapi data is missing ---
if (!item.title) {
console.warn(
`⚠️ Session at index ${index} is missing a title`,
item,
);
}
if (!item.startTime || !item.endTime) {
console.warn(
`⚠️ Session "${item.title ?? "?"}" has no start or end time`,
item,
);
}
if (!item.room) {
console.warn(
`⚠️ Session "${item.title ?? "?"}" has no room assigned`,
item,
);
}
if (!item.track) {
console.warn(
`⚠️ Session "${item.title ?? "?"}" has no track assigned`,
item,
);
}
if (!item.speakers || Object.keys(item.speakers).length === 0) {
console.warn(
`⚠️ Session "${item.title ?? "?"}" has no speakers`,
item,
);
}
// -----------------------------------------

return (
<React.Fragment key={index}>
{
// Divider between days
index > 0 &&
new Date(filteredSessions[index - 1].startTime).getDate() <
new Date(item.startTime).getDate() && (
<Separator.Root
attr-text={new Date(item.startTime).toLocaleDateString(
"en-DE",
{
weekday: "long",
timeZone: "Europe/Berlin",
},
)}
className={classNames(
"h-px my-16 bg-gradient-tbc w-full text-center overflow-visible",
"after:bg-black after:px-4 after:relative after:-top-[0.75em]",
"after:content-[attr(attr-text)]",
)}
/>
)
}
<SessionComponent session={item} speakers={speakers} />
</React.Fragment>
);
})}

{filteredSessions?.length === 0 && (
<Text className="text-gray-500">
There is no session with that filter :(
Expand Down
123 changes: 5 additions & 118 deletions app/agenda/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,125 +5,12 @@ import { Container } from "@/components/container";
import { Text } from "@/components/text";
import { useSession } from "@/hooks/useSession";
import { Session, Stages, Tracks } from "@/model/session";
import { fetchSessions } from "@/components/service/contentStrapi_static";
import { fetchSpeakers } from "@/components/service/contentStrapi";

const AgendaPage = async () => {
const sessions: Session[] = [
{
title: "Blockchain 101: The Historic Evolution of Blockchain",
description:
"Even though blockchains have been around for just a few years, many projects push the boundaries forward. We provide a short overview of the stepping-stone projects and various design choices to consider. Last, we contextualized many previous decades of research and how current systems are built on top of those experiences.",
startTime: "2024-09-12T09:15:00+02:00",
endTime: "2024-09-12T09:25:00+02:00",
room: Stages[1],
track: Tracks[0],
isSpecialSession: true,
type: "Talk",
speakers: [
{
name: "Filip Rezabek",
description: "PhD, TUM",
priority: 2,
},
],
},
{
title: "New Forms of Money",
description:
"Overview on emerging DLT-based forms of money incl. Tokenized Deposits, Stablecoins and CBDCs.",
startTime: "2024-09-12T11:00:00+02:00",
endTime: "2024-09-12T12:00:00+02:00",
room: Stages[2],
track: Tracks[1],
isSpecialSession: false,
type: "Talk",
speakers: [
{
name: "Maximilian Baum",
description: "Digital Currencies, Deutsche Bank",
priority: 1,
},
],
},
{
title: "Ethereum Protocol R&D Roadmap",
description:
"The talk explains the latest roadmap of Ethereum protocol development. It provides a technical dive into the current state of the protocol, recent and upcoming upgrades. We will dive into proposed solutions like PeerDAS, EOF, verkle trees and more.",
startTime: "2024-09-12T11:00:00+02:00",
endTime: "2024-09-12T12:00:00+02:00",
room: Stages[3],
track: Tracks[2],
isSpecialSession: false,
type: "Workshop",
speakers: [
{
name: "Mario Havel",
description: "Protocol Supporter, Ethereum Foundation",
priority: 2,
},
{
name: "David Kim",
description: "Protocol Architect",
priority: 3,
},
],
},
{
title: "Introduction to Regulation of Crypto Assets",
description:
"Alireza will present an Introduction to the Regulation of Crypto Assets, beginning with an overview of how crypto asset regulation has evolved from both a global and EU perspective. He will also explore the future direction of these regulations. The presentation will delve into the regulation of specific use cases and provide an in-depth discussion on the regulation of decentralized finance (DeFi).",
startTime: "2024-09-13T10:30:00+02:00",
endTime: "2024-09-13T11:30:00+02:00",
room: Stages[3],
track: Tracks[3],
isSpecialSession: false,
type: "Talk",
speakers: [
{
name: "Alireza Siadat",
description: "Crypto & DLT Advisor",
priority: 2,
},
],
},
{
title:
"Enhancing Smart Contract Security through AI: Promises and Limitations",
description:
"This talk explores the potential of AI in advancing DeFi security. We'll examine how AI can guide fuzzers to uncover smart contract vulnerabilities and work towards real-time detection of exploit transactions. While AI offers exciting possibilities, it's not a silver bullet. We'll balance the discussion by highlighting areas where traditional approaches may still have an edge, providing a comprehensive view of the current state and future potential of AI in DeFi security.",
startTime: "2024-09-13T10:30:00+02:00",
endTime: "2024-09-13T11:30:00+02:00",
room: Stages[0],
track: Tracks[4],
isSpecialSession: true,
type: "Talk",
speakers: [
{
name: "Arthur Gervais",
description: "Prof. of Information Security, UCL & Co-Founder, D23E",
priority: 2,
},
],
},
{
title:
"Deanonymizing Ethereum Validators: The P2P Network Has a Privacy Issue",
description:
"This presentation reveals how easily validators can be deanonymized in the Ethereum P2P network. We explore extracted data such as validator distribution and geolocation, discuss associated security risks, and propose solutions to improve privacy.",
startTime: "2024-09-13T10:30:00+02:00",
endTime: "2024-09-13T11:30:00+02:00",
room: Stages[3],
track: Tracks[5],
isSpecialSession: true,
type: "Talk",
speakers: [
{
name: "Yann Vonlanthen",
description: "PhD student, ETH Zurich",
priority: 2,
},
],
},
];
const sessions = await fetchSessions();
const speakers = await fetchSpeakers();

return (
<div className={"flex justify-center"}>
Expand All @@ -139,7 +26,7 @@ const AgendaPage = async () => {
</Text>
</div>
</div>
<Agenda sessions={sessions} />
<Agenda sessions={sessions} speakers={speakers} />
</Container>
</main>
</div>
Expand Down
Loading
Loading