diff --git a/pwa/api/contributorsRank.ts b/pwa/api/contributorsRank.ts index 117e6a9f8..5528be91f 100644 --- a/pwa/api/contributorsRank.ts +++ b/pwa/api/contributorsRank.ts @@ -145,29 +145,42 @@ export const getAllContributors = async () => { ); const allContributors = await Promise.all( sortedContributors.map(async (contributor) => { - const { data } = await octokit.rest.users.getByUsername({ - username: contributor.login || "", - }); - if (data.blog) { - data.blog = addHttpsToUrls(data.blog); - } + try { + const { data } = await octokit.rest.users.getByUsername({ + username: contributor.login || "", + }); + if (data.blog) { + data.blog = addHttpsToUrls(data.blog); + } - return { - login: data.login, - repos: contributor.repos, - rank: contributor.rank, - contributions: contributor.contributions, - isCoreTeam: contributor.isCoreTeam, - avatar_url: contributor.avatar_url, - bio: data.bio, - name: data.name, - location: data.location, - company: data.company, - blog: data.blog, - }; + return { + login: data.login, + repos: contributor.repos, + rank: contributor.rank, + contributions: contributor.contributions, + isCoreTeam: contributor.isCoreTeam, + avatar_url: contributor.avatar_url, + bio: data.bio, + name: data.name, + location: data.location, + company: data.company, + blog: data.blog, + }; + } catch (e: any) { + // Some accounts (e.g. the Copilot bot) have no public user + // profile and return 404. Skip them instead of failing the + // whole run, which would wipe the entire dataset. + if (e?.status === 404) { + console.warn( + `Skipping contributor without a user profile: ${contributor.login}` + ); + return null; + } + throw e; + } }) ); - return allContributors; + return allContributors.filter(Boolean); } catch (e) { console.error(e); return []; diff --git a/pwa/app/(con)/[locale]/con/[edition]/conferences/ConferencesPage.tsx b/pwa/app/(con)/[locale]/con/[edition]/conferences/ConferencesPage.tsx index 8e6dd5d19..c045ab311 100644 --- a/pwa/app/(con)/[locale]/con/[edition]/conferences/ConferencesPage.tsx +++ b/pwa/app/(con)/[locale]/con/[edition]/conferences/ConferencesPage.tsx @@ -1,7 +1,7 @@ "use client"; -import React, { Fragment, useContext } from "react"; +import React, { Fragment, useContext, useState } from "react"; import SectionTitle from "components/con/common/typography/SectionTitle"; -import { Conference, Day } from "types/con"; +import { Conference, Day, Track } from "types/con"; import { LanguageContext } from "contexts/con/LanguageContext"; import styles from "./conferencesPage.module.css"; import SpeakerImage2025 from "components/con/speakers/SpeakerImage2025"; @@ -10,166 +10,285 @@ import classNames from "classnames"; import { getConferenceDate } from "utils/con"; import Link from "next/link"; import TagLabel from "components/con/conferences/TagLabel"; +import ScheduleDay from "../schedule/components/ScheduleDay"; + +type ViewMode = "list" | "agenda"; interface ConferencesProps { conferences: Conference[]; + scheduleConferences: Conference[]; + tracks: Track[]; edition: string; days: Day[]; } +function ViewToggle({ + view, + onChange, +}: { + view: ViewMode; + onChange: (view: ViewMode) => void; +}) { + const { t } = useContext(LanguageContext); + const options: { value: ViewMode; label: string; icon: JSX.Element }[] = [ + { + value: "list", + label: t("conferences.view_list"), + icon: ( + + ), + }, + { + value: "agenda", + label: t("conferences.view_agenda"), + icon: ( + + ), + }, + ]; + + return ( +
+ + {day.title?.[locale]} + + {conference.track + ? ` - ${conference.track.title?.[locale]}` + : null} +
+ ) : null} + {conference.date ? ( ++ {getConferenceDate( + conference.date, + conference.start, + conference.end + )} +
+ ) : null} + > + {conference.description ? (- - {day.title?.[locale]} - - {conference.track - ? ` - ${conference.track.title?.[locale]}` - : null} -
- ) : null} - {conference.date ? ( -- {getConferenceDate( - conference.date, - conference.start, - conference.end + "font-light leading-relaxed mt-4 text-justify md:text-left", + styles.description )} -
+ dangerouslySetInnerHTML={{ + __html: conference.description.replaceAll( + "h2>", + "h3>" + ), + }} + /> ) : null} - > - {conference.description ? ( -