From ebe84e27101a9f9dcb5dbf6ad6c594321ae9d052 Mon Sep 17 00:00:00 2001
From: Anyul Rivas
Date: Thu, 13 Mar 2025 18:06:51 +0100
Subject: [PATCH 01/16] test: test useFetchSpeaker
---
src/services/speakerAdapter.test.ts | 318 ++++++++++++++++++++++++++++
1 file changed, 318 insertions(+)
create mode 100644 src/services/speakerAdapter.test.ts
diff --git a/src/services/speakerAdapter.test.ts b/src/services/speakerAdapter.test.ts
new file mode 100644
index 000000000..35635b116
--- /dev/null
+++ b/src/services/speakerAdapter.test.ts
@@ -0,0 +1,318 @@
+import { IResponse, ISpeaker } from "../types/speakers";
+import { speakerAdapter } from "./speakerAdapter";
+
+describe("speakerAdapter", () => {
+ it("should correctly adapt a single response to a speaker", () => {
+ const response: IResponse[] = [
+ {
+ id: "1",
+ fullName: "John Doe",
+ profilePicture: "john.jpg",
+ tagLine: "Tech Enthusiast",
+ bio: "A passionate developer",
+ sessions: [
+ { id: 1, name: "Session 1" },
+ {
+ id: 2,
+ name: "Session 2",
+ },
+ ],
+ links: [
+ {
+ title: "",
+ linkType: "Twitter",
+ url: "https://twitter.com/johndoe",
+ },
+ {
+ title: "",
+ linkType: "LinkedIn",
+ url: "https://linkedin.com/in/johndoe",
+ },
+ ],
+ },
+ ];
+
+ const expectedSpeaker: ISpeaker[] = [
+ {
+ id: "1",
+ fullName: "John Doe",
+ speakerImage: "john.jpg",
+ tagLine: "Tech Enthusiast",
+ bio: "A passionate developer",
+ sessions: [
+ { id: 1, name: "Session 1" },
+ {
+ id: 2,
+ name: "Session 2",
+ },
+ ],
+ twitterUrl: {
+ linkType: "Twitter",
+ url: "https://twitter.com/johndoe",
+ title: "",
+ },
+ linkedInUrl: {
+ linkType: "LinkedIn",
+ url: "https://linkedin.com/in/johndoe",
+ title: "",
+ },
+ },
+ ];
+
+ const result = speakerAdapter(response);
+ expect(result).toEqual(expectedSpeaker);
+ });
+
+ it("should correctly adapt multiple responses to speakers", () => {
+ const response: IResponse[] = [
+ {
+ id: "1",
+ fullName: "John Doe",
+ profilePicture: "john.jpg",
+ tagLine: "Tech Enthusiast",
+ bio: "A passionate developer",
+ sessions: [
+ { id: 1, name: "Session 1" },
+ {
+ id: 2,
+ name: "Session 2",
+ },
+ ],
+ links: [
+ {
+ linkType: "Twitter",
+ url: "https://twitter.com/johndoe",
+ title: "",
+ },
+ {
+ linkType: "LinkedIn",
+ url: "https://linkedin.com/in/johndoe",
+ title: "",
+ },
+ ],
+ },
+ {
+ id: "2",
+ fullName: "Jane Smith",
+ profilePicture: "jane.jpg",
+ tagLine: "AI Expert",
+ bio: "Specialized in AI",
+ sessions: [{ id: 3, name: "Session 3" }],
+ links: [
+ {
+ linkType: "Twitter",
+ url: "https://twitter.com/janesmith",
+ title: "",
+ },
+ {
+ linkType: "LinkedIn",
+ url: "https://linkedin.com/in/janesmith",
+ title: "",
+ },
+ ],
+ },
+ ];
+
+ const expectedSpeakers: ISpeaker[] = [
+ {
+ id: "1",
+ fullName: "John Doe",
+ speakerImage: "john.jpg",
+ tagLine: "Tech Enthusiast",
+ bio: "A passionate developer",
+ sessions: [
+ { id: 1, name: "Session 1" },
+ {
+ id: 2,
+ name: "Session 2",
+ },
+ ],
+ twitterUrl: {
+ linkType: "Twitter",
+ url: "https://twitter.com/johndoe",
+ title: "",
+ },
+ linkedInUrl: {
+ linkType: "LinkedIn",
+ url: "https://linkedin.com/in/johndoe",
+ title: "",
+ },
+ },
+ {
+ id: "2",
+ fullName: "Jane Smith",
+ speakerImage: "jane.jpg",
+ tagLine: "AI Expert",
+ bio: "Specialized in AI",
+ sessions: [{ id: 3, name: "Session 3" }],
+ twitterUrl: {
+ linkType: "Twitter",
+ url: "https://twitter.com/janesmith",
+ title: "",
+ },
+ linkedInUrl: {
+ linkType: "LinkedIn",
+ url: "https://linkedin.com/in/janesmith",
+ title: "",
+ },
+ },
+ ];
+
+ const result = speakerAdapter(response);
+ expect(result).toEqual(expectedSpeakers);
+ });
+
+ it("should handle missing Twitter URL", () => {
+ const response: IResponse[] = [
+ {
+ id: "1",
+ fullName: "John Doe",
+ profilePicture: "john.jpg",
+ tagLine: "Tech Enthusiast",
+ bio: "A passionate developer",
+ sessions: [
+ { id: 1, name: "Session 1" },
+ {
+ id: 2,
+ name: "Session 2",
+ },
+ ],
+ links: [
+ {
+ linkType: "LinkedIn",
+ url: "https://linkedin.com/in/johndoe",
+ title: "",
+ },
+ ],
+ },
+ ];
+
+ const expectedSpeaker: ISpeaker[] = [
+ {
+ id: "1",
+ fullName: "John Doe",
+ speakerImage: "john.jpg",
+ tagLine: "Tech Enthusiast",
+ bio: "A passionate developer",
+ sessions: [
+ { id: 1, name: "Session 1" },
+ {
+ id: 2,
+ name: "Session 2",
+ },
+ ],
+ twitterUrl: undefined,
+ linkedInUrl: {
+ linkType: "LinkedIn",
+ url: "https://linkedin.com/in/johndoe",
+ title: "",
+ },
+ },
+ ];
+
+ const result = speakerAdapter(response);
+ expect(result).toEqual(expectedSpeaker);
+ });
+
+ it("should handle missing LinkedIn URL", () => {
+ const response: IResponse[] = [
+ {
+ id: "1",
+ fullName: "John Doe",
+ profilePicture: "john.jpg",
+ tagLine: "Tech Enthusiast",
+ bio: "A passionate developer",
+ sessions: [
+ { id: 1, name: "Session 1" },
+ {
+ id: 2,
+ name: "Session 2",
+ },
+ ],
+ links: [
+ {
+ linkType: "Twitter",
+ url: "https://twitter.com/johndoe",
+ title: "",
+ },
+ ],
+ },
+ ];
+
+ const expectedSpeaker: ISpeaker[] = [
+ {
+ id: "1",
+ fullName: "John Doe",
+ speakerImage: "john.jpg",
+ tagLine: "Tech Enthusiast",
+ bio: "A passionate developer",
+ sessions: [
+ { id: 1, name: "Session 1" },
+ {
+ id: 2,
+ name: "Session 2",
+ },
+ ],
+ twitterUrl: {
+ linkType: "Twitter",
+ url: "https://twitter.com/johndoe",
+ title: "",
+ },
+ linkedInUrl: undefined,
+ },
+ ];
+
+ const result = speakerAdapter(response);
+ expect(result).toEqual(expectedSpeaker);
+ });
+
+ it("should handle empty links array", () => {
+ const response: IResponse[] = [
+ {
+ id: "1",
+ fullName: "John Doe",
+ profilePicture: "john.jpg",
+ tagLine: "Tech Enthusiast",
+ bio: "A passionate developer",
+ sessions: [
+ { id: 1, name: "Session 1" },
+ {
+ id: 2,
+ name: "Session 2",
+ },
+ ],
+ links: [],
+ },
+ ];
+
+ const expectedSpeaker: ISpeaker[] = [
+ {
+ id: "1",
+ fullName: "John Doe",
+ speakerImage: "john.jpg",
+ tagLine: "Tech Enthusiast",
+ bio: "A passionate developer",
+ sessions: [
+ { id: 1, name: "Session 1" },
+ {
+ id: 2,
+ name: "Session 2",
+ },
+ ],
+ twitterUrl: undefined,
+ linkedInUrl: undefined,
+ },
+ ];
+
+ const result = speakerAdapter(response);
+ expect(result).toEqual(expectedSpeaker);
+ });
+
+ it("should handle an empty response array", () => {
+ const response: IResponse[] = [];
+ const expectedSpeaker: ISpeaker[] = [];
+
+ const result = speakerAdapter(response);
+ expect(result).toEqual(expectedSpeaker);
+ });
+});
From 0b3575a8567204d0c7a81e003084d38fb4b96b42 Mon Sep 17 00:00:00 2001
From: Anyul Rivas
Date: Thu, 13 Mar 2025 18:07:08 +0100
Subject: [PATCH 02/16] feat: parameterize url
---
src/data/2023.json | 1 +
src/data/2024.json | 1 +
src/data/2025.json | 1 +
3 files changed, 3 insertions(+)
diff --git a/src/data/2023.json b/src/data/2023.json
index b14898e15..725b45b36 100644
--- a/src/data/2023.json
+++ b/src/data/2023.json
@@ -24,6 +24,7 @@
"schedule": {
"enabled": true
},
+ "sessionizeUrl": "https://sessionize.com/api/v2/ttsitynd",
"showCountdown": false,
"showInfoButtons": true,
"sponsors": {
diff --git a/src/data/2024.json b/src/data/2024.json
index 27d3517c5..7efeeab51 100644
--- a/src/data/2024.json
+++ b/src/data/2024.json
@@ -24,6 +24,7 @@
"schedule": {
"enabled": true
},
+ "sessionizeUrl": "https://sessionize.com/api/v2/teq4asez",
"showCountdown": false,
"showInfoButtons": true,
"sponsors": {
diff --git a/src/data/2025.json b/src/data/2025.json
index 4e3d1f17f..02e7382d8 100644
--- a/src/data/2025.json
+++ b/src/data/2025.json
@@ -24,6 +24,7 @@
"schedule": {
"enabled": false
},
+ "sessionizeUrl": "https://sessionize.com/api/v2/xhudniix",
"showCountdown": true,
"showInfoButtons": false,
"sponsors": {
From 017ac8ed94624c14193ab59df1c6301558555751 Mon Sep 17 00:00:00 2001
From: Anyul Rivas
Date: Sat, 15 Mar 2025 05:48:14 +0100
Subject: [PATCH 03/16] test: mock API calls
---
src/App.test.tsx | 69 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
diff --git a/src/App.test.tsx b/src/App.test.tsx
index 2da1c4718..b5bd20319 100644
--- a/src/App.test.tsx
+++ b/src/App.test.tsx
@@ -3,8 +3,77 @@ import { BrowserRouter, Route, Routes } from "react-router";
import App from "./App";
import React from "react";
import userEvent from "@testing-library/user-event";
+import { IResponse } from "./types/speakers";
+import axios, { AxiosHeaders, AxiosResponse } from "axios";
+
+jest.mock("axios");
+const mockedAxios = axios as jest.Mocked;
+const axiosHeaders = new AxiosHeaders();
+const payload: AxiosResponse = {
+ status: 200,
+ statusText: "OK",
+ headers: {},
+ config: {
+ headers: axiosHeaders,
+ },
+ data: [
+ {
+ id: "1",
+ fullName: "John Smith",
+ profilePicture: "https://example.com/john.jpg",
+ tagLine: "Software engineer",
+ bio: "I am a software engineer",
+ sessions: [
+ {
+ id: 4567,
+ name: "sample session",
+ },
+ ],
+ links: [
+ {
+ linkType: "Twitter",
+ url: "https://twitter.com/johnsmith",
+ title: "",
+ },
+ {
+ linkType: "LinkedIn",
+ url: "https://linkedin.com/in/johnsmith",
+ title: "",
+ },
+ ],
+ },
+ {
+ id: "2",
+ fullName: "Jane Doe",
+ profilePicture: "https://example.com/jane.jpg",
+ tagLine: "Data scientist",
+ bio: "I am a data scientist",
+ sessions: [],
+ links: [
+ {
+ linkType: "Twitter",
+ url: "https://twitter.com/janedoe",
+ title: "",
+ },
+ {
+ linkType: "LinkedIn",
+ url: "https://linkedin.com/in/janedoe",
+ title: "",
+ },
+ ],
+ },
+ ],
+};
describe("navigation pages", () => {
+ beforeAll(() => {
+ jest.mock("axios");
+ mockedAxios.get.mockImplementation(() => Promise.resolve(payload));
+ });
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
test("it render the HOME page", async () => {
render(
Loading...}>
From fa771705aa63bd75b8d30ba123a285155680028c Mon Sep 17 00:00:00 2001
From: Anyul Rivas
Date: Tue, 18 Mar 2025 15:18:19 +0100
Subject: [PATCH 04/16] fix: fix 2024 diversity route
---
src/2023/Cfp/CfpSection2023.test.tsx | 2 +-
src/2023/Cfp/CfpSection2023.tsx | 6 +-
src/2023/Communities/Communities2023.tsx | 5 +-
src/2023/Diversity/Diversity2023.tsx | 7 +-
src/2023/Home/Home2023Wrapper.tsx | 4 +-
src/2023/JobOffers/JobOffers2023.tsx | 5 +-
src/2023/Schedule/Schedule2023.tsx | 5 +-
.../SessionFeedback/SessionFeedback2023.tsx | 5 +-
src/2023/TalkDetail/TalkDetail.tsx | 11 +-
src/2024/Cfp/CfpSection.test.tsx | 2 +-
src/2024/Cfp/CfpSection2024.tsx | 55 +-
src/2024/HomeWrapper2024.tsx | 60 +-
src/2024/SpeakerDetail/SpeakerDetail.tsx | 292 +++++----
src/2024/TalkDetail/MeetingDetail.tsx | 498 +++++++--------
.../NotFoundError/NotFoundError.tsx | 11 +-
src/services/useDocumentTitleUpdate.ts | 7 +
src/services/useSentryErrorReport.ts | 7 +
src/views/About/About.tsx | 5 +-
src/views/Attendee/AttendeeInformation.tsx | 7 +-
src/views/Cfp/CfpSection.test.tsx | 2 +-
src/views/Cfp/CfpSection.tsx | 64 +-
src/views/CodeOfConduct/CodeOfConduct.tsx | 7 +-
src/views/Communities/Communities.tsx | 6 +-
src/views/Conditions/Conditions.tsx | 50 +-
src/views/Diversity/Diversity.tsx | 7 +-
src/views/Home/HomeWrapper.tsx | 4 +-
src/views/JobOffers/JobOffers.tsx | 5 +-
src/views/MeetingDetail/MeetingDetail.tsx | 11 +-
src/views/Schedule/Schedule.tsx | 5 +-
src/views/SessionFeedback/SessionFeedback.tsx | 5 +-
src/views/Travel/Travel.tsx | 54 +-
src/views/kcd/Kcd.tsx | 13 +-
src/views/sponsorship/Sponsorship.tsx | 600 +++++++++---------
33 files changed, 911 insertions(+), 916 deletions(-)
create mode 100644 src/services/useDocumentTitleUpdate.ts
create mode 100644 src/services/useSentryErrorReport.ts
diff --git a/src/2023/Cfp/CfpSection2023.test.tsx b/src/2023/Cfp/CfpSection2023.test.tsx
index e8bacfd8e..67e989bed 100644
--- a/src/2023/Cfp/CfpSection2023.test.tsx
+++ b/src/2023/Cfp/CfpSection2023.test.tsx
@@ -98,7 +98,7 @@ describe("CfpSection2023", () => {
render( );
await waitFor(() => {
expect(document.title).toBe(
- `CFP Committee - DevBcn - ${conferenceData.edition}`,
+ `CFP Committee — DevBcn - Barcelona Developers Conference — ${conferenceData.edition}`,
);
});
});
diff --git a/src/2023/Cfp/CfpSection2023.tsx b/src/2023/Cfp/CfpSection2023.tsx
index c03e02a41..94558ccbd 100644
--- a/src/2023/Cfp/CfpSection2023.tsx
+++ b/src/2023/Cfp/CfpSection2023.tsx
@@ -21,6 +21,7 @@ import {
StyledAboutImage,
StyledSocialIconsWrapper,
} from "../../views/About/components/Style.AboutCard";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const TrackName = styled.h2`
padding-top: 1.2rem;
@@ -75,9 +76,8 @@ const CfpTrackComponent: FC> = ({
const CfpSection2023: FC> = () => {
const { width } = useWindowSize();
- React.useEffect(() => {
- document.title = `CFP Committee - DevBcn - ${conferenceData.edition}`;
- }, []);
+
+ useDocumentTitleUpdater("CFP Committee", conferenceData.edition);
return (
<>
diff --git a/src/2023/Communities/Communities2023.tsx b/src/2023/Communities/Communities2023.tsx
index 301429a78..53a349199 100644
--- a/src/2023/Communities/Communities2023.tsx
+++ b/src/2023/Communities/Communities2023.tsx
@@ -3,6 +3,7 @@ import styled from "styled-components";
import TwitterIcon from "../../components/Icons/Twitter";
import { Color } from "../../styles/colors";
import WebsiteIcon from "../../components/Icons/website";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const Heading = styled.h1`
padding-top: 10rem;
@@ -29,9 +30,7 @@ const FoSS = styled.div`
`;
const Communities2023: FC> = () => {
- React.useEffect(() => {
- document.title = "Communities";
- });
+ useDocumentTitleUpdater("Communities", "2023");
return (
<>
FOSS & Diversity Communities
diff --git a/src/2023/Diversity/Diversity2023.tsx b/src/2023/Diversity/Diversity2023.tsx
index abe51093c..06f8a9d38 100644
--- a/src/2023/Diversity/Diversity2023.tsx
+++ b/src/2023/Diversity/Diversity2023.tsx
@@ -1,4 +1,4 @@
-import { FC, useEffect } from "react";
+import { FC } from "react";
import { Color } from "../../styles/colors";
import data from "../../data/2023.json";
import styled from "styled-components";
@@ -8,6 +8,7 @@ import {
ROUTE_CODE_OF_CONDUCT,
ROUTE_CONDITIONS,
} from "../../constants/routes";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const StyledSection = styled.section`
{
@@ -96,9 +97,7 @@ const StyledParagraph = styled.section`
}
`;
const Diversity2023: FC> = () => {
- useEffect(() => {
- document.title = `Diversity - DevBcn ${data.edition}`;
- });
+ useDocumentTitleUpdater("Diversity", data.edition);
return (
diff --git a/src/2023/Home/Home2023Wrapper.tsx b/src/2023/Home/Home2023Wrapper.tsx
index a7a77d7c3..cc45e91fd 100644
--- a/src/2023/Home/Home2023Wrapper.tsx
+++ b/src/2023/Home/Home2023Wrapper.tsx
@@ -7,6 +7,7 @@ import Sponsors from "./components/Sponsors/Sponsors";
import styled from "styled-components";
import data from "../../data/2023.json";
import { useLocation } from "react-router";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const StyledContainer = styled.div`
padding-bottom: 10rem;
@@ -20,12 +21,13 @@ export const Home2023Wrapper: FC> = () => {
const { hash } = useLocation();
React.useEffect(() => {
- document.title = `Home - DevBcn - ${data.edition}`;
if (hash != null && hash !== "") {
const scroll = document.getElementById(hash.substring(1));
scroll?.scrollIntoView();
}
}, [hash]);
+
+ useDocumentTitleUpdater("Home", data.edition);
return (
diff --git a/src/2023/JobOffers/JobOffers2023.tsx b/src/2023/JobOffers/JobOffers2023.tsx
index cb1696447..b166d8dd7 100644
--- a/src/2023/JobOffers/JobOffers2023.tsx
+++ b/src/2023/JobOffers/JobOffers2023.tsx
@@ -14,6 +14,7 @@ import {
StyledTitleContainer
} from "../../styles/JobOffers/JobOffers.Style";
import CompanyOffers from "../../components/JobOffers/CompanyOffers";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const NoOffersAvailable = () => (
No job offers available yet
@@ -29,9 +30,7 @@ const MoreThanLessThan = (props: { width: number }) => (
const JobOffers2023: FC> = () => {
const { width } = useWindowSize();
- React.useEffect(() => {
- document.title = `Job Offers - DevBcn - ${data.edition}`;
- }, []);
+ useDocumentTitleUpdater("Job Offers", data.edition);
return (
diff --git a/src/2023/Schedule/Schedule2023.tsx b/src/2023/Schedule/Schedule2023.tsx
index 81f437d87..792d08335 100644
--- a/src/2023/Schedule/Schedule2023.tsx
+++ b/src/2023/Schedule/Schedule2023.tsx
@@ -13,13 +13,14 @@ import {
StyledScheduleSection,
} from "../../styles/Schedule/Schedule.style";
import * as Sentry from "@sentry/react";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const Schedule2023: FC> = () => {
const { width } = useWindowSize();
- React.useEffect(() => {
- document.title = `Schedule - DevBcn - ${data.edition}`;
+ useDocumentTitleUpdater("Schedule", data.edition);
+ React.useEffect(() => {
fetch("https://sessionize.com/api/v2/a2sw0wks/view/GridSmart")
.then((value) => value.text())
.then((value) => {
diff --git a/src/2023/SessionFeedback/SessionFeedback2023.tsx b/src/2023/SessionFeedback/SessionFeedback2023.tsx
index d40132e4d..2e2aa1a38 100644
--- a/src/2023/SessionFeedback/SessionFeedback2023.tsx
+++ b/src/2023/SessionFeedback/SessionFeedback2023.tsx
@@ -15,6 +15,7 @@ import { FilterMatchMode } from "primereact/api";
import { Color } from "../../styles/colors";
import { Link } from "react-router";
import { ROUTE_TALK_DETAIL } from "../../constants/routes";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const SessionFeedback2023: FC> = () => {
const bodyTemplate = React.useCallback(
@@ -65,9 +66,7 @@ const SessionFeedback2023: FC> = () => {
);
- React.useEffect(() => {
- document.title = "DevBcn 2023 - Session Feedback";
- });
+ useDocumentTitleUpdater("Session Feedback", "2023");
const header = renderHeader();
diff --git a/src/2023/TalkDetail/TalkDetail.tsx b/src/2023/TalkDetail/TalkDetail.tsx
index e8ec2f5dd..a52e14a75 100644
--- a/src/2023/TalkDetail/TalkDetail.tsx
+++ b/src/2023/TalkDetail/TalkDetail.tsx
@@ -4,7 +4,7 @@ import {
MOBILE_BREAKPOINT,
} from "../../constants/BreakPoints";
import {Color} from "../../styles/colors";
-import React, {FC, Suspense, useEffect} from "react";
+import React, { FC, Suspense } from "react";
import LessThanIconWhite from "../../assets/images/LessThanIconWhite.svg";
import LessThanIcon from "../../assets/images/LessThanBlueIcon.svg";
import MoreThanIcon from "../../assets/images/MoreThanBlueIcon.svg";
@@ -33,8 +33,9 @@ import {
ROUTE_2023_TALKS,
} from "../../constants/routes";
import conferenceData from "../../data/2023.json";
-import {Tag} from "../../components/Tag/Tag";
-import {IMeetingDetailProps, MyType} from "../../types/sessions";
+import { Tag } from "../../components/Tag/Tag";
+import { IMeetingDetailProps, MyType } from "../../types/sessions";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const getVideoHeight = (windowWidth: number) => {
let videoHeight;
@@ -102,9 +103,7 @@ const TalkDetail: FC> = ({
}) => {
const { width } = useWindowSize();
- useEffect(() => {
- document.title = `${meeting.title} - DevBcn ${conferenceData.edition}`;
- }, [meeting.title]);
+ useDocumentTitleUpdater(meeting.title, conferenceData.edition);
const finalMeetingInfo: MyType = {
...meeting,
diff --git a/src/2024/Cfp/CfpSection.test.tsx b/src/2024/Cfp/CfpSection.test.tsx
index 43f2ea263..a97bcce1e 100644
--- a/src/2024/Cfp/CfpSection.test.tsx
+++ b/src/2024/Cfp/CfpSection.test.tsx
@@ -9,7 +9,7 @@ describe("CfpSection", () => {
it("sets document title on mount", () => {
render( );
expect(document.title).toBe(
- `CFP Committee — ${conferenceData.title}— ${conferenceData.edition}`,
+ `CFP Committee — DevBcn - Barcelona Developers Conference — ${conferenceData.edition}`,
);
});
diff --git a/src/2024/Cfp/CfpSection2024.tsx b/src/2024/Cfp/CfpSection2024.tsx
index 2740852e4..e20dba775 100644
--- a/src/2024/Cfp/CfpSection2024.tsx
+++ b/src/2024/Cfp/CfpSection2024.tsx
@@ -18,9 +18,10 @@ import conferenceData from "../../data/2024.json";
import { CfpTrackProps, data } from "./CfpData";
import { MemberName, TrackName } from "./Cfp.style";
import {
- StyledAboutImage,
- StyledSocialIconsWrapper
+ StyledAboutImage,
+ StyledSocialIconsWrapper,
} from "../../views/About/components/Style.AboutCard";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
export const CfpTrackComponent: FC> = ({
track,
@@ -62,35 +63,33 @@ export const CfpTrackComponent: FC> = ({
const CfpSection2024: FC> = () => {
const { width } = useWindowSize();
- React.useEffect(() => {
- document.title = `CFP Committee — ${conferenceData.title} — ${conferenceData.edition}`;
- }, []);
- return (
- <>
-
-
-
+
+
+
- {width > MOBILE_BREAKPOINT && (
- <>
-
-
- >
- )}
-
- {data.map((track) => (
-
- ))}
-
-
- >
- );
+ color={Color.BLUE}
+ />
+ {width > MOBILE_BREAKPOINT && (
+ <>
+
+
+ >
+ )}
+
+ {data.map((track) => (
+
+ ))}
+
+
+ >
+ );
};
export default CfpSection2024;
diff --git a/src/2024/HomeWrapper2024.tsx b/src/2024/HomeWrapper2024.tsx
index 5668c53f4..79ef08891 100644
--- a/src/2024/HomeWrapper2024.tsx
+++ b/src/2024/HomeWrapper2024.tsx
@@ -1,45 +1,47 @@
-import React, {FC, useState} from "react";
+import React, { FC, useState } from "react";
import styled from "styled-components";
-import {useLocation} from "react-router";
-import {BIG_BREAKPOINT} from "../constants/BreakPoints";
+import { useLocation } from "react-router";
+import { BIG_BREAKPOINT } from "../constants/BreakPoints";
-import {useEventEdition} from "../views/Home/UseEventEdition";
+import { useEventEdition } from "../views/Home/UseEventEdition";
import Faqs from "../views/Home/components/Faqs/Faqs";
import Home from "./Home/Home";
import SpeakersCarousel from "./SpeakersCarousel/SpeakersCarousel";
import Sponsors from "./Sponsors/Sponsors";
-import {Edition} from "../types/types";
+import { Edition } from "../types/types";
+import { useDocumentTitleUpdater } from "../services/useDocumentTitleUpdate";
const StyledContainer = styled.div`
- padding-bottom: 10rem;
+ padding-bottom: 10rem;
- @media only screen and (max-width: ${BIG_BREAKPOINT}px) {
- padding-bottom: 20rem;
- }
+ @media only screen and (max-width: ${BIG_BREAKPOINT}px) {
+ padding-bottom: 20rem;
+ }
`;
export const HomeWrapper2024: FC> = () => {
- const {hash} = useLocation();
- const [edition, setEdition] = useState();
-
- useEventEdition(setEdition);
- React.useEffect(() => {
- document.title = `Home - ${edition?.title} - ${edition?.edition}`;
- if (hash != null && hash !== "") {
- const scroll = document.getElementById(hash.substring(1));
- scroll?.scrollIntoView();
- }
- }, [hash, edition]);
-
- return (
-
-
-
-
-
-
- );
+ const { hash } = useLocation();
+ const [edition, setEdition] = useState();
+
+ useEventEdition(setEdition);
+ React.useEffect(() => {
+ if (hash != null && hash !== "") {
+ const scroll = document.getElementById(hash.substring(1));
+ scroll?.scrollIntoView();
+ }
+ }, [hash, edition]);
+
+ useDocumentTitleUpdater("Home", edition?.edition ?? "2024");
+
+ return (
+
+
+
+
+
+
+ );
};
diff --git a/src/2024/SpeakerDetail/SpeakerDetail.tsx b/src/2024/SpeakerDetail/SpeakerDetail.tsx
index eabc6c613..1b655449a 100644
--- a/src/2024/SpeakerDetail/SpeakerDetail.tsx
+++ b/src/2024/SpeakerDetail/SpeakerDetail.tsx
@@ -1,172 +1,164 @@
-import {BIG_BREAKPOINT} from "../../constants/BreakPoints";
+import { BIG_BREAKPOINT } from "../../constants/BreakPoints";
-import {FC, Suspense, useEffect} from "react";
+import { FC, Suspense } from "react";
import MoreThanIcon from "../../assets/images/MoreThanBlueIcon.svg";
import LessThan from "../../assets/images/MoreThanIcon.svg";
import SlashesWhite from "../../assets/images/SlashesWhite.svg";
import linkedinIcon from "../../assets/images/linkedinIcon.svg";
import twitterIcon from "../../assets/images/twitterIcon.svg";
-import {useWindowSize} from "react-use";
+import { useWindowSize } from "react-use";
-import {ROUTE_SPEAKERS, ROUTE_TALK_DETAIL} from "../../constants/routes";
-import {Link} from "react-router";
-import {Color} from "../../styles/colors";
+import { ROUTE_SPEAKERS, ROUTE_TALK_DETAIL } from "../../constants/routes";
+import { Link } from "react-router";
+import { Color } from "../../styles/colors";
import conferenceData from "../../data/2024.json";
import {
- StyledDetailsContainer,
- StyledFlexCol,
- StyledImageContainer,
- StyledInfoContainer,
- StyledLink,
- StyledMoreThanIcon,
- StyledMoreThanIconContainer,
- StyledName,
- StyledNameContainer,
- StyledRightContainer,
- StyledSlashes,
- StyledSocialMediaContainer,
- StyledSocialMediaIcon,
- StyledSpeakerDescription,
- StyledSpeakerDetailContainer,
- StyledSpeakerImg,
- StyledSpeakerTitle
+ StyledDetailsContainer,
+ StyledFlexCol,
+ StyledImageContainer,
+ StyledInfoContainer,
+ StyledLink,
+ StyledMoreThanIcon,
+ StyledMoreThanIconContainer,
+ StyledName,
+ StyledNameContainer,
+ StyledRightContainer,
+ StyledSlashes,
+ StyledSocialMediaContainer,
+ StyledSocialMediaIcon,
+ StyledSpeakerDescription,
+ StyledSpeakerDetailContainer,
+ StyledSpeakerImg,
+ StyledSpeakerTitle,
} from "../../views/SpeakerDetail/Speaker.style";
-import {
- StyledTalkDescription
-} from "../../views/SpeakerDetail/SpeakerDetail.style";
-import {ISpeaker} from "../../types/speakers";
+import { StyledTalkDescription } from "../../views/SpeakerDetail/SpeakerDetail.style";
+import { ISpeaker } from "../../types/speakers";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
interface ISpeakerDetailProps {
- speaker: ISpeaker;
+ speaker: ISpeaker;
}
-const SpeakerDetail: FC> = ({speaker}) => {
- const {width} = useWindowSize();
+const SpeakerDetail: FC> = ({
+ speaker,
+}) => {
+ const { width } = useWindowSize();
- useEffect(() => {
- document.title = `${speaker.fullName} — ${conferenceData.title} — ${conferenceData.edition}`;
- }, [speaker.fullName]);
+ useDocumentTitleUpdater(speaker.fullName, conferenceData.edition);
- const hasSessions = (): boolean =>
- (speaker.sessions && speaker.sessions.length > 0) || false;
+ const hasSessions = (): boolean =>
+ (speaker.sessions && speaker.sessions.length > 0) || false;
- return (
-
-
- {width > BIG_BREAKPOINT && (
-
- loading
}>
-
-
-
- {speaker.twitterUrl && (
-
-
-
- )}
- {speaker.linkedInUrl && (
-
-
-
- )}
-
-
- )}
-
-
- {speaker.fullName}
- {width < BIG_BREAKPOINT && (
- <>
- loading}>
-
-
-
- {speaker.twitterUrl && (
-
-
-
- )}
- {speaker.linkedInUrl && (
-
-
-
- )}
-
- >
- )}
-
-
-
-
- {speaker.tagLine}
- {speaker.bio}
+ return (
+
+
+ {width > BIG_BREAKPOINT && (
+
+ loading}>
+
+
+
+ {speaker.twitterUrl && (
+
+
+
+ )}
+ {speaker.linkedInUrl && (
+
+
+
+ )}
+
+
+ )}
+
+
+ {speaker.fullName}
+ {width < BIG_BREAKPOINT && (
+ <>
+ loading}>
+
+
+
+ {speaker.twitterUrl && (
+
+
+
+ )}
+ {speaker.linkedInUrl && (
+
+
+
+ )}
+
+ >
+ )}
+
+
+
+
+ {speaker.tagLine}
+ {speaker.bio}
- {hasSessions() && (
- <>
- Sessions
-
- {speaker?.sessions?.map((session) => (
-
-
-
-
- {session.name}
-
-
-
- ))}
-
- >
- )}
+ {hasSessions() && (
+ <>
+ Sessions
+
+ {speaker?.sessions?.map((session) => (
+
+
+
+
+ {session.name}
+
+
+
+ ))}
+
+ >
+ )}
-
- Go back
-
-
-
-
-
-
-
-
-
- );
+
+ Go back
+
+
+
+
+
+
+
+
+
+ );
};
export default SpeakerDetail;
diff --git a/src/2024/TalkDetail/MeetingDetail.tsx b/src/2024/TalkDetail/MeetingDetail.tsx
index 163e0ab5c..4be336846 100644
--- a/src/2024/TalkDetail/MeetingDetail.tsx
+++ b/src/2024/TalkDetail/MeetingDetail.tsx
@@ -1,301 +1,301 @@
import {
- BIG_BREAKPOINT,
- LARGE_BREAKPOINT,
- MOBILE_BREAKPOINT,
+ BIG_BREAKPOINT,
+ LARGE_BREAKPOINT,
+ MOBILE_BREAKPOINT,
} from "../../constants/BreakPoints";
-import {Color} from "../../styles/colors";
-import React, {FC, Suspense, useEffect} from "react";
+import { Color } from "../../styles/colors";
+import React, { FC, Suspense } from "react";
import LessThanIconWhite from "../../assets/images/LessThanIconWhite.svg";
import LessThanIcon from "../../assets/images/LessThanBlueIcon.svg";
import MoreThanIcon from "../../assets/images/MoreThanBlueIcon.svg";
import SectionWrapper from "../../components/SectionWrapper/SectionWrapper";
-import {useWindowSize} from "react-use";
+import { useWindowSize } from "react-use";
-import {Link} from "react-router";
+import { Link } from "react-router";
import {
- ROUTE_2024_SPEAKER_DETAIL,
- ROUTE_2024_TALKS,
+ ROUTE_2024_SPEAKER_DETAIL,
+ ROUTE_2024_TALKS,
} from "../../constants/routes";
import conferenceData from "../../data/2024.json";
-import {Tag} from "../../components/Tag/Tag";
+import { Tag } from "../../components/Tag/Tag";
import styled from "styled-components";
-import {AddToCalendarButton} from "add-to-calendar-button-react";
+import { AddToCalendarButton } from "add-to-calendar-button-react";
import {
- StyledContainer,
- StyledDetailsContainer,
- StyledFlexCol,
- StyledName,
- StyledNameContainer,
- StyledRightContainer,
- StyledSpeakerDetailContainer
+ StyledContainer,
+ StyledDetailsContainer,
+ StyledFlexCol,
+ StyledName,
+ StyledNameContainer,
+ StyledRightContainer,
+ StyledSpeakerDetailContainer,
} from "../../views/SpeakerDetail/Speaker.style";
import {
- StyledDescription,
- StyledExtraInfo,
- StyledLessThan,
- StyledMeetingTitleContainer,
- StyledTitleImg,
- StyledVideoContainer,
- StyledVideoTagsContainer
+ StyledDescription,
+ StyledExtraInfo,
+ StyledLessThan,
+ StyledMeetingTitleContainer,
+ StyledTitleImg,
+ StyledVideoContainer,
+ StyledVideoTagsContainer,
} from "../../views/MeetingDetail/Style.MeetingDetail";
-import {StyledTitle} from "../Home/Style.Home";
-import {ISpeaker} from "../../types/speakers";
-import {IMeeting} from "../../types/sessions";
+import { StyledTitle } from "../Home/Style.Home";
+import { ISpeaker } from "../../types/speakers";
+import { IMeeting } from "../../types/sessions";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const getVideoHeight = (windowWidth: number) => {
- let videoHeight;
- if (windowWidth < MOBILE_BREAKPOINT) {
- videoHeight = 250;
- } else if (windowWidth >= MOBILE_BREAKPOINT && windowWidth < BIG_BREAKPOINT) {
- videoHeight = 300;
- } else if (windowWidth >= BIG_BREAKPOINT && windowWidth < LARGE_BREAKPOINT) {
- videoHeight = 450;
- } else {
- videoHeight = 600;
- }
+ let videoHeight;
+ if (windowWidth < MOBILE_BREAKPOINT) {
+ videoHeight = 250;
+ } else if (windowWidth >= MOBILE_BREAKPOINT && windowWidth < BIG_BREAKPOINT) {
+ videoHeight = 300;
+ } else if (windowWidth >= BIG_BREAKPOINT && windowWidth < LARGE_BREAKPOINT) {
+ videoHeight = 450;
+ } else {
+ videoHeight = 600;
+ }
- return videoHeight.toString();
+ return videoHeight.toString();
};
const leftVariants = {
- initial: {
- x: -100,
- opacity: 0,
- },
- animate: {
- x: 0,
- opacity: 1,
- },
+ initial: {
+ x: -100,
+ opacity: 0,
+ },
+ animate: {
+ x: 0,
+ opacity: 1,
+ },
};
const rightVariants = {
- initial: {
- x: 100,
- opacity: 0,
- },
- animate: {
- x: 0,
- opacity: 1,
- },
+ initial: {
+ x: 100,
+ opacity: 0,
+ },
+ animate: {
+ x: 0,
+ opacity: 1,
+ },
};
const downVariants = {
- initial: {
- y: 100,
- opacity: 0,
- },
- animate: {
- y: 0,
- opacity: 1,
- },
+ initial: {
+ y: 100,
+ opacity: 0,
+ },
+ animate: {
+ y: 0,
+ opacity: 1,
+ },
};
const opacityVariants = {
- initial: {
- opacity: 0,
- },
- animate: {
- opacity: 1,
- transition: {
- duration: 1,
- },
+ initial: {
+ opacity: 0,
+ },
+ animate: {
+ opacity: 1,
+ transition: {
+ duration: 1,
},
+ },
};
export const StyledVoteTalkLink = styled.a`
- text-decoration: none;
- color: ${Color.BLACK_BLUE};
- font-size: 0.8rem;
+ text-decoration: none;
+ color: ${Color.BLACK_BLUE};
+ font-size: 0.8rem;
`;
interface IMeetingDetailProps {
- meeting: IMeeting;
- speakers?: ISpeaker[];
+ meeting: IMeeting;
+ speakers?: ISpeaker[];
}
type MyType = {
- urlName?: string;
- videoUrl?: string;
- level?: string;
- videoTags?: string[];
- speakers?: ISpeaker[];
- description: string;
- language?: string;
- title: string;
- type?: string;
- track?: string;
+ urlName?: string;
+ videoUrl?: string;
+ level?: string;
+ videoTags?: string[];
+ speakers?: ISpeaker[];
+ description: string;
+ language?: string;
+ title: string;
+ type?: string;
+ track?: string;
};
const MeetingDetail: FC> = ({
- meeting,
- speakers: mySpeakers,
- }) => {
- const {width} = useWindowSize();
+ meeting,
+ speakers: mySpeakers,
+}) => {
+ const { width } = useWindowSize();
- useEffect(() => {
- document.title = `${meeting.title} — ${conferenceData.title} — ${conferenceData.edition}`;
- }, [meeting.title]);
+ useDocumentTitleUpdater(meeting.title, conferenceData.edition);
- const finalMeetingInfo: MyType = {
- ...meeting,
- speakers: mySpeakers,
- };
+ const finalMeetingInfo: MyType = {
+ ...meeting,
+ speakers: mySpeakers,
+ };
- return (
-
-
-
-
-
- / {meeting.title}
- Description
- {meeting.description}
-
- {`${meeting.type} ${meeting.level}`}
- Track:
- {meeting.track}
+ return (
+
+
+
+
+
+ / {meeting.title}
+ Description
+ {meeting.description}
+
+ {`${meeting.type} ${meeting.level}`}
+ Track:
+ {meeting.track}
- {meeting.slidesURL !== "" && (
-
-
-
-
-
- {" "}
- Slides
-
-
- )}
-
-
-
-
-
- {meeting.videoUrl && (
-
- )}
-
- {meeting.videoTags?.map((tag) => )}
-
-
-
- 🗳️ Vote this talk
-
-
-
-
-
-
-
-
- {finalMeetingInfo.speakers?.map((speaker) => (
-
- loading}>
-
-
-
-
- {speaker.fullName}
-
-
-
- ))}
-
-
-
-
-
-
+
- Go back
- {" "}
-
-
-
- );
+
+ {" "}
+ Slides
+
+
+ )}
+
+
+
+
+
+ {meeting.videoUrl && (
+
+ )}
+
+ {meeting.videoTags?.map((tag) => )}
+
+
+
+ 🗳️ Vote this talk
+
+
+
+
+
+
+
+
+ {finalMeetingInfo.speakers?.map((speaker) => (
+
+ loading}>
+
+
+
+
+ {speaker.fullName}
+
+
+
+ ))}
+
+
+
+
+
+
+ Go back
+ {" "}
+
+
+
+ );
};
export default MeetingDetail;
diff --git a/src/components/NotFoundError/NotFoundError.tsx b/src/components/NotFoundError/NotFoundError.tsx
index 72b76e2f3..32cf74be0 100644
--- a/src/components/NotFoundError/NotFoundError.tsx
+++ b/src/components/NotFoundError/NotFoundError.tsx
@@ -1,10 +1,11 @@
import { Color } from "../../styles/colors";
-import { FC, useEffect } from "react";
+import { FC } from "react";
import { Link } from "react-router";
import SectionWrapper from "../SectionWrapper/SectionWrapper";
import styled from "styled-components";
import ActionButtons from "../../views/Home/components/ActionButtons/ActionButtons";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const StyledContainer = styled.div`
display: flex;
@@ -34,10 +35,10 @@ interface INotFoundErrorProps {
message?: string;
}
-const NotFoundError: FC> = ({ message = "Page" }) => {
- useEffect(() => {
- document.title = "DevBcn - page not Found";
- });
+const NotFoundError: FC> = ({
+ message = "Page",
+}) => {
+ useDocumentTitleUpdater("Page not Found", "");
return (
diff --git a/src/services/useDocumentTitleUpdate.ts b/src/services/useDocumentTitleUpdate.ts
new file mode 100644
index 000000000..74f63ae72
--- /dev/null
+++ b/src/services/useDocumentTitleUpdate.ts
@@ -0,0 +1,7 @@
+import React from "react";
+
+export const useDocumentTitleUpdater = (title: string, year: string) => {
+ React.useEffect(() => {
+ document.title = `${title} — DevBcn - Barcelona Developers Conference — ${year}`;
+ }, [title, year]);
+};
diff --git a/src/services/useSentryErrorReport.ts b/src/services/useSentryErrorReport.ts
new file mode 100644
index 000000000..e44b641f6
--- /dev/null
+++ b/src/services/useSentryErrorReport.ts
@@ -0,0 +1,7 @@
+import * as Sentry from "@sentry/react";
+
+export const useSentryErrorReport = (error: unknown) => {
+ if (error instanceof Error) {
+ Sentry.captureException(error);
+ }
+};
diff --git a/src/views/About/About.tsx b/src/views/About/About.tsx
index 1196ae850..dad94c652 100644
--- a/src/views/About/About.tsx
+++ b/src/views/About/About.tsx
@@ -16,6 +16,7 @@ import {
} from "../Speakers/Speakers.style";
import { StyledMarginBottom } from "../Talks/Talks.style";
import data from "../../data/2024.json";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const StyledUsersWrapper = styled.div`
padding-top: 5rem;
@@ -42,9 +43,7 @@ const StyledLink = styled.a`
const About: FC> = () => {
const { width } = useWindowSize();
- React.useEffect(() => {
- document.title = `About us — ${data.title} — ${data.edition}`;
- }, []);
+ useDocumentTitleUpdater("About us", data.edition);
return (
diff --git a/src/views/Attendee/AttendeeInformation.tsx b/src/views/Attendee/AttendeeInformation.tsx
index 0bfac404d..8f3fd65c9 100644
--- a/src/views/Attendee/AttendeeInformation.tsx
+++ b/src/views/Attendee/AttendeeInformation.tsx
@@ -1,9 +1,10 @@
-import { FC, useEffect } from "react";
+import { FC } from "react";
import { Color } from "../../styles/colors";
import styled from "styled-components";
import { BIG_BREAKPOINT } from "../../constants/BreakPoints";
import data from "../../data/2024.json";
import { format } from "date-fns";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const PrePartyImg = styled.img`
{
@@ -64,9 +65,7 @@ const SectionWrapper = styled.div`
const AttendeeInformation: FC> = () => {
const formattedDate = format(new Date(data.startDay), "EEEE, MMMM do");
- useEffect(() => {
- document.title = `Attendee information — ${data.title} — ${data.edition}`;
- }, []);
+ useDocumentTitleUpdater("Attendee information", data.edition);
return (
diff --git a/src/views/Cfp/CfpSection.test.tsx b/src/views/Cfp/CfpSection.test.tsx
index 509eab3e2..4cee0f4b8 100644
--- a/src/views/Cfp/CfpSection.test.tsx
+++ b/src/views/Cfp/CfpSection.test.tsx
@@ -9,7 +9,7 @@ describe("CfpSection", () => {
it("sets document title on mount", () => {
render( );
expect(document.title).toBe(
- `CFP Committee — ${conferenceData.title}— ${conferenceData.edition}`,
+ `CFP Committee — DevBcn - Barcelona Developers Conference — ${conferenceData.edition}`,
);
});
diff --git a/src/views/Cfp/CfpSection.tsx b/src/views/Cfp/CfpSection.tsx
index 7e64f2745..70854254d 100644
--- a/src/views/Cfp/CfpSection.tsx
+++ b/src/views/Cfp/CfpSection.tsx
@@ -22,6 +22,7 @@ import {
import conferenceData from "../../data/2025.json";
import {CfpTrackProps, data} from "./CfpData";
import {MemberName, TrackName} from "./Cfp.style";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
export const CfpTrackComponent: FC> = ({
track,
@@ -63,42 +64,43 @@ export const CfpTrackComponent: FC> = ({
);
const CfpSection: FC> = () => {
- const {width} = useWindowSize();
- React.useEffect(() => {
- document.title = `CFP Committee — ${conferenceData.title} — ${conferenceData.edition}`;
- }, []);
+ const { width } = useWindowSize();
- const isCFPCommitteeReady = (): boolean => data.every((track) => track.members.length > 0)
+ useDocumentTitleUpdater("CFP Committee", conferenceData.edition);
- return (
- <>
-
-
-
- {width > MOBILE_BREAKPOINT && (
- <>
-
-
- >
- )}
-
- {!isCFPCommitteeReady() &&
- CFP Committee in
- progress }
- {isCFPCommitteeReady() && data.map((track) => (
-
- ))}
-
-
- >
- );
+ color={Color.BLUE}
+ />
+ {width > MOBILE_BREAKPOINT && (
+ <>
+
+
+ >
+ )}
+
+ {!isCFPCommitteeReady() && (
+ CFP Committee in progress
+ )}
+ {isCFPCommitteeReady() &&
+ data.map((track) => (
+
+ ))}
+
+
+ >
+ );
};
export default CfpSection;
diff --git a/src/views/CodeOfConduct/CodeOfConduct.tsx b/src/views/CodeOfConduct/CodeOfConduct.tsx
index fe46fdf34..9bb1e8f87 100644
--- a/src/views/CodeOfConduct/CodeOfConduct.tsx
+++ b/src/views/CodeOfConduct/CodeOfConduct.tsx
@@ -1,4 +1,4 @@
-import React, { FC, useEffect } from "react";
+import React, { FC } from "react";
import TitleSection from "../../components/SectionTitle/TitleSection";
import SectionWrapper from "../../components/SectionWrapper/SectionWrapper";
import { BIG_BREAKPOINT, MOBILE_BREAKPOINT } from "../../constants/BreakPoints";
@@ -21,6 +21,7 @@ import {
import { StyledMarginBottom, StyledTagsWrapper } from "../Talks/Talks.style";
import data from "../../data/2024.json";
import { format } from "date-fns";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const StyledWaveContainer = styled.div`
background: ${Color.DARK_BLUE};
@@ -82,9 +83,7 @@ const StyleMoreIcon = styled.img`
export const CodeOfConduct: FC = () => {
const { width } = useWindowSize();
- useEffect(() => {
- document.title = `Code of Conduct — ${data.title} — ${data.edition}`;
- });
+ useDocumentTitleUpdater("Code of Conduct", data.edition);
return (
<>
diff --git a/src/views/Communities/Communities.tsx b/src/views/Communities/Communities.tsx
index 1aa891ed3..22896ef86 100644
--- a/src/views/Communities/Communities.tsx
+++ b/src/views/Communities/Communities.tsx
@@ -4,6 +4,7 @@ import TwitterIcon from "../../components/Icons/Twitter";
import { Color } from "../../styles/colors";
import WebsiteIcon from "../../components/Icons/website";
import data from "../../data/2024.json";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const Heading = styled.h1`
{
@@ -93,9 +94,8 @@ const FoSS = styled.div`
`;
const Communities: FC> = () => {
- React.useEffect(() => {
- document.title = `Communities — ${data.title} — ${data.edition}`;
- });
+ useDocumentTitleUpdater("Communities", data.edition);
+
return (
<>
FOSS & Diversity Communities
diff --git a/src/views/Conditions/Conditions.tsx b/src/views/Conditions/Conditions.tsx
index 887cc4398..4b8464009 100644
--- a/src/views/Conditions/Conditions.tsx
+++ b/src/views/Conditions/Conditions.tsx
@@ -2,42 +2,42 @@ import React, { FC } from "react";
import styled from "styled-components";
import { Color } from "../../styles/colors";
import data from "../../data/2024.json";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const StyledDiv = styled.div`
- {
+{
width: 70%;
margin: 90px auto;
- }
+}
- p {
- text-align: justify;
- margin: 5px;
- }
+ p {
+ text-align: justify;
+ margin: 5px;
+ }
- h1,
- h2,
- h3,
- h4 {
- text-align: left;
- margin-top: 10px;
- margin-bottom: 20px;
- }
+ h1,
+ h2,
+ h3,
+ h4 {
+ text-align: left;
+ margin-top: 10px;
+ margin-bottom: 20px;
+ }
- li {
- margin-left: 30px;
- text-align: left;
- }
+ li {
+ margin-left: 30px;
+ text-align: left;
+ }
- hr {
- color: ${Color.DARK_BLUE};
- margin: 20px;
- }
+ hr {
+ color: ${Color.DARK_BLUE};
+ margin: 20px;
+ }
`;
const Conditions: FC> = () => {
- React.useEffect(() => {
- document.title = `Communities — ${data.title} — ${data.edition}`;
- });
+ useDocumentTitleUpdater("Communities", data.edition);
+
return (
TERMS AND CONDITIONS
diff --git a/src/views/Diversity/Diversity.tsx b/src/views/Diversity/Diversity.tsx
index 2636d1961..deb931fb3 100644
--- a/src/views/Diversity/Diversity.tsx
+++ b/src/views/Diversity/Diversity.tsx
@@ -1,4 +1,4 @@
-import React, { FC, useEffect } from "react";
+import React, { FC } from "react";
import { Color } from "../../styles/colors";
import data from "../../data/2024.json";
import styled from "styled-components";
@@ -8,6 +8,7 @@ import {
ROUTE_CODE_OF_CONDUCT,
ROUTE_CONDITIONS,
} from "../../constants/routes";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const StyledSection = styled.section`
{
@@ -93,9 +94,7 @@ const StyledParagraph = styled.section`
`;
const Diversity: FC> = () => {
- useEffect(() => {
- document.title = `Diversity — ${data.title} — ${data.edition}`;
- });
+ useDocumentTitleUpdater("Diversity", data.edition);
return (
diff --git a/src/views/Home/HomeWrapper.tsx b/src/views/Home/HomeWrapper.tsx
index 5e87ec7cd..646fcfa3a 100644
--- a/src/views/Home/HomeWrapper.tsx
+++ b/src/views/Home/HomeWrapper.tsx
@@ -9,6 +9,7 @@ import styled from "styled-components";
import {useLocation} from "react-router";
import {useEventEdition} from "./UseEventEdition";
import {Edition} from "../../types/types";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const StyledContainer = styled.div`
padding-bottom: 10rem;
@@ -24,13 +25,14 @@ const HomeWrapper: FC> = () => {
useEventEdition(setEdition);
React.useEffect(() => {
- document.title = `Home - ${edition?.title} - ${edition?.edition}`;
if (hash != null && hash !== "") {
const scroll = document.getElementById(hash.substring(1));
scroll?.scrollIntoView();
}
}, [hash, edition]);
+ useDocumentTitleUpdater("Home", edition?.edition ?? "2025");
+
return (
diff --git a/src/views/JobOffers/JobOffers.tsx b/src/views/JobOffers/JobOffers.tsx
index 64f308cce..335de69e5 100644
--- a/src/views/JobOffers/JobOffers.tsx
+++ b/src/views/JobOffers/JobOffers.tsx
@@ -17,6 +17,7 @@ import {
StyledTitleContainer,
} from "../../styles/JobOffers/JobOffers.Style";
import CompanyOffers from "../../components/JobOffers/CompanyOffers";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const NoOffersAvailable = () => (
<>
@@ -40,9 +41,7 @@ const MoreThanLessThan = (props: { width: number }) => (
const JobOffers: FC> = () => {
const { width } = useWindowSize();
- React.useEffect(() => {
- document.title = `Job Offers - ${data.title} - ${data.edition}`;
- }, []);
+ useDocumentTitleUpdater("Job Offers", data.edition);
return (
diff --git a/src/views/MeetingDetail/MeetingDetail.tsx b/src/views/MeetingDetail/MeetingDetail.tsx
index c4fd20023..d521e5b73 100644
--- a/src/views/MeetingDetail/MeetingDetail.tsx
+++ b/src/views/MeetingDetail/MeetingDetail.tsx
@@ -4,7 +4,7 @@ import {
MOBILE_BREAKPOINT,
} from "../../constants/BreakPoints";
import {Color} from "../../styles/colors";
-import React, {FC, Suspense, useEffect} from "react";
+import React, { FC, Suspense } from "react";
import LessThanIconWhite from "../../assets/images/LessThanIconWhite.svg";
import LessThanIcon from "../../assets/images/LessThanBlueIcon.svg";
import MoreThanIcon from "../../assets/images/MoreThanBlueIcon.svg";
@@ -32,8 +32,9 @@ import {ROUTE_SPEAKER_DETAIL, ROUTE_TALKS} from "../../constants/routes";
import conferenceData from "../../data/2025.json";
import {Tag} from "../../components/Tag/Tag";
import styled from "styled-components";
-import {AddToCalendarButton} from "add-to-calendar-button-react";
-import {IMeetingDetailProps, MyType} from "../../types/sessions";
+import { AddToCalendarButton } from "add-to-calendar-button-react";
+import { IMeetingDetailProps, MyType } from "../../types/sessions";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const getVideoHeight = (windowWidth: number) => {
let videoHeight;
@@ -107,9 +108,7 @@ const MeetingDetail: FC> = ({
}) => {
const { width } = useWindowSize();
- useEffect(() => {
- document.title = `${meeting.title} — ${conferenceData.title} — ${conferenceData.edition}`;
- }, [meeting.title]);
+ useDocumentTitleUpdater(meeting.title, conferenceData.edition);
const finalMeetingInfo: MyType = {
...meeting,
diff --git a/src/views/Schedule/Schedule.tsx b/src/views/Schedule/Schedule.tsx
index 984b44c76..05a2f5662 100644
--- a/src/views/Schedule/Schedule.tsx
+++ b/src/views/Schedule/Schedule.tsx
@@ -10,6 +10,7 @@ import data from "../../data/2024.json";
import * as Sentry from "@sentry/react";
import { Link } from "react-router";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
import {
StyledLessIcon, StyledMoreIcon,
StyledScheduleSection
@@ -19,8 +20,6 @@ const Schedule: FC> = () => {
const { width } = useWindowSize();
React.useEffect(() => {
- document.title = `Schedule — ${data.title} — ${data.edition}`;
-
fetch("https://sessionize.com/api/v2/w8mdb9k5/view/GridSmart")
.then((value) => value.text())
.then((value) => {
@@ -32,6 +31,8 @@ const Schedule: FC> = () => {
.catch((err) => Sentry.captureException(err));
}, []);
+ useDocumentTitleUpdater("Schedule", data.edition);
+
return (
diff --git a/src/views/SessionFeedback/SessionFeedback.tsx b/src/views/SessionFeedback/SessionFeedback.tsx
index 9ef9ee144..73855ec27 100644
--- a/src/views/SessionFeedback/SessionFeedback.tsx
+++ b/src/views/SessionFeedback/SessionFeedback.tsx
@@ -16,6 +16,7 @@ import { Color } from "../../styles/colors";
import { Link } from "react-router";
import { ROUTE_TALK_DETAIL } from "../../constants/routes";
import data from "../../data/2024.json";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const SessionFeedback: FC> = () => {
const bodyTemplate = React.useCallback(
@@ -65,9 +66,7 @@ const SessionFeedback: FC> = () => {
);
- React.useEffect(() => {
- document.title = `Session Feedback — ${data.title} - ${data.edition}`;
- });
+ useDocumentTitleUpdater("Session Feedback", data.edition);
const header = renderHeader();
diff --git a/src/views/Travel/Travel.tsx b/src/views/Travel/Travel.tsx
index 591c5dc84..ea79c4138 100644
--- a/src/views/Travel/Travel.tsx
+++ b/src/views/Travel/Travel.tsx
@@ -1,41 +1,39 @@
-import React, {FC, useEffect} from "react";
-import {Venue} from "./Venue";
-import {ToBarcelona} from "./ToBarcelona";
+import React, { FC } from "react";
+import { Venue } from "./Venue";
+import { ToBarcelona } from "./ToBarcelona";
import data from "../../data/2024.json";
-import {StyledWaveContainer} from "../Speakers/Speakers.style";
+import { StyledWaveContainer } from "../Speakers/Speakers.style";
import styled from "styled-components";
-import {Color} from "../../styles/colors";
-import {Accommodation} from "./Accommodation";
+import { Color } from "../../styles/colors";
+import { Accommodation } from "./Accommodation";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const StyledTravel = styled.div`
+ max-width: 85rem;
+ margin-left: auto;
+ margin-right: auto;
- max-width: 85rem;
- margin-left: auto;
- margin-right: auto;
-
- .top {
- clip-path: polygon(0 0, 100% 0, 100% 100%, 0 calc(100% - 50px));
- height: 51px;
- background-color: ${Color.LIGHT_BLUE};
- border-top: 1px solid ${Color.LIGHT_BLUE};
- }
+ .top {
+ clip-path: polygon(0 0, 100% 0, 100% 100%, 0 calc(100% - 50px));
+ height: 51px;
+ background-color: ${Color.LIGHT_BLUE};
+ border-top: 1px solid ${Color.LIGHT_BLUE};
+ }
- .bottom {
- clip-path: polygon(0 0, 100% 50px, 100% 100%, 0 100%);
- margin-top: -50px;
- height: 50px;
- background-color: ${Color.DARK_BLUE};
- }
+ .bottom {
+ clip-path: polygon(0 0, 100% 50px, 100% 100%, 0 100%);
+ margin-top: -50px;
+ height: 50px;
+ background-color: ${Color.DARK_BLUE};
+ }
- .to-barcelona {
- background-color: ${Color.DARK_BLUE};
- }
+ .to-barcelona {
+ background-color: ${Color.DARK_BLUE};
+ }
`;
const Travel: FC> = () => {
- useEffect(() => {
- document.title = `Travel — ${data.title} — ${data.edition}`;
- }, []);
+ useDocumentTitleUpdater("Travel", data.edition);
return (
diff --git a/src/views/kcd/Kcd.tsx b/src/views/kcd/Kcd.tsx
index 36cf598ee..1e0380362 100644
--- a/src/views/kcd/Kcd.tsx
+++ b/src/views/kcd/Kcd.tsx
@@ -1,4 +1,3 @@
-import { useEffect } from "react";
import SectionWrapper from "../../components/SectionWrapper/SectionWrapper";
import { Color } from "../../styles/colors";
import {
@@ -17,6 +16,7 @@ import { useWindowSize } from "react-use";
import youtube from "../../assets/images/youtube.svg";
import linkedinIcon from "../../assets/images/linkedinIcon.svg";
import twitterIcon from "../../assets/images/twitterIcon.svg";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const StyledParagraph = styled.p`
color: white;
@@ -60,9 +60,8 @@ const StyledImage = styled.img`
export default function Kcd() {
const { width } = useWindowSize();
- useEffect(() => {
- document.title = `KCD Barcelona — ${data.title} — ${data.edition}`;
- });
+
+ useDocumentTitleUpdater("KCD Barcelona", data.edition);
return (
<>
@@ -84,7 +83,11 @@ export default function Kcd() {
-
+
KCD Barcelona
{" "}
is an event within the CNCF framework called Kubernetes Community Days
diff --git a/src/views/sponsorship/Sponsorship.tsx b/src/views/sponsorship/Sponsorship.tsx
index 8b6b65b75..f144f3a37 100644
--- a/src/views/sponsorship/Sponsorship.tsx
+++ b/src/views/sponsorship/Sponsorship.tsx
@@ -1,347 +1,337 @@
-import {FC, useEffect} from "react";
+import { FC } from "react";
import TitleSection from "../../components/SectionTitle/TitleSection";
import SectionWrapper from "../../components/SectionWrapper/SectionWrapper";
-import {BIG_BREAKPOINT, MOBILE_BREAKPOINT} from "../../constants/BreakPoints";
-import {Color} from "../../styles/colors";
+import { BIG_BREAKPOINT, MOBILE_BREAKPOINT } from "../../constants/BreakPoints";
+import { Color } from "../../styles/colors";
import LessThanBlue from "../../assets/images/MoreThanBlueWhiteIcon.svg";
-import LessThanTransparentIcon
- from "../../assets/images/LessThanTransparentIcon.svg";
+import LessThanTransparentIcon from "../../assets/images/LessThanTransparentIcon.svg";
import MoreThanBlue from "../../assets/images/LessThanBlueWhiteIcon.svg";
-import MoreThanTransparentIcon
- from "../../assets/images/MoreThanTransparentIcon.svg";
+import MoreThanTransparentIcon from "../../assets/images/MoreThanTransparentIcon.svg";
import styled from "styled-components";
-import {useWindowSize} from "react-use";
+import { useWindowSize } from "react-use";
import {
- StyledLessIcon,
- StyledMoreIcon,
- StyledSpeakersSection,
+ StyledLessIcon,
+ StyledMoreIcon,
+ StyledSpeakersSection,
} from "../Speakers/Speakers.style";
-import {StyledMarginBottom} from "../Talks/Talks.style";
+import { StyledMarginBottom } from "../Talks/Talks.style";
import data from "../../data/2025.json";
-import {format} from "date-fns";
+import { format } from "date-fns";
import Flicking from "@egjs/react-flicking";
-import {AutoPlay} from "@egjs/flicking-plugins";
+import { AutoPlay } from "@egjs/flicking-plugins";
import "@egjs/react-flicking/dist/flicking.css";
import Button from "../../components/UI/Button";
-import {gaEventTracker} from "../../components/analytics/Analytics";
-
+import { gaEventTracker } from "../../components/analytics/Analytics";
+import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
const StyledWaveContainer = styled.div`
- background: ${Color.DARK_BLUE};
- overflow-y: hidden;
- height: 3rem;
- width: 100%;
+ background: ${Color.DARK_BLUE};
+ overflow-y: hidden;
+ height: 3rem;
+ width: 100%;
`;
export const StyledSectionsSeparator = styled.div`
- background: ${Color.WHITE};
- height: 3rem;
- @media (min-width: ${BIG_BREAKPOINT}px) {
- height: 5rem;
- }
+ background: ${Color.WHITE};
+ height: 3rem;
+ @media (min-width: ${BIG_BREAKPOINT}px) {
+ height: 5rem;
+ }
`;
const StyledSponsorshipText = styled.div`
- text-align: start;
- color: ${Color.BLACK_BLUE};
- max-width: 95vw;
+ text-align: start;
+ color: ${Color.BLACK_BLUE};
+ max-width: 95vw;
- p {
- margin: 5px 20px;
- text-align: justify;
- }
+ p {
+ margin: 5px 20px;
+ text-align: justify;
+ }
- ul {
- margin: 5px 20px;
+ ul {
+ margin: 5px 20px;
- li {
- margin: 5px 0;
- }
+ li {
+ margin: 5px 0;
}
+ }
- h4 {
- margin: 20px 0;
- }
+ h4 {
+ margin: 20px 0;
+ }
- a:visited {
- color: ${Color.DARK_BLUE};
- font-weight: normal;
- }
+ a:visited {
+ color: ${Color.DARK_BLUE};
+ font-weight: normal;
+ }
- @media only screen and (max-width: ${BIG_BREAKPOINT}px) {
- iframe {
- width: 90vw;
- }
+ @media only screen and (max-width: ${BIG_BREAKPOINT}px) {
+ iframe {
+ width: 90vw;
}
+ }
`;
const StyleLessIcon = styled.img`
- position: absolute;
- left: -1rem;
- top: 12rem;
- height: 5rem;
- @media (min-width: ${BIG_BREAKPOINT}px) {
- height: 10rem;
- }
+ position: absolute;
+ left: -1rem;
+ top: 12rem;
+ height: 5rem;
+ @media (min-width: ${BIG_BREAKPOINT}px) {
+ height: 10rem;
+ }
`;
const StyleMoreIcon = styled.img`
- position: absolute;
- right: -1rem;
- top: 2rem;
- height: 5rem;
- @media (min-width: 800px) {
- height: 10rem;
- }
+ position: absolute;
+ right: -1rem;
+ top: 2rem;
+ height: 5rem;
+ @media (min-width: 800px) {
+ height: 10rem;
+ }
`;
const Sponsorship: FC> = () => {
- const {width} = useWindowSize();
- const plugins = [
- new AutoPlay({duration: 2000, direction: "NEXT", stopOnHover: false})
- ];
+ const { width } = useWindowSize();
+ const plugins = [
+ new AutoPlay({ duration: 2000, direction: "NEXT", stopOnHover: false }),
+ ];
- const handleCLick = () => {
- gaEventTracker("download brochure", "download brochure");
- };
+ const handleCLick = () => {
+ gaEventTracker("download brochure", "download brochure");
+ };
- useEffect(() => {
- document.title = `Sponsorship — ${data.title} — ${data.edition}`;
- });
+ useDocumentTitleUpdater("Sponsorship", data.edition);
- return (
-
-
-
-
- {width > MOBILE_BREAKPOINT && (
- <>
-
-
- >
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ {width > MOBILE_BREAKPOINT && (
+ <>
+
+
+ >
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {width > MOBILE_BREAKPOINT && (
+ <>
+
+
+ >
+ )}
+
+
+ Mark Your Calendars!
+
+ DevBcn {data?.edition} is set for{" "}
+
+ {format(new Date(data.startDay), "MMMM do")} —
+ {" ".concat(format(data.endDay, "do"))}
+ {" "}
+ at the iconic La Farga, Hospitalet de Llobregat. 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.
+
+ A New Era of Tech Innovation
+
+ Dive into tracks covering Java, JVM, Cloud, DevOps, Frontend
+ technologies, Leadership, Big Data, AI, and more. DevBcn{" "}
+ {data?.edition} is the perfect stage to connect with tech
+ professionals, thought leaders, and innovators.
+
+ Tailored Sponsorship Opportunities
+
+ While we're keeping the details of our sponsorship packages
+ exclusive, we promise they're more engaging and impactful than
+ ever. Curious? Access our{" "}
+
+
-
-
-
-
- {width > MOBILE_BREAKPOINT && (
- <>
-
-
- >
- )}
-
-
- Mark Your Calendars!
-
- DevBcn {data?.edition} is set for {format(new Date(data.startDay),"MMMM do")} —
- {" ".concat(format(data.endDay,"do"))} at the
- iconic La Farga, Hospitalet de Llobregat. 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.
-
- A New Era of Tech Innovation
-
- Dive into tracks covering Java, JVM, Cloud, DevOps,
- Frontend
- technologies, Leadership, Big Data, AI, and more.
- DevBcn {data?.edition} is
- the perfect stage to connect with tech
- professionals, thought
- leaders, and innovators.
-
- Tailored Sponsorship Opportunities
-
- While we're keeping the details of our sponsorship
- packages
- exclusive, we promise they're more engaging and
- impactful than
- ever. Curious? Access our{" "}
-
-
- detailed brochure
- {" "}
- {" "}
- at and discover the myriad of ways you can shine at
- DevBcn {data?.edition}.
-
-
- Why Partner with DevBcn?
-
-
-
- Expand Your Reach: Engage
- with a diverse,
- tech-savvy audience. Our latest edition held
- more than 800
- attendees.
-
-
- Elevate Your
- Brand: Showcase your products
- and innovations in a dynamic environment.
-
-
- Network with the
- Best: Connect with industry
- leaders and potential collaborators. Nearly
- 30 companies have
- pledged their trust in DevBcn.
-
-
- Showcase Thought
- Leadership: Share your
- expertise and insights with a global
- audience.
-
-
-
- Join us on this exciting journey
-
- To discuss how we can align our sponsorship
- opportunities with
- your brand's vision, contact us at{" "}
- sponsors@devbcn.com
-
-
- Let’s make DevBcn {data?.edition} an unforgettable
- experience together! Stay
- updated and spread the excitement using{" "}
-
- #devbcn25.
-
-
-
- We eagerly await the opportunity to collaborate with
- you once more
- for an extraordinary event!
-
- Take a look at our latest edition summary
- VIDEO
- Explore DevBcn Talks Online!
-
-
-
-
-
-
- );
+ detailed brochure
+ {" "}
+ {" "}
+ at and discover the myriad of ways you can shine at DevBcn{" "}
+ {data?.edition}.
+
+
+ Why Partner with DevBcn?
+
+
+
+ Expand Your Reach: Engage with a diverse,
+ tech-savvy audience. Our latest edition held more than 800
+ attendees.
+
+
+ Elevate Your Brand: Showcase your products
+ and innovations in a dynamic environment.
+
+
+ Network with the Best: Connect with industry
+ leaders and potential collaborators. Nearly 30 companies have
+ pledged their trust in DevBcn.
+
+
+ Showcase Thought Leadership: Share your
+ expertise and insights with a global audience.
+
+
+
+ Join us on this exciting journey
+
+ To discuss how we can align our sponsorship opportunities with
+ your brand's vision, contact us at{" "}
+ sponsors@devbcn.com
+
+
+ Let’s make DevBcn {data?.edition} an unforgettable experience
+ together! Stay updated and spread the excitement using{" "}
+
+ #devbcn25.
+
+
+
+ We eagerly await the opportunity to collaborate with you once more
+ for an extraordinary event!
+
+ Take a look at our latest edition summary
+ VIDEO
+ Explore DevBcn Talks Online!
+
+
+
+
+
+
+ );
};
-export default Sponsorship;
\ No newline at end of file
+export default Sponsorship;
From f26631f6349639d292caefcc99d77b1b58b67941 Mon Sep 17 00:00:00 2001
From: Anyul Rivas
Date: Thu, 20 Mar 2025 08:45:51 +0100
Subject: [PATCH 05/16] refactor: remove duplicated code. Home wrapper
---
package.json | 1 +
src/2023/Home/Home2023Wrapper.tsx | 5 +-
src/2024/HomeWrapper2024.tsx | 21 ++--
.../SpeakersCarousel/SpeakersCarousel.scss | 29 -----
.../SpeakersCarousel/SpeakersCarousel.tsx | 106 ------------------
.../Swiper}/SpeakersCarousel.scss | 0
.../Swiper}/SpeakersCarousel.tsx | 26 +++--
src/services/shuffleArray.ts | 17 +++
src/views/Home/HomeWrapper.tsx | 32 +++---
.../SpeakersCarousel/SpeakersCarousel.scss | 29 -----
.../SpeakersCarousel/SpeakersCarousel.tsx | 104 -----------------
11 files changed, 66 insertions(+), 304 deletions(-)
delete mode 100644 src/2024/SpeakersCarousel/SpeakersCarousel.scss
delete mode 100644 src/2024/SpeakersCarousel/SpeakersCarousel.tsx
rename src/{2023/Home/components/SpeakersCarousel => components/Swiper}/SpeakersCarousel.scss (100%)
rename src/{2023/Home/components/SpeakersCarousel => components/Swiper}/SpeakersCarousel.tsx (79%)
create mode 100644 src/services/shuffleArray.ts
delete mode 100644 src/views/Home/components/SpeakersCarousel/SpeakersCarousel.scss
delete mode 100644 src/views/Home/components/SpeakersCarousel/SpeakersCarousel.tsx
diff --git a/package.json b/package.json
index 001bac9d9..68bd0532f 100644
--- a/package.json
+++ b/package.json
@@ -24,6 +24,7 @@
"react-cookie-consent": "^9.0.0",
"react-countdown": "^2.3.6",
"react-dom": "^18.3.1",
+ "react-error-boundary": "^5.0.0",
"react-query": "^3.39.2",
"react-router-dom": "^7.3.0",
"react-scripts": "5.0.1",
diff --git a/src/2023/Home/Home2023Wrapper.tsx b/src/2023/Home/Home2023Wrapper.tsx
index cc45e91fd..a73664252 100644
--- a/src/2023/Home/Home2023Wrapper.tsx
+++ b/src/2023/Home/Home2023Wrapper.tsx
@@ -2,12 +2,13 @@ import { BIG_BREAKPOINT } from "../../constants/BreakPoints";
import React, { FC } from "react";
import Faqs from "./components/Faqs/Faqs";
import Home from "./components/Home/Home";
-import SpeakersCarousel from "./components/SpeakersCarousel/SpeakersCarousel";
import Sponsors from "./components/Sponsors/Sponsors";
import styled from "styled-components";
import data from "../../data/2023.json";
import { useLocation } from "react-router";
import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
+import SpeakersCarousel from "../../components/Swiper/SpeakersCarousel";
+import {ROUTE_2023_SPEAKERS} from "../../constants/routes";
const StyledContainer = styled.div`
padding-bottom: 10rem;
@@ -32,7 +33,7 @@ export const Home2023Wrapper: FC> = () => {
-
+
);
diff --git a/src/2024/HomeWrapper2024.tsx b/src/2024/HomeWrapper2024.tsx
index 79ef08891..86f3c4453 100644
--- a/src/2024/HomeWrapper2024.tsx
+++ b/src/2024/HomeWrapper2024.tsx
@@ -1,18 +1,16 @@
-import React, { FC, useState } from "react";
+import React, { FC } from "react";
import styled from "styled-components";
import { useLocation } from "react-router";
import { BIG_BREAKPOINT } from "../constants/BreakPoints";
-
-import { useEventEdition } from "../views/Home/UseEventEdition";
+import conferenceData from "../data/2024.json";
import Faqs from "../views/Home/components/Faqs/Faqs";
import Home from "./Home/Home";
-import SpeakersCarousel from "./SpeakersCarousel/SpeakersCarousel";
import Sponsors from "./Sponsors/Sponsors";
-
-import { Edition } from "../types/types";
import { useDocumentTitleUpdater } from "../services/useDocumentTitleUpdate";
+import SpeakersCarousel from "../components/Swiper/SpeakersCarousel";
+import { ROUTE_2024_SPEAKERS } from "../constants/routes";
const StyledContainer = styled.div`
padding-bottom: 10rem;
@@ -24,23 +22,24 @@ const StyledContainer = styled.div`
export const HomeWrapper2024: FC> = () => {
const { hash } = useLocation();
- const [edition, setEdition] = useState();
- useEventEdition(setEdition);
React.useEffect(() => {
if (hash != null && hash !== "") {
const scroll = document.getElementById(hash.substring(1));
scroll?.scrollIntoView();
}
- }, [hash, edition]);
+ }, [hash]);
- useDocumentTitleUpdater("Home", edition?.edition ?? "2024");
+ useDocumentTitleUpdater("Home", conferenceData.edition);
return (
-
+
);
diff --git a/src/2024/SpeakersCarousel/SpeakersCarousel.scss b/src/2024/SpeakersCarousel/SpeakersCarousel.scss
deleted file mode 100644
index 5238a6c3b..000000000
--- a/src/2024/SpeakersCarousel/SpeakersCarousel.scss
+++ /dev/null
@@ -1,29 +0,0 @@
-.swiper {
- width: 100%;
- overflow-x: hidden;
- margin: 2rem 0;
-}
-
-.swiper-slide {
- background: transparent;
- position: relative;
- /* Center slide text vertically */
- display: -webkit-box;
- display: -ms-flexbox;
- display: -webkit-flex;
- display: flex;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- -webkit-align-items: center;
- align-items: center;
-}
-
-.link--text {
- text-decoration: none;
- display: flex;
- align-items: center;
-}
\ No newline at end of file
diff --git a/src/2024/SpeakersCarousel/SpeakersCarousel.tsx b/src/2024/SpeakersCarousel/SpeakersCarousel.tsx
deleted file mode 100644
index a199012d5..000000000
--- a/src/2024/SpeakersCarousel/SpeakersCarousel.tsx
+++ /dev/null
@@ -1,106 +0,0 @@
-import {FC} from "react";
-import {Link} from "react-router";
-import LessThanBlueWhiteIcon
- from "../../assets/images/MoreThanBlueWhiteIcon.svg";
-import {motion} from "framer-motion";
-import styled from "styled-components";
-import SpeakerSwiper from "./SpeakerSwiper";
-import {useWindowSize} from "react-use";
-import {
- BIGGER_BREAKPOINT,
- TABLET_BREAKPOINT
-} from "../../constants/BreakPoints";
-import {ROUTE_SPEAKERS} from "../../constants/routes";
-import TitleSection from "../../components/SectionTitle/TitleSection";
-import SectionWrapper from "../../components/SectionWrapper/SectionWrapper";
-import {Color} from "../../styles/colors";
-
-const StyledSpeakersContainer = styled.section`
- background-color: ${Color.LIGHT_BLUE};
- position: relative;
- display: flex;
- flex-direction: column;
- align-items: center;
-`;
-
-const StyledTitleWrapper = styled.div`
- max-width: 1280px;
-`;
-
-const StyledLink = styled.div`
- display: flex;
- justify-content: center;
- padding-bottom: 3rem;
- @media (min-width: ${TABLET_BREAKPOINT}px) {
- justify-content: flex-end;
- padding-right: 10rem;
- }
-`;
-
-const StyledSubtitle = styled.h2`
- color: ${Color.DARK_BLUE};
- padding-right: 0.75rem;
-`;
-
-const StyledLessThanRed = styled.img`
- height: 1.5rem;
-`;
-
-export const StyledBottomSlash = styled(motion.div)`
- position: absolute;
- bottom: -8px;
- left: 0;
- width: 40%;
- height: 2rem;
-`;
-
-const StyledBlueSlash = styled(motion.p)`
- font-family: "Square 721 Regular", sans-serif;
- color: ${Color.DARK_BLUE};
- font-size: 2rem;
- overflow-y: hidden;
- height: 100%;
-`;
-
-const SpeakersCarousel: FC> = () => {
- const {width} = useWindowSize();
- return (
-
-
-
-
-
-
-
-
- View all speakers
-
-
-
-
- {width > BIGGER_BREAKPOINT && (
-
- / / / / / / / / / / / / / / / / / / / / / / / / / /
- / / / / / / /
- / / / / / / / / / / / / / / / / / / / / / / / / / /
- / / / / / / /{" "}
-
- )}
-
-
-
- );
-};
-
-export default SpeakersCarousel;
diff --git a/src/2023/Home/components/SpeakersCarousel/SpeakersCarousel.scss b/src/components/Swiper/SpeakersCarousel.scss
similarity index 100%
rename from src/2023/Home/components/SpeakersCarousel/SpeakersCarousel.scss
rename to src/components/Swiper/SpeakersCarousel.scss
diff --git a/src/2023/Home/components/SpeakersCarousel/SpeakersCarousel.tsx b/src/components/Swiper/SpeakersCarousel.tsx
similarity index 79%
rename from src/2023/Home/components/SpeakersCarousel/SpeakersCarousel.tsx
rename to src/components/Swiper/SpeakersCarousel.tsx
index e4eb0bc22..2162fc39c 100644
--- a/src/2023/Home/components/SpeakersCarousel/SpeakersCarousel.tsx
+++ b/src/components/Swiper/SpeakersCarousel.tsx
@@ -1,15 +1,13 @@
-import { Color } from "../../../../styles/colors";
-
import { FC } from "react";
import { Link } from "react-router";
-import LessThanBlueWhiteIcon from ".././../../../assets/images/MoreThanBlueIcon.svg";
-import SectionWrapper from "../../../../components/SectionWrapper/SectionWrapper";
-import { TABLET_BREAKPOINT } from "../../../../constants/BreakPoints";
-import TitleSection from "../../../../components/SectionTitle/TitleSection";
+import LessThanBlueWhiteIcon from "../../assets/images/LessThanBlueIcon.svg";
import { motion } from "framer-motion";
import styled from "styled-components";
-import { ROUTE_2023_SPEAKERS } from "../../../../constants/routes";
import SpeakerSwiper from "./SpeakerSwiper";
+import { Color } from "../../styles/colors";
+import { TABLET_BREAKPOINT } from "../../constants/BreakPoints";
+import SectionWrapper from "../SectionWrapper/SectionWrapper";
+import TitleSection from "../SectionTitle/TitleSection";
const StyledSpeakersContainer = styled.section`
background-color: ${Color.LIGHT_BLUE};
@@ -58,7 +56,15 @@ const StyledBlueSlash = styled(motion.p)`
height: 100%;
`;
-const SpeakersCarousel: FC> = () => {
+interface Props {
+ speakersLink: string;
+ sessionizeUrl: string;
+}
+
+const SpeakersCarousel: FC> = ({
+ speakersLink,
+ sessionizeUrl,
+}) => {
return (
@@ -72,9 +78,9 @@ const SpeakersCarousel: FC> = () => {
color={Color.WHITE}
/>
-
+
-
+
View all speakers
diff --git a/src/services/shuffleArray.ts b/src/services/shuffleArray.ts
new file mode 100644
index 000000000..ed7cfafee
--- /dev/null
+++ b/src/services/shuffleArray.ts
@@ -0,0 +1,17 @@
+/** Fisher-Yates shuffle algorithm using window.crypto.getRandomValues() */
+export const shuffleArray = (array: T[]): T[] => {
+ if (!array) {
+ return [];
+ }
+ const shuffledArray = [...array]; // Create a copy to avoid modifying the original array
+ for (let i = shuffledArray.length - 1; i > 0; i--) {
+ let j;
+ const max = (i + 1) * (2 ** 32 / (i + 1));
+ do {
+ j = window.crypto.getRandomValues(new Uint32Array(1))[0];
+ } while (j >= max);
+ j = j % (i + 1);
+ [shuffledArray[i], shuffledArray[j]] = [shuffledArray[j], shuffledArray[i]];
+ }
+ return shuffledArray;
+};
\ No newline at end of file
diff --git a/src/views/Home/HomeWrapper.tsx b/src/views/Home/HomeWrapper.tsx
index 646fcfa3a..05770dfa3 100644
--- a/src/views/Home/HomeWrapper.tsx
+++ b/src/views/Home/HomeWrapper.tsx
@@ -1,15 +1,16 @@
-import {BIG_BREAKPOINT} from "../../constants/BreakPoints";
-import React, {FC, useState} from "react";
+import { BIG_BREAKPOINT } from "../../constants/BreakPoints";
+import React, { FC } from "react";
import Faqs from "./components/Faqs/Faqs";
import Home from "./components/Home/Home";
-import SpeakersCarousel from "./components/SpeakersCarousel/SpeakersCarousel";
import Sponsors from "./components/Sponsors/Sponsors";
import styled from "styled-components";
+import conferenceData from "../../data/2025.json";
+import { useLocation } from "react-router";
-import {useLocation} from "react-router";
-import {useEventEdition} from "./UseEventEdition";
-import {Edition} from "../../types/types";
import { useDocumentTitleUpdater } from "../../services/useDocumentTitleUpdate";
+import SpeakersCarousel from "../../components/Swiper/SpeakersCarousel";
+import { ROUTE_SPEAKERS } from "../../constants/routes";
+import { ErrorBoundary } from "react-error-boundary";
const StyledContainer = styled.div`
padding-bottom: 10rem;
@@ -21,26 +22,31 @@ const StyledContainer = styled.div`
const HomeWrapper: FC> = () => {
const { hash } = useLocation();
- const [edition, setEdition] = useState();
- useEventEdition(setEdition);
React.useEffect(() => {
if (hash != null && hash !== "") {
const scroll = document.getElementById(hash.substring(1));
scroll?.scrollIntoView();
}
- }, [hash, edition]);
+ }, [hash]);
- useDocumentTitleUpdater("Home", edition?.edition ?? "2025");
+ useDocumentTitleUpdater("Home", conferenceData?.edition ?? "2025");
return (
-
+ Something went wrong}>
+
+
- {edition?.carrousel.enabled && }
+ {conferenceData?.carrousel.enabled && (
+
+ )}
);
};
-export default HomeWrapper;
\ No newline at end of file
+export default HomeWrapper;
diff --git a/src/views/Home/components/SpeakersCarousel/SpeakersCarousel.scss b/src/views/Home/components/SpeakersCarousel/SpeakersCarousel.scss
deleted file mode 100644
index 5238a6c3b..000000000
--- a/src/views/Home/components/SpeakersCarousel/SpeakersCarousel.scss
+++ /dev/null
@@ -1,29 +0,0 @@
-.swiper {
- width: 100%;
- overflow-x: hidden;
- margin: 2rem 0;
-}
-
-.swiper-slide {
- background: transparent;
- position: relative;
- /* Center slide text vertically */
- display: -webkit-box;
- display: -ms-flexbox;
- display: -webkit-flex;
- display: flex;
- -webkit-box-pack: center;
- -ms-flex-pack: center;
- -webkit-justify-content: center;
- justify-content: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- -webkit-align-items: center;
- align-items: center;
-}
-
-.link--text {
- text-decoration: none;
- display: flex;
- align-items: center;
-}
\ No newline at end of file
diff --git a/src/views/Home/components/SpeakersCarousel/SpeakersCarousel.tsx b/src/views/Home/components/SpeakersCarousel/SpeakersCarousel.tsx
deleted file mode 100644
index d459e430f..000000000
--- a/src/views/Home/components/SpeakersCarousel/SpeakersCarousel.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-import { Color } from "../../../../styles/colors";
-
-import { FC } from "react";
-import { Link } from "react-router";
-import LessThanBlueWhiteIcon from ".././../../../assets/images/MoreThanBlueIcon.svg";
-import SectionWrapper from "../../../../components/SectionWrapper/SectionWrapper";
-import {
- BIGGER_BREAKPOINT,
- TABLET_BREAKPOINT,
-} from "../../../../constants/BreakPoints";
-import TitleSection from "../../../../components/SectionTitle/TitleSection";
-import { motion } from "framer-motion";
-import styled from "styled-components";
-import { ROUTE_SPEAKERS } from "../../../../constants/routes";
-import SpeakerSwiper from "../../../../components/Swiper/SpeakerSwiper";
-import { useWindowSize } from "react-use";
-
-const StyledSpeakersContainer = styled.section`
- background-color: ${Color.LIGHT_BLUE};
- position: relative;
- display: flex;
- flex-direction: column;
- align-items: center;
-`;
-
-const StyledTitleWrapper = styled.div`
- max-width: 1280px;
-`;
-
-const StyledLink = styled.div`
- display: flex;
- justify-content: center;
- padding-bottom: 3rem;
- @media (min-width: ${TABLET_BREAKPOINT}px) {
- justify-content: flex-end;
- padding-right: 10rem;
- }
-`;
-
-const StyledSubtitle = styled.h2`
- color: ${Color.DARK_BLUE};
- padding-right: 0.75rem;
-`;
-
-const StyledLessThanRed = styled.img`
- height: 1.5rem;
-`;
-
-export const StyledBottomSlash = styled(motion.div)`
- position: absolute;
- bottom: -8px;
- left: 0;
- width: 40%;
- height: 2rem;
-`;
-
-const StyledBlueSlash = styled(motion.p)`
- font-family: "Square 721 Regular", sans-serif;
- color: ${Color.DARK_BLUE};
- font-size: 2rem;
- overflow-y: hidden;
- height: 100%;
-`;
-
-const SpeakersCarousel: FC> = () => {
- const { width } = useWindowSize();
- return (
-
-
-
-
-
-
-
-
- View all speakers
-
-
-
-
- {width > BIGGER_BREAKPOINT && (
-
- / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
- / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /{" "}
-
- )}
-
-
-
- );
-};
-
-export default SpeakersCarousel;
From 21da48fe374ae20c9b19330999cdf8355efe7753 Mon Sep 17 00:00:00 2001
From: Anyul Rivas
Date: Thu, 27 Mar 2025 11:44:43 +0100
Subject: [PATCH 06/16] refactor: more refactor
---
.output.txt | 4538 +++++++++++++++++
src/2023/Cfp/CfpSection2023.tsx | 2 +-
src/2023/Communities/Communities2023.tsx | 2 +-
src/2023/Diversity/Diversity2023.tsx | 2 +-
src/2023/Home/Home2023Wrapper.tsx | 9 +-
.../SpeakersCarousel/SpeakerSwiper.tsx | 6 +-
src/2023/JobOffers/JobOffers2023.tsx | 21 +-
src/2023/Schedule/Schedule2023.tsx | 2 +-
.../SessionFeedback/SessionFeedback2023.tsx | 2 +-
.../SpeakerDetailContainer2023.tsx | 6 +-
src/2023/Speakers/Speakers2023.tsx | 18 +-
src/2023/TalkDetail/TalkDetail.tsx | 24 +-
.../TalkDetail/TalkDetailContainer2023.tsx | 6 +-
src/2023/Talks/Talks2023.tsx | 6 +-
src/2023/Workshops/Workshops2023.tsx | 13 +-
src/2024/Cfp/CfpSection2024.tsx | 2 +-
src/2024/HomeWrapper2024.tsx | 2 +-
src/2024/SpeakerDetail/SpeakerDetail.tsx | 2 +-
.../SpeakerDetailContainer2024.tsx | 6 +-
src/2024/Speakers/Speakers2024.tsx | 18 +-
src/2024/SpeakersCarousel/SpeakerSwiper.tsx | 190 +-
src/2024/TalkDetail/MeetingDetail.tsx | 2 +-
.../TalkDetail/MeetingDetailContainer2024.tsx | 6 +-
src/2024/Talks/LiveView.tsx | 8 +-
src/2024/Talks/Talks2024.tsx | 6 +-
.../NotFoundError/NotFoundError.tsx | 2 +-
src/components/Swiper/SpeakerSwiper.tsx | 181 +-
.../useDocumentTitleUpdate.ts | 0
.../useSentryErrorReport.ts | 0
src/views/About/About.tsx | 2 +-
src/views/Attendee/AttendeeInformation.tsx | 46 +-
src/views/Cfp/CfpSection.tsx | 101 +-
src/views/CodeOfConduct/CodeOfConduct.tsx | 2 +-
src/views/Communities/Communities.tsx | 6 +-
src/views/Conditions/Conditions.tsx | 2 +-
src/views/Diversity/Diversity.tsx | 2 +-
src/views/Home/HomeWrapper.tsx | 2 +-
src/views/JobOffers/JobOffers.tsx | 25 +-
src/views/MeetingDetail/MeetingDetail.tsx | 28 +-
.../MeetingDetail/TalkDetailContainer.tsx | 6 +-
src/views/Schedule/Schedule.tsx | 7 +-
src/views/SessionFeedback/SessionFeedback.tsx | 9 +-
.../SpeakerDetail/SpeakerDetailContainer.tsx | 6 +-
src/views/Speakers/Speakers.tsx | 18 +-
src/views/Talks/LiveView.tsx | 8 +-
src/views/Talks/Talks.tsx | 6 +-
src/views/Travel/Travel.tsx | 2 +-
src/views/Workshops/Workshops.tsx | 13 +-
src/views/kcd/Kcd.tsx | 2 +-
src/views/sponsorship/Sponsorship.tsx | 2 +-
static-analysis.datadog.yml | 11 +
51 files changed, 4959 insertions(+), 429 deletions(-)
create mode 100644 .output.txt
rename src/{services => hooks}/useDocumentTitleUpdate.ts (100%)
rename src/{services => hooks}/useSentryErrorReport.ts (100%)
create mode 100644 static-analysis.datadog.yml
diff --git a/.output.txt b/.output.txt
new file mode 100644
index 000000000..9b51d145b
--- /dev/null
+++ b/.output.txt
@@ -0,0 +1,4538 @@
+ />
+
+
+ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
+
+
+
+
+
+ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
+
+
+
+
+
+ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
+
+
+
+
+
+ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
+
+
+
+
+
+
+
+
+