diff --git a/package.json b/package.json
index 9c034f39..212fdc2e 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
"dependencies": {
+ "dayjs": "^1.11.13",
"@apollo/client": "^3.10.8"
}
}
diff --git a/web/__test__/components/UpcomingEventHomeCard.test.tsx b/web/__test__/components/UpcomingEventHomeCard.test.tsx
new file mode 100644
index 00000000..62619525
--- /dev/null
+++ b/web/__test__/components/UpcomingEventHomeCard.test.tsx
@@ -0,0 +1,33 @@
+import { describe, expect, it } from "vitest";
+import { render, screen } from "@testing-library/react";
+import UpcomingEventHomeCard from "../../src/components/UpcomingEventHomeCard";
+import React from "react";
+
+const mockEvents = {
+ Events: [
+ {
+ id: 1,
+ title: "Test event",
+ description: "Test description",
+ subtitle: "Test subtitle",
+ location: "Test location",
+ locationLink: "Test link",
+ eventDateStart: "25 December",
+ eventDateEnd: "26 December",
+ isLive: false,
+ termsAndConditions: "Test terms and conditions",
+ eventCapacityRemaining: 12,
+ image: "/uploads/john_doe.jpg",
+ },
+ ],
+};
+
+describe("UpcomingEventHomeCard", () => {
+ it("renders the event card", () => {
+ render();
+ expect(screen.getByText("25 December")).toBeInTheDocument();
+ expect(screen.getByText("Test event")).toBeInTheDocument();
+ const partnerImage = screen.getByAltText("Event Image");
+ expect(partnerImage).toHaveAttribute("src", mockEvents.image);
+ });
+});
diff --git a/web/package.json b/web/package.json
index f682ca5f..5d0c2d5c 100644
--- a/web/package.json
+++ b/web/package.json
@@ -18,6 +18,7 @@
"@types/react-router-dom": "^5.3.3",
"@types/react-slick": "^0.23.13",
"axios": "^1.6.7",
+ "dayjs": "^1.11.13",
"graphql": "^16.8.2",
"react": "^18.2.0",
"react-cookies": "^0.1.1",
diff --git a/web/src/components/UpcomingEventHomeCard.tsx b/web/src/components/UpcomingEventHomeCard.tsx
new file mode 100644
index 00000000..f97107be
--- /dev/null
+++ b/web/src/components/UpcomingEventHomeCard.tsx
@@ -0,0 +1,38 @@
+import { Event } from "../types/types";
+
+interface UpcomingEventCardProps {
+ upcomingEvent: Event;
+}
+
+export default function UpcomingEventHomeCard({
+ upcomingEvent,
+}: UpcomingEventCardProps) {
+ const formattedDate = new Date(
+ upcomingEvent.eventDateStart
+ ).toLocaleDateString("en-NZ", {
+ day: "numeric",
+ month: "long",
+ });
+
+ return (
+
+
+
+
+ {upcomingEvent.title}
+
+
+
+
+ );
+}
diff --git a/web/src/components/UpcomingEventHomeSlider.tsx b/web/src/components/UpcomingEventHomeSlider.tsx
new file mode 100644
index 00000000..18d2db7a
--- /dev/null
+++ b/web/src/components/UpcomingEventHomeSlider.tsx
@@ -0,0 +1,109 @@
+import Slider from "react-slick";
+import "slick-carousel/slick/slick.css";
+import "slick-carousel/slick/slick-theme.css";
+import {
+ IoArrowBackCircleOutline,
+ IoArrowForwardCircleOutline,
+} from "react-icons/io5";
+import { useRef } from "react";
+import LoadingSpinner from "./LoadingSpinner";
+import { useQuery, gql } from "@apollo/client";
+import UpcomingEventHomeCard from "./UpcomingEventHomeCard";
+import { GET_EVENTS } from "../graphql/queries";
+import dayjs from "dayjs";
+import { Mapper } from "../utils/Mapper";
+import type { Event } from "../types/types";
+
+export default function UpcomingEventHomeSlider() {
+ const sliderRef = useRef(null);
+
+ const {
+ loading: eventsLoading,
+ error: eventsError,
+ data: eventsData,
+ } = useQuery(GET_EVENTS);
+
+ if (eventsLoading) {
+ return ;
+ }
+
+ if (eventsError) {
+ return CMS Offline
;
+ }
+
+ if (!eventsData) {
+ return No data available
;
+ }
+
+ const events = Mapper.mapToEvents(eventsData);
+
+ const now = dayjs(); // current date and time
+ const upcomingEvents = events
+ .filter((event) => dayjs(event.eventDateStart).isAfter(now)) // only future events
+ .sort((a, b) => dayjs(a.eventDateStart).diff(dayjs(b.eventDateStart))); // sort by start date
+
+ const settings = {
+ dots: true,
+ infinite: false,
+ speed: 500,
+ slidesToShow: 3,
+ slidesToScroll: 1,
+ arrows: false,
+ responsive: [
+ {
+ breakpoint: 1080,
+ settings: {
+ slidesToShow: 2,
+ },
+ },
+ {
+ breakpoint: 800,
+ settings: {
+ slidesToShow: 1,
+ },
+ },
+ ],
+ };
+
+ const next = () => {
+ sliderRef.current?.slickNext();
+ };
+
+ const previous = () => {
+ sliderRef.current?.slickPrev();
+ };
+
+ function SliderNoArrow() {
+ return (
+
+
+ {upcomingEvents.map((event) => (
+
+
+
+ ))}
+
+
+ );
+ }
+
+ return (
+
+ );
+}
diff --git a/web/src/components/UpcomingEvents.tsx b/web/src/components/UpcomingEvents.tsx
index d3c0014b..f8c7b58c 100644
--- a/web/src/components/UpcomingEvents.tsx
+++ b/web/src/components/UpcomingEvents.tsx
@@ -1,4 +1,4 @@
-import SimpleSlider from "./SimpleSlider";
+import UpcomingEventHomeSlider from "./UpcomingEventHomeSlider";
function UpcomingEvents() {
return (
@@ -8,7 +8,7 @@ function UpcomingEvents() {
Our Upcoming Events!
-
+
>
diff --git a/yarn.lock b/yarn.lock
index dd816149..a98e7ce8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -132,6 +132,11 @@ date-fns@^2.30.0:
dependencies:
"@babel/runtime" "^7.21.0"
+dayjs@^1.11.13:
+ version "1.11.13"
+ resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c"
+ integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==
+
emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"