-
-
-
+
+
+
{String(idx + 1).padStart(2, "0")}
+
+ {!isEven ? (
+ <>
+
+
+
-
- >
- ) : (
- <>
-
-
-
- -
-
-
{" "}
- {event.time ? `${event.time} - ` : ""}
- {formatEventDate(event.date)}
-
-
- {event.location && event.location.trim() && (
+
+
+
+
+
+
-
-
{" "}
- {event.location}
+
{" "}
+ {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.time ? `${event.time} - ` : ""}
+ {formatEventDate(event.date)}
+
+
+ {event.location && event.location.trim() && (
+ -
+
+
{" "}
+ {event.location}
+
+
+ )}
+
+
+
{event.title}
+
+
+ {event.desc}
+
+
+
+
+ {event.btnText || "Online Tickets"}
+
+
+
-
- >
- )}
+
+
+
+
+
+

+
+
+ >
+ )}
+
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 (
+
+
+
+ );
+ }
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.time ? event.time + " - " : ""}{event.date} |
-
-
-
- -
-
-
{event.location}
-
-
-
-
-
-
-
{event.title}
-
-
- {event.desc}
-
-
-
-
-
{event.btnText || "purchase ticket"}
-
+ <>
+
+
+
-
-
- >
- ) : (
- <>
-
-
-
- -
-
-
-
- {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.time ? event.time + " - " : ""}{event.date} |
+
+
+
+ -
+
+
{event.location}
+
+
+
+
+
+
+
{event.title}
+
+
+ {event.desc}
+
+
+
+
+ {event.btnText || "purchase ticket"}
+
+
+
+
+
-
- >
- )}
-
+
+
+
+

