Fixed room 404 issues

This commit is contained in:
Atridad Lahiji 2023-09-27 12:46:15 -06:00 committed by atridadl
parent 0579022489
commit 12f928aa93
No known key found for this signature in database
2 changed files with 87 additions and 78 deletions

View file

@ -1,10 +1,18 @@
"use client"; "use client";
import { EventTypes } from "@/_utils/types";
import Image from "next/image"; import Image from "next/image";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { EventTypes } from "@/_utils/types";
import LoadingIndicator from "@/_components/LoadingIndicator";
import type { PresenceItem, RoomResponse, VoteResponse } from "@/_utils/types";
import { useUser } from "@clerk/nextjs";
import { useChannel, usePresence } from "ably/react";
import { isAdmin, isVIP, jsonToCsv } from "app/_utils/helpers";
import { env } from "env.mjs";
import { useParams } from "next/navigation"; import { useParams } from "next/navigation";
import { FaShieldAlt } from "react-icons/fa";
import { GiStarFormation } from "react-icons/gi";
import { import {
IoCheckmarkCircleOutline, IoCheckmarkCircleOutline,
IoCopyOutline, IoCopyOutline,
@ -15,15 +23,7 @@ import {
IoReloadOutline, IoReloadOutline,
IoSaveOutline, IoSaveOutline,
} from "react-icons/io5"; } from "react-icons/io5";
import { GiStarFormation } from "react-icons/gi";
import { FaShieldAlt } from "react-icons/fa";
import { RiVipCrownFill } from "react-icons/ri"; import { RiVipCrownFill } from "react-icons/ri";
import { env } from "env.mjs";
import { isAdmin, isVIP, jsonToCsv } from "app/_utils/helpers";
import type { PresenceItem, RoomResponse, VoteResponse } from "@/_utils/types";
import LoadingIndicator from "@/_components/LoadingIndicator";
import { useUser } from "@clerk/nextjs";
import { useChannel, usePresence } from "ably/react";
import NoRoomUI from "./NoRoomUI"; import NoRoomUI from "./NoRoomUI";
const VoteUI = () => { const VoteUI = () => {
@ -40,12 +40,15 @@ const VoteUI = () => {
const [votesFromDb, setVotesFromDb] = useState<VoteResponse>(undefined); const [votesFromDb, setVotesFromDb] = useState<VoteResponse>(undefined);
const getRoomHandler = async () => { const getRoomHandler = async () => {
const dbRoomResponse = await fetch(`/api/internal/room/${roomId}`, { fetch(`/api/internal/room/${roomId}`, {
cache: "no-cache", cache: "no-cache",
method: "GET", method: "GET",
}).then(async (response) => {
const dbRoom = (await response.json()) as RoomResponse;
setRoomFromDb(dbRoom);
}).catch(() => {
setRoomFromDb(null);
}); });
const dbRoom = (await dbRoomResponse.json()) as RoomResponse;
setRoomFromDb(dbRoom);
}; };
const getVotesHandler = async () => { const getVotesHandler = async () => {
@ -196,7 +199,7 @@ const VoteUI = () => {
if (visible) { if (visible) {
if (!!matchedVote) { if (!!matchedVote) {
return <div>{matchedVote.value}</div>; return <div>{ matchedVote.value }</div>;
} else { } else {
return <IoHourglassOutline className="text-xl text-error" />; return <IoHourglassOutline className="text-xl text-error" />;
} }
@ -216,30 +219,30 @@ const VoteUI = () => {
} else if (roomFromDb) { } else if (roomFromDb) {
return ( return (
<div className="flex flex-col gap-4 text-center justify-center items-center"> <div className="flex flex-col gap-4 text-center justify-center items-center">
<div className="text-2xl">{roomFromDb.roomName}</div> <div className="text-2xl">{ roomFromDb.roomName }</div>
<div className="flex flex-row flex-wrap text-center justify-center items-center gap-1 text-md"> <div className="flex flex-row flex-wrap text-center justify-center items-center gap-1 text-md">
<div>ID:</div> <div>ID:</div>
<div>{roomFromDb.id}</div> <div>{ roomFromDb.id }</div>
<button> <button>
{copied ? ( { copied ? (
<IoCheckmarkCircleOutline className="mx-1 text-success animate-bounce" /> <IoCheckmarkCircleOutline className="mx-1 text-success animate-bounce" />
) : ( ) : (
<IoCopyOutline <IoCopyOutline
className="mx-1 hover:text-primary" className="mx-1 hover:text-primary"
onClick={copyRoomURLHandler} onClick={ copyRoomURLHandler }
></IoCopyOutline> ></IoCopyOutline>
)} ) }
</button> </button>
</div> </div>
{roomFromDb && ( { roomFromDb && (
<div className="card card-compact bg-base-100 shadow-xl"> <div className="card card-compact bg-base-100 shadow-xl">
<div className="card-body"> <div className="card-body">
<h2 className="card-title">Story: {roomFromDb.storyName}</h2> <h2 className="card-title">Story: { roomFromDb.storyName }</h2>
<ul className="p-0 flex flex-row flex-wrap justify-center items-center text-ceter gap-4"> <ul className="p-0 flex flex-row flex-wrap justify-center items-center text-ceter gap-4">
{presenceData && { presenceData &&
presenceData presenceData
.filter( .filter(
(value, index, self) => (value, index, self) =>
@ -252,81 +255,80 @@ const VoteUI = () => {
.map((presenceItem) => { .map((presenceItem) => {
return ( return (
<li <li
key={presenceItem.clientId} key={ presenceItem.clientId }
className="flex flex-row items-center justify-center gap-2" className="flex flex-row items-center justify-center gap-2"
> >
<div className="w-10 rounded-full avatar"> <div className="w-10 rounded-full avatar">
<Image <Image
src={presenceItem.data.image} src={ presenceItem.data.image }
alt={`${presenceItem.data.name}'s Profile Picture`} alt={ `${presenceItem.data.name}'s Profile Picture` }
height={32} height={ 32 }
width={32} width={ 32 }
/> />
</div> </div>
<p className="flex flex-row flex-wrap text-center justify-center items-center gap-1 text-md"> <p className="flex flex-row flex-wrap text-center justify-center items-center gap-1 text-md">
{presenceItem.data.name}{" "} { presenceItem.data.name }{ " " }
{presenceItem.data.isAdmin && ( { presenceItem.data.isAdmin && (
<span <span
className="tooltip tooltip-primary" className="tooltip tooltip-primary"
data-tip="Admin" data-tip="Admin"
> >
<FaShieldAlt className="inline-block text-primary" /> <FaShieldAlt className="inline-block text-primary" />
</span> </span>
)}{" "} ) }{ " " }
{presenceItem.data.isVIP && ( { presenceItem.data.isVIP && (
<span <span
className="tooltip tooltip-secondary" className="tooltip tooltip-secondary"
data-tip="VIP" data-tip="VIP"
> >
<GiStarFormation className="inline-block text-secondary" /> <GiStarFormation className="inline-block text-secondary" />
</span> </span>
)}{" "} ) }{ " " }
{presenceItem.clientId === roomFromDb.userId && ( { presenceItem.clientId === roomFromDb.userId && (
<span <span
className="tooltip tooltip-warning" className="tooltip tooltip-warning"
data-tip="Room Owner" data-tip="Room Owner"
> >
<RiVipCrownFill className="inline-block text-yellow-500" /> <RiVipCrownFill className="inline-block text-yellow-500" />
</span> </span>
)} ) }
{" : "} { " : " }
</p> </p>
{roomFromDb && { roomFromDb &&
votesFromDb && votesFromDb &&
voteString( voteString(
roomFromDb.visible, roomFromDb.visible,
votesFromDb, votesFromDb,
presenceItem.data presenceItem.data
)} ) }
</li> </li>
); );
})} }) }
</ul> </ul>
<div className="join md:btn-group-horizontal"> <div className="join md:btn-group-horizontal">
{roomFromDb.scale?.split(",").map((scaleItem, index) => { { roomFromDb.scale?.split(",").map((scaleItem, index) => {
return ( return (
<button <button
key={index} key={ index }
className={`join-item ${ className={ `join-item ${getVoteForCurrentUser()?.value === scaleItem
getVoteForCurrentUser()?.value === scaleItem ? "btn btn-active btn-primary"
? "btn btn-active btn-primary" : "btn"
: "btn" }` }
}`} onClick={ () => void setVoteHandler(scaleItem) }
onClick={() => void setVoteHandler(scaleItem)}
> >
{scaleItem} { scaleItem }
</button> </button>
); );
})} }) }
</div> </div>
</div> </div>
</div> </div>
)} ) }
{!!roomFromDb && { !!roomFromDb &&
(roomFromDb.userId === user?.id || isAdmin(user?.publicMetadata)) && ( (roomFromDb.userId === user?.id || isAdmin(user?.publicMetadata)) && (
<> <>
<div className="card card-compact bg-base-100 shadow-xl"> <div className="card card-compact bg-base-100 shadow-xl">
@ -334,40 +336,40 @@ const VoteUI = () => {
<h2 className="card-title">Room Settings</h2> <h2 className="card-title">Room Settings</h2>
<label className="label"> <label className="label">
{"Vote Scale (Comma Separated):"}{" "} { "Vote Scale (Comma Separated):" }{ " " }
</label> </label>
<input <input
type="text" type="text"
placeholder="Scale (Comma Separated)" placeholder="Scale (Comma Separated)"
className="input input-bordered" className="input input-bordered"
value={roomScale} value={ roomScale }
onChange={(event) => { onChange={ (event) => {
setRoomScale(event.target.value); setRoomScale(event.target.value);
}} } }
/> />
<label className="label">{"Story Name:"} </label> <label className="label">{ "Story Name:" } </label>
<input <input
type="text" type="text"
placeholder="Story Name" placeholder="Story Name"
className="input input-bordered" className="input input-bordered"
value={storyNameText} value={ storyNameText }
onChange={(event) => { onChange={ (event) => {
setStoryNameText(event.target.value); setStoryNameText(event.target.value);
}} } }
/> />
<div className="flex flex-row flex-wrap text-center items-center justify-center gap-2"> <div className="flex flex-row flex-wrap text-center items-center justify-center gap-2">
<div> <div>
<button <button
onClick={() => onClick={ () =>
void setRoomHandler(!roomFromDb.visible, false) void setRoomHandler(!roomFromDb.visible, false)
} }
className="btn btn-primary inline-flex" className="btn btn-primary inline-flex"
> >
{roomFromDb.visible ? ( { roomFromDb.visible ? (
<> <>
<IoEyeOffOutline className="text-xl mr-1" /> <IoEyeOffOutline className="text-xl mr-1" />
Hide Hide
@ -377,13 +379,13 @@ const VoteUI = () => {
<IoEyeOutline className="text-xl mr-1" /> <IoEyeOutline className="text-xl mr-1" />
Show Show
</> </>
)} ) }
</button> </button>
</div> </div>
<div> <div>
<button <button
onClick={() => onClick={ () =>
void setRoomHandler( void setRoomHandler(
false, false,
true, true,
@ -400,8 +402,8 @@ const VoteUI = () => {
).length <= 1 ).length <= 1
} }
> >
{roomFromDb.storyName === storyNameText || { roomFromDb.storyName === storyNameText ||
votesFromDb?.length === 0 ? ( votesFromDb?.length === 0 ? (
<> <>
<IoReloadOutline className="text-xl mr-1" /> Reset <IoReloadOutline className="text-xl mr-1" /> Reset
</> </>
@ -409,16 +411,16 @@ const VoteUI = () => {
<> <>
<IoSaveOutline className="text-xl mr-1" /> Save <IoSaveOutline className="text-xl mr-1" /> Save
</> </>
)} ) }
</button> </button>
</div> </div>
{votesFromDb && { votesFromDb &&
(roomFromDb.logs.length > 0 || (roomFromDb.logs.length > 0 ||
votesFromDb.length > 0) && ( votesFromDb.length > 0) && (
<div> <div>
<button <button
onClick={() => downloadLogs()} onClick={ () => downloadLogs() }
className="btn btn-primary inline-flex hover:animate-pulse" className="btn btn-primary inline-flex hover:animate-pulse"
> >
<> <>
@ -426,12 +428,12 @@ const VoteUI = () => {
</> </>
</button> </button>
</div> </div>
)} ) }
</div> </div>
</div> </div>
</div> </div>
</> </>
)} ) }
</div> </div>
); );
// Room does not exist // Room does not exist

View file

@ -1,13 +1,13 @@
import { type NextRequest, NextResponse } from "next/server"; import { NextResponse, type NextRequest } from "next/server";
import { db } from "@/_lib/db";
import { logs, rooms, votes } from "@/_lib/schema";
import { eq } from "drizzle-orm";
import { publishToChannel } from "@/_lib/ably"; import { publishToChannel } from "@/_lib/ably";
import { EventTypes } from "@/_utils/types"; import { db } from "@/_lib/db";
import { invalidateCache } from "@/_lib/redis"; import { invalidateCache } from "@/_lib/redis";
import { createId } from "@paralleldrive/cuid2"; import { logs, rooms, votes } from "@/_lib/schema";
import { EventTypes } from "@/_utils/types";
import { getAuth } from "@clerk/nextjs/server"; import { getAuth } from "@clerk/nextjs/server";
import { createId } from "@paralleldrive/cuid2";
import { eq } from "drizzle-orm";
export const runtime = "edge"; export const runtime = "edge";
export const preferredRegion = ["pdx1"]; export const preferredRegion = ["pdx1"];
@ -30,10 +30,17 @@ export async function GET(
}, },
}); });
return NextResponse.json(roomFromDb, { if (roomFromDb) {
status: 200, return NextResponse.json(roomFromDb, {
statusText: "SUCCESS", status: 200,
}); statusText: "SUCCESS",
});
} else {
return new NextResponse("ROOM NOT FOUND", {
status: 404,
statusText: "ROOM NOT FOUND",
});
}
} }
export async function DELETE( export async function DELETE(