Skip to content

Commit 842abd9

Browse files
committed
feat: add register page
1 parent e825fd4 commit 842abd9

File tree

10 files changed

+392
-61
lines changed

10 files changed

+392
-61
lines changed

pwa/app/(con)/[locale]/con/2025/call-for-papers/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
2020
alternates: {
2121
languages: {
2222
en: locale === "en" ? undefined : "/con/2025",
23-
fr: locale === "fr" ? undefined : "/fr/con/2024",
23+
fr: locale === "fr" ? undefined : "/fr/con/2025",
2424
},
2525
},
2626
};

pwa/app/(con)/[locale]/con/2025/components/HomePage.tsx

Lines changed: 86 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,19 @@ import Button from "components/con/common/Button";
33
import SpeakerList from "components/con/speakers/SpeakerList";
44
import SectionTitle from "components/con/common/typography/SectionTitle";
55
import SectionSubTitle from "components/con/common/typography/SectionSubtitle";
6-
import Web from "components/con/common/Web";
6+
import { currentEdition } from "data/con/editions";
77
import Wave from "components/con/common/Wave";
88
import Venue from "components/con/home/Venue";
9-
import Image from "next/image";
109
import Partners from "components/con/home/Partners";
1110
import LookingSponsorCard from "components/con/home/LookingSponsorCard";
1211
import { Partner, Speaker } from "types/con";
1312
import { useContext } from "react";
1413
import { LanguageContext } from "contexts/con/LanguageContext";
1514
import Section from "components/con/home/Section";
16-
import PictureGallery from "components/con/common/PictureGallery";
15+
import prices from "data/con/2024/prices";
1716
import Logo from "./Logo";
18-
import AfterMovie from "app/con/2024/components/AfterMovie";
17+
import PricingCard from "components/con/home/Pricing/PricingCard";
18+
import BuyButton from "components/con/common/BuyButton";
1919