+
+
+ >
+ )}
+
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
-
+
-
Home
{/*
@@ -235,23 +255,15 @@ export default function Header1({ scroll, isMobileMenu, handleMobileMenu, isSear
-
- Events
+ Upcoming Event
- -
-
- Upcoming Event
-
-
- {upcomingEvents.map((event: any) => (
- -
-
- {event.title}
-
-
- ))}
-
-
- {/* - Photos Gallery
*/}
+ {upcomingEvents.map((event: any) => (
+ -
+
+ {event.title}
+
+
+ ))}
-
diff --git a/next.config.mjs b/next.config.mjs
index 9030961..a3c5333 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -1,8 +1,7 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
- output: "export",
reactStrictMode: false,
- trailingSlash: true, // if needed for static export
+ trailingSlash: true,
};
export default nextConfig;
diff --git a/public/assets/css/main.css b/public/assets/css/main.css
index 35d5a90..c470de0 100644
--- a/public/assets/css/main.css
+++ b/public/assets/css/main.css
@@ -9762,7 +9762,7 @@ html {
color: #000000cf;
display: inline-block;
transition: all 0.4s;
- padding: 0 20px;
+ padding: 0 12px;
}
.homepage1-body .header-area.homepage1 .header-elements .main-menu ul li:hover>a {
@@ -9795,7 +9795,9 @@ html {
position: absolute;
background: var(--ztc-text-text-1);
top: 100px;
- width: 225px;
+ min-width: 360px;
+ width: max-content;
+ max-width: 440px;
z-index: 1;
transition: all 0.4s;
border-radius: 5px;
@@ -9875,11 +9877,13 @@ html {
font-weight: var(--ztc-weight-medium);
transition: all 0.4s;
padding: 8px;
- display: inline-block;
+ display: block;
position: relative;
z-index: 1;
border-radius: 4px;
color: var(--ztc-text-text-2);
+ white-space: normal;
+ word-break: break-word;
}
.homepage1-body .header-area.homepage1 .header-elements .main-menu ul li ul.dropdown-padding li a::after {
@@ -10252,7 +10256,9 @@ html {
background: var(--ztc-text-text-1);
top: 201.3%;
transform: scale(1, 0);
- width: 225px;
+ min-width: 360px;
+ width: max-content;
+ max-width: 440px;
z-index: 0;
transition: all 0.4s;
border-radius: 5px;
@@ -18048,7 +18054,8 @@ html {
content: "";
height: 93%;
width: 1px;
- left: 45.7%;
+ left: 50%;
+ transform: translateX(-50%);
top: 0;
transition: all 0.4s;
background: #E6E7E8;
@@ -18082,7 +18089,8 @@ html {
background: #FFBA00;
border-radius: 50%;
position: absolute;
- left: 43%;
+ left: 50%;
+ transform: translateX(-50%);
top: 88px;
z-index: 1;
}
@@ -24348,7 +24356,8 @@ html {
content: "";
height: 93%;
width: 1px;
- left: 45.7%;
+ left: 50%;
+ transform: translateX(-50%);
top: 0;
transition: all 0.4s;
background: #E6E7E8;
@@ -24382,7 +24391,8 @@ html {
background: var(--ztc-text-text-15);
border-radius: 50%;
position: absolute;
- left: 43%;
+ left: 50%;
+ transform: translateX(-50%);
top: 88px;
z-index: 1;
}
@@ -25296,7 +25306,8 @@ html {
content: "";
height: 93%;
width: 1px;
- left: 45.7%;
+ left: 50%;
+ transform: translateX(-50%);
top: 0;
transition: all 0.4s;
background: #E6E7E8;
@@ -25330,7 +25341,8 @@ html {
background: #FFBA00;
border-radius: 50%;
position: absolute;
- left: 43%;
+ left: 50%;
+ transform: translateX(-50%);
top: 88px;
z-index: 1;
}
@@ -25610,7 +25622,8 @@ html {
content: "";
height: 93%;
width: 1px;
- left: 45.7%;
+ left: 50%;
+ transform: translateX(-50%);
top: 0;
transition: all 0.4s;
background: #5D9BFA;
@@ -25644,7 +25657,8 @@ html {
background: linear-gradient(135deg, #FF7A00 0%, #F00 100%);
border-radius: 50%;
position: absolute;
- left: 43%;
+ left: 50%;
+ transform: translateX(-50%);
top: 88px;
z-index: 1;
}
@@ -26989,7 +27003,8 @@ html {
content: "";
height: 93%;
width: 1px;
- left: 45.7%;
+ left: 50%;
+ transform: translateX(-50%);
top: 0;
transition: all 0.4s;
background: #E6E7E8;
@@ -27023,7 +27038,8 @@ html {
background: var(--LLL, linear-gradient(135deg, #FF5000 0%, #FF00B8 100%));
border-radius: 50%;
position: absolute;
- left: 43%;
+ left: 50%;
+ transform: translateX(-50%);
top: 88px;
z-index: 1;
}
diff --git a/public/assets/img/event/upcoming-event/tca-singapengal-information-night.webp b/public/assets/img/event/upcoming-event/tca-singapengal-information-night.webp
new file mode 100644
index 0000000..5665b53
Binary files /dev/null and b/public/assets/img/event/upcoming-event/tca-singapengal-information-night.webp differ
diff --git a/public/assets/scss/layout/header/_header-1.scss b/public/assets/scss/layout/header/_header-1.scss
index a34a86a..f8d6cc8 100644
--- a/public/assets/scss/layout/header/_header-1.scss
+++ b/public/assets/scss/layout/header/_header-1.scss
@@ -158,7 +158,7 @@ html {
color: var(--ztc-text-text-2);
display: inline-block;
transition: all .4s;
- padding: 0 20px;
+ padding: 0 12px;
}
&:hover>a {
@@ -192,7 +192,9 @@ html {
position: absolute;
background: var(--ztc-text-text-1);
top: 100px;
- width: 225px;
+ min-width: 360px;
+ width: max-content;
+ max-width: 440px;
z-index: 1;
transition: all .4s;
border-radius: 5px;
diff --git a/public/assets/scss/layout/pages/_event.scss b/public/assets/scss/layout/pages/_event.scss
index f3c28cb..14e4e59 100644
--- a/public/assets/scss/layout/pages/_event.scss
+++ b/public/assets/scss/layout/pages/_event.scss
@@ -597,7 +597,8 @@
content: "";
height: 93%;
width: 1px;
- left: 45.7%;
+ left: 50%;
+ transform: translateX(-50%);
top: 0;
transition: all 0.4s;
background: #E6E7E8;
@@ -627,7 +628,8 @@
background: var(--LLL, linear-gradient(135deg, #FF5000 0%, #FF00B8 100%));
border-radius: 50%;
position: absolute;
- left: 43%;
+ left: 50%;
+ transform: translateX(-50%);
top: 88px;
z-index: 1;
@@ -1558,7 +1560,8 @@
content: "";
height: 93%;
width: 1px;
- left: 45.7%;
+ left: 50%;
+ transform: translateX(-50%);
top: 0;
transition: all 0.4s;
background: #E6E7E8;
@@ -1588,7 +1591,8 @@
background: #FFBA00;
border-radius: 50%;
position: absolute;
- left: 43%;
+ left: 50%;
+ transform: translateX(-50%);
top: 88px;
z-index: 1;
@@ -1871,7 +1875,8 @@
content: "";
height: 93%;
width: 1px;
- left: 45.7%;
+ left: 50%;
+ transform: translateX(-50%);
top: 0;
transition: all 0.4s;
background: #5D9BFA;
@@ -1901,7 +1906,8 @@
background: linear-gradient(135deg, #FF7A00 0%, #F00 100%);
border-radius: 50%;
position: absolute;
- left: 43%;
+ left: 50%;
+ transform: translateX(-50%);
top: 88px;
z-index: 1;
@@ -2967,7 +2973,8 @@
content: "";
height: 93%;
width: 1px;
- left: 45.7%;
+ left: 50%;
+ transform: translateX(-50%);
top: 0;
transition: all 0.4s;
background: #E6E7E8;
@@ -2997,7 +3004,8 @@
background: var(--LLL, linear-gradient(135deg, #FF5000 0%, #FF00B8 100%));
border-radius: 50%;
position: absolute;
- left: 43%;
+ left: 50%;
+ transform: translateX(-50%);
top: 88px;
z-index: 1;