From 888172dea47c3d3cd0d7b94a37b5c4ad9317255b Mon Sep 17 00:00:00 2001 From: Domingo Dirutigliano Date: Wed, 18 Sep 2024 13:21:09 +0200 Subject: [PATCH 01/14] fix: removed endTime forcing on schedule --- .../Schedule/Pages/ScheduleList.astro | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/components/Schedule/Pages/ScheduleList.astro b/src/components/Schedule/Pages/ScheduleList.astro index 01acf33..7e12595 100644 --- a/src/components/Schedule/Pages/ScheduleList.astro +++ b/src/components/Schedule/Pages/ScheduleList.astro @@ -4,27 +4,7 @@ import ScheduleCard from "../ScheduleCard.astro"; import { getLangFromUrl, useTranslations } from "../../../i18n/utils"; import { getSchedule } from "../../../data/api/sessionize_api"; -const schedule = (await getSchedule()).map((s) => { - s.rooms = s.rooms.map((r) => { - r.sessions = r.sessions.map((si) => { - if (si.title.indexOf("42!") != -1){ - si.endsAt = "2024-10-26T14:35:00Z" - } - return si - }); - return r - }); - s.timeSlots = s.timeSlots.map((ts) => { - ts.rooms = ts.rooms.map((r) => { - if (r.session.title.indexOf("42!") != -1){ - r.session.endsAt = "2024-10-26T14:35:00Z" - } - return r - }); - return ts - }) - return s -}); +const schedule = await getSchedule() const lang = getLangFromUrl(Astro.url); const t = useTranslations(lang); From 37e8bdc72b8349a122f7b780ccc460ccdc521589 Mon Sep 17 00:00:00 2001 From: Domingo Dirutigliano Date: Wed, 18 Sep 2024 14:33:43 +0200 Subject: [PATCH 02/14] add: tabulated schedules --- .../Schedule/Pages/ScheduleList.astro | 210 ++++-------------- .../Schedule/Pages/ScheduleTab.astro | 180 +++++++++++++++ 2 files changed, 224 insertions(+), 166 deletions(-) create mode 100644 src/components/Schedule/Pages/ScheduleTab.astro diff --git a/src/components/Schedule/Pages/ScheduleList.astro b/src/components/Schedule/Pages/ScheduleList.astro index 7e12595..e1f962b 100644 --- a/src/components/Schedule/Pages/ScheduleList.astro +++ b/src/components/Schedule/Pages/ScheduleList.astro @@ -3,179 +3,57 @@ import ScheduleCard from "../ScheduleCard.astro"; import { getLangFromUrl, useTranslations } from "../../../i18n/utils"; import { getSchedule } from "../../../data/api/sessionize_api"; +import ScheduleTab from "./ScheduleTab.astro"; + + +/* + - 51235:"Frontend" + - 51236:"Mobile" + - 51237:"Cloud" + - 53346:"Soft skill" + - 53347:"AI" + - 53348:"WS I" + - 53349:"WS II" + - 53350:"WS III" +*/ + + const schedule = await getSchedule() const lang = getLangFromUrl(Astro.url); const t = useTranslations(lang); +const tab1Rooms = [51235, 51236, 51237, 53347, 53346]; +const tab2Rooms = [53348, 53349, 53350]; + ---
- -{ - schedule.map((s) => { - const totalScheduleCols = s.rooms.length; - const totalScheduleRows = s.timeSlots.length; - let skipPadding: {[key:string]:number} = s.rooms.map((room) => ({[room.id]:0})).reduce((a,b)=>({...a,...b}),{}) - return ( -
-

- {new Date(s.date).toLocaleDateString("en-US", { - day: "numeric", - month: "long", - weekday: "long", - })} -

- {/* Some classes are created manually due to tilewind issues */} -
- {s.timeSlots.map((ts,ts_idx) => { - - const hasServiceSession = ts.rooms.some( - (tsr) => tsr.session.isServiceSession, - ); - - const sessionsInTimeSlot = ts.rooms.map((tsr) => { - const endDate = new Date(tsr.session.endsAt); - endDate.setSeconds(0) - endDate.setMilliseconds(0) - const slots = !hasServiceSession? ( - //Function that calculate the rows to take for this session - (()=>{ - //Calculate the space to take (how many timeSlot takes this session (until a service session)) - let session_len = 1 - let last_is_service = false - for (let i = ts_idx+1; i < s.timeSlots.length; i++){ - //No sessions - if (s.timeSlots[i].rooms.length == 0) continue - //Take time from one of the sessions - //Get next start date - const next_date = new Date(s.timeSlots[i].rooms[0].session.startsAt) - next_date.setSeconds(0) - next_date.setMilliseconds(0) - //If it's a service session, can't take this space - if (s.timeSlots[i].rooms.some( (tsr) => tsr.session.isServiceSession)){ - last_is_service = true - continue //We need to check if replicate this session for the next timeSlot that is not a service session - } - if (last_is_service){ //We stopped at a service session and need to check if replicate this session in next timeSlots - if (next_date < endDate){ - s.timeSlots[i].rooms.push(tsr) //Replicate - } - break - } - //Continue to get space until this session ends - if (next_date < endDate){ - session_len ++ - }else{ - break - } - } - return session_len - })() - ) : 1; - if (slots > 1){ - skipPadding[tsr.id.toString()] = slots-1 - } - return { - data: tsr, - html:
- -
- }; - }); - - const orderedSessions = ( - !hasServiceSession? - s.rooms.map( - (room) => { - let session = sessionsInTimeSlot.find((target) => room.id == target.data.id) - if (!session){ - if (skipPadding[room.id.toString()]){ - skipPadding[room.id.toString()]-- - return null - } - return
- } - return session?.html - } - ).filter((ele)=>ele!=null) : sessionsInTimeSlot.map((session) => session.html) - ) - - return [ -
-

{ts.slotStart.substring(0, 5)}

-
, - ...orderedSessions - ]; - })} -
-
- ); - }) - } +
+ +
+ +
+ + +
+ +
+
+ {schedule.length == 0?

{t("scheduling.noschedule")}

:null} - +
\ No newline at end of file diff --git a/src/components/Schedule/Pages/ScheduleTab.astro b/src/components/Schedule/Pages/ScheduleTab.astro new file mode 100644 index 0000000..a1b0e48 --- /dev/null +++ b/src/components/Schedule/Pages/ScheduleTab.astro @@ -0,0 +1,180 @@ +--- +import ScheduleCard from "../ScheduleCard.astro"; + +interface Props { + schedule: any; + rooms?: any; +} + +const { schedule, rooms } = Astro.props; + +const calcSlotsTaken = (s, tsr, ts_idx) => { + const endDate = new Date(tsr.session.endsAt); + endDate.setSeconds(0) + endDate.setMilliseconds(0) + //Calculate the space to take (how many timeSlot takes this session (until a service session)) + let session_len = 1; + let last_is_service = false; + for (let i = ts_idx+1; i < s.timeSlots.length; i++){ + //No sessions + if (s.timeSlots[i].rooms.length == 0) continue + //Take time from one of the sessions + //Get next start date + const next_date = new Date(s.timeSlots[i].rooms[0].session.startsAt) + next_date.setSeconds(0) + next_date.setMilliseconds(0) + //If it's a service session, can't take this space + if (s.timeSlots[i].rooms.some( (tsr) => tsr.session.isServiceSession)){ + last_is_service = true + continue //We need to check if replicate this session for the next timeSlot that is not a service session + } + if (last_is_service){ //We stopped at a service session and need to check if replicate this session in next timeSlots + if (next_date < endDate){ + s.timeSlots[i].rooms.push(tsr) //Replicate + } + break + } + //Continue to get space until this session ends + if (next_date < endDate){ + session_len ++ + }else{ + break + } + } + return session_len + } + + +--- +
+ {schedule.map((s) => { + const roomsSelected = rooms?s.rooms.filter((r) => rooms.includes(r.id)):s.rooms + const totalScheduleCols = roomsSelected.length; + const totalScheduleRows = s.timeSlots.length; + let skipPadding: {[key:string]:number} = roomsSelected.map((room) => ({[room.id]:0})).reduce((a,b)=>({...a,...b}),{}); + return <> +
+

+ {new Date(s.date).toLocaleDateString("en-US", { + day: "numeric", + month: "long", + weekday: "long", + })} +

+ {/* Some classes are created manually due to tilewind issues */} +
+ {s.timeSlots.map((ts,ts_idx) => { + + const hasServiceSession = ts.rooms.some( + (tsr) => tsr.session.isServiceSession, + ); + + const sessionsInTimeSlot = ts.rooms.map((tsr) => { + const slots = !hasServiceSession? calcSlotsTaken(s, tsr, ts_idx) : 1; + if (slots > 1){ + skipPadding[tsr.id.toString()] = slots-1 + } + return { + data: tsr, + html: <> +
+ +
+ , + }; + }); + + const orderedSessions = ( + !hasServiceSession? + roomsSelected.map( + (room) => { + let session = sessionsInTimeSlot.find((target) => room.id == target.data.id) + if (!session){ + if (skipPadding[room.id.toString()]){ + skipPadding[room.id.toString()]-- + return null + } + return <>
+ } + return session?.html + } + ).filter((ele)=>ele!=null) : sessionsInTimeSlot.map((session) => session.html) + ) + + return [ +
+

{ts.slotStart.substring(0, 5)}

+
, + ...orderedSessions + ]; + })} +
+
+ + }) + } + +
\ No newline at end of file From 36c3fbec7687bb05e5fca498d12e4cecbcf3939a Mon Sep 17 00:00:00 2001 From: Domingo Dirutigliano Date: Wed, 18 Sep 2024 15:01:55 +0200 Subject: [PATCH 03/14] fix: minor general fixes --- public/assets/vectors/pin.svg | 2 +- public/assets/vectors/time.svg | 4 ++-- .../Schedule/Pages/ScheduleList.astro | 4 ---- .../Schedule/Pages/ScheduleTab.astro | 12 ++++++---- .../Sessions/Pages/SessionDetail.astro | 23 +++++-------------- src/components/Sessions/SessionCard.astro | 2 +- .../Speakers/Pages/SpeakerDetail.astro | 2 +- src/i18n/ui.ts | 2 ++ src/react/utils/index.ts | 6 ++--- 9 files changed, 24 insertions(+), 33 deletions(-) diff --git a/public/assets/vectors/pin.svg b/public/assets/vectors/pin.svg index 3bcd148..f9e90dd 100644 --- a/public/assets/vectors/pin.svg +++ b/public/assets/vectors/pin.svg @@ -1,3 +1,3 @@ - + diff --git a/public/assets/vectors/time.svg b/public/assets/vectors/time.svg index b0175e1..7c36279 100644 --- a/public/assets/vectors/time.svg +++ b/public/assets/vectors/time.svg @@ -1,10 +1,10 @@ - + - + diff --git a/src/components/Schedule/Pages/ScheduleList.astro b/src/components/Schedule/Pages/ScheduleList.astro index e1f962b..14a2b03 100644 --- a/src/components/Schedule/Pages/ScheduleList.astro +++ b/src/components/Schedule/Pages/ScheduleList.astro @@ -1,11 +1,9 @@ --- -import ScheduleCard from "../ScheduleCard.astro"; import { getLangFromUrl, useTranslations } from "../../../i18n/utils"; import { getSchedule } from "../../../data/api/sessionize_api"; import ScheduleTab from "./ScheduleTab.astro"; - /* - 51235:"Frontend" - 51236:"Mobile" @@ -17,8 +15,6 @@ import ScheduleTab from "./ScheduleTab.astro"; - 53350:"WS III" */ - - const schedule = await getSchedule() const lang = getLangFromUrl(Astro.url); const t = useTranslations(lang); diff --git a/src/components/Schedule/Pages/ScheduleTab.astro b/src/components/Schedule/Pages/ScheduleTab.astro index a1b0e48..38ba55f 100644 --- a/src/components/Schedule/Pages/ScheduleTab.astro +++ b/src/components/Schedule/Pages/ScheduleTab.astro @@ -1,11 +1,15 @@ --- +import type { ScheduleDay } from "../../../data/types/sessionize"; +import { getLangFromUrl } from "../../../i18n/utils"; import ScheduleCard from "../ScheduleCard.astro"; +import { capitalizeFirstLetter } from "../../../react/utils"; interface Props { - schedule: any; - rooms?: any; + schedule: ScheduleDay[]; + rooms?: number[]; } +const lang = getLangFromUrl(Astro.url); const { schedule, rooms } = Astro.props; const calcSlotsTaken = (s, tsr, ts_idx) => { @@ -55,11 +59,11 @@ const calcSlotsTaken = (s, tsr, ts_idx) => { return <>

- {new Date(s.date).toLocaleDateString("en-US", { + {capitalizeFirstLetter(new Date(s.date).toLocaleDateString(lang, { day: "numeric", month: "long", weekday: "long", - })} + }))}

{/* Some classes are created manually due to tilewind issues */}
diff --git a/src/components/Sessions/Pages/SessionDetail.astro b/src/components/Sessions/Pages/SessionDetail.astro index 913e887..a29e0c6 100644 --- a/src/components/Sessions/Pages/SessionDetail.astro +++ b/src/components/Sessions/Pages/SessionDetail.astro @@ -5,6 +5,7 @@ import { getLangFromUrl, useTranslatedPath, useTranslations } from '../../../i18 import AddToCalendar from '../../Common/AddToCalendar.astro'; import BaseLayout from '../../Common/BaseLayout.astro'; import SessionTopic from '../SessionTopic.astro'; +import { capitalizeFirstLetter } from "../../../react/utils"; interface Props { entry: SessionInfo; @@ -30,33 +31,21 @@ const dateEnd = new Date(entry.endsAt); const isScheduled = dateStart.getTime() != 0; -var date = dateStart.toLocaleDateString("en-US", { +var date = capitalizeFirstLetter(dateStart.toLocaleDateString(lang, { day: "numeric", month: "short", -}); +})); -const start = dateStart.toLocaleTimeString("en-US", { +const start = dateStart.toLocaleTimeString(lang, { hour: "numeric", minute: "numeric", }); -const end = dateEnd.toLocaleTimeString("en-US", { +const end = dateEnd.toLocaleTimeString(lang, { hour: "numeric", minute: "numeric", }); -function formatDate(date: Date) { - const year = date.getUTCFullYear(); - const month = date.getUTCMonth() + 1; - const day = date.getUTCDate(); - const hours = date.getUTCHours(); - const minutes = date.getUTCMinutes(); - - return `${year}${month}${day > 9 ? day : "0" + day}T${ - hours > 9 ? hours : "0" + hours - }${minutes > 9 ? minutes : "0" + minutes}00Z`; -} - const pageTitle = entry.title; const pageDesc = entry.description; --- @@ -92,7 +81,7 @@ const pageDesc = entry.description; {entry.topics.map((t) => )}
-

{entry.room}

+

{t("session.room")}: {entry.room}

{ isScheduled && (

diff --git a/src/components/Sessions/SessionCard.astro b/src/components/Sessions/SessionCard.astro index 134e81b..8c88553 100644 --- a/src/components/Sessions/SessionCard.astro +++ b/src/components/Sessions/SessionCard.astro @@ -23,7 +23,7 @@ const t = useTranslations(lang); ---

{session.title}

diff --git a/src/components/Speakers/Pages/SpeakerDetail.astro b/src/components/Speakers/Pages/SpeakerDetail.astro index e0c4377..5bdceed 100644 --- a/src/components/Speakers/Pages/SpeakerDetail.astro +++ b/src/components/Speakers/Pages/SpeakerDetail.astro @@ -70,7 +70,7 @@ const pageTitle = `${speaker.fullName} @ ${WebsiteConfig.DEVFEST_NAME}`; const dateStart = new Date(session.startsAt); const dateEnd = new Date(session.endsAt); - const date = dateStart.toLocaleDateString("en-US", { + const date = dateStart.toLocaleDateString(lang, { month: "long", day: "numeric", }); diff --git a/src/i18n/ui.ts b/src/i18n/ui.ts index 061e2c7..9637e90 100644 --- a/src/i18n/ui.ts +++ b/src/i18n/ui.ts @@ -40,6 +40,7 @@ export const ui = { 'speakers.detailTitle': 'Speaker details', 'speakers.sessionList': 'Sessions', 'scheduling.noschedule': 'Schedule not available', + 'session.room': 'Room', }, it: { 'nav.home': 'Home', @@ -74,5 +75,6 @@ export const ui = { 'speakers.detailTitle': 'Dettagli speaker', 'speakers.sessionList': 'Sessioni', 'scheduling.noschedule': 'Schedule non disponibile', + 'session.room': 'Aula', }, } as const; \ No newline at end of file diff --git a/src/react/utils/index.ts b/src/react/utils/index.ts index 07bbbcc..210d2b0 100644 --- a/src/react/utils/index.ts +++ b/src/react/utils/index.ts @@ -30,7 +30,7 @@ export const isEmailValid = (email: string) => { return emailRegex.test(email) } - - - +export function capitalizeFirstLetter(string:string) { + return string.charAt(0).toUpperCase() + string.slice(1); +} From 6b7d5de398561e38831304f781e0163ba3f27c04 Mon Sep 17 00:00:00 2001 From: Domingo Dirutigliano Date: Wed, 18 Sep 2024 15:22:06 +0200 Subject: [PATCH 04/14] fix: removed excessive time slots --- .../Schedule/Pages/ScheduleTab.astro | 56 +++++-------------- 1 file changed, 13 insertions(+), 43 deletions(-) diff --git a/src/components/Schedule/Pages/ScheduleTab.astro b/src/components/Schedule/Pages/ScheduleTab.astro index 38ba55f..763429c 100644 --- a/src/components/Schedule/Pages/ScheduleTab.astro +++ b/src/components/Schedule/Pages/ScheduleTab.astro @@ -12,29 +12,29 @@ interface Props { const lang = getLangFromUrl(Astro.url); const { schedule, rooms } = Astro.props; -const calcSlotsTaken = (s, tsr, ts_idx) => { +const calcSlotsTaken = (timeSlots, tsr, ts_idx) => { const endDate = new Date(tsr.session.endsAt); endDate.setSeconds(0) endDate.setMilliseconds(0) //Calculate the space to take (how many timeSlot takes this session (until a service session)) let session_len = 1; let last_is_service = false; - for (let i = ts_idx+1; i < s.timeSlots.length; i++){ + for (let i = ts_idx+1; i < timeSlots.length; i++){ //No sessions - if (s.timeSlots[i].rooms.length == 0) continue + if (timeSlots[i].rooms.length == 0) continue //Take time from one of the sessions //Get next start date - const next_date = new Date(s.timeSlots[i].rooms[0].session.startsAt) + const next_date = new Date(timeSlots[i].rooms[0].session.startsAt) next_date.setSeconds(0) next_date.setMilliseconds(0) //If it's a service session, can't take this space - if (s.timeSlots[i].rooms.some( (tsr) => tsr.session.isServiceSession)){ + if (timeSlots[i].rooms.some( (tsr) => tsr.session.isServiceSession)){ last_is_service = true continue //We need to check if replicate this session for the next timeSlot that is not a service session } if (last_is_service){ //We stopped at a service session and need to check if replicate this session in next timeSlots if (next_date < endDate){ - s.timeSlots[i].rooms.push(tsr) //Replicate + timeSlots[i].rooms.push(tsr) //Replicate } break } @@ -48,13 +48,15 @@ const calcSlotsTaken = (s, tsr, ts_idx) => { return session_len } + const isServiceTimeSlot = (ts) => ts.rooms.some((tsr) => tsr.session.isServiceSession); ---
{schedule.map((s) => { const roomsSelected = rooms?s.rooms.filter((r) => rooms.includes(r.id)):s.rooms + const timeSlotSelected = s.timeSlots.filter((ts) => ts.rooms.some((tsr) => roomsSelected.map(r => r.id).includes(tsr.id)) || isServiceTimeSlot(ts)); const totalScheduleCols = roomsSelected.length; - const totalScheduleRows = s.timeSlots.length; + const totalScheduleRows = timeSlotSelected.length; let skipPadding: {[key:string]:number} = roomsSelected.map((room) => ({[room.id]:0})).reduce((a,b)=>({...a,...b}),{}); return <>
@@ -66,15 +68,13 @@ const calcSlotsTaken = (s, tsr, ts_idx) => { }))}

{/* Some classes are created manually due to tilewind issues */} -
- {s.timeSlots.map((ts,ts_idx) => { +
+ {timeSlotSelected.map((ts,ts_idx) => { - const hasServiceSession = ts.rooms.some( - (tsr) => tsr.session.isServiceSession, - ); + const hasServiceSession = isServiceTimeSlot(ts) const sessionsInTimeSlot = ts.rooms.map((tsr) => { - const slots = !hasServiceSession? calcSlotsTaken(s, tsr, ts_idx) : 1; + const slots = !hasServiceSession? calcSlotsTaken(timeSlotSelected, tsr, ts_idx) : 1; if (slots > 1){ skipPadding[tsr.id.toString()] = slots-1 } @@ -122,63 +122,33 @@ const calcSlotsTaken = (s, tsr, ts_idx) => { .grid-cols-layout-1 { grid-template-columns: 90px repeat(1, minmax(0, 1fr)); } - .grid-rows-layout-1 { - grid-template-rows: repeat(1, minmax(0, 1fr)); - } .grid-cols-layout-2 { grid-template-columns: 90px repeat(2, minmax(0, 1fr)); } - .grid-rows-layout-2 { - grid-template-rows: repeat(2, minmax(0, 1fr)); - } .grid-cols-layout-3 { grid-template-columns: 90px repeat(3, minmax(0, 1fr)); } - .grid-rows-layout-3 { - grid-template-rows: repeat(3, minmax(0, 1fr)); - } .grid-cols-layout-4 { grid-template-columns: 90px repeat(4, minmax(0, 1fr)); } - .grid-rows-layout-4 { - grid-template-rows: repeat(4, minmax(0, 1fr)); - } .grid-cols-layout-5 { grid-template-columns: 90px repeat(5, minmax(0, 1fr)); } - .grid-rows-layout-5 { - grid-template-rows: repeat(5, minmax(0, 1fr)); - } .grid-cols-layout-6 { grid-template-columns: 90px repeat(6, minmax(0, 1fr)); } - .grid-rows-layout-6 { - grid-template-rows: repeat(6, minmax(0, 1fr)); - } .grid-cols-layout-7 { grid-template-columns: 90px repeat(7, minmax(0, 1fr)); } - .grid-rows-layout-7 { - grid-template-rows: repeat(7, minmax(0, 1fr)); - } .grid-cols-layout-8 { grid-template-columns: 90px repeat(8, minmax(0, 1fr)); } - .grid-rows-layout-8 { - grid-template-rows: repeat(8, minmax(0, 1fr)); - } .grid-cols-layout-9 { grid-template-columns: 90px repeat(9, minmax(0, 1fr)); } - .grid-rows-layout-9 { - grid-template-rows: repeat(9, minmax(0, 1fr)); - } .grid-cols-layout-10 { grid-template-columns: 90px repeat(10, minmax(0, 1fr)); } - .grid-rows-layout-10 { - grid-template-rows: repeat(10, minmax(0, 1fr)); - } }
\ No newline at end of file From cdaf0cf555765fc7f80795f9ad0a39eb482d1c71 Mon Sep 17 00:00:00 2001 From: Domingo Dirutigliano Date: Wed, 18 Sep 2024 15:58:44 +0200 Subject: [PATCH 05/14] fix: timezone fixed --- src/components/Home/Jumbo.astro | 1 + src/components/Schedule/Pages/ScheduleTab.astro | 5 +++-- .../Sessions/Pages/SessionDetail.astro | 4 ++++ .../Speakers/Pages/SpeakerDetail.astro | 1 + src/config.ts | 1 + src/data/api/sessionize_api.ts | 16 ++++++++++------ src/pages/redirect/[url_encoded].astro | 1 + src/pages/ticket.astro | 1 + src/react/pages/LoginPage.tsx | 1 + src/react/pages/SignupPage.tsx | 1 + 10 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/components/Home/Jumbo.astro b/src/components/Home/Jumbo.astro index e1fb930..7623598 100644 --- a/src/components/Home/Jumbo.astro +++ b/src/components/Home/Jumbo.astro @@ -15,6 +15,7 @@ const t = useTranslations(lang);

{ WebsiteConfig.EVENT_START.toLocaleDateString(lang, { + timeZone: WebsiteConfig.EVENT_TIMEZONE, day: "numeric", month: "long", year: "numeric", diff --git a/src/components/Schedule/Pages/ScheduleTab.astro b/src/components/Schedule/Pages/ScheduleTab.astro index 763429c..8ff20aa 100644 --- a/src/components/Schedule/Pages/ScheduleTab.astro +++ b/src/components/Schedule/Pages/ScheduleTab.astro @@ -3,6 +3,7 @@ import type { ScheduleDay } from "../../../data/types/sessionize"; import { getLangFromUrl } from "../../../i18n/utils"; import ScheduleCard from "../ScheduleCard.astro"; import { capitalizeFirstLetter } from "../../../react/utils"; +import { WebsiteConfig } from "../../../config"; interface Props { schedule: ScheduleDay[]; @@ -56,12 +57,12 @@ const calcSlotsTaken = (timeSlots, tsr, ts_idx) => { const roomsSelected = rooms?s.rooms.filter((r) => rooms.includes(r.id)):s.rooms const timeSlotSelected = s.timeSlots.filter((ts) => ts.rooms.some((tsr) => roomsSelected.map(r => r.id).includes(tsr.id)) || isServiceTimeSlot(ts)); const totalScheduleCols = roomsSelected.length; - const totalScheduleRows = timeSlotSelected.length; let skipPadding: {[key:string]:number} = roomsSelected.map((room) => ({[room.id]:0})).reduce((a,b)=>({...a,...b}),{}); return <>

{capitalizeFirstLetter(new Date(s.date).toLocaleDateString(lang, { + timeZone: WebsiteConfig.EVENT_TIMEZONE, day: "numeric", month: "long", weekday: "long", @@ -107,7 +108,7 @@ const calcSlotsTaken = (timeSlots, tsr, ts_idx) => { return [

-

{ts.slotStart.substring(0, 5)}

+

{ts.slotStart}

, ...orderedSessions ]; diff --git a/src/components/Sessions/Pages/SessionDetail.astro b/src/components/Sessions/Pages/SessionDetail.astro index a29e0c6..2b03a22 100644 --- a/src/components/Sessions/Pages/SessionDetail.astro +++ b/src/components/Sessions/Pages/SessionDetail.astro @@ -6,6 +6,7 @@ import AddToCalendar from '../../Common/AddToCalendar.astro'; import BaseLayout from '../../Common/BaseLayout.astro'; import SessionTopic from '../SessionTopic.astro'; import { capitalizeFirstLetter } from "../../../react/utils"; +import { WebsiteConfig } from '../../../config'; interface Props { entry: SessionInfo; @@ -32,16 +33,19 @@ const dateEnd = new Date(entry.endsAt); const isScheduled = dateStart.getTime() != 0; var date = capitalizeFirstLetter(dateStart.toLocaleDateString(lang, { + timeZone: WebsiteConfig.EVENT_TIMEZONE, day: "numeric", month: "short", })); const start = dateStart.toLocaleTimeString(lang, { + timeZone: WebsiteConfig.EVENT_TIMEZONE, hour: "numeric", minute: "numeric", }); const end = dateEnd.toLocaleTimeString(lang, { + timeZone: WebsiteConfig.EVENT_TIMEZONE, hour: "numeric", minute: "numeric", }); diff --git a/src/components/Speakers/Pages/SpeakerDetail.astro b/src/components/Speakers/Pages/SpeakerDetail.astro index 5bdceed..6f24fee 100644 --- a/src/components/Speakers/Pages/SpeakerDetail.astro +++ b/src/components/Speakers/Pages/SpeakerDetail.astro @@ -71,6 +71,7 @@ const pageTitle = `${speaker.fullName} @ ${WebsiteConfig.DEVFEST_NAME}`; const dateEnd = new Date(session.endsAt); const date = dateStart.toLocaleDateString(lang, { + timeZone: WebsiteConfig.EVENT_TIMEZONE, month: "long", day: "numeric", }); diff --git a/src/config.ts b/src/config.ts index 577221d..cde38d9 100644 --- a/src/config.ts +++ b/src/config.ts @@ -22,6 +22,7 @@ export class WebsiteConfig { public static readonly EVENT_START : Date = new Date('2024-10-26'); public static readonly EVENT_END : Date = new Date('2024-10-26'); + public static readonly EVENT_TIMEZONE : string = 'Europe/Rome'; public static readonly EVENT_LOCATION_NAME : String = 'Polythecnic of Bari'; public static readonly EVENT_LOCATION_CITY : String = 'Bari'; public static readonly EVENT_LOCATION_ADDRESS : String = 'Via Edoardo Orabona 4'; diff --git a/src/data/api/sessionize_api.ts b/src/data/api/sessionize_api.ts index e6d325d..bb663c2 100644 --- a/src/data/api/sessionize_api.ts +++ b/src/data/api/sessionize_api.ts @@ -1,3 +1,4 @@ +import { WebsiteConfig } from "../../config"; import type { ScheduleDay, SessionInfo, Speaker } from "../types/sessionize"; const API_ID = "1rh747m6" @@ -19,12 +20,15 @@ export async function getSchedule(): Promise> { schedule.forEach( day => day.timeSlots.forEach( - slot => slot.rooms.forEach( - room => { - const sessionInfoFound = sessionsInfo.find((_s) => _s.id == room.session.id); - room.session.info = sessionInfoFound; - }, - ), + (slot, slot_idx) => { + day.timeSlots[slot_idx].slotStart = new Date(slot.rooms[0].session.startsAt).toLocaleString("it", {timeZone: WebsiteConfig.EVENT_TIMEZONE, hour:"numeric", minute:"numeric"}) + slot.rooms.forEach( + room => { + const sessionInfoFound = sessionsInfo.find((_s) => _s.id == room.session.id); + room.session.info = sessionInfoFound; + }, + ) + } ), ); diff --git a/src/pages/redirect/[url_encoded].astro b/src/pages/redirect/[url_encoded].astro index b1a7a27..c7d140a 100644 --- a/src/pages/redirect/[url_encoded].astro +++ b/src/pages/redirect/[url_encoded].astro @@ -69,6 +69,7 @@ const t = useTranslations(lang);

{ WebsiteConfig.EVENT_START.toLocaleDateString(lang, { + timeZone: WebsiteConfig.EVENT_TIMEZONE, day: "numeric", month: "long", year: "numeric", diff --git a/src/pages/ticket.astro b/src/pages/ticket.astro index 70ada61..c8e1d17 100644 --- a/src/pages/ticket.astro +++ b/src/pages/ticket.astro @@ -34,6 +34,7 @@ import { WebsiteConfig } from "../config"

{ WebsiteConfig.EVENT_START.toLocaleDateString(lang, { + timeZone: WebsiteConfig.EVENT_TIMEZONE, day: "numeric", month: "long", year: "numeric", diff --git a/src/react/pages/LoginPage.tsx b/src/react/pages/LoginPage.tsx index ff9ca90..3e136c8 100644 --- a/src/react/pages/LoginPage.tsx +++ b/src/react/pages/LoginPage.tsx @@ -88,6 +88,7 @@ export const LoginPage = () => {

{ WebsiteConfig.EVENT_START.toLocaleDateString("en", { + timeZone: WebsiteConfig.EVENT_TIMEZONE, day: "numeric", month: "long", year: "numeric", diff --git a/src/react/pages/SignupPage.tsx b/src/react/pages/SignupPage.tsx index 89b2139..766e821 100644 --- a/src/react/pages/SignupPage.tsx +++ b/src/react/pages/SignupPage.tsx @@ -94,6 +94,7 @@ export const SignupPage = ({ token }: { token:string }) => {

{ WebsiteConfig.EVENT_START.toLocaleDateString("en", { + timeZone: WebsiteConfig.EVENT_TIMEZONE, day: "numeric", month: "long", year: "numeric", From 1c3593d78471af647597f252b9e1c57e381819b1 Mon Sep 17 00:00:00 2001 From: Domingo Dirutigliano Date: Wed, 18 Sep 2024 16:19:49 +0200 Subject: [PATCH 06/14] add: room on service sessions --- src/components/Schedule/ScheduleCard.astro | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/Schedule/ScheduleCard.astro b/src/components/Schedule/ScheduleCard.astro index a5cf74f..aaca5c4 100644 --- a/src/components/Schedule/ScheduleCard.astro +++ b/src/components/Schedule/ScheduleCard.astro @@ -1,5 +1,6 @@ --- import type { ScheduleSlotRoom } from '../../data/types/sessionize'; +import { getLangFromUrl, useTranslatedPath, useTranslations } from '../../i18n/utils'; interface Props { @@ -7,6 +8,9 @@ interface Props { } const { value } = Astro.props; +const lang = getLangFromUrl(Astro.url); +const t = useTranslations(lang); +const getPath = useTranslatedPath(lang); const hasSpeakers = value.session.info && value.session.info.speakers; @@ -16,14 +20,16 @@ const url = !value.session.isServiceSession --- -{!value.session.isServiceSession &&

{value.name}

} + {!value.session.isServiceSession &&

{value.name}

}

{value.session.title}

+
+ {value.session.isServiceSession &&

{t("session.room")}: {value.name}

}
{ hasSpeakers && From e736e872fa0426827cd7eb967de9935b63f69c89 Mon Sep 17 00:00:00 2001 From: Domingo Dirutigliano Date: Wed, 18 Sep 2024 17:08:20 +0200 Subject: [PATCH 07/14] refactror: small code refactor --- src/react/pages/AppPage.tsx | 3 ++- src/react/pages/LoginPage.tsx | 3 ++- src/react/pages/SignupPage.tsx | 3 ++- src/react/utils/index.ts | 15 +-------------- src/react/utils/query.ts | 15 ++++++++++++++- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/react/pages/AppPage.tsx b/src/react/pages/AppPage.tsx index a01811e..3083ebe 100644 --- a/src/react/pages/AppPage.tsx +++ b/src/react/pages/AppPage.tsx @@ -1,7 +1,8 @@ import { Button } from "react-daisyui" import { AppMain } from "../AppMain" -import { firebase, useFirebaseUserInfo } from "../utils" +import { firebase } from "../utils" import { useEffect } from "react" +import { useFirebaseUserInfo } from "../utils/query"; import { sendEmailVerification } from "firebase/auth" import { showNotification } from "@mantine/notifications" diff --git a/src/react/pages/LoginPage.tsx b/src/react/pages/LoginPage.tsx index 3e136c8..469fd7b 100644 --- a/src/react/pages/LoginPage.tsx +++ b/src/react/pages/LoginPage.tsx @@ -4,7 +4,8 @@ import { useForm } from "@mantine/form" import { WebsiteConfig } from "../../config"; import { useTranslations } from "../../i18n/utils"; import { notifications, showNotification } from "@mantine/notifications"; -import { firebase, isEmailValid, useFirebaseUserInfo } from "../utils"; +import { firebase, isEmailValid } from "../utils"; +import { useFirebaseUserInfo } from "../utils/query"; import { useEffect, useState } from "react"; import { signInWithEmailAndPassword } from "firebase/auth"; diff --git a/src/react/pages/SignupPage.tsx b/src/react/pages/SignupPage.tsx index 766e821..55b9f05 100644 --- a/src/react/pages/SignupPage.tsx +++ b/src/react/pages/SignupPage.tsx @@ -3,7 +3,8 @@ import { Card, Checkbox, Form, Input } from "react-daisyui" import { useForm } from "@mantine/form" import { useEffect, useState } from "react"; import { notifications, showNotification } from "@mantine/notifications"; -import { isEmailValid, useFirebaseUserInfo } from "../utils"; +import { isEmailValid } from "../utils"; +import { useFirebaseUserInfo } from "../utils/query"; import { WebsiteConfig } from "../../config"; import { useTranslations } from "../../i18n/utils"; diff --git a/src/react/utils/index.ts b/src/react/utils/index.ts index 210d2b0..4655dd4 100644 --- a/src/react/utils/index.ts +++ b/src/react/utils/index.ts @@ -1,9 +1,8 @@ // Import the functions you need from the SDKs you need import { initializeApp } from "firebase/app"; -import { getAuth, onAuthStateChanged } from "firebase/auth"; +import { getAuth } from "firebase/auth"; import { WebsiteConfig } from "../../config"; -import { useEffect, useState } from "react"; export const firebaseApp = initializeApp(WebsiteConfig.FIREBASE_CONFIG); @@ -11,18 +10,6 @@ export const firebase = { auth: getAuth(firebaseApp), } -export const useFirebaseUserInfo = () => { - const [hasLoaded, setHasLoaded] = useState(false) - useEffect(() => { - onAuthStateChanged(firebase.auth, (user) => { - setUser(user) - setHasLoaded(true) - }) - }, []) - const [user, setUser] = useState(firebase.auth.currentUser) - return { user, hasLoaded } -} - //By https://emailregex.com/ const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ diff --git a/src/react/utils/query.ts b/src/react/utils/query.ts index a3aa050..7e2aa46 100644 --- a/src/react/utils/query.ts +++ b/src/react/utils/query.ts @@ -1,3 +1,16 @@ +import { onAuthStateChanged } from "firebase/auth" +import { useEffect, useState } from "react" +import { firebase } from "." -//Here will be created the react query hook to fetch the data from the server \ No newline at end of file +export const useFirebaseUserInfo = () => { + const [hasLoaded, setHasLoaded] = useState(false) + useEffect(() => { + onAuthStateChanged(firebase.auth, (user) => { + setUser(user) + setHasLoaded(true) + }) + }, []) + const [user, setUser] = useState(firebase.auth.currentUser) + return { user, hasLoaded } +} \ No newline at end of file From db8b2ba66ea9e175201ad60c2fb831f816240a91 Mon Sep 17 00:00:00 2001 From: Bonfry Date: Sun, 22 Sep 2024 10:38:17 +0200 Subject: [PATCH 08/14] finished signup ui and repository --- .astro/astro/content.d.ts | 2 +- src/data/api/authentication_api.ts | 11 ++ src/data/api/firebase_api.ts | 0 .../repositories/authentication_repository.ts | 25 +++ src/data/types/authentication.ts | 13 ++ src/react/pages/SignupPage.tsx | 143 +++++++++++------- 6 files changed, 137 insertions(+), 57 deletions(-) create mode 100644 src/data/api/authentication_api.ts delete mode 100644 src/data/api/firebase_api.ts create mode 100644 src/data/repositories/authentication_repository.ts create mode 100644 src/data/types/authentication.ts diff --git a/.astro/astro/content.d.ts b/.astro/astro/content.d.ts index a5a0287..d89741c 100644 --- a/.astro/astro/content.d.ts +++ b/.astro/astro/content.d.ts @@ -307,5 +307,5 @@ declare module 'astro:content' { type AnyEntryMap = ContentEntryMap & DataEntryMap; - export type ContentConfig = typeof import("../../src/content/config.js"); + export type ContentConfig = typeof import("./../../src/content/config.js"); } diff --git a/src/data/api/authentication_api.ts b/src/data/api/authentication_api.ts new file mode 100644 index 0000000..0d71292 --- /dev/null +++ b/src/data/api/authentication_api.ts @@ -0,0 +1,11 @@ +import type { CheckTokenResponse, SignupResponse } from "../types/authentication"; + +export class AuthenticationApi { + async checkToken(token: string): Promise { + return { status: true, errorMessage: null }; + } + + async signInWithEmailAndPassword(email: string, password: string): Promise { + return { status: true, errorMessage: null }; + } +} \ No newline at end of file diff --git a/src/data/api/firebase_api.ts b/src/data/api/firebase_api.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/data/repositories/authentication_repository.ts b/src/data/repositories/authentication_repository.ts new file mode 100644 index 0000000..514fe58 --- /dev/null +++ b/src/data/repositories/authentication_repository.ts @@ -0,0 +1,25 @@ +import { AuthenticationApi } from "../api/authentication_api"; +import type { SignUpException } from "../types/authentication"; + +export class AuthenticationRepository { + api: AuthenticationApi; + + constructor() { + this.api = new AuthenticationApi(); + } + + async checkToken(token: string): Promise { + const result = await this.api.checkToken(token); + return result.status; + } + + async signInWithEmailAndPassword(email: string, password: string): Promise { + const result = await this.api.signInWithEmailAndPassword(email, password); + + if (!result.status) { + throw { + message: result.errorMessage + } as SignUpException; + } + } +} \ No newline at end of file diff --git a/src/data/types/authentication.ts b/src/data/types/authentication.ts new file mode 100644 index 0000000..28adf07 --- /dev/null +++ b/src/data/types/authentication.ts @@ -0,0 +1,13 @@ +export type CheckTokenResponse = { + status: boolean; + errorMessage: string | null; +} + +export type SignupResponse = { + status: boolean; + errorMessage: string | null; +} + +export type SignUpException = { + message: string; +} \ No newline at end of file diff --git a/src/react/pages/SignupPage.tsx b/src/react/pages/SignupPage.tsx index 55b9f05..27aaab2 100644 --- a/src/react/pages/SignupPage.tsx +++ b/src/react/pages/SignupPage.tsx @@ -4,12 +4,35 @@ import { useForm } from "@mantine/form" import { useEffect, useState } from "react"; import { notifications, showNotification } from "@mantine/notifications"; import { isEmailValid } from "../utils"; -import { useFirebaseUserInfo } from "../utils/query"; import { WebsiteConfig } from "../../config"; import { useTranslations } from "../../i18n/utils"; +import { AuthenticationRepository } from "../../data/repositories/authentication_repository"; -export const SignupPage = ({ token }: { token:string }) => { +enum SignUpPageStatus { Initial, InvalidToken, Ready, SignUpInProgress, SignUpError, SignUpComplete } + +export const SignupPage = ({ token }: { token: string }) => { const t = useTranslations("en") + const authRepository = new AuthenticationRepository(); + const [pageStatus, setPageStatus] = useState(SignUpPageStatus.Initial); + const [showPasswords, setShowPasswords] = useState(false) + + useEffect(() => { + if (pageStatus !== SignUpPageStatus.Initial) { + return; + } else if (token) { + authRepository + .checkToken(token) + .then((tokenIsValid) => { + setPageStatus(tokenIsValid + ? SignUpPageStatus.Ready + : SignUpPageStatus.InvalidToken + ); + }); + } else { + setPageStatus(SignUpPageStatus.InvalidToken); + } + }, [pageStatus, token]); + const checkErrors = () => { if (!form.isValid()) { @@ -28,9 +51,9 @@ export const SignupPage = ({ token }: { token:string }) => { confirmPassword: "", }, validate: { - email: (value) => value.length > 0? isEmailValid(value)? undefined: "The email given is invalid": "Email is required", - password: (value) => value.length > 0? undefined: "Password is required", - confirmPassword: (value, values) => value === values.password? undefined: "Passwords do not match" + email: (value) => value.length > 0 ? isEmailValid(value) ? undefined : "The email given is invalid" : "Email is required", + password: (value) => value.length > 0 ? undefined : "Password is required", + confirmPassword: (value, values) => value === values.password ? undefined : "Passwords do not match" }, validateInputOnChange: true, initialErrors: { @@ -40,82 +63,90 @@ export const SignupPage = ({ token }: { token:string }) => { } }) - const [showPasswords, setShowPasswords] = useState(false) - const [loading, setLoading] = useState(false) - - const { user, hasLoaded } = useFirebaseUserInfo() - useEffect(() => { - if(user != null && hasLoaded) { - location.href = "/app" - } - }, [user]) - if(!token) { + if (pageStatus === SignUpPageStatus.Initial) { + return
+ } else if (pageStatus === SignUpPageStatus.InvalidToken) { return Invalid token } + + return ( {/*

registration token: {token}

*/} -
{ - const requestId = notifications.show({ - loading: true, - title: "Signing up...", - message: "Please wait untils the registration is complete", - autoClose: false - }) - setLoading(true) - fetch("http://127.0.0.1/fakeAPI") - .then((userInfo) => { - notifications.update({ - id: requestId, - loading: false, - title: "Registration Completed", - message: `Welcome ${user?.displayName}`, - color: "green", - autoClose: true - }) - }).catch((error) => { - notifications.update({ - id: requestId, - loading: false, - title: `Registration error [${error.code}]`, - message: error.message, - color: "red", - autoClose: true - }) - }).finally(() => { - setLoading(false) - }) + { + const requestId = notifications.show({ + loading: true, + title: "Signing up...", + message: "Please wait untils the sign up is complete", + autoClose: false }) + + setPageStatus(SignUpPageStatus.SignUpInProgress); + + authRepository + .signInWithEmailAndPassword(data.email, data.password) + .then(() => { + notifications.update({ + id: requestId, + loading: false, + title: "Sign up Completed", + message: `Welcome ${form.values.email}`, + color: "green", + autoClose: true + }); + setPageStatus(SignUpPageStatus.SignUpComplete); + + setTimeout(() => { + location.href = "/login"; + }, 1500); + + }).catch((error) => { + notifications.update({ + id: requestId, + loading: false, + title: `Registration error [${error.code}]`, + message: error.message, + color: "red", + autoClose: true + }); + setPageStatus(SignUpPageStatus.SignUpError); + }); + }) }>

{ - WebsiteConfig.EVENT_START.toLocaleDateString("en", { - timeZone: WebsiteConfig.EVENT_TIMEZONE, - day: "numeric", - month: "long", - year: "numeric", - }) + WebsiteConfig.EVENT_START.toLocaleDateString("en", { + timeZone: WebsiteConfig.EVENT_TIMEZONE, + day: "numeric", + month: "long", + year: "numeric", + }) }

{t("info.locationName")}

- - - + + +
- setShowPasswords(e.target.checked)} checked={showPasswords} /> + setShowPasswords(e.target.checked)} checked={showPasswords} />
- +
From 74c0cb6f0013f43c774151e53809716002791e05 Mon Sep 17 00:00:00 2001 From: Bonfry Date: Sun, 22 Sep 2024 11:41:21 +0200 Subject: [PATCH 09/14] app page refactory --- src/react/components/AppBar.tsx | 23 ++++++++ src/react/pages/AppPage.tsx | 57 +++++++------------ src/react/pages/app/EmailVerificationPage.tsx | 38 +++++++++++++ src/react/pages/app/UserInfoPage.tsx | 12 ++++ 4 files changed, 94 insertions(+), 36 deletions(-) create mode 100644 src/react/components/AppBar.tsx create mode 100644 src/react/pages/app/EmailVerificationPage.tsx create mode 100644 src/react/pages/app/UserInfoPage.tsx diff --git a/src/react/components/AppBar.tsx b/src/react/components/AppBar.tsx new file mode 100644 index 0000000..3506930 --- /dev/null +++ b/src/react/components/AppBar.tsx @@ -0,0 +1,23 @@ +import { Button, Navbar } from 'react-daisyui'; +import { firebase } from "../utils" + +export const AppBar = () => { + + + return +
+ Devfest Logo + +
+ +
+} \ No newline at end of file diff --git a/src/react/pages/AppPage.tsx b/src/react/pages/AppPage.tsx index 3083ebe..9c4e129 100644 --- a/src/react/pages/AppPage.tsx +++ b/src/react/pages/AppPage.tsx @@ -1,51 +1,36 @@ -import { Button } from "react-daisyui" import { AppMain } from "../AppMain" import { firebase } from "../utils" import { useEffect } from "react" import { useFirebaseUserInfo } from "../utils/query"; -import { sendEmailVerification } from "firebase/auth" -import { showNotification } from "@mantine/notifications" - - +import { AppBar } from "../components/AppBar"; +import { UserInfoPage } from "./app/UserInfoPage"; +import { EmailVerificationPage } from "./app/EmailVerificationPage"; export const AppPage = () => { const { user, hasLoaded } = useFirebaseUserInfo() useEffect(() => { - if(user == null && hasLoaded) { + if (user == null && hasLoaded) { location.href = "/login" } }, [user]) - const emailVerified = firebase.auth.currentUser?.emailVerified??false + const emailVerified = firebase.auth.currentUser?.emailVerified ?? false + + let subPage = Loading...; + + //TODO: Implement Sub Router for App Page + if(user && emailVerified){ + subPage = UserInfoPage(user); + }else if(user && !emailVerified){ + subPage = EmailVerificationPage(user); + } + + return
+ +
- return <> - {user? - Welcome to your app menù! - You are {firebase.auth.currentUser?.displayName} with {firebase.auth.currentUser?.email} - email verified: {emailVerified?"yes":"no"} - {!emailVerified && } - UID: {firebase.auth.currentUser?.uid} - - - :Loading...} - + {subPage} +
+
} \ No newline at end of file diff --git a/src/react/pages/app/EmailVerificationPage.tsx b/src/react/pages/app/EmailVerificationPage.tsx new file mode 100644 index 0000000..b5526d7 --- /dev/null +++ b/src/react/pages/app/EmailVerificationPage.tsx @@ -0,0 +1,38 @@ +import { useEffect } from "react" +import { useFirebaseUserInfo } from "../../utils/query" +import { sendEmailVerification, type User } from "firebase/auth" +import { Button } from "react-daisyui" +import { showNotification } from "@mantine/notifications" +import { AppMain } from "../../AppMain" + +export const EmailVerificationPage = (user: User) => { + return +
+
+

+ Your email has not been verified. + You must verify it before continue + with this application. +

+ + +
+
+
+} \ No newline at end of file diff --git a/src/react/pages/app/UserInfoPage.tsx b/src/react/pages/app/UserInfoPage.tsx new file mode 100644 index 0000000..6f765a8 --- /dev/null +++ b/src/react/pages/app/UserInfoPage.tsx @@ -0,0 +1,12 @@ +import type { User } from "firebase/auth" +import { AppMain } from "../../AppMain" +import { firebase } from "../../utils" + +export const UserInfoPage = (user: User) => { + return +

Welcome to your app menù!

+

You are {firebase.auth.currentUser?.displayName} with {firebase.auth.currentUser?.email}

+

email verified: {user.emailVerified ? "yes" : "no"}

+

UID: {firebase.auth.currentUser?.uid}

+
+} \ No newline at end of file From 726845cdd8837658dca45286541c6cd05ed8ce07 Mon Sep 17 00:00:00 2001 From: Domingo Dirutigliano Date: Sun, 22 Sep 2024 18:49:45 +0200 Subject: [PATCH 10/14] add: quiz add form --- .astro/astro/content.d.ts | 2 +- package-lock.json | 31 +++- package.json | 3 +- src/pages/app.astro | 4 +- src/pages/login.astro | 4 +- src/pages/redirect/[url_encoded].astro | 4 +- src/pages/signup.astro | 4 +- src/pages/ticket.astro | 4 +- src/react/components/AppBar.tsx | 4 +- src/react/pages/AppPage.tsx | 44 +++-- src/react/pages/SignupPage.tsx | 3 +- src/react/pages/app/EmailVerificationPage.tsx | 4 +- src/react/pages/app/QuizAdd.tsx | 167 ++++++++++++++++++ src/react/pages/app/QuizList.tsx | 18 ++ src/react/pages/app/UserInfoPage.tsx | 2 +- src/react/utils/net.ts | 3 - src/react/utils/store.ts | 15 ++ src/style/base.scss | 5 + 18 files changed, 281 insertions(+), 40 deletions(-) create mode 100644 src/react/pages/app/QuizAdd.tsx create mode 100644 src/react/pages/app/QuizList.tsx delete mode 100644 src/react/utils/net.ts create mode 100644 src/react/utils/store.ts diff --git a/.astro/astro/content.d.ts b/.astro/astro/content.d.ts index d89741c..a5a0287 100644 --- a/.astro/astro/content.d.ts +++ b/.astro/astro/content.d.ts @@ -307,5 +307,5 @@ declare module 'astro:content' { type AnyEntryMap = ContentEntryMap & DataEntryMap; - export type ContentConfig = typeof import("./../../src/content/config.js"); + export type ContentConfig = typeof import("../../src/content/config.js"); } diff --git a/package-lock.json b/package-lock.json index 735c7c4..cb9b6cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,7 +32,8 @@ "react-icons": "^5.3.0", "react-qrcode-logo": "^3.0.0", "sass": "^1.77.8", - "tailwindcss": "^3.3.5" + "tailwindcss": "^3.3.5", + "zustand": "^5.0.0-rc.2" }, "devDependencies": { "daisyui": "^4.12.10", @@ -9278,6 +9279,34 @@ "zod": "^3" } }, + "node_modules/zustand": { + "version": "5.0.0-rc.2", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.0-rc.2.tgz", + "integrity": "sha512-o2Nwuvnk8vQBX7CcHL8WfFkZNJdxB/VKeWw0tNglw8p4cypsZ3tRT7rTRTDNeUPFS0qaMBRSKe+fVwL5xpcE3A==", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/package.json b/package.json index 15774e9..0ec5e32 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,8 @@ "react-icons": "^5.3.0", "react-qrcode-logo": "^3.0.0", "sass": "^1.77.8", - "tailwindcss": "^3.3.5" + "tailwindcss": "^3.3.5", + "zustand": "^5.0.0-rc.2" }, "devDependencies": { "daisyui": "^4.12.10", diff --git a/src/pages/app.astro b/src/pages/app.astro index 9d5f3c9..ce8963b 100644 --- a/src/pages/app.astro +++ b/src/pages/app.astro @@ -5,9 +5,9 @@ import { PageComponent } from "../react/PageComponent"; - + -
+
diff --git a/src/pages/login.astro b/src/pages/login.astro index d800524..bb34688 100644 --- a/src/pages/login.astro +++ b/src/pages/login.astro @@ -5,9 +5,9 @@ import { PageComponent } from "../react/PageComponent"; - + -
+
diff --git a/src/pages/redirect/[url_encoded].astro b/src/pages/redirect/[url_encoded].astro index c7d140a..9ee1e1d 100644 --- a/src/pages/redirect/[url_encoded].astro +++ b/src/pages/redirect/[url_encoded].astro @@ -57,13 +57,13 @@ const t = useTranslations(lang); some magic sprinkled in to help you build great templates. --> - + -
+

diff --git a/src/pages/signup.astro b/src/pages/signup.astro index baa7b49..cea1911 100644 --- a/src/pages/signup.astro +++ b/src/pages/signup.astro @@ -5,9 +5,9 @@ import { PageComponent } from "../react/PageComponent"; - + -

+
diff --git a/src/pages/ticket.astro b/src/pages/ticket.astro index c8e1d17..b02ffc4 100644 --- a/src/pages/ticket.astro +++ b/src/pages/ticket.astro @@ -12,9 +12,9 @@ const t = useTranslations(lang); some magic sprinkled in to help you build great templates. --> - + -
+