From 94a72ca73f85d58d10dbcdec6db4d07414a2a504 Mon Sep 17 00:00:00 2001 From: jojocoelho Date: Fri, 31 Jan 2025 19:56:34 +0000 Subject: [PATCH 01/10] feat: first draft, calendar, event card, event list --- package.json | 4 +- src/app/[lang]/events/page.tsx | 92 ++++++++++++++++++++++++++++++++-- src/components/calendar.tsx | 90 +++++++++++++++++++++++++++++++++ src/components/event-card.tsx | 44 ++++++++++++++++ src/components/event-list.tsx | 12 +++++ src/lib/types.ts | 30 +++++++++++ src/lib/utils.ts | 77 ++++++++++++++++++++++++++++ 7 files changed, 345 insertions(+), 4 deletions(-) create mode 100644 src/components/calendar.tsx create mode 100644 src/components/event-card.tsx create mode 100644 src/components/event-list.tsx diff --git a/package.json b/package.json index 3dac749..9092ad3 100644 --- a/package.json +++ b/package.json @@ -14,12 +14,14 @@ "@formatjs/intl-localematcher": "^0.5.7", "@headlessui/react": "^2.2.0", "@types/negotiator": "^0.6.3", + "lucide-react": "^0.474.0", "motion": "^11.11.15", "negotiator": "^1.0.0", "next": "14.2.16", "react": "^18", "react-dom": "^18", - "react-intersection-observer": "^9.13.1" + "react-intersection-observer": "^9.13.1", + "react-swipeable": "^7.0.2" }, "devDependencies": { "@types/eslint": "^8.56.6", diff --git a/src/app/[lang]/events/page.tsx b/src/app/[lang]/events/page.tsx index a1b37a4..ed9f4b5 100644 --- a/src/app/[lang]/events/page.tsx +++ b/src/app/[lang]/events/page.tsx @@ -1,3 +1,89 @@ -export default function Events() { - return
Events
; -} +import { Calendar } from "@/components/calendar" +import { EventList } from "@/components/event-list" +import PromotionalCard from "@/components/promotional-card" +import { type Event, CardType } from "@/lib/types" + +const events: Event[] = [ + { + id: "1", + title: "Hackathon Bugsbyte", + startDate: new Date(2024, 3, 5), + endDate: new Date(2024, 3, 7), + location: "Altice Forum Braga", + instagramLink: "https://instagram.com", + description: + "Na Hackathon Bugsbyte qualquer estudante pode fazer nascer uma idea, basta ter um espírito competitivo e alguns dotes", + }, + { + id: "2", + title: "Karaoke", + startDate: new Date(2024, 2, 14), + time: "21:00", + location: "Rick Universal", + instagramLink: "https://instagram.com", + description: + "O karaoke do CeSIUM está de volta! Prepara a tua voz 🎤 Junta-te a nós, no Rick's, na próxima quinta-feira, dia 14", + }, + { + id: "3", + title: "Showoff Typst", + startDate: new Date(2024, 2, 14), + time: "16:00", + location: "DI - Auditório 1", + instagramLink: "https://instagram.com", + description: + "Farto de demorar mais a escrever um relatório do que a implementar uma feature? Vem à demonstração do Typst", + }, +] + +export default function EventsPage() { + return ( + <> +
+
+

Eventos

+
+ + Calendarium + + + + + + Instagram + + + + +
+
+
+ +
+
+
+ +
+ +
+
+
+ +

+ Por agora a lista acabou. Esta lista só mostra eventos organizados pelo CeSIUM. Para veres mais eventos, + como festas ou feriados, visita o{" "} + + Calendarium + + . Mantém-te a par das novidades no nosso{" "} + + Instagram + + . +

+
+
+
+ + ) +} \ No newline at end of file diff --git a/src/components/calendar.tsx b/src/components/calendar.tsx new file mode 100644 index 0000000..e134ce3 --- /dev/null +++ b/src/components/calendar.tsx @@ -0,0 +1,90 @@ +"use client" + +import { useState } from "react" +import { useSwipeable } from "react-swipeable" +import { ChevronLeft, ChevronRight } from "lucide-react" +import type { CalendarProps, Event } from "../lib/types" +import { getMonthDays, isSameDay, isWithinRange } from "../lib/utils" + +export function Calendar({ events = [], onDateSelect, onEventClick, className }: CalendarProps) { + const [currentDate, setCurrentDate] = useState(new Date()) + const [selectedDate, setSelectedDate] = useState(null) + + const handlers = useSwipeable({ + onSwipedLeft: () => handleNextMonth(), + onSwipedRight: () => handlePreviousMonth(), + preventScrollOnSwipe: true, + trackMouse: true, + }) + + const handlePreviousMonth = () => { + setCurrentDate(new Date(currentDate.getFullYear(), currentDate.getMonth() - 1)) + } + + const handleNextMonth = () => { + setCurrentDate(new Date(currentDate.getFullYear(), currentDate.getMonth() + 1)) + } + + const handleDateSelect = (date: Date) => { + setSelectedDate(date) + onDateSelect?.(date) + } + + const days = getMonthDays(currentDate) + const weekDays = ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sab"] + + return ( +
+
+
+ +

{currentDate.toLocaleString("pt-BR", { month: "long", year: "numeric" })}

+ +
+ +
+
+ {weekDays.map((day) => ( +
+ {day} +
+ ))} +
+
+ {days.map((date, index) => { + const isCurrentMonth = date.getMonth() === currentDate.getMonth() + const hasEvent = events.some((event: Event) => { + const eventDate = new Date(event.startDate) + if (event.endDate) { + return isWithinRange(date, eventDate, new Date(event.endDate)) + } + return isSameDay(eventDate, date) + }) + + return ( + + ) + })} +
+
+
+
+ ) +} \ No newline at end of file diff --git a/src/components/event-card.tsx b/src/components/event-card.tsx new file mode 100644 index 0000000..332ea94 --- /dev/null +++ b/src/components/event-card.tsx @@ -0,0 +1,44 @@ +import { Calendar, MapPin, Instagram } from "lucide-react" +import type { EventCardProps } from "../lib/types" +import { getMonthAbbreviation, getDay } from "../lib/utils" + +export function EventCard({ event }: EventCardProps) { + const month = getMonthAbbreviation(event.startDate) + const day = getDay(event.startDate) + + return ( +
+
+
{month}
+
{day}
+
+
+

{event.title}

+
+ {event.time && ( +
+ + {event.time} + {event.endDate && • {event.endDate.toLocaleDateString("pt-BR")}} +
+ )} +
+ + {event.location} +
+ {event.instagramLink && ( + + )} +
+

+ {event.description} +

+
+
+ ) +} \ No newline at end of file diff --git a/src/components/event-list.tsx b/src/components/event-list.tsx new file mode 100644 index 0000000..20d78d7 --- /dev/null +++ b/src/components/event-list.tsx @@ -0,0 +1,12 @@ +import type { EventListProps } from "../lib/types" +import { EventCard } from "./event-card" + +export function EventList({ events }: EventListProps) { + return ( +
+ {events.map((event) => ( + + ))} +
+ ) +} \ No newline at end of file diff --git a/src/lib/types.ts b/src/lib/types.ts index 83831a3..cfa4711 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -24,3 +24,33 @@ export type TeamData = Team[]; export interface MemberInfo extends Member { imageUrl: string; } + +export interface Event { + id: string + title: string + startDate: Date + endDate?: Date + time?: string + location: string + instagramLink?: string + description: string +} + +export interface EventsPageProps { + events: Event[] +} + +export interface EventCardProps { + event: Event +} + +export interface EventListProps { + events: Event[] +} + +export interface CalendarProps { + events: Event[] + onDateSelect?: (date: Date) => void + onEventClick?: (event: Event) => void + className?: string +} \ No newline at end of file diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 751eb15..a90f602 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -120,6 +120,74 @@ function classNames(...classes: string[]) { return classes.filter(Boolean).join(" "); } +function formatEventDate(date: Date): string { + return date.toLocaleDateString("pt-BR", { + day: "numeric", + month: "long", + year: "numeric", + }) +} + +function getMonthAbbreviation(date: Date): string { + return date.toLocaleString("pt-BR", { month: "short" }).toUpperCase() +} + +function getDay(date: Date): number { + return date.getDate() +} + +function getDaysInMonth(date: Date): Date[] { + const year = date.getFullYear() + const month = date.getMonth() + const daysInMonth = new Date(year, month + 1, 0).getDate() + + const days: Date[] = [] + for (let day = 1; day <= daysInMonth; day++) { + days.push(new Date(year, month, day)) + } + + return days +} + +function getMonthDays(date: Date): Date[] { + const year = date.getFullYear() + const month = date.getMonth() + const firstDay = new Date(year, month, 1) + const lastDay = new Date(year, month + 1, 0) + + const days: Date[] = [] + + const daysFromPrevMonth = firstDay.getDay() + for (let i = daysFromPrevMonth; i > 0; i--) { + days.push(new Date(year, month, -i + 1)) + } + + days.push(...getDaysInMonth(date)) + + const daysFromNextMonth = 7 - lastDay.getDay() - 1 + for (let i = 1; i <= daysFromNextMonth; i++) { + days.push(new Date(year, month + 1, i)) + } + + return days +} + +function isSameDay(date1: Date, date2: Date): boolean { + return ( + date1.getFullYear() === date2.getFullYear() && + date1.getMonth() === date2.getMonth() && + date1.getDate() === date2.getDate() + ) +} + +function isWithinRange(date: Date, start: Date, end: Date): boolean { + const normalizedDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()) + const normalizedStart = new Date(start.getFullYear(), start.getMonth(), start.getDate()) + const normalizedEnd = new Date(end.getFullYear(), end.getMonth(), end.getDate()) + + return normalizedDate >= normalizedStart && normalizedDate <= normalizedEnd +} + export { generateYearRanges, generateUrlsForTeams, @@ -128,4 +196,13 @@ export { getDepartmentByName, classNames, getDepartmentMembersInfo, + formatEventDate, + getMonthAbbreviation, + getDay, + getDaysInMonth, + getMonthDays, + isSameDay, + isWithinRange }; + + From 8caec4d8b420a1df653170fc632e5a8a742c25f4 Mon Sep 17 00:00:00 2001 From: jojocoelho Date: Fri, 31 Jan 2025 20:59:20 +0000 Subject: [PATCH 02/10] fix: border and text color --- src/app/[lang]/events/page.tsx | 6 +++--- src/components/event-card.tsx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/[lang]/events/page.tsx b/src/app/[lang]/events/page.tsx index ed9f4b5..e516bb3 100644 --- a/src/app/[lang]/events/page.tsx +++ b/src/app/[lang]/events/page.tsx @@ -42,7 +42,7 @@ export default function EventsPage() {

Eventos

-
+
Calendarium @@ -61,7 +61,7 @@ export default function EventsPage() {
-
+
@@ -69,7 +69,7 @@ export default function EventsPage() {
-

+

Por agora a lista acabou. Esta lista só mostra eventos organizados pelo CeSIUM. Para veres mais eventos, como festas ou feriados, visita o{" "} diff --git a/src/components/event-card.tsx b/src/components/event-card.tsx index 332ea94..7fe5490 100644 --- a/src/components/event-card.tsx +++ b/src/components/event-card.tsx @@ -7,7 +7,7 @@ export function EventCard({ event }: EventCardProps) { const day = getDay(event.startDate) return ( -

From c1339facfcdd5d803cd3dd8a7a3634eb6856992c Mon Sep 17 00:00:00 2001 From: jojocoelho Date: Fri, 31 Jan 2025 21:00:25 +0000 Subject: [PATCH 03/10] fix: calendar arrows --- src/components/calendar.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/calendar.tsx b/src/components/calendar.tsx index e134ce3..3e8ef97 100644 --- a/src/components/calendar.tsx +++ b/src/components/calendar.tsx @@ -36,13 +36,13 @@ export function Calendar({ events = [], onDateSelect, onEventClick, className }: return (
-
+

{currentDate.toLocaleString("pt-BR", { month: "long", year: "numeric" })}

From c7c4c85f195657587cf1fa0f75ae94f361e95a39 Mon Sep 17 00:00:00 2001 From: jojocoelho Date: Fri, 31 Jan 2025 21:19:17 +0000 Subject: [PATCH 04/10] fix: event indication not working on calendar component --- src/app/[lang]/events/page.tsx | 8 ++++---- src/components/event-card.tsx | 2 +- src/lib/utils.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/[lang]/events/page.tsx b/src/app/[lang]/events/page.tsx index e516bb3..f96a64d 100644 --- a/src/app/[lang]/events/page.tsx +++ b/src/app/[lang]/events/page.tsx @@ -7,8 +7,8 @@ const events: Event[] = [ { id: "1", title: "Hackathon Bugsbyte", - startDate: new Date(2024, 3, 5), - endDate: new Date(2024, 3, 7), + startDate: new Date(2025, 3, 5), + endDate: new Date(2025, 3, 7), location: "Altice Forum Braga", instagramLink: "https://instagram.com", description: @@ -17,7 +17,7 @@ const events: Event[] = [ { id: "2", title: "Karaoke", - startDate: new Date(2024, 2, 14), + startDate: new Date(2025, 2, 14), time: "21:00", location: "Rick Universal", instagramLink: "https://instagram.com", @@ -27,7 +27,7 @@ const events: Event[] = [ { id: "3", title: "Showoff Typst", - startDate: new Date(2024, 2, 14), + startDate: new Date(2025, 2, 14), time: "16:00", location: "DI - Auditório 1", instagramLink: "https://instagram.com", diff --git a/src/components/event-card.tsx b/src/components/event-card.tsx index 7fe5490..7da8dd7 100644 --- a/src/components/event-card.tsx +++ b/src/components/event-card.tsx @@ -8,7 +8,7 @@ export function EventCard({ event }: EventCardProps) { return (
-
+
{month}
{day}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts index a90f602..ba16891 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -129,7 +129,7 @@ function formatEventDate(date: Date): string { } function getMonthAbbreviation(date: Date): string { - return date.toLocaleString("pt-BR", { month: "short" }).toUpperCase() + return date.toLocaleString("pt-BR", { month: "short" }).replace('.', '').toUpperCase(); } function getDay(date: Date): number { From e009ba403c0470c7491f4c5dc2fbfba8cdd75c7e Mon Sep 17 00:00:00 2001 From: jojocoelho Date: Fri, 31 Jan 2025 21:22:52 +0000 Subject: [PATCH 05/10] fix: event card opacity --- src/components/event-card.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/event-card.tsx b/src/components/event-card.tsx index 7da8dd7..7f58c21 100644 --- a/src/components/event-card.tsx +++ b/src/components/event-card.tsx @@ -8,7 +8,7 @@ export function EventCard({ event }: EventCardProps) { return (
-
+
{month}
{day}
From 3ef2e05cee7a116c2036a09655e669ee0e32da73 Mon Sep 17 00:00:00 2001 From: jojocoelho Date: Mon, 3 Feb 2025 13:50:55 +0000 Subject: [PATCH 06/10] feat: added internationalization to events page --- src/app/[lang]/events/page.tsx | 39 +++++++++++-------- src/components/calendar.tsx | 9 +++-- src/components/event-card.tsx | 11 ++++-- src/internationalization/dictionaries/en.json | 4 ++ src/internationalization/dictionaries/pt.json | 4 ++ src/lib/utils.ts | 4 +- 6 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/app/[lang]/events/page.tsx b/src/app/[lang]/events/page.tsx index f96a64d..57f0295 100644 --- a/src/app/[lang]/events/page.tsx +++ b/src/app/[lang]/events/page.tsx @@ -1,7 +1,11 @@ +"use client" + import { Calendar } from "@/components/calendar" import { EventList } from "@/components/event-list" import PromotionalCard from "@/components/promotional-card" +import { useDictionary } from "@/contexts/dictionary-provider" import { type Event, CardType } from "@/lib/types" +import Link from "next/link" const events: Event[] = [ { @@ -37,24 +41,26 @@ const events: Event[] = [ ] export default function EventsPage() { + const dict = useDictionary() + return ( <>
@@ -70,16 +76,15 @@ export default function EventsPage() {

- Por agora a lista acabou. Esta lista só mostra eventos organizados pelo CeSIUM. Para veres mais eventos, - como festas ou feriados, visita o{" "} - - Calendarium - - . Mantém-te a par das novidades no nosso{" "} - - Instagram - - . + {dict.events.warning.split("Calendarium")[0]} + + Calendarium + + {dict.events.warning.split("Calendarium")[1]?.split("Instagram")[0]} + + Instagram + + {dict.events.warning.split("Instagram")[1]}

diff --git a/src/components/calendar.tsx b/src/components/calendar.tsx index 3e8ef97..90bbfe1 100644 --- a/src/components/calendar.tsx +++ b/src/components/calendar.tsx @@ -5,6 +5,7 @@ import { useSwipeable } from "react-swipeable" import { ChevronLeft, ChevronRight } from "lucide-react" import type { CalendarProps, Event } from "../lib/types" import { getMonthDays, isSameDay, isWithinRange } from "../lib/utils" +import { useLang } from "@/contexts/dictionary-provider" export function Calendar({ events = [], onDateSelect, onEventClick, className }: CalendarProps) { const [currentDate, setCurrentDate] = useState(new Date()) @@ -37,11 +38,11 @@ export function Calendar({ events = [], onDateSelect, onEventClick, className }:
- -

{currentDate.toLocaleString("pt-BR", { month: "long", year: "numeric" })}

-
@@ -78,7 +79,7 @@ export function Calendar({ events = [], onDateSelect, onEventClick, className }: > {date.getDate()} - {hasEvent && } + {hasEvent && } ) })} diff --git a/src/components/event-card.tsx b/src/components/event-card.tsx index 7f58c21..26bcdce 100644 --- a/src/components/event-card.tsx +++ b/src/components/event-card.tsx @@ -1,15 +1,18 @@ +"use client" + import { Calendar, MapPin, Instagram } from "lucide-react" import type { EventCardProps } from "../lib/types" import { getMonthAbbreviation, getDay } from "../lib/utils" +import { useLang } from "@/contexts/dictionary-provider" export function EventCard({ event }: EventCardProps) { - const month = getMonthAbbreviation(event.startDate) + const month = getMonthAbbreviation(event.startDate, useLang()) const day = getDay(event.startDate) return (
-
{month}
+
{month}
{day}
@@ -27,7 +30,7 @@ export function EventCard({ event }: EventCardProps) { {event.location}
{event.instagramLink && ( -
diff --git a/src/internationalization/dictionaries/en.json b/src/internationalization/dictionaries/en.json index b8c9288..0fb4eb7 100644 --- a/src/internationalization/dictionaries/en.json +++ b/src/internationalization/dictionaries/en.json @@ -60,6 +60,10 @@ "description": "The departments at CeSIUM handle various aspects of the organization, from event planning and partnership management to communication and software development." } }, + "events": { + "title": "Events", + "warning": "For now, the list is over. This list only shows events organized by CeSIUM. To see more events, such as parties or holidays, visit the Calendarium. Stay updated on our Instagram." + }, "social_media": "Social media", "socials": [ { "name": "Facebook", "url": "https://www.facebook.com/cesiuminho" }, diff --git a/src/internationalization/dictionaries/pt.json b/src/internationalization/dictionaries/pt.json index faaf5df..9097ad5 100644 --- a/src/internationalization/dictionaries/pt.json +++ b/src/internationalization/dictionaries/pt.json @@ -60,6 +60,10 @@ "description": "Os departamentos do CeSIUM são responsáveis por diferentes áreas de atuação do núcleo, desde a organização de eventos, à gestão de parcerias, passando pela comunicação e pelo desenvolvimento de software." } }, + "events": { + "title": "Eventos", + "warning": "Por agora a lista acabou. Esta lista só mostra eventos organizados pelo CeSIUM. Para veres mais eventos, como festas ou feriados, visita o Calendarium. Mantém-te a par das novidades no nosso Instagram." + }, "social_media": "Redes sociais", "socials": [ { "name": "Facebook", "url": "https://www.facebook.com/cesiuminho" }, diff --git a/src/lib/utils.ts b/src/lib/utils.ts index ba16891..a6b28f0 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -128,8 +128,8 @@ function formatEventDate(date: Date): string { }) } -function getMonthAbbreviation(date: Date): string { - return date.toLocaleString("pt-BR", { month: "short" }).replace('.', '').toUpperCase(); +function getMonthAbbreviation(date: Date, lang: string): string { + return date.toLocaleString(lang, { month: "short" }).replace('.', '').toUpperCase(); } function getDay(date: Date): number { From a5ff9c22e35d544680ae35a5c65115d1ca62500a Mon Sep 17 00:00:00 2001 From: jojocoelho Date: Mon, 3 Feb 2025 13:58:47 +0000 Subject: [PATCH 07/10] feat: complete internationalization --- src/components/calendar.tsx | 7 ++++--- src/internationalization/dictionaries/en.json | 3 ++- src/internationalization/dictionaries/pt.json | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/components/calendar.tsx b/src/components/calendar.tsx index 90bbfe1..9e18184 100644 --- a/src/components/calendar.tsx +++ b/src/components/calendar.tsx @@ -1,11 +1,11 @@ "use client" -import { useState } from "react" +import { use, useState } from "react" import { useSwipeable } from "react-swipeable" import { ChevronLeft, ChevronRight } from "lucide-react" import type { CalendarProps, Event } from "../lib/types" import { getMonthDays, isSameDay, isWithinRange } from "../lib/utils" -import { useLang } from "@/contexts/dictionary-provider" +import { useDictionary, useLang } from "@/contexts/dictionary-provider" export function Calendar({ events = [], onDateSelect, onEventClick, className }: CalendarProps) { const [currentDate, setCurrentDate] = useState(new Date()) @@ -31,8 +31,9 @@ export function Calendar({ events = [], onDateSelect, onEventClick, className }: onDateSelect?.(date) } + const dict = useDictionary(); const days = getMonthDays(currentDate) - const weekDays = ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sab"] + const weekDays = dict.events.weekDays.split(", ") return (
diff --git a/src/internationalization/dictionaries/en.json b/src/internationalization/dictionaries/en.json index 0fb4eb7..dfe6181 100644 --- a/src/internationalization/dictionaries/en.json +++ b/src/internationalization/dictionaries/en.json @@ -62,7 +62,8 @@ }, "events": { "title": "Events", - "warning": "For now, the list is over. This list only shows events organized by CeSIUM. To see more events, such as parties or holidays, visit the Calendarium. Stay updated on our Instagram." + "warning": "For now, the list is over. This list only shows events organized by CeSIUM. To see more events, such as parties or holidays, visit the Calendarium. Stay updated on our Instagram.", + "weekDays": "Sun, Mon, Tue, Wed, Thu, Fri, Sat" }, "social_media": "Social media", "socials": [ diff --git a/src/internationalization/dictionaries/pt.json b/src/internationalization/dictionaries/pt.json index 9097ad5..79d252e 100644 --- a/src/internationalization/dictionaries/pt.json +++ b/src/internationalization/dictionaries/pt.json @@ -62,7 +62,8 @@ }, "events": { "title": "Eventos", - "warning": "Por agora a lista acabou. Esta lista só mostra eventos organizados pelo CeSIUM. Para veres mais eventos, como festas ou feriados, visita o Calendarium. Mantém-te a par das novidades no nosso Instagram." + "warning": "Por agora a lista acabou. Esta lista só mostra eventos organizados pelo CeSIUM. Para veres mais eventos, como festas ou feriados, visita o Calendarium. Mantém-te a par das novidades no nosso Instagram.", + "weekDays": "Dom, Seg, Ter, Qua, Qui, Sex, Sab" }, "social_media": "Redes sociais", "socials": [ From 07b8af9046b9aa6a0b8202b3ffdc7f37798f44d1 Mon Sep 17 00:00:00 2001 From: jojocoelho Date: Mon, 3 Feb 2025 16:13:13 +0000 Subject: [PATCH 08/10] feat: added events and changed the used icons --- package.json | 2 +- src/app/[lang]/events/page.tsx | 82 ++++++++++++++++++++-------------- src/components/calendar.tsx | 13 +++--- src/components/event-card.tsx | 34 +++++++------- src/components/event-list.tsx | 4 +- src/lib/api/getEvents.ts | 14 ++++++ src/lib/types.ts | 13 +++--- 7 files changed, 92 insertions(+), 70 deletions(-) create mode 100644 src/lib/api/getEvents.ts diff --git a/package.json b/package.json index 9092ad3..08e019a 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "@formatjs/intl-localematcher": "^0.5.7", "@headlessui/react": "^2.2.0", "@types/negotiator": "^0.6.3", - "lucide-react": "^0.474.0", + "axios": "^1.7.9", "motion": "^11.11.15", "negotiator": "^1.0.0", "next": "14.2.16", diff --git a/src/app/[lang]/events/page.tsx b/src/app/[lang]/events/page.tsx index 57f0295..d13f104 100644 --- a/src/app/[lang]/events/page.tsx +++ b/src/app/[lang]/events/page.tsx @@ -4,48 +4,62 @@ import { Calendar } from "@/components/calendar" import { EventList } from "@/components/event-list" import PromotionalCard from "@/components/promotional-card" import { useDictionary } from "@/contexts/dictionary-provider" +import getEvents from "@/lib/api/getEvents" import { type Event, CardType } from "@/lib/types" import Link from "next/link" -const events: Event[] = [ - { - id: "1", - title: "Hackathon Bugsbyte", - startDate: new Date(2025, 3, 5), - endDate: new Date(2025, 3, 7), - location: "Altice Forum Braga", - instagramLink: "https://instagram.com", - description: - "Na Hackathon Bugsbyte qualquer estudante pode fazer nascer uma idea, basta ter um espírito competitivo e alguns dotes", - }, - { - id: "2", - title: "Karaoke", - startDate: new Date(2025, 2, 14), - time: "21:00", - location: "Rick Universal", - instagramLink: "https://instagram.com", - description: - "O karaoke do CeSIUM está de volta! Prepara a tua voz 🎤 Junta-te a nós, no Rick's, na próxima quinta-feira, dia 14", - }, - { - id: "3", - title: "Showoff Typst", - startDate: new Date(2025, 2, 14), - time: "16:00", - location: "DI - Auditório 1", - instagramLink: "https://instagram.com", - description: - "Farto de demorar mais a escrever um relatório do que a implementar uma feature? Vem à demonstração do Typst", - }, -] +import { useEffect, useState } from "react" export default function EventsPage() { const dict = useDictionary() + /* + const [events, setEvents] = useState([]) + + useEffect(() => { + async function fetchEvents() { + const eventsData = await getEvents() + setEvents(eventsData) + } + fetchEvents().catch(error => console.error('Failed to fetch events:', error)) + }, []) + */ + + const events: Event[] = [ + { + title: "[AL] Teste", + place: "CP2 - 0.11 + 0.20 + 1.03 + 1.05 + 1.07", + link: "https://instagram.com/cesiuminho", + start: new Date("2025-10-31T00:00:00"), + end: new Date("2025-10-31T00:00:00"), + }, + { + title: "[AL] Teste", + place: "CP2 - 0.11 + 0.20 + 1.03 + 1.05 + 1.07", + link: "https://instagram.com/cesiuminho", + start: new Date("2025-01-04T00:00:00"), + end: new Date("2025-01-04T00:00:00"), + }, + { + title: "[AL] Recurso", + place: "CP2 - 0.11 + 0.20 + 1.03 + 1.05 + 1.07", + link: "https://instagram.com/cesiuminho", + start: new Date("2025-01-25T09:00:00"), + end: new Date("2025-01-25T12:00:00"), + }, + { + title: "[AL] Época Especial", + place: "CP2 - 0.11 + 0.20 + 1.03 + 1.05 + 1.07", + link: "https://instagram.com/cesiuminho", + start: new Date("2025-07-19T09:00:00"), + end: new Date("2025-07-19T12:00:00"), + } + ]; + + return ( <> -
+

{dict.events.title}

@@ -65,7 +79,7 @@ export default function EventsPage() {
-
+
diff --git a/src/components/calendar.tsx b/src/components/calendar.tsx index 9e18184..9c408d7 100644 --- a/src/components/calendar.tsx +++ b/src/components/calendar.tsx @@ -2,7 +2,6 @@ import { use, useState } from "react" import { useSwipeable } from "react-swipeable" -import { ChevronLeft, ChevronRight } from "lucide-react" import type { CalendarProps, Event } from "../lib/types" import { getMonthDays, isSameDay, isWithinRange } from "../lib/utils" import { useDictionary, useLang } from "@/contexts/dictionary-provider" @@ -38,13 +37,13 @@ export function Calendar({ events = [], onDateSelect, onEventClick, className }: return (
-
+

{currentDate.toLocaleString(useLang(), { month: "long" }).charAt(0).toUpperCase() + currentDate.toLocaleString(useLang(), { month: "long" }).slice(1)} {currentDate.getFullYear()}

@@ -60,9 +59,9 @@ export function Calendar({ events = [], onDateSelect, onEventClick, className }: {days.map((date, index) => { const isCurrentMonth = date.getMonth() === currentDate.getMonth() const hasEvent = events.some((event: Event) => { - const eventDate = new Date(event.startDate) - if (event.endDate) { - return isWithinRange(date, eventDate, new Date(event.endDate)) + const eventDate = new Date(event.start) + if (event.end) { + return isWithinRange(date, eventDate, new Date(event.end)) } return isSameDay(eventDate, date) }) diff --git a/src/components/event-card.tsx b/src/components/event-card.tsx index 26bcdce..d96c258 100644 --- a/src/components/event-card.tsx +++ b/src/components/event-card.tsx @@ -1,13 +1,14 @@ "use client" -import { Calendar, MapPin, Instagram } from "lucide-react" import type { EventCardProps } from "../lib/types" import { getMonthAbbreviation, getDay } from "../lib/utils" import { useLang } from "@/contexts/dictionary-provider" export function EventCard({ event }: EventCardProps) { - const month = getMonthAbbreviation(event.startDate, useLang()) - const day = getDay(event.startDate) + const lang = useLang() + const month = getMonthAbbreviation(event.start, lang) + const day = getDay(event.start) + const time = new Date(event.start).toLocaleTimeString(lang, { hour: '2-digit', minute: '2-digit' }) return (
@@ -17,30 +18,27 @@ export function EventCard({ event }: EventCardProps) {

{event.title}

-
- {event.time && ( +
+ {time && (
- - {event.time} - {event.endDate && • {event.endDate.toLocaleDateString("pt-BR")}} + calendar_month + {time} + {event.end && • {event.end.toLocaleDateString(lang)}}
)}
- - {event.location} + location_on + {event.place}
- {event.instagramLink && ( - -

- {event.description} -

) diff --git a/src/components/event-list.tsx b/src/components/event-list.tsx index 20d78d7..047a4bd 100644 --- a/src/components/event-list.tsx +++ b/src/components/event-list.tsx @@ -4,8 +4,8 @@ import { EventCard } from "./event-card" export function EventList({ events }: EventListProps) { return (
- {events.map((event) => ( - + {events.map((event, index) => ( + ))}
) diff --git a/src/lib/api/getEvents.ts b/src/lib/api/getEvents.ts new file mode 100644 index 0000000..a602b19 --- /dev/null +++ b/src/lib/api/getEvents.ts @@ -0,0 +1,14 @@ +import axios from 'axios'; +import { type Event } from "@/lib/types" + +const getEvents = async () => { + try { + const response = await axios.get('https://calendario.cesium.di.uminho.pt/api/transfer/events'); + return Array.isArray(response.data) ? response.data : [response.data]; + } catch (error) { + console.error('Error fetching events:', error); + throw error; + } +}; + +export default getEvents; \ No newline at end of file diff --git a/src/lib/types.ts b/src/lib/types.ts index cfa4711..e7150d9 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -26,14 +26,11 @@ export interface MemberInfo extends Member { } export interface Event { - id: string - title: string - startDate: Date - endDate?: Date - time?: string - location: string - instagramLink?: string - description: string + title: string, + place?: string, + link?: string, + start: Date, + end: Date } export interface EventsPageProps { From fc3f18260a1b1a90a7e537222e5272cda6408cb1 Mon Sep 17 00:00:00 2001 From: jojocoelho Date: Thu, 6 Feb 2025 10:54:09 +0000 Subject: [PATCH 09/10] refactor: link icon --- src/components/event-card.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/event-card.tsx b/src/components/event-card.tsx index d96c258..9158c70 100644 --- a/src/components/event-card.tsx +++ b/src/components/event-card.tsx @@ -32,7 +32,7 @@ export function EventCard({ event }: EventCardProps) {
{event.link && (
- link + explore {event.link.split("://")[1]} From bc54e218015ff258eb198fd65aaf338f5de8453a Mon Sep 17 00:00:00 2001 From: jojocoelho Date: Thu, 6 Feb 2025 11:36:14 +0000 Subject: [PATCH 10/10] feat: not required place field in event card --- src/components/event-card.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/event-card.tsx b/src/components/event-card.tsx index 9158c70..a06102a 100644 --- a/src/components/event-card.tsx +++ b/src/components/event-card.tsx @@ -26,10 +26,12 @@ export function EventCard({ event }: EventCardProps) { {event.end && • {event.end.toLocaleDateString(lang)}}
)} + {event.place && (
location_on {event.place}
+ )} {event.link && (
explore