diff --git a/app/components/EventDetailsTopInfoSection.tsx b/app/components/EventDetailsTopInfoSection.tsx
new file mode 100644
index 0000000..f96543a
--- /dev/null
+++ b/app/components/EventDetailsTopInfoSection.tsx
@@ -0,0 +1,42 @@
+import React from "react";
+import BondscapeButton from "@/components/BondscapeButton";
+
+interface Props {
+ visible: boolean;
+ title: string;
+ description: string;
+ buttonText: string;
+ onButtonClick: () => void;
+}
+
+const EventDetailsTopInfoSection = ({
+ visible,
+ title,
+ description,
+ buttonText,
+ onButtonClick,
+}: Props) => {
+ return (
+
+
+ {title}
+
+
+
+ {description}
+
+ {visible && (
+
+ )}
+
+
+ );
+};
+
+export default EventDetailsTopInfoSection;
diff --git a/app/components/EventQRCodeDialog.tsx b/app/components/EventQRCodeDialog.tsx
new file mode 100644
index 0000000..3545b2c
--- /dev/null
+++ b/app/components/EventQRCodeDialog.tsx
@@ -0,0 +1,134 @@
+"use client";
+import React, { useCallback } from "react";
+import Image from "next/image";
+import { PuffLoader } from "react-spinners";
+import Skeleton from "react-loading-skeleton";
+import { Button } from "primereact/button";
+import { toast } from "react-toastify";
+import { Dialog } from "primereact/dialog";
+
+interface Props {
+ /**
+ * Name of the event to which the QR code is associated.
+ */
+ eventName: string | undefined;
+
+ /**
+ * Link associated to the QR code. If undefined, the button to copy the link will not be disabled.
+ */
+ linkUrl: string | undefined;
+
+ /**
+ * The QR code image source.
+ */
+ qrCodeImageSrc: string | undefined;
+
+ /**
+ * Whether the dialog is visible or not.
+ */
+ visible: boolean;
+
+ /**
+ * Callback to be called when the dialog is hidden.
+ */
+ onHide: () => void;
+}
+
+const EventQRCodeDialog = ({
+ eventName,
+ linkUrl,
+ qrCodeImageSrc,
+ visible,
+ onHide,
+}: Props) => {
+ const [isLoading, setIsLoading] = React.useState(false);
+
+ const saveQrCode = useCallback(async () => {
+ if (!qrCodeImageSrc) return;
+
+ setIsLoading(true);
+ try {
+ // Get the QR Code image data
+ const response = await fetch(qrCodeImageSrc);
+ const block = await response.blob();
+ const url = URL.createObjectURL(block);
+
+ // Create a link that contains the image data
+ const a = document.createElement("a");
+ a.href = url;
+ a.download = `bondscape_${eventName}_qr_code.png`;
+ document.body.appendChild(a);
+
+ // Click the link to download the image
+ a.click();
+
+ // Remove the link
+ document.body.removeChild(a);
+ } catch (error) {
+ console.error(error);
+ setIsLoading(false);
+ }
+ }, [eventName, qrCodeImageSrc]);
+
+ return (
+
+ );
+};
+
+export default EventQRCodeDialog;
diff --git a/app/creator/events/[id]/page.tsx b/app/creator/events/[id]/page.tsx
index 3bfc86b..f5f9f3d 100644
--- a/app/creator/events/[id]/page.tsx
+++ b/app/creator/events/[id]/page.tsx
@@ -1,70 +1,59 @@
"use client";
-import BondscapeButton from "@/components/BondscapeButton";
import useCustomLazyQuery from "@/hooks/graphql/useCustomLazyQuery";
import useBreakpoints from "@/hooks/layout/useBreakpoints";
import useFormatDateToTZ from "@/hooks/timeformat/useFormatDateToTZ";
import MainLayout from "@/layouts/MainLayout";
-import {
- extractTimezoneOffset,
- serializeTimezoneOffset,
-} from "@/lib/DateUtils";
+import {extractTimezoneOffset, serializeTimezoneOffset,} from "@/lib/DateUtils";
import GetEventJoinLink from "@/services/axios/requests/GetEventJoinLink";
import GetQrCode from "@/services/axios/requests/GetQrCode";
import GetEventById from "@/services/graphql/queries/bondscape/GetEventById";
-import { Event, GQLEventsResult } from "@/types/event";
+import {Event, GQLEventsResult} from "@/types/event";
import Image from "next/image";
import Link from "next/link";
-import { useRouter } from "next/navigation";
-import { Button } from "primereact/button";
-import { Dialog } from "primereact/dialog";
-import { ProgressBar } from "primereact/progressbar";
-import { classNames } from "primereact/utils";
-import React, { useCallback, useEffect, useMemo, useState } from "react";
+import {useRouter} from "next/navigation";
+import {ProgressBar} from "primereact/progressbar";
+import {classNames} from "primereact/utils";
+import React, {useCallback, useEffect, useMemo, useState} from "react";
import Skeleton from "react-loading-skeleton";
-import { PuffLoader } from "react-spinners";
-import { toast } from "react-toastify";
+import GetEventDetailsLink from "@/services/axios/requests/GetEventDetailsLink";
+import EventDetailsTopInfoSection from "@/components/EventDetailsTopInfoSection";
+import EventQRCodeDialog from "@/components/EventQRCodeDialog";
+/**
+ * Event details page.
+ * @constructor
+ */
export default function EventDetails({ params }: { params: any }) {
- // States
+ // ------------------------------------------------------------------------------------------------------------------
+ // --- States
+ // ------------------------------------------------------------------------------------------------------------------
+
const [selectedEvent, setSelectedEvent] = useState();
- const [eventQrCode, setEventQrCode] = useState("");
- const [generatingQr, setGeneratingQr] = useState(false);
- const [qrCodeVisible, setQrCodeVisible] = useState(false);
- // Hooks
+ const [eventQRCodeDialogURL, setEventQRCodeDialogURL] = useState<
+ string | undefined
+ >(undefined);
+ const [eventQRCodeDialogImageSrc, setEventQRCodeDialogImageSrc] = useState<
+ string | undefined
+ >(undefined);
+ const [eventQRCodeDialogVisible, setEventQRCodeDialogVisible] =
+ useState(false);
+
+ const [eventShareQRCode, setEventShareQRCode] = useState("");
+ const [eventJoinQRCode, setEventJoinQRCode] = useState("");
+
+ // ------------------------------------------------------------------------------------------------------------------
+ // --- Hooks
+ // ------------------------------------------------------------------------------------------------------------------
+
const [isMobile, isMd] = useBreakpoints();
const router = useRouter();
const [getEventById] = useCustomLazyQuery(GetEventById);
const { getEventPeriodExtended } = useFormatDateToTZ();
- // Callbacks
-
- const generateQrCode = useCallback(async (url: string) => {
- const result = await GetQrCode(url, "url");
- if (result.isOk()) {
- setEventQrCode(result.value.url);
- }
- }, []);
-
- const toDataURL = useCallback(async () => {
- setGeneratingQr(true);
- try {
- const response = await fetch(eventQrCode);
- const blob = await response.blob();
- return URL.createObjectURL(blob);
- } finally {
- setGeneratingQr(false);
- }
- }, [eventQrCode]);
-
- const saveQrCode = useCallback(async () => {
- const a = document.createElement("a");
- a.href = await toDataURL();
- a.download = `bondscape_${selectedEvent?.name}_qr_code.png`;
- document.body.appendChild(a);
- a.click();
- document.body.removeChild(a);
- }, [selectedEvent?.name, toDataURL]);
+ // ------------------------------------------------------------------------------------------------------------------
+ // --- Callbacks
+ // ------------------------------------------------------------------------------------------------------------------
const loadEvent = useCallback(
async (eventId: string) => {
@@ -80,17 +69,41 @@ export default function EventDetails({ params }: { params: any }) {
[getEventById],
);
- // Effects
+ const showEventJoinQRCode = useCallback(() => {
+ setEventQRCodeDialogImageSrc(eventJoinQRCode);
+ setEventQRCodeDialogURL(undefined);
+ setEventQRCodeDialogVisible(true);
+ }, [eventJoinQRCode]);
+
+ const showEventShareQRCode = useCallback(() => {
+ setEventQRCodeDialogImageSrc(eventShareQRCode);
+ setEventQRCodeDialogURL(selectedEvent?.detailsLink);
+ setEventQRCodeDialogVisible(true);
+ }, [eventShareQRCode, selectedEvent?.detailsLink]);
+
+ // ------------------------------------------------------------------------------------------------------------------
+ // --- Effects
+ // ------------------------------------------------------------------------------------------------------------------
useEffect(() => {
if (selectedEvent) {
- GetEventJoinLink(selectedEvent.id).then((result) => {
- if (result.isOk()) {
- generateQrCode(result.value);
- }
- });
+ GetEventJoinLink(selectedEvent.id)
+ .andThen((url) => GetQrCode(url, "url"))
+ .then((result) => {
+ if (result.isOk()) {
+ setEventJoinQRCode(result.value.url);
+ }
+ });
+
+ GetEventDetailsLink(selectedEvent.id)
+ .andThen((url) => GetQrCode(url, "url"))
+ .then((result) => {
+ if (result.isOk()) {
+ setEventShareQRCode(result.value.url);
+ }
+ });
}
- }, [generateQrCode, selectedEvent]);
+ }, [selectedEvent]);
useEffect(() => {
const eventId = params.id as string;
@@ -110,6 +123,10 @@ export default function EventDetails({ params }: { params: any }) {
}
}, [selectedEvent]);
+ // ------------------------------------------------------------------------------------------------------------------
+ // --- Screen rendering
+ // ------------------------------------------------------------------------------------------------------------------
+
if (isMobile || isMd) {
return (
@@ -128,26 +145,24 @@ export default function EventDetails({ params }: { params: any }) {
editButtonHref={`/creator/create/${params.id}`}
>
-
-
- Event Check-in
-
-
-
- Save this QR and shows it to attendees at the event to let them
- join the memories creation!
-
- {selectedEvent && (
-
setQrCodeVisible(true)}
- />
- )}
-
-
+
+
{selectedEvent ? (
@@ -435,63 +450,13 @@ export default function EventDetails({ params }: { params: any }) {
-
+
setEventQRCodeDialogVisible(false)}
+ />
);
}
diff --git a/app/services/axios/requests/GetEventDetailsLink/index.ts b/app/services/axios/requests/GetEventDetailsLink/index.ts
new file mode 100644
index 0000000..92189f1
--- /dev/null
+++ b/app/services/axios/requests/GetEventDetailsLink/index.ts
@@ -0,0 +1,11 @@
+import { ResultAsync } from "neverthrow";
+import axiosInstance from "../../index";
+
+const GetEventDetailsLink = (eventId: string): ResultAsync => {
+ return ResultAsync.fromPromise(
+ axiosInstance.get(`/events/${eventId}/links/details`),
+ (e: any) => e ?? Error("Error getting the link"),
+ ).map((response) => response.data);
+};
+
+export default GetEventDetailsLink;