import { getAuth } from "@clerk/remix/ssr.server"; import { type LoaderFunction, redirect } from "@remix-run/node"; import { useParams } from "@remix-run/react"; import { CheckCircleIcon, CopyIcon, CrownIcon, DownloadIcon, EyeIcon, EyeOffIcon, HourglassIcon, RefreshCwIcon, SaveIcon, ShieldIcon, StarIcon, } from "lucide-react"; import { useEffect, useState } from "react"; import LoadingIndicator from "~/components/LoadingIndicator"; import { useEventSource } from "remix-utils/sse/react"; import type { PresenceItem, RoomResponse, VoteResponse, } from "~/services/types.client"; import { isAdmin, jsonToCsv } from "~/services/helpers.client"; import { ClerkLoaded, ClerkLoading, useUser } from "@clerk/remix"; import { db } from "~/services/db.server"; import { rooms } from "~/services/schema.server"; import { eq } from "drizzle-orm"; import ErrorPage from "~/components/ErrorPage"; import { isShit } from "~/services/helpers.server"; // Loader export const loader: LoaderFunction = async (args) => { const { userId, sessionClaims } = await getAuth(args); if (!userId) { return redirect("/sign-in"); } const room = await db.query.rooms.findFirst({ where: eq(rooms.id, args.params.roomId as string), }); if (!room) { throw new Response( "Oops! This room does not appear to exist, or may have been deleted!", { status: 404, statusText: "NOT FOUND", } ); } const email = sessionClaims.email as string; const shit = isShit(email); if (shit) { throw new Response( "Gee Willikers! I'm sure I put that room around here somewhere... sorry one moment while I look around... I swear I just had it...", { status: 418, statusText: "I'M A LITTLE TEA POT", } ); } return {}; }; // Error handler export function ErrorBoundary() { return ; } // Page Entry Point export default function Room() { return ( <> ); } function RoomContent() { const { user } = useUser(); const params = useParams(); const roomId = params.roomId; let roomFromDb = useEventSource(`/api/room/get/${roomId}`, { event: `room-${params.roomId}`, }); let votesFromDb = useEventSource(`/api/votes/get/${roomId}`, { event: `votes-${params.roomId}`, }); let presenceData = useEventSource(`/api/room/presence/get/${roomId}`, { event: `${user?.id}-${params.roomId}`, }); let roomFromDbParsed = (roomFromDb ? JSON.parse(roomFromDb!) : undefined) as | RoomResponse | null | undefined; let votesFromDbParsed = JSON.parse(votesFromDb!) as VoteResponse | undefined; let presenceDateParsed = JSON.parse(presenceData!) as | PresenceItem[] | undefined; const [storyNameText, setStoryNameText] = useState(""); const [roomScale, setRoomScale] = useState(""); const [copied, setCopied] = useState(false); // Handlers // ================================= async function setVoteHandler(value: string) { if (roomFromDb) { await fetch(`/api/vote/set/${roomId}`, { cache: "no-cache", method: "PUT", body: JSON.stringify({ value, }), }); } } async function setRoomHandler(data: { visible: boolean; reset: boolean | undefined; log: boolean | undefined; }) { if (roomFromDb) { await fetch(`/api/room/set/${roomId}`, { cache: "no-cache", method: "PUT", body: JSON.stringify({ name: storyNameText, visible: data.visible, scale: roomScale, reset: data.reset ? data.reset : false, log: data.log ? data.log : false, }), }); } } // Helpers // ================================= const getVoteForCurrentUser = () => { if (roomFromDb) { return ( votesFromDbParsed && votesFromDbParsed.find((vote) => vote.userId === user?.id) ); } else { return null; } }; const downloadLogs = () => { if (roomFromDbParsed && votesFromDbParsed) { const jsonObject = roomFromDbParsed?.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: roomFromDbParsed.userId, roomId: roomFromDbParsed.id, roomName: roomFromDbParsed.roomName, storyName: storyNameText, scale: roomScale, votes: votesFromDbParsed?.map((vote) => { return { value: vote.value, }; }), }); jsonToCsv(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 votesFromDbParsed, presenceItem: PresenceItem ) => { const matchedVote = votes?.find( (vote) => vote.userId === presenceItem.userId ); if (visible) { if (matchedVote) { return
{matchedVote.value}
; } else { return ; } } else if (matchedVote) { return ; } else { return ; } }; // Hooks // ================================= useEffect(() => { if (roomFromDb) { setStoryNameText(roomFromDbParsed?.storyName || ""); setRoomScale(roomFromDbParsed?.scale || "ERROR"); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [roomFromDb]); // UI // ================================= // Room is loading if (!roomFromDbParsed) { return ; // Room has been loaded } else { return (
{roomFromDbParsed?.roomName}
ID:
{roomFromDbParsed?.id}
{roomFromDb && (

Story: {roomFromDbParsed?.storyName}

    {presenceData && presenceDateParsed ?.filter( (value, index, self) => index === self.findIndex( (presenceItem) => presenceItem.userId === value.userId ) ) .map((presenceItem) => { return (
  • {`${presenceItem.userFullName}'s

    {presenceItem.userFullName}{" "} {presenceItem.isAdmin && ( )}{" "} {presenceItem.isVIP && ( )}{" "} {presenceItem.userId === roomFromDbParsed?.userId && ( )} {" : "}

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

Room Settings

{ setRoomScale(event.target.value); }} /> { setStoryNameText(event.target.value); }} />
{votesFromDb && (roomFromDbParsed?.logs.length > 0 || votesFromDb.length > 0) && (
)}
)}
); } }