import { type GetServerSideProps, type NextPage } from "next"; import Head from "next/head"; import Image from "next/image"; import { useEffect, useState } from "react"; import { useSession } from "next-auth/react"; import { useRouter } from "next/router"; import { IoCheckmarkCircleOutline, IoCopyOutline, IoDownloadOutline, IoEyeOffOutline, IoEyeOutline, IoHourglassOutline, IoReloadOutline, IoSaveOutline, } from "react-icons/io5"; import { GiStarFormation } from "react-icons/gi"; import { z } from "zod"; import { api } from "~/utils/api"; import { getServerAuthSession } from "../../server/auth"; 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 } from "~/utils/helpers"; import type { PresenceItem } from "~/utils/types"; export const getServerSideProps: GetServerSideProps = async (ctx) => { const session = await getServerAuthSession(ctx); // Redirect to login if not signed in if (!session) { return { redirect: { destination: `/api/auth/signin?callbackUrl=${ctx.resolvedUrl}`, permanent: false, }, }; } // Return session if logged in return { props: { session }, }; }; const Room: NextPage = () => { return ( <> Sprint Padawan
); }; export default Room; const RoomBody: React.FC = ({}) => { const { data: sessionData } = useSession(); const { query } = useRouter(); const roomId = z.string().parse(query.id); const [storyNameText, setStoryNameText] = useState(""); const [roomScale, setRoomScale] = useState(""); const [copied, setCopied] = useState(false); const { data: roomFromDb, refetch: refetchRoomFromDb } = api.room.get.useQuery({ id: roomId }); const { data: votesFromDb, refetch: refetchVotesFromDb } = api.vote.getAllByRoomId.useQuery({ roomId }); const setVoteInDb = api.vote.set.useMutation({}); const setRoomInDb = api.room.set.useMutation({}); configureAbly({ key: env.NEXT_PUBLIC_ABLY_PUBLIC_KEY, clientId: sessionData?.user.id, recover: (_, cb) => { cb(true); }, }); const [channel] = useChannel( { channelName: `${env.NEXT_PUBLIC_APP_ENV}-${roomId}`, }, ({ name }) => { if (name === "ROOM_UPDATE") { void refetchVotesFromDb(); void refetchRoomFromDb(); } else if (name === "VOTE_UPDATE") { void refetchVotesFromDb(); } } ); const [presenceData] = usePresence( `${env.NEXT_PUBLIC_APP_ENV}-${roomId}`, { name: sessionData?.user.name || "", image: sessionData?.user.image || "", client_id: sessionData?.user.id || "", isAdmin: sessionData?.user.isAdmin || false, isVIP: sessionData?.user.isVIP || false, } ); // 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 (sessionData && roomFromDb) { setStoryNameText(roomFromDb.storyName || ""); setRoomScale(roomFromDb.scale || "ERROR"); } }, [roomFromDb, roomId, sessionData]); // Helper functions const getVoteForCurrentUser = () => { if (roomFromDb && sessionData) { return ( votesFromDb && votesFromDb.find((vote) => vote.userId === sessionData.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 { ...item, scale: item.scale, votes: item.votes, roomName: item.roomName, storyName: item.storyName, }; }) .concat({ id: "LATEST", createdAt: new Date(), userId: roomFromDb.owner.id, roomId: roomFromDb.id, scale: roomScale, votes: votesFromDb.map((vote) => { return { name: vote.owner.name, value: vote.value, }; }), roomName: roomFromDb.roomName, storyName: storyNameText, }); downloadCSV(jsonObject, `sprint-padawan-room-${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 ( ); })}
)} {sessionData && !!roomFromDb && roomFromDb.userId === sessionData.user.id && ( <>

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
); } };