"use client"; import Image from "next/image"; import { useEffect, useState } from "react"; import { EventTypes } from "@/utils/types"; import { useParams } from "next/navigation"; import { IoCheckmarkCircleOutline, IoCopyOutline, IoDownloadOutline, IoEyeOffOutline, IoEyeOutline, IoHourglassOutline, IoReloadOutline, IoSaveOutline, } from "react-icons/io5"; import { GiStarFormation } from "react-icons/gi"; import { configureAbly, useChannel, usePresence } from "@ably-labs/react-hooks"; import Link from "next/link"; import { FaShieldAlt } from "react-icons/fa"; import { RiVipCrownFill } from "react-icons/ri"; import { env } from "@/env.mjs"; import { downloadCSV, isAdmin, isVIP } from "@/utils/helpers"; import type { PresenceItem } from "@/utils/types"; import { useUser } from "@clerk/nextjs"; import { trpc } from "@/app/_trpc/client"; export const dynamic = "force-dynamic"; const Room = () => { const { isSignedIn } = useUser(); return (
{!isSignedIn ? (
) : ( )}
); }; export default Room; const RoomBody = ({}) => { const { isSignedIn, user } = useUser(); const params = useParams(); const roomId = params?.id as string; const [storyNameText, setStoryNameText] = useState(""); const [roomScale, setRoomScale] = useState(""); const [copied, setCopied] = useState(false); const { data: roomFromDb, refetch: refetchRoomFromDb } = trpc.room.get.useQuery({ id: roomId }); const { data: votesFromDb, refetch: refetchVotesFromDb } = trpc.vote.getAllByRoomId.useQuery({ roomId }); const setVoteInDb = trpc.vote.set.useMutation({}); const setRoomInDb = trpc.room.set.useMutation({}); configureAbly({ key: env.NEXT_PUBLIC_ABLY_PUBLIC_KEY, clientId: user?.id, recover: (_, cb) => { cb(true); }, }); const [channel] = useChannel( { channelName: `${env.NEXT_PUBLIC_APP_ENV}-${roomId}`, }, ({ name }) => { if (name === EventTypes.ROOM_UPDATE) { void refetchVotesFromDb(); void refetchRoomFromDb(); } else if (name === EventTypes.VOTE_UPDATE) { void refetchVotesFromDb(); } } ); const [presenceData] = usePresence( `${env.NEXT_PUBLIC_APP_ENV}-${roomId}`, { name: user?.fullName || "", image: user?.imageUrl || "", client_id: user?.id || "", isAdmin: isAdmin(user?.publicMetadata), isVIP: isVIP(user?.publicMetadata), } ); // Subscribe on mount and unsubscribe on unmount useEffect(() => { window.addEventListener("beforeunload", () => channel.presence.leave()); return () => { window.removeEventListener("beforeunload", () => channel.presence.leave() ); channel.presence.leave(); }; }, [channel.presence, roomId]); // Init story name useEffect(() => { if (isSignedIn && roomFromDb) { setStoryNameText(roomFromDb.storyName || ""); setRoomScale(roomFromDb.scale || "ERROR"); } }, [roomFromDb, roomId, isSignedIn, user]); // Helper functions const getVoteForCurrentUser = () => { if (roomFromDb && isSignedIn) { return votesFromDb && votesFromDb.find((vote) => vote.userId === user.id); } else { return null; } }; const setVote = (value: string) => { if (roomFromDb) { setVoteInDb.mutate({ roomId: roomFromDb.id, value: value, }); } }; const saveRoom = (visible: boolean, reset = false, log = false) => { if (roomFromDb) { setRoomInDb.mutate({ name: storyNameText, roomId: roomFromDb.id, scale: roomScale, visible: visible, reset: reset, log: log, }); } }; const downloadLogs = () => { if (roomFromDb && votesFromDb) { const jsonObject = roomFromDb?.logs .map((item) => { return { id: item.id, created_at: item.created_at, userId: item.userId, roomId: item.roomId, roomName: item.roomName, storyName: item.storyName, scale: item.scale, votes: item.votes, }; }) .concat({ id: "LATEST", created_at: new Date(), userId: roomFromDb.userId, roomId: roomFromDb.id, roomName: roomFromDb.roomName, storyName: storyNameText, scale: roomScale, votes: votesFromDb.map((vote) => { return { value: vote.value, }; }), }); downloadCSV(jsonObject, `sp_${roomId}.csv`); } }; const copyRoomURLHandler = () => { navigator.clipboard .writeText(window.location.href) .then(() => { console.log(`Copied Room Link to Clipboard!`); setCopied(true); setTimeout(() => { setCopied(false); }, 2000); }) .catch(() => { console.log(`Error Copying Room Link to Clipboard!`); }); }; const voteString = ( visible: boolean, votes: typeof votesFromDb, presenceItem: PresenceItem ) => { const matchedVote = votes?.find( (vote) => vote.userId === presenceItem.client_id ); if (visible) { if (!!matchedVote) { return

{matchedVote.value}

; } else { return ; } } else if (!!matchedVote) { return ( ); } else { return ( ); } }; // Room is loading if (roomFromDb === undefined) { return (
{" "}
); // Room has been loaded } else if (roomFromDb) { return (
{roomFromDb.roomName}
ID:
{roomFromDb.id}
{roomFromDb && (

Story: {roomFromDb.storyName}

    {presenceData && presenceData .filter( (value, index, self) => index === self.findIndex( (presenceItem) => presenceItem.clientId === value.clientId ) ) .map((presenceItem) => { return (
  • {`${presenceItem.data.name}'s

    {presenceItem.data.name}{" "} {presenceItem.data.isAdmin && (

    )}{" "} {presenceItem.data.isVIP && (
    )}{" "} {presenceItem.clientId === roomFromDb.userId && (
    )} {" : "}

    {roomFromDb && votesFromDb && voteString( roomFromDb.visible, votesFromDb, presenceItem.data )}
  • ); })}
{roomFromDb.scale.split(",").map((scaleItem, index) => { return ( ); })}
)} {isSignedIn && !!roomFromDb && (roomFromDb.userId === user.id || isAdmin(user?.publicMetadata)) && ( <>

Room Settings

{ setRoomScale(event.target.value); }} /> { setStoryNameText(event.target.value); }} />
{votesFromDb && (roomFromDb.logs.length > 0 || votesFromDb.length > 0) && (
)}
)}
); // Room does not exist } else { return (

4️⃣0️⃣4️⃣

Oops! This room does not appear to exist, or may have been deleted! 😢

Back to Home
); } };