import { type NextPage } from "next";
import Image from "next/image";
import Head from "next/head";
import { type GetServerSideProps } from "next";
import { useEffect, useState } from "react";
import { getServerAuthSession } from "../../server/auth";
import { useRouter } from "next/router";
import { api } from "~/utils/api";
import { z } from "zod";
import { useSession } from "next-auth/react";
import {
IoCopyOutline,
IoHourglassOutline,
IoCheckmarkCircleOutline,
IoEyeOutline,
IoEyeOffOutline,
IoSaveOutline,
IoReloadOutline,
IoDownloadOutline,
} from "react-icons/io5";
import type { Prisma, Vote } from "@prisma/client";
import { configureAbly, useChannel, usePresence } from "@ably-labs/react-hooks";
import type { PresenceItem } from "~/utils/types";
import { env } from "~/env.mjs";
import Loading from "~/components/Loading";
import { FaShieldAlt } from "react-icons/fa";
import { RiVipCrownFill } from "react-icons/ri";
import Link from "next/link";
import { downloadCSV } from "~/utils/helpers";
export const getServerSideProps: GetServerSideProps = async (ctx) => {
const session = await getServerAuthSession(ctx);
// Redirect to home if not logged in
if (!session) {
return {
redirect: {
destination: `/api/auth/signin?callbackUrl=${ctx.resolvedUrl}`,
permanent: false,
},
};
}
// Return session if logged in
return {
props: { session },
};
};
interface ExtendedVote extends Vote {
id: string;
userId: string;
roomId: string;
owner: {
image: string | null;
_count: Prisma.UserCountOutputType;
name: string | null;
email: string | null;
};
value: string;
}
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 { data: roomFromDb, refetch: refetchRoomFromDb } =
api.room.get.useQuery({ id: 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}`,
},
() => void refetchRoomFromDb()
);
const [presenceData] = usePresence(
`${env.NEXT_PUBLIC_APP_ENV}-${roomId}`,
{
name: sessionData?.user.name || "",
image: sessionData?.user.image || "",
client_id: sessionData?.user.id || "",
role: sessionData?.user.role || "USER",
}
);
// Subscribe on mount and unsubscribe on unmount
useEffect(() => {
window.addEventListener("beforeunload", () => channel.presence.leave());
return () => {
localStorage.removeItem(`${roomId}_story_name`);
localStorage.removeItem(`${roomId}_room_scale`);
window.removeEventListener("beforeunload", () =>
channel.presence.leave()
);
channel.presence.leave();
};
}, [channel.presence]);
// Init story name
useEffect(() => {
if (sessionData && roomFromDb) {
setStoryNameText(
localStorage.getItem(`${roomId}_story_name`) ||
roomFromDb.storyName ||
""
);
setRoomScale(
localStorage.getItem(`${roomId}_room_scale`) ||
roomFromDb.scale ||
"ERROR"
);
}
}, [roomFromDb, sessionData]);
// Helper functions
const getVoteForCurrentUser = () => {
if (roomFromDb && sessionData) {
return (
roomFromDb &&
roomFromDb.votes.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) {
// const element = document.createElement("a");
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: roomFromDb.votes.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!`);
})
.catch(() => {
console.log(`Error Copying Room Link to Clipboard!`);
});
};
const voteString = (
visible: boolean,
votes: ExtendedVote[],
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}
{roomFromDb && (
Story: {roomFromDb.storyName}
{roomFromDb.scale.split(",").map((scaleItem, index) => {
return (
);
})}
)}
{sessionData &&
!!roomFromDb &&
roomFromDb.userId === sessionData.user.id && (
<>
Room Settings
{
setRoomScale(event.target.value);
localStorage.setItem(
`${roomId}_room_scale`,
event.target.value
);
}}
/>
{
setStoryNameText(event.target.value);
localStorage.setItem(
`${roomId}_story_name`,
event.target.value
);
}}
/>
{(roomFromDb.logs.length > 0 ||
roomFromDb.votes.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
);
}
};