> = ({
> = ({
speaker,
+ edition = conferenceData.edition,
+ speakersRoute = ROUTE_SPEAKERS,
+ talkDetailRoute = ROUTE_TALK_DETAIL,
}) => {
const { width } = useWindowSize();
useEffect(() => {
- document.title = `${speaker.fullName} — ${conferenceData.title} — ${conferenceData.edition}`;
- }, [speaker.fullName]);
+ document.title = `${speaker.fullName} — ${conferenceData.title} — ${edition}`;
+ }, [speaker.fullName, edition]);
const hasSessions = (): boolean =>
(speaker.sessions && speaker.sessions.length > 0) || false;
@@ -124,7 +130,7 @@ const SpeakerDetail: FC
> = ({
{speaker?.sessions?.map((session) => (
> = ({
)}
({
captureException: vi.fn(),
}));
-// Mock the 2025.json data
-vi.mock("../../data/2025.json", () => {
+// Mock the 2026.json data
+vi.mock("../../data/2026.json", () => {
const mockData = {
hideSpeakers: false,
- edition: "2024",
+ edition: "2026",
title: "DevBcn",
cfp: {
- startDay: "2023-01-01T00:00:00",
- endDay: "2023-02-01T00:00:00",
+ startDay: "2026-01-01T00:00:00",
+ endDay: "2026-03-01T00:00:00",
link: "https://example.com/cfp",
},
};
@@ -94,7 +94,7 @@ describe("Speakers component", () => {
// Mock Date to return a date within the CFP period
const originalDate = Date;
- const mockDate = new Date("2023-01-15");
+ const mockDate = new Date("2026-01-15");
// This ensures that both new Date() and Date.now() use our mock date
global.Date = class extends Date {
@@ -130,7 +130,7 @@ describe("Speakers component", () => {
// Mock Date to return a date within the CFP period
const originalDate = Date;
- const mockDate = new Date("2023-01-15");
+ const mockDate = new Date("2026-01-15");
// This ensures that both new Date() and Date.now() use our mock date
global.Date = class extends Date {
diff --git a/src/views/Speakers/Speakers.tsx b/src/views/Speakers/Speakers.tsx
index 606fbd0a6..9f4b05240 100644
--- a/src/views/Speakers/Speakers.tsx
+++ b/src/views/Speakers/Speakers.tsx
@@ -15,7 +15,7 @@ import {
StyledSpeakersSection,
StyledWaveContainer,
} from "./Speakers.style";
-import webData from "@data/2025.json";
+import webData from "@data/2026.json";
import Button from "@components/UI/Button";
import { gaEventTracker } from "@components/analytics/Analytics";
import { useFetchSpeakers } from "@hooks/useFetchSpeakers";
@@ -29,13 +29,19 @@ const LessThanGreaterThan = () => (
>
);
-const Speakers: FC> = () => {
+interface SpeakersProps {
+ conferenceConfig?: typeof webData;
+}
+
+const Speakers: FC> = ({
+ conferenceConfig = webData,
+}) => {
const { width } = useWindowSize();
const today = new Date();
const isBetween = (startDay: Date, endDay: Date): boolean =>
startDay < new Date() && endDay > today;
- const { error, data, isLoading } = useFetchSpeakers();
+ const { error, data, isLoading } = useFetchSpeakers(conferenceConfig.edition);
useSentryErrorReport(error);
@@ -44,11 +50,11 @@ const Speakers: FC> = () => {
}, []);
useEffect(() => {
- document.title = `Speakers — ${webData.title} — ${webData.edition}`;
+ document.title = `Speakers — ${conferenceConfig.title} — ${conferenceConfig.edition}`;
});
- const CFPStartDay = new Date(webData.cfp.startDay);
- const CFPEndDay = new Date(webData.cfp.endDay);
+ const CFPStartDay = new Date(conferenceConfig.cfp.startDay);
+ const CFPEndDay = new Date(conferenceConfig.cfp.endDay);
return (
<>
@@ -75,11 +81,11 @@ const Speakers: FC> = () => {
)}
- {webData.hideSpeakers ? (
+ {conferenceConfig.hideSpeakers ? (
No selected speakers yet. Keep in touch in our social media for
upcoming announcements
@@ -89,7 +95,7 @@ const Speakers: FC> = () => {
))
)}
diff --git a/src/views/Talks/LiveView.test.tsx b/src/views/Talks/LiveView.test.tsx
index 64eea81de..ba68a5090 100644
--- a/src/views/Talks/LiveView.test.tsx
+++ b/src/views/Talks/LiveView.test.tsx
@@ -3,8 +3,8 @@ import * as useFetchTalksModule from "@hooks/useFetchTalks";
import { useFetchLiveView } from "@hooks/useFetchTalks";
import { Loading } from "@components/Loading/Loading";
import { UngroupedSession } from "./liveView.types";
-import conference from "@data/2025.json";
-import { TalkCard } from "./components/TalkCard";
+import conference from "@data/2026.json";
+import { TalkCard } from "@components/common/TalkCard";
import { StyledAgenda, StyledMain } from "./Talks.style";
import { talkCardAdapter } from "./TalkCardAdapter";
import { useSentryErrorReport } from "@hooks/useSentryErrorReport";
diff --git a/src/views/Talks/LiveView.tsx b/src/views/Talks/LiveView.tsx
index b4da5ab7a..8a5d8fbe5 100644
--- a/src/views/Talks/LiveView.tsx
+++ b/src/views/Talks/LiveView.tsx
@@ -3,7 +3,7 @@ import { useFetchLiveView } from "@hooks/useFetchTalks";
import { Loading } from "@components/Loading/Loading";
import { UngroupedSession } from "./liveView.types";
import conference from "@data/2025.json";
-import { TalkCard } from "./components/TalkCard";
+import { TalkCard } from "@components/common/TalkCard";
import { StyledAgenda, StyledMain } from "./Talks.style";
import { talkCardAdapter } from "./TalkCardAdapter";
import { useSentryErrorReport } from "@hooks/useSentryErrorReport";
diff --git a/src/views/Talks/TalkCardAdapter.ts b/src/views/Talks/TalkCardAdapter.ts
index fa3b64ec4..22fba67ca 100644
--- a/src/views/Talks/TalkCardAdapter.ts
+++ b/src/views/Talks/TalkCardAdapter.ts
@@ -1,5 +1,5 @@
import { UngroupedSession } from "./liveView.types";
-import { TalkCardProps } from "./components/TalkCard";
+import { TalkCardProps } from "@components/common/TalkCard";
import {
QuestionAnswers,
diff --git a/src/views/Talks/Talks.test.tsx b/src/views/Talks/Talks.test.tsx
index 43c14857c..3019c2026 100644
--- a/src/views/Talks/Talks.test.tsx
+++ b/src/views/Talks/Talks.test.tsx
@@ -7,7 +7,11 @@ import {
} from "../../utils/testing/testUtils";
import { ROUTE_MEETING_DETAIL_PLAIN } from "@constants/routes";
import { useFetchTalks } from "@hooks/useFetchTalks";
-import { IGroup } from "@/types/sessions";
+import {
+ IGroup,
+ TopRatedTalk,
+ TopTalkWithSpeaker,
+} from "@/types/sessions";
import userEvent from "@testing-library/user-event";
import { vi } from "vitest";
@@ -37,6 +41,99 @@ vi.mock("../../utils/testing/testUtils", async (importOriginal) => {
};
});
+const mockTopTenTalks: TopRatedTalk[] = [
+ {
+ id: "df057475-0b6a-4fab-8e0d-c5576230dd5c",
+ speaker: "Victor Rentea",
+ talk: "Top 10 Rest API Design Falls",
+ link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "838798"),
+ },
+ {
+ id: "d32cdd87-3c7d-47bb-98ec-b255d1e4b9ba",
+ speaker: "Laura Perea",
+ talk: "GenAI among us",
+ link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "945091"),
+ },
+ {
+ id: "eb3852c1-acf8-42a6-988d-365fad2a5668",
+ speaker: "Brian Vermeer",
+ talk: "Don't Get Burned! Secure Coding Essentials in Java to protect your application",
+ link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "851481"),
+ },
+ {
+ id: "625b53c9-edea-4e47-a5ba-2ee661c539e3",
+ speaker: "Álvaro Sánchez-Mariscal",
+ talk: "Revealing the magic behind Java annotations",
+ link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "843845"),
+ },
+ {
+ id: "7b1c534c-39a5-4398-93e5-626010f00198",
+ speaker: "Alexander Chatzizacharias",
+ talk: "What is multimodal RAG, and can we build a village with it?",
+ link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "832774"),
+ },
+ {
+ id: "ebab2b92-503f-4baa-b3ab-064865853223",
+ speaker: "Bert Jan Schrijver",
+ talk: "Generic or Specific? Making sensible software design decisions",
+ link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "827688"),
+ },
+ {
+ id: "11554c51-dc18-407b-b7b4-b8ad2f925b2a",
+ speaker: "Marc Nuri",
+ talk: "Model Context Protocol Servers 101: Unlocking the Power of AI",
+ link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "874255"),
+ },
+ {
+ id: "10937eaf-a0da-48c9-82d6-8711ca26fb16",
+ speaker: "Andres Almiray",
+ talk: "Maven Productivity Tips",
+ link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "860854"),
+ },
+ {
+ id: "5ce27637-12b4-4dfe-830d-166d88c837ad",
+ speaker: "Milen Dyankov",
+ talk: "AI for Java Developers - From Buzzword to Code",
+ link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "873844"),
+ },
+ {
+ id: "2aea7252-6822-4f42-a9d4-fa830f29df40",
+ speaker: "Rijo Sam",
+ talk: "Java Beyond Frameworks: Avoiding Lock-In with Agnostic Design",
+ link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "875233"),
+ },
+];
+
+const mockTopThreeTalks: TopTalkWithSpeaker[] = [
+ {
+ id: "df057475-0b6a-4fab-8e0d-c5576230dd5c",
+ award: "Funniest talk",
+ speaker: "Victor Rentea",
+ speakerImage:
+ "https://sessionize.com/image/2fde-400o400o1-NVbZAJzrFZpcRjEe5khxjo.png",
+ talk: "Top 10 Rest API Design Falls",
+ link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "838798"),
+ },
+ {
+ id: "d32cdd87-3c7d-47bb-98ec-b255d1e4b9ba",
+ speaker: "Laura Perea",
+ award: "Best Rated",
+ speakerImage:
+ "https://sessionize.com/image/8df6-400o400o1-LKJE9Ej5xvBK92FtxJDo6U.png",
+ talk: "GenAI among us",
+ link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "945091"),
+ },
+ {
+ id: "11554c51-dc18-407b-b7b4-b8ad2f925b2a",
+ speaker: "Marc Nuri",
+ award: "Most original",
+ speakerImage:
+ "https://sessionize.com/image/3a9a-400o400o1-sJBQfR5Ki5BGPEDG8GQgKM.jpg",
+ talk: "Model Context Protocol Servers 101: Unlocking the Power of AI",
+ link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "874255"),
+ },
+];
+
describe("Talks", () => {
beforeEach(() => {
// Reset all mocks before each test
@@ -106,7 +203,12 @@ describe("Talks", () => {
// Tests for the topThreeTalks array
it("renders the top three talks section with correct awards", () => {
- renderWithQueryClient();
+ renderWithQueryClient(
+ ,
+ );
// Check for award titles
expect(screen.getByText("Funniest talk")).toBeInTheDocument();
@@ -115,7 +217,12 @@ describe("Talks", () => {
});
it("renders all top three talks with correct speaker names and talk titles", () => {
- renderWithQueryClient();
+ renderWithQueryClient(
+ ,
+ );
// Check for speaker names
expect(screen.getByText("Victor Rentea")).toBeInTheDocument();
@@ -135,7 +242,12 @@ describe("Talks", () => {
});
it("renders top three talks with correct images", () => {
- renderWithQueryClient();
+ renderWithQueryClient(
+ ,
+ );
// Check for images with correct src attributes
const images = screen.getAllByRole("img");
@@ -173,7 +285,12 @@ describe("Talks", () => {
});
it("renders top three talks with correct links", () => {
- renderWithQueryClient();
+ renderWithQueryClient(
+ ,
+ );
// Check that links are correctly formatted
const victorLink = screen.getByText("Victor Rentea").closest("a");
@@ -196,12 +313,22 @@ describe("Talks", () => {
// Tests for the topTenTalks array
it("renders the top ten talks section", () => {
- renderWithQueryClient();
+ renderWithQueryClient(
+ ,
+ );
expect(screen.getByText("🔝 Top Ten rated talks")).toBeInTheDocument();
});
it("renders all top ten talks with correct links", () => {
- renderWithQueryClient();
+ renderWithQueryClient(
+ ,
+ );
// Check for specific talks
expect(
diff --git a/src/views/Talks/Talks.tsx b/src/views/Talks/Talks.tsx
index 143145de6..db0f9c04c 100644
--- a/src/views/Talks/Talks.tsx
+++ b/src/views/Talks/Talks.tsx
@@ -17,30 +17,27 @@ import { SelectButton, SelectButtonChangeEvent } from "primereact/selectbutton";
import "primereact/resources/themes/lara-light-indigo/theme.css";
import "@styles/theme.css";
import { useSentryErrorReport } from "@hooks/useSentryErrorReport";
-import { ROUTE_MEETING_DETAIL_PLAIN } from "@constants/routes";
-
-interface TrackInfo {
- name: string;
- code?: string;
-}
-
-interface TopRatedTalk {
- id: string;
- speaker: string;
- talk: string;
- link: string;
-}
+import {
+ TopRatedTalk,
+ TopTalkWithSpeaker,
+ TrackInfo,
+} from "@/types/sessions";
-interface TopTalkWithSpeaker extends TopRatedTalk {
- speakerImage: string;
- award: string;
+interface TalksProps {
+ conferenceConfig?: typeof conferenceData;
+ topTenTalks?: Array;
+ topThreeTalks?: Array;
}
-const Talks: FC> = () => {
+const Talks: FC> = ({
+ conferenceConfig = conferenceData,
+ topTenTalks = [],
+ topThreeTalks = [],
+}) => {
const [selectedGroupId, setSelectedGroupId] = useState(
null,
);
- const { isLoading, error, data } = useFetchTalks();
+ const { isLoading, error, data } = useFetchTalks(conferenceConfig.edition);
useEffect(() => {
const sessionSelectedGroupCode =
@@ -48,7 +45,7 @@ const Talks: FC> = () => {
const sessionSelectedGroupName =
sessionStorage.getItem("selectedGroupName");
- document.title = `Talks - ${conferenceData.title} - ${conferenceData.edition}`;
+ document.title = `Talks - ${conferenceConfig.title} - ${conferenceConfig.edition}`;
if (sessionSelectedGroupCode && sessionSelectedGroupName) {
setSelectedGroupId({
@@ -56,7 +53,7 @@ const Talks: FC> = () => {
code: sessionSelectedGroupCode,
});
}
- }, []);
+ }, [conferenceConfig.title, conferenceConfig.edition]);
useSentryErrorReport(error);
@@ -68,106 +65,15 @@ const Talks: FC> = () => {
{ name: "All Tracks", code: undefined },
...(data !== undefined
? data
- .flatMap((group) => ({
- code: group?.groupId?.toString(),
- name: removeParenthesesContent(group.groupName),
- }))
- .sort((a, b) => a.name.localeCompare(b.name))
+ .flatMap((group) => ({
+ code: group?.groupId?.toString(),
+ name: removeParenthesesContent(group.groupName),
+ }))
+ .sort((a, b) => a.name.localeCompare(b.name))
: []),
];
- const topTenTalks: Array = [
- {
- id: "df057475-0b6a-4fab-8e0d-c5576230dd5c",
- speaker: "Victor Rentea",
- talk: "Top 10 Rest API Design Falls",
- link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "838798"),
- },
- {
- id: "d32cdd87-3c7d-47bb-98ec-b255d1e4b9ba",
- speaker: "Laura Perea",
- talk: "GenAI among us",
- link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "945091"),
- },
- {
- id: "eb3852c1-acf8-42a6-988d-365fad2a5668",
- speaker: "Brian Vermeer",
- talk: "Don't Get Burned! Secure Coding Essentials in Java to protect your application",
- link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "851481"),
- },
- {
- id: "625b53c9-edea-4e47-a5ba-2ee661c539e3",
- speaker: "Álvaro Sánchez-Mariscal",
- talk: "Revealing the magic behind Java annotations",
- link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "843845"),
- },
- {
- id: "7b1c534c-39a5-4398-93e5-626010f00198",
- speaker: "Alexander Chatzizacharias",
- talk: "What is multimodal RAG, and can we build a village with it?",
- link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "832774"),
- },
- {
- id: "ebab2b92-503f-4baa-b3ab-064865853223",
- speaker: "Bert Jan Schrijver",
- talk: "Generic or Specific? Making sensible software design decisions",
- link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "827688"),
- },
- {
- id: "11554c51-dc18-407b-b7b4-b8ad2f925b2a",
- speaker: "Marc Nuri",
- talk: "Model Context Protocol Servers 101: Unlocking the Power of AI",
- link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "874255"),
- },
- {
- id: "10937eaf-a0da-48c9-82d6-8711ca26fb16",
- speaker: "Andres Almiray",
- talk: "Maven Productivity Tips",
- link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "860854"),
- },
- {
- id: "5ce27637-12b4-4dfe-830d-166d88c837ad",
- speaker: "Milen Dyankov",
- talk: "AI for Java Developers - From Buzzword to Code",
- link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "873844"),
- },
- {
- id: "2aea7252-6822-4f42-a9d4-fa830f29df40",
- speaker: "Rijo Sam",
- talk: "Java Beyond Frameworks: Avoiding Lock-In with Agnostic Design",
- link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "875233"),
- },
- ];
- const topThreeTalks: Array = [
- {
- id: "df057475-0b6a-4fab-8e0d-c5576230dd5c",
- award: "Funniest talk",
- speaker: "Victor Rentea",
- speakerImage:
- "https://sessionize.com/image/2fde-400o400o1-NVbZAJzrFZpcRjEe5khxjo.png",
- talk: "Top 10 Rest API Design Falls",
- link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "838798"),
- },
- {
- id: "d32cdd87-3c7d-47bb-98ec-b255d1e4b9ba",
- speaker: "Laura Perea",
- award: "Best Rated",
- speakerImage:
- "https://sessionize.com/image/8df6-400o400o1-LKJE9Ej5xvBK92FtxJDo6U.png",
- talk: "GenAI among us",
- link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "945091"),
- },
- {
- id: "11554c51-dc18-407b-b7b4-b8ad2f925b2a",
- speaker: "Marc Nuri",
- award: "Most original",
- speakerImage:
- "https://sessionize.com/image/3a9a-400o400o1-sJBQfR5Ki5BGPEDG8GQgKM.jpg",
- talk: "Model Context Protocol Servers 101: Unlocking the Power of AI",
- link: ROUTE_MEETING_DETAIL_PLAIN.replace(":id", "874255"),
- },
- ];
const filteredTalks = selectedGroupId?.code
? data?.filter((talk) => talk.groupId.toString() === selectedGroupId.code)
@@ -267,7 +173,7 @@ const Talks: FC> = () => {
{isLoading && Loading
}
- {conferenceData.hideTalks ? (
+ {conferenceConfig.hideTalks ? (
No talks selected yet. Keep in tap in our social media for
upcoming announcements
@@ -325,8 +231,8 @@ const Talks: FC> = () => {
))}
>
diff --git a/src/views/Talks/components/TalkCard.tsx b/src/views/Talks/components/TalkCard.tsx
deleted file mode 100644
index 9b80d8a08..000000000
--- a/src/views/Talks/components/TalkCard.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from "react";
-import {
- TalkCard as CommonTalkCard,
- TalkCardProps,
-} from "@components/common/TalkCard";
-
-export type { TalkCardProps };
-
-export const TalkCard: React.FC> = (
- props,
-) => {
- return ;
-};
diff --git a/src/views/Travel/Travel.tsx b/src/views/Travel/Travel.tsx
index ee30b01b5..8dbf64729 100644
--- a/src/views/Travel/Travel.tsx
+++ b/src/views/Travel/Travel.tsx
@@ -1,12 +1,13 @@
-import React, { FC } from "react";
+import { FC } from "react";
+import { useParams } from "react-router";
import { Venue } from "./Venue";
import { ToBarcelona } from "./ToBarcelona";
-import data from "@data/2024.json";
import { StyledWaveContainer } from "../Speakers/Speakers.style";
import { styled } from "styled-components";
import { Color } from "@styles/colors";
import { Accommodation } from "./Accommodation";
import { useDocumentTitleUpdater } from "@hooks/useDocumentTitleUpdate";
+import { VenueWTC } from "./VenueWTC";
const StyledTravel = styled.div`
max-width: 85rem;
@@ -33,11 +34,14 @@ const StyledTravel = styled.div`
`;
const Travel: FC> = () => {
- useDocumentTitleUpdater("Travel", data.edition);
+ const { id } = useParams<{ id: string }>();
+ const edition = id || "2026";
+
+ useDocumentTitleUpdater("Travel", edition);
return (
-
+ {edition === "2026" ? : }
diff --git a/src/views/Travel/VenueWTC.tsx b/src/views/Travel/VenueWTC.tsx
new file mode 100644
index 000000000..0ac2b1653
--- /dev/null
+++ b/src/views/Travel/VenueWTC.tsx
@@ -0,0 +1,157 @@
+import React, { FC, Suspense } from "react";
+import "./map.css";
+import { styled } from "styled-components";
+import TitleSection from "@components/SectionTitle/TitleSection";
+import { Color } from "@styles/colors";
+import {
+ BIG_BREAKPOINT,
+ MAX_WIDTH,
+ MOBILE_BREAKPOINT,
+} from "@constants/BreakPoints";
+import { useWindowSize } from "react-use";
+import { StyledLoadingImage } from "@components/Loading/Loading";
+
+const StyledVenue = styled.div`
+ padding: 0.5rem 2rem 0.5rem;
+ text-align: left;
+ max-width: ${MAX_WIDTH}px;
+ margin: 0 auto;
+
+ @media (max-width: ${BIG_BREAKPOINT}px) {
+ padding: 100px 1rem 50px;
+ }
+
+ .image {
+ img.venue {
+ width: 95%;
+ margin: 0 2.5%;
+ text-align: center;
+ }
+
+ a,
+ p {
+ padding-left: 10px;
+ }
+
+ a {
+ text-decoration: none;
+ color: ${Color.DARK_BLUE};
+ font-weight: bold;
+ }
+ }
+
+ section.venue {
+ display: flex;
+ @media (max-width: ${BIG_BREAKPOINT}px) {
+ flex-direction: column;
+ }
+ }
+
+ h4 {
+ margin: 15px 0 3px 10px;
+ }
+
+ .image,
+ .map {
+ width: 50%;
+ @media (max-width: ${BIG_BREAKPOINT}px) {
+ width: 100%;
+ }
+ }
+`;
+
+const StyledTrainLine = styled.span`
+ background-color: #00f200;
+ font-weight: bold;
+ padding: 1px 2px;
+ font-family: sans-serif;
+ font-size: 12px;
+`;
+export const StyledLessIcon = styled.img`
+ position: absolute;
+ left: -1rem;
+ top: 5rem;
+ height: 5rem;
+
+ @media (min-width: ${BIG_BREAKPOINT}px) {
+ height: 10rem;
+ }
+`;
+export const StyledMoreIcon = styled.img`
+ position: absolute;
+ right: -1rem;
+ top: 5rem;
+ height: 5rem;
+
+ @media (min-width: ${BIG_BREAKPOINT}px) {
+ height: 10rem;
+ }
+`;
+
+export const VenueWTC: FC> = () => {
+ const { width } = useWindowSize();
+ return (
+
+
+ {width > MOBILE_BREAKPOINT && (
+ <>
+
+
+ >
+ )}
+
+
+
}>
+

+
+
+ World Trade Center, Barcelona
+
+
+ 1ª planta Edif. Este, Moll de Barcelona, s/n, 08039 Barcelona
+
+
Access by public transportation
+
🚇 Metro: Líneas L3: Parada Drassanes, Línea L2: Parada Paral·lel.
+
+ 🚍 Bus: Línea V11, parada Moll de Barcelona.
+
+
+ 🚙 Access by car: via C-31 & B-10(14 minutes from the
+ Airport)
+
+
Paid parking options
+
+
+ World Trade Center, Barcelona
+
+
+
+
+

+
+
+
+ );
+};
diff --git a/src/views/Workshops/Workshops.tsx b/src/views/Workshops/Workshops.tsx
index 06069418c..39dce348e 100644
--- a/src/views/Workshops/Workshops.tsx
+++ b/src/views/Workshops/Workshops.tsx
@@ -1,7 +1,7 @@
import React, { FC, useEffect } from "react";
import { SectionWrapper } from "@components/SectionWrapper/SectionWrapper";
import { useFetchTalks } from "@hooks/useFetchTalks";
-import { TalkCard } from "../Talks/components/TalkCard";
+import { TalkCard } from "@components/common/TalkCard";
import conferenceData from "@data/2025.json";
import { styled } from "styled-components";
import { BIG_BREAKPOINT } from "@constants/BreakPoints";
diff --git a/src/views/sponsorship/Sponsorship.tsx b/src/views/sponsorship/Sponsorship.tsx
index 18b0bc852..4c3bb8411 100644
--- a/src/views/sponsorship/Sponsorship.tsx
+++ b/src/views/sponsorship/Sponsorship.tsx
@@ -11,7 +11,6 @@ import {
StyledSpeakersSection,
} from "../Speakers/Speakers.style";
import { StyledMarginBottom } from "../Talks/Talks.style";
-import data from "@data/2025.json";
import { format } from "date-fns";
import Flicking from "@egjs/react-flicking";
import { AutoPlay } from "@egjs/flicking-plugins";
@@ -21,6 +20,18 @@ import { gaEventTracker } from "@components/analytics/Analytics";
import { useDocumentTitleUpdater } from "@hooks/useDocumentTitleUpdate";
// @ts-expect-error some quirky import
import { AnimatePresence, motion } from "framer-motion";
+import { useParams } from "react-router";
+import data2023 from "@data/2023.json";
+import data2024 from "@data/2024.json";
+import data2025 from "@data/2025.json";
+import data2026 from "@data/2026.json";
+
+const editions: Record = {
+ "2023": data2023,
+ "2024": data2024,
+ "2025": data2025,
+ "2026": data2026,
+};
const StyledWaveContainer = styled.div`
background: ${Color.DARK_BLUE};
@@ -92,6 +103,9 @@ const StyleMoreIcon = styled.img`
`;
const Sponsorship: FC> = () => {
+ const { id } = useParams<{ id: string }>();
+ const edition = id || "2026";
+ const data = editions[edition] || editions["2026"];
const { width } = useWindowSize();
const plugins = [
new AutoPlay({ duration: 2000, direction: "NEXT", stopOnHover: false }),
@@ -137,7 +151,7 @@ const Sponsorship: FC> = () => {
subtitle={`The DevBcn is the yearly event organised by Conferencia DevBcn S.L. Conference Talks will held on ${format(
new Date(data.startDay),
"MMMM do, yyyy",
- )} at La Farga, Hospitalet de Llobregat`}
+ )} at ${data.venue}`}
color={Color.DARK_BLUE}
/>
@@ -275,7 +289,7 @@ const Sponsorship: FC> = () => {
{format(new Date(data.startDay), "MMMM do")} —
{" ".concat(format(data.endDay, "do"))}
{" "}
- at the iconic La Farga, Hospitalet de Llobregat. This year,
+ at the iconic {data.venue}. This year,
we're diving deep into the realms of Java, JVM, Cloud,
DevOps, Frontend technologies, Leadership strategies, and
groundbreaking advancements in Big Data and AI.
@@ -294,7 +308,7 @@ const Sponsorship: FC> = () => {
than ever. Curious? Access our{" "}
@@ -310,7 +324,7 @@ const Sponsorship: FC> = () => {
>
@@ -352,11 +366,11 @@ const Sponsorship: FC> = () => {
Let’s make DevBcn {data?.edition} an unforgettable experience
together! Stay updated and spread the excitement using{" "}
- #devbcn25.
+ #devbcn{data?.edition.substring(2)}.
@@ -373,7 +387,7 @@ const Sponsorship: FC> = () => {