import { type NextPage } from "next";
import Head from "next/head";
import Image from "next/image";
import { useEffect, useState } from "react";
import { EventTypes } from "~/utils/types";
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 { api } from "~/utils/api";
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";
const Room: NextPage = () => {
const { isSignedIn } = useUser();
return (
<>
Sprint Padawan
{!isSignedIn ? (
) : (
)}
>
);
};
export default Room;
const RoomBody = ({}) => {
const { isSignedIn, user } = useUser();
const { query } = useRouter();
const roomId = query.id as string;
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: 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 {
...item,
scale: item.scale,
votes: item.votes,
roomName: item.roomName,
storyName: item.storyName,
};
})
.concat({
id: "LATEST",
created_at: new Date(),
userId: roomFromDb.userId,
roomId: roomFromDb.id,
scale: roomScale,
votes: votesFromDb.map((vote) => {
return {
value: vote.value,
};
}),
room: roomFromDb,
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}
{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
);
}
};