2020
type HomePageProps = {
2121
speakers: Speaker[];
@@ -43,61 +43,28 @@ const HomePage = ({ speakers, partners, images }: HomePageProps) => {
4343
{t("2025.subbaseline")}
4444
</p>
4545
<div className="flex gap-2">
46-
<Button className="pink" to={`/${locale}/con/2024/review`}>
46+
{currentEdition === "2025" && (
47+
<BuyButton className="mr-2" id="cover">
48+
{t("buy_tickets")}
49+
</BuyButton>
50+
)}
51+
<Button empty to={`/${locale}/con/2024/review`}>
4752
{t("2025.previous_edition")}
4853
</Button>
4954
</div>
5055
</div>
5156
</div>
5257
<Wave className="absolute opacity-30 z-0 bottom-0 h-[60vh] right-[7%] top-[63%] -translate-y-1/2" />
5358
</Section>
54-
<Section
55-
section="lastYear"
56-
className="bg-white z-10 relative pb-10 overflow-y-clip"
57-
>
58-
<div className="container text-center">
59-
<SectionTitle>
60-
<Translate translationKey="last_edition.title" />
61-
</SectionTitle>
62-
<SectionSubTitle>
63-
<Translate
64-
translationKey="2025.see_review.subtitle"
65-
translationParams={{
66-
edition: "2024",
67-
link: (
68-
<a href={`/${locale}/con/2024/review`} className="link">
69-
{t("2025.see_review.link")}
70-
</a>
71-
),
72-
}}
73-
/>
74-
</SectionSubTitle>
75-
<PictureGallery
76-
className="py-4"
77-
link="https://www.flickr.com/photos/194052559@N02/albums/72177720320499314/"
78-
>
79-
{images.map((image: string) => (
80-
<Image
81-
className="object-cover"
82-
key={image}
83-
fill
84-
src={image}
85-
alt=""
86-
sizes="(max-width: 640px) 200px, (max-width: 768px) 240px, (max-width: 1536px) 300px, 400px"
87-
/>
88-
))}
89-
</PictureGallery>
90-
</div>
91-
</Section>
9259
<Section
9360
section="speakers"
94-
className="z-10 relative py-4 overflow-x-hidden text-white"
61+
className="bg-white z-10 relative py-4 overflow-x-hidden"
9562
>
9663
<div className="container text-center">
97-
<SectionTitle dark h1>
64+
<SectionTitle h1>
9865
<Translate translationKey="2025.our_speakers.title" />
9966
</SectionTitle>
100-
<SectionSubTitle dark>
67+
<SectionSubTitle>
10168
<Translate
10269
translationKey="2025.our_speakers.subtitle"
10370
translationParams={{
@@ -130,15 +97,86 @@ const HomePage = ({ speakers, partners, images }: HomePageProps) => {
13097
</Button>
13198
</div>
13299
</Section>
100+
{currentEdition === "2025" && (
101+
<Section
102+
className="relative py-10 before:bg-grey before:h-[calc(100%-500px)] before:absolute before:left-0 before:bottom-0 before:w-full after:bg-wave2 after:w-[1300px] after:h-[800px] after:absolute after:top-24 after:left-1/2 after:bg-top after:bg-contain after:opacity-50 after:bg-no-repeat after:-translate-x-1/2 after:rotate-6"
103+
section="pricing"
104+
>
105+
<div className="container relative z-10">
106+
<SectionTitle dark>
107+
<Translate translationKey="pricing.title" />
108+
</SectionTitle>
109+
<div className="max-w-4xl mx-auto flex flex-row flex-wrap justify-center">
110+
{prices.map((price) => (
111+
<PricingCard key={price.id} price={price} />
112+
))}
113+
<div className="w-full self-center max-w-md mt-10 | lg:pl-10 lg:mt-0 lg:w-1/3">
114+
<div className="p-5 dotted-corner flex flex-col items-center text-center bg-blue bg-blue-gradient shadow-md border-blue-dark border-4">
115+
<span className="font-bold text-white leading-tight font-title uppercase lined-center lined-white relative">
116+
{t("pricing.student")}
117+
</span>
118+
<div className="mt-2 text-blue-black/80 font-semibold">
119+
<Translate translationKey="pricing.free_ticket" />
120+
</div>
121+
<Button
122+
size="small"
123+
square
124+
className="white mt-2 mb-5"
125+
to="mailto:events@les-tilleuls.coop"
126+
>
127+
{t("contact_us")}
128+
</Button>
129+
<small className="text-xs text-blue-black/50 font-bold">
130+
*{t("pricing.certificate_needed")}
131+
</small>
132+
</div>
133+
</div>
134+
</div>
135+
</div>
136+
</Section>
137+
)}
138+
<Venue subtitle={t("2025.venue.subtitle")} />
139+
<Section
140+
section="lastYear"
141+
className=" z-10 relative pb-10 overflow-y-clip"
142+
>
143+
<div className="container text-center flex flex-col items-center pt-12">
144+
<SectionTitle dark>
145+
<Translate translationKey="last_edition.title" />
146+
</SectionTitle>
147+
<SectionSubTitle dark>
148+
<Translate
149+
translationKey="2025.see_review.subtitle"
150+
translationParams={{
151+
edition: "2024",
152+
link: (
153+
<a href={`/${locale}/con/2024/review`} className="link">
154+
{t("2025.see_review.link")}
155+
</a>
156+
),
157+
}}
158+
/>
159+
</SectionSubTitle>
160+
<iframe
161+
className="aspect-video w-full max-w-2xl border-white border-8 shadow-2xl"
162+
src="https://www.youtube.com/embed/XXj8NCvLuis?si=hWGWKS81UriUkJ3R&amp;controls=0"
163+
title="YouTube video player"
164+
frameBorder="0"
165+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
166+
referrerPolicy="strict-origin-when-cross-origin"
167+
allowFullScreen
168+
></iframe>
169+
</div>
170+
</Section>
133171
<Section
134172
section="missing"
135-
className="relative z-10 text-center overflow-y-clip bg-white"
173+
className="relative bg-grey z-10 text-center overflow-y-clip"
136174
>
137175
<div className="container text-center">
138176
<SectionTitle>
139177
<Translate
140178
translationKey="missing_conferences.title"
141-
translationParams={{ edition: "2024" }}
179+
translationParams={{ edition: "2025" }}
142180
/>
143181
</SectionTitle>
144182
<SectionSubTitle>{t("missing_conferences.subtitle")}</SectionSubTitle>
@@ -151,10 +189,6 @@ const HomePage = ({ speakers, partners, images }: HomePageProps) => {
151189
</Button>
152190
</div>
153191
</Section>
154-
<div className="pb-12">
155-
<AfterMovie />
156-
</div>
157-
<Venue subtitle={t("2025.venue.subtitle")} />
158192
<Section section="sponsorship" className="py-8">
159193
<div className="container text-center">
160194
<SectionTitle dark>

pwa/app/(con)/[locale]/con/2025/layout.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,7 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
4141
function EditionLayout({ children }: { children: React.ReactNode }) {
4242
const eventData = getEditionEventData("2025");
4343
return (
44-
<LayoutBase
45-
edition="2025"
46-
nav={nav}
47-
footer={footer}
48-
isTicketingOpen={false}
49-
>
44+
<LayoutBase edition="2025" nav={nav} footer={footer} isTicketingOpen>
5045
<script
5146
type="application/ld+json"
5247
dangerouslySetInnerHTML={{ __html: JSON.stringify(eventData) }}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
"use client";
2+
import { useContext } from "react";
3+
import { LanguageContext } from "contexts/con/LanguageContext";
4+
import SectionTitle from "components/con/common/typography/SectionTitle";
5+
import SectionSubTitle from "components/con/common/typography/SectionSubtitle";
6+
import Script from "next/script";
7+
import prices from "data/con/2025/prices";
8+
import { Offer } from "types/con";
9+
import dayjs from "dayjs";
10+
import classNames from "classnames";
11+
import { toLocaleDate } from "utils/con";
12+
13+
export default function RegisterPage() {
14+
const { t, Translate, locale, getLocaleDictionary } =
15+
useContext(LanguageContext);
16+
const timelinePrices = prices
17+
.find((p) => p.id === 1)
18+
?.offers.filter((o) => o.type);
19+
20+
const isActiveOffer = (offer: Offer) => {
21+
if (offer.limitDate && dayjs(offer.limitDate).isBefore(dayjs(), "day"))
22+
return false;
23+
if (offer.startDate && dayjs(offer.startDate).isAfter(dayjs(), "day"))
24+
return false;
25+
return true;
26+
};
27+
28+
const isPastOffer = (offer: Offer) => {
29+
if (isActiveOffer(offer)) return false;
30+
if (offer.startDate && dayjs(offer.startDate).isBefore(dayjs(), "day"))
31+
return true;
32+
return false;
33+
};
34+
35+
const expectations =
36+
getLocaleDictionary?.()[2025].tickets.expect.points || [];
37+
38+
const onIframeLoaded = () => {
39+
const iframe = document.getElementById("yurplan-widget-141690") as HTMLIFrameElement | null;
40+
if (!iframe) return;
41+
const contenu = iframe.contentWindow?.document.body.scrollHeight;
42+
iframe.style.height = contenu + "px";
43+
}
44+
45+
return (
46+
<>
47+
<div className="container max-w-5xl flex flex-col items-center py-12 relative z-10">
48+
<SectionTitle small h1 dark lined>
49+
<Translate translationKey="2025.tickets.title" />
50+
</SectionTitle>
51+
<SectionSubTitle dark>{t("2025.tickets.subtitle")}</SectionSubTitle>
52+
</div>
53+
<div className="after:h-1/3 after:absolute after:w-full after:bg-grey after:bottom-0 after:left-0 relative">
54+
<div className="container max-w-6xl relative z-10">
55+
<div className="flex flex-col lg:flex-row w-full max-w-6xl items-center lg:items-start">
56+
<div className="translate-y-12 relative z-10 w-4/5 lg:w-2/5 max-w-md before:absolute before:w-full before:h-full before:bg-blue before:-translate-x-3 before:-translate-y-3 before:left-0 before:top-0">
57+
<img
58+
className="relative"
59+
src="/images/con/2024/review/pic-06.jpg"
60+
/>
61+
</div>
62+
<div className="flex-1 relative bg-white shadow-floating dotted-corner p-12 pt-24 lg:pt-12 lg:pl-24 lg:-translate-x-12 leading-relaxed font-light">
63+
<Translate translationKey="2025.tickets.description" />
64+
<p className="mt-4 text-lg font-bold">
65+
{t("2025.tickets.description2")}
66+
</p>
67+
</div>
68+
</div>
69+
</div>
70+
</div>
71+
<div className="bg-grey py-12">
72+
<div className="container max-w-6xl">
73+
<SectionTitle small lined>
74+
<Translate translationKey="2025.tickets.expect.title" />
75+
</SectionTitle>
76+
<div className="mx-auto max-w-64 sm:max-w-xl grid grid-cols-1 sm:grid-cols-2 xl:max-w-none xl:grid-cols-4 gap-8 text-white">
77+
{expectations.map((e, i) => (
78+
<div
79+
key={i}
80+
className={classNames(
81+
"p-8 aspect-square flex flex-col justify-center",
82+
i === 0 && "bg-blue-dark",
83+
i === 1 && "bg-blue-black/80",
84+
i === 2 && "bg-blue-darkest",
85+
i === 3 && "bg-blue-dark"
86+
)}
87+
>
88+
<p className="uppercase font-bold text-xl">{e.title}</p>
89+
<p>{e.text}</p>
90+
</div>
91+
))}
92+
</div>
93+
</div>
94+
</div>
95+
<div className="bg-white">
96+
<div className="container max-w-4xl py-12">
97+
<SectionTitle small lined>
98+
<strong>{t("2025.tickets.buy")}</strong>
99+
</SectionTitle>
100+
<div className="hidden relative w-full gap-0 md:grid grid-cols-3 py-12 overflow-hidden">
101+
<div className="absolute w-1.5 h-full left-4 -translate-x-1/2 md:-translate-x-0 top-0 md:h-1.5 md:w-full md:top-1/2 md:left-0 md:-translate-y-1/2 bg-blue-black/30"></div>
102+
{timelinePrices?.map((p) => (
103+
<div
104+
key={p.type}
105+
className="relative flex flex-col items-center gap-2"
106+
>
107+
<div className="ml-8 md:ml-0 whitespace-nowrap absolute left-full md:left-1/2 top-1/2 -translate-y-1/2 -translate-x-1/2">
108+
<div
109+
className={classNames(
110+
"font-bold uppercase md:mb-12 text-left md:text-center",
111+
isActiveOffer(p) ? "text-blue" : isPastOffer(p) ? "text-blue-black/30" : "text-blue-black"
112+
)}
113+
>
114+
{p.type}
115+
</div>
116+
<p className={classNames(isPastOffer(p) ? "text-blue-black/30" : "text-blue-black/70")}>
117+
{t("2025.tickets.until_date", {
118+
date: toLocaleDate(p.limitDate as string),
119+
})}
120+
</p>
121+
</div>
122+
<div
123+
className={classNames(
124+
"relative rounded-full border-4 size-8",
125+
isActiveOffer(p)
126+
? "border-blue bg-blue before:h-screen before:w-1.5 before:md:w-screen before:absolute before:md:h-1.5 before:bottom-full before:-translate-x-1/2 before:md:-translate-x-0 before:md:right-full before:bg-blue before:left-1/2 before:md:left-auto before:md:top-1/2 before:md:-translate-y-1/2"
127+
: isPastOffer(p) ? "border-blue bg-white z-10" : "border-blue-black/30 bg-white"
128+
)}
129+
/>
130+
</div>
131+
))}
132+
</div>
133+
<div className="yurplan-widget-container max-w-5xl container pb-40 md:pt-12 -mb-[180px]">
134+
<iframe
135+
onLoad={() => onIframeLoaded()}
136+
title="yurplan"
137+
src={`https://yurplan.com/events/API-Platform-Conference-2025/138927/tickets/widget?widget=dGlja2V0aW5nV2lkZ2V0WXBfMTM2ODk5XzE0MTY5MA%3D%3D&from=widget_141690&wversion=1&culture=${locale}`}
138+
width="100%"
139+
height="100%"
140+
frameBorder="0"
141+
scrolling="no"
142+
className="yurplan-widget"
143+
style={{ height: "auto", clipPath: "inset(0px 0px 180px 0px);" }}
144+
id="yurplan-widget-141690"
145+
data-id="141690"
146+
></iframe>
147+
</div>
148+
<Script
149+
type="text/javascript"
150+
src="https://assets.yurplan.com/yurplan-v1/dist/widget.js"
151+
/>
152+
</div>
153+
</div>
154+
</>
155+
);
156+
}
157+

0 commit comments

Comments
 (0)