From 2a7aa7d2ff0c6bd90a0bc011e01f1c0282ccc6d9 Mon Sep 17 00:00:00 2001 From: srikanth_M Date: Thu, 6 Aug 2026 09:56:58 +0530 Subject: [PATCH] upcoming events dynamaic --- app/(event)/upcoming-event/[slug]/page.jsx | 63 +++-- components/events/UpcomingEventData.jsx | 248 ++++++++++-------- components/events/UpcomingEventSinglePage.jsx | 78 +++++- components/home/HomeUpcomingEvent.tsx | 247 +++++++++-------- components/layout/MobileMenu.tsx | 52 ++-- components/layout/header/Header1.tsx | 54 ++-- next.config.mjs | 3 +- public/assets/css/main.css | 44 +++- .../tca-singapengal-information-night.webp | Bin 0 -> 774796 bytes .../assets/scss/layout/header/_header-1.scss | 6 +- public/assets/scss/layout/pages/_event.scss | 24 +- 11 files changed, 508 insertions(+), 311 deletions(-) create mode 100644 public/assets/img/event/upcoming-event/tca-singapengal-information-night.webp diff --git a/app/(event)/upcoming-event/[slug]/page.jsx b/app/(event)/upcoming-event/[slug]/page.jsx index 1e5cf6e..4d69be1 100644 --- a/app/(event)/upcoming-event/[slug]/page.jsx +++ b/app/(event)/upcoming-event/[slug]/page.jsx @@ -1,31 +1,60 @@ import UpcomingEventSinglePage from "@/components/events/UpcomingEventSinglePage"; -import { events } from "@/utility/constant.utils"; -const getEvent = (slug) => events.find((event) => event.slug === slug); +export const dynamic = 'force-dynamic'; +export const revalidate = 0; -export function generateStaticParams() { - return events - .filter((event) => event.slug) - .map((event) => ({ - slug: event.slug, - })); +export async function generateStaticParams() { + try { + const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3006/api'; + const res = await fetch(`${API_BASE_URL}/upcoming-events`); + const data = await res.json(); + if (data && data.success && data.data && data.data.length > 0) { + const paramsList = []; + data.data.forEach(event => { + if (event.slug && String(event.slug).trim()) { + paramsList.push({ slug: String(event.slug).trim() }); + } + if (event.id) { + paramsList.push({ slug: String(event.id) }); + } + const title = event.title || event.eventtitle || ''; + if (title) { + const titleSlug = String(title).toLowerCase().trim().replace(/\s+/g, '-').replace(/[^\w\-]+/g, ''); + if (titleSlug) { + paramsList.push({ slug: titleSlug }); + } + } + }); + return paramsList.length > 0 ? paramsList : [{ slug: 'default' }]; + } + } catch (e) { + console.error("Error in generateStaticParams:", e); + } + return [{ slug: 'default' }]; } export async function generateMetadata({ params }) { - const event = getEvent(params.slug); - - if (!event) { - return { - title: "Upcoming Event | Tamil Culture Waterloo", - }; + try { + const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3006/api'; + const res = await fetch(`${API_BASE_URL}/upcoming-events/slug/${params.slug}`); + const data = await res.json(); + if (data && data.success && data.data) { + const event = data.data; + return { + title: `${event.title || event.eventtitle} | Tamil Culture Waterloo`, + description: event.description || event.eventdescription || `Details for ${event.title || event.eventtitle}.`, + }; + } + } catch (e) { + console.error("Error in generateMetadata:", e); } - + return { - title: `${event.title} | Tamil Culture Waterloo`, - description: event.desc || `Details for ${event.title}.`, + title: "Upcoming Event | Tamil Culture Waterloo", }; } export default function Page({ params }) { return ; } + diff --git a/components/events/UpcomingEventData.jsx b/components/events/UpcomingEventData.jsx index c3b390e..f32d329 100644 --- a/components/events/UpcomingEventData.jsx +++ b/components/events/UpcomingEventData.jsx @@ -1,11 +1,37 @@ 'use client' import Link from 'next/link' import moment from "moment"; -import { useState } from "react" -import { events } from "@/utility/constant.utils"; // <-- import the events array here +import { useState, useEffect } from "react" +import axios from "axios"; export default function UpcomingEventData() { const [currentMonth, setCurrentMonth] = useState(moment()); + const [events, setEvents] = useState([]); + + useEffect(() => { + const fetchEvents = async () => { + try { + const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3006/api'; + const response = await axios.get(`${API_BASE_URL}/upcoming-events`); + if (response.data && response.data.success) { + const normalizedEvents = response.data.data.map(e => ({ + ...e, + title: e.title || e.eventtitle, + date: e.date || e.eventdate, + image: e.image || e.eventimageurl, + desc: e.description || e.eventdescription, + btnText: e.btn_text || e.btnText, + link: e.link || (e.slug ? `/upcoming-event/${e.slug}` : `/upcoming-event/${e.id}`), + location: e.location || e.venue, + })); + setEvents(normalizedEvents); + } + } catch (error) { + console.error("Error fetching upcoming events:", error); + } + }; + fetchEvents(); + }, []); // Get start and end of current month const startOfMonth = currentMonth.clone().startOf("month"); @@ -135,125 +161,125 @@ export default function UpcomingEventData() { return (
-
-
-
-

{String(idx + 1).padStart(2, "0")}

- - {!isEven ? ( - <> -
-
- {event.title} -
-
- -
- -
-
-
    -
  • - - {event.time{" "} - {event.time ? `${event.time} - ` : ""} - {formatEventDate(event.date)} - -
  • - {event.location && event.location.trim() && ( -
  • - - {" "} - {event.location} - -
  • - )} -
-
- {event.title} -
-

- {event.desc} -

- -
-
- - {event.btnText || "Online Tickets"} - +
+
+

{String(idx + 1).padStart(2, "0")}

+
+ {!isEven ? ( + <> +
+
+ {event.title}
-
- - ) : ( - <> -
-
-
    -
  • - - {event.time{" "} - {event.time ? `${event.time} - ` : ""} - {formatEventDate(event.date)} - -
  • - {event.location && event.location.trim() && ( + +
    + +
    +
    +
    • - {" "} - {event.location} + {event.time{" "} + {event.time ? `${event.time} - ` : ""} + {formatEventDate(event.date)}
    • - )} -
    -
    - {event.title} -
    -

    - {event.desc} -

    -
    -
    - + + {" "} + {event.location} + + + )} +
+
+ {event.title} +
+

- {event.btnText || "Online Tickets"} - + {event.desc} +

+ +
+
+ + {event.btnText || "Online Tickets"} + +
-
- -
- -
-
- {event.title} + + ) : ( + <> +
+
+
    +
  • + + {event.time{" "} + {event.time ? `${event.time} - ` : ""} + {formatEventDate(event.date)} + +
  • + {event.location && event.location.trim() && ( +
  • + + {" "} + {event.location} + +
  • + )} +
+
+ {event.title} +
+

+ {event.desc} +

+
+
+ + {event.btnText || "Online Tickets"} + +
+
-
- - )} + +
+ +
+
+ {event.title} +
+
+ + )} +
diff --git a/components/events/UpcomingEventSinglePage.jsx b/components/events/UpcomingEventSinglePage.jsx index 8ef0851..afe1f56 100644 --- a/components/events/UpcomingEventSinglePage.jsx +++ b/components/events/UpcomingEventSinglePage.jsx @@ -1,7 +1,9 @@ +'use client' import Layout from "@/components/layout/Layout"; import Link from "next/link"; import moment from "moment"; -import { events } from "@/utility/constant.utils"; +import { useState, useEffect } from "react"; +import axios from "axios"; const formatEventDate = (dateStr) => { if (!dateStr) return "Details will be announced"; @@ -12,11 +14,79 @@ const formatEventDate = (dateStr) => { }); }; -export default function UpcomingEventSinglePage({ slug }) { - const event = events.find((item) => item.slug === slug); +import { useSearchParams } from "next/navigation"; + +export default function UpcomingEventSinglePage({ slug: propSlug }) { + const searchParams = useSearchParams(); + const [event, setEvent] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + let activeSlug = propSlug; + if (!activeSlug && searchParams) { + activeSlug = searchParams.get('slug') || searchParams.get('id'); + } + if (!activeSlug && typeof window !== 'undefined') { + const parts = window.location.pathname.split('/').filter(Boolean); + if (parts.length > 0) { + activeSlug = parts[parts.length - 1]; + } + } + + const fetchEvent = async () => { + try { + const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3006/api'; + const response = await axios.get(`${API_BASE_URL}/upcoming-events/slug/${activeSlug}`); + if (response.data && response.data.success) { + const e = response.data.data; + setEvent({ + ...e, + title: e.title || e.eventtitle, + date: e.date || e.eventdate, + image: e.image || e.eventimageurl, + desc: e.description || e.eventdescription, + btnText: e.btn_text || e.btnText, + link: e.link || `/upcoming-event/${e.slug}`, + location: e.location || e.venue, + }); + } + } catch (error) { + console.error("Error fetching event details:", error); + } finally { + setLoading(false); + } + }; + if (activeSlug) { + fetchEvent(); + } else { + setLoading(false); + } + }, [propSlug, searchParams]); + + if (loading) { + return ( + +
+
+ Loading... +
+
+
+ ); + } if (!event) { - return null; + return ( + +
+

Event not found

+
+ + Back to Events + +
+ + ); } const eventDate = formatEventDate(event.date); diff --git a/components/home/HomeUpcomingEvent.tsx b/components/home/HomeUpcomingEvent.tsx index fabfa2c..0d0ea16 100644 --- a/components/home/HomeUpcomingEvent.tsx +++ b/components/home/HomeUpcomingEvent.tsx @@ -1,16 +1,40 @@ 'use client' import Link from 'next/link' -import { useState } from "react" -import { events } from "@/utility/constant.utils" // import your events array +import { useState, useEffect } from "react" +import axios from "axios" +import { events as staticEvents } from "@/utility/constant.utils" export default function HomeUpcomingEvent() { const [isTab, setIsTab] = useState(1) - const handleTab = (i: number) => { - setIsTab(i) - } + const [liveEvents, setLiveEvents] = useState([]) - // Take only the first 3 events - const displayEvents = events.slice(0, 3) as any[]; + useEffect(() => { + const fetchEvents = async () => { + try { + const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3006/api'; + const response = await axios.get(`${API_BASE_URL}/upcoming-events`); + if (response.data && response.data.success && response.data.data.length > 0) { + const normalizedEvents = response.data.data.map((e: any) => ({ + ...e, + title: e.title || e.eventtitle, + date: e.date || e.eventdate, + image: e.image || e.eventimageurl, + desc: e.description || e.desc || e.eventdescription, + btnText: e.btn_text || e.btnText, + link: e.link || `/upcoming-event/${e.slug || e.id}`, + location: e.location || e.venue, + })); + setLiveEvents(normalizedEvents); + } + } catch (error) { + console.error("Error fetching homepage upcoming events:", error); + } + }; + fetchEvents(); + }, []); + + // Take only the first 3 events from API or fallback + const displayEvents = (liveEvents.length > 0 ? liveEvents : staticEvents).slice(0, 3) as any[]; return ( <> @@ -44,117 +68,118 @@ export default function HomeUpcomingEvent() {
{/* Alternating layout */} {idx % 2 === 0 ? ( - <> -
-
- {event.title} -
-
-
-
-
-
    -
  • - - - - {event.time ? event.time + " - " : ""}{event.date} | - - -
  • -
  • - - {event.location} - - - -
  • -
-
- {event.title} -
-

- {event.desc} -

-
-
- - {event.btnText || "purchase ticket"} - + <> +
+
+ {event.title}
-
-
- - ) : ( - <> -
-
-
    -
  • - - - - {event.time ? event.time + " - " : ""}{event.date} | - - -
  • -
  • - - {event.location} - +
    +
    +
    +
      +
    • + + + + {event.time ? event.time + " - " : ""}{event.date} | + + +
    • +
    • + + {event.location} + - -
    • -
    -
    - {event.title} -
    -

    - {event.desc} -

    -
    -
    - +
  • +
+
+ {event.title} +
+

- {event.btnText || "purchase ticket"} - -

+ {event.desc} +

+
+
+ + {event.btnText || "purchase ticket"} + +
+
-
-
-
-
- {event.title} + + ) : ( + <> +
+
+
    +
  • + + + + {event.time ? event.time + " - " : ""}{event.date} | + + +
  • +
  • + + {event.location} + + + +
  • +
+
+ {event.title} +
+

+ {event.desc} +

+
+
+ + {event.btnText || "purchase ticket"} + +
+ +
+
-
- - )} -
+
+
+
+ {event.title} +
+
+ + )} +
diff --git a/components/layout/MobileMenu.tsx b/components/layout/MobileMenu.tsx index b9034e5..734eb1f 100644 --- a/components/layout/MobileMenu.tsx +++ b/components/layout/MobileMenu.tsx @@ -1,11 +1,31 @@ 'use client' -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import Link from 'next/link' -import { events } from "@/utility/constant.utils"; +import axios from "axios"; export default function MobileMenu({ isMobileMenu, handleMobileMenu }: any) { const [isAccordion, setIsAccordion] = useState(null); - const upcomingEvents = events.filter((event: any) => event.link); + const [upcomingEvents, setUpcomingEvents] = useState([]); + + useEffect(() => { + const fetchEvents = async () => { + try { + const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3006/api'; + const response = await axios.get(`${API_BASE_URL}/upcoming-events`); + if (response.data && response.data.success) { + const evts = response.data.data.map((e: any) => ({ + id: e.id, + title: e.title || e.eventtitle, + link: e.link || (e.slug ? `/upcoming-event/${e.slug}` : `/upcoming-event/${e.id}`) + })); + setUpcomingEvents(evts); + } + } catch (error) { + console.error("Error fetching upcoming events for mobile menu:", error); + } + }; + fetchEvents(); + }, []); const handleAccordion = (key: any) => { setIsAccordion(prevState => prevState === key ? null : key) @@ -105,25 +125,15 @@ export default function MobileMenu({ isMobileMenu, handleMobileMenu }: any) {
  • handleAccordion(5)}> - Events + Upcoming Event
      -
    • - setSubAccordion(subAccordion === 1 ? 0 : 1)}> - Upcoming Event - -
        - {upcomingEvents.map((event: any) => ( -
      • - - {event.title} - -
      • - ))} -
      -
    • -
    • - Photos Gallery -
    • + {upcomingEvents.map((event: any) => ( +
    • + + {event.title} + +
    • + ))}
  • handleAccordion(2)}> diff --git a/components/layout/header/Header1.tsx b/components/layout/header/Header1.tsx index 001c8e0..a606d66 100644 --- a/components/layout/header/Header1.tsx +++ b/components/layout/header/Header1.tsx @@ -1,17 +1,37 @@ "use client"; import Link from "next/link"; -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import { Swiper, SwiperSlide } from "swiper/react"; import { Autoplay, Pagination } from "swiper/modules"; -import { events } from "@/utility/constant.utils"; +import axios from "axios"; import "swiper/css"; import "swiper/css/pagination"; export default function Header1({ scroll, isMobileMenu, handleMobileMenu, isSearch, handleSearch }: any) { const [mobileMenu, setMobileMenu] = useState(false); - const upcomingEvents = events.filter((event: any) => event.link); + const [upcomingEvents, setUpcomingEvents] = useState([]); + + useEffect(() => { + const fetchEvents = async () => { + try { + const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3006/api'; + const response = await axios.get(`${API_BASE_URL}/upcoming-events`); + if (response.data && response.data.success) { + const evts = response.data.data.map((e: any) => ({ + id: e.id, + title: e.title || e.eventtitle, + link: e.link || (e.slug ? `/upcoming-event/${e.slug}` : `/upcoming-event/${e.id}`) + })); + setUpcomingEvents(evts); + } + } catch (error) { + console.error("Error fetching upcoming events for header:", error); + } + }; + fetchEvents(); + }, []); return ( <> @@ -55,7 +75,7 @@ export default function Header1({ scroll, isMobileMenu, handleMobileMenu, isSear style={{ background: "#000000ff", borderTop: "1px solid #cbc5c557" }} > -
    +
    @@ -63,7 +83,7 @@ export default function Header1({ scroll, isMobileMenu, handleMobileMenu, isSear logo
    -