From b830170642b45de698e66143ec65ff1c00203bbd Mon Sep 17 00:00:00 2001
From: Izan Gil <66965250+SrIzan10@users.noreply.github.com>
Date: Fri, 24 Jan 2025 23:32:20 +0100
Subject: [PATCH] feat: add stream info editing functionality
---
next.config.mjs | 8 +-
package.json | 5 +-
.../migration.sql | 15 +++
.../20250118223753_add_is_live/migration.sql | 8 ++
.../migration.sql | 11 ++
prisma/schema.prisma | 15 +++
src/app/(protected)/[username]/page.tsx | 10 +-
src/app/layout.tsx | 7 +-
.../app/EditLivestream/EditLivestream.tsx | 63 +++++++++
src/components/app/Livestream/Livestream.tsx | 14 +-
src/components/app/NavBar/NavBar.tsx | 15 ++-
.../app/StreamPlayer/StreamPlayer.tsx | 2 +
.../app/UniversalForm/UniversalForm.tsx | 7 +-
.../app/UserInfoCard/UserInfoCard.tsx | 13 +-
src/components/ui/dialog.tsx | 122 ++++++++++++++++++
src/lib/auth/index.ts | 2 +-
src/lib/form/actions.ts | 30 +++++
src/lib/form/zod.ts | 8 +-
yarn.lock | 110 +++++++++-------
19 files changed, 387 insertions(+), 78 deletions(-)
create mode 100644 prisma/migrations/20250118220020_stream_infov1/migration.sql
create mode 100644 prisma/migrations/20250118223753_add_is_live/migration.sql
create mode 100644 prisma/migrations/20250124215305_owned_by_stream_info/migration.sql
create mode 100644 src/components/app/EditLivestream/EditLivestream.tsx
create mode 100644 src/components/ui/dialog.tsx
create mode 100644 src/lib/form/actions.ts
diff --git a/next.config.mjs b/next.config.mjs
index b5bcefb..8c4eaec 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -1,9 +1,9 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
- webpack: (config) => {
- config.externals.push("@node-rs/argon2");
- return config;
- }
+ webpack: (config) => {
+ config.externals.push('@node-rs/argon2');
+ return config;
+ },
};
export default nextConfig;
diff --git a/package.json b/package.json
index 85021f7..85f6c07 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"scripts": {
- "dev": "docker compose --file dev/docker-compose.yml up -d && next dev --turbo --experimental-https",
+ "dev": "docker compose --file dev/docker-compose.yml up -d && next dev --experimental-https --turbo",
"setup": "docker compose --file dev/docker-compose.yml up -d && prisma migrate deploy",
"build": "prisma generate && next build",
"start": "next start",
@@ -32,7 +32,7 @@
"livekit-server-sdk": "^2.9.7",
"lucia": "^3.2.2",
"lucide-react": "^0.473.0",
- "next": "^15.1.2",
+ "next": "^15.1.6",
"next-themes": "^0.4.4",
"react": "19",
"react-dom": "19",
@@ -40,6 +40,7 @@
"sonner": "^1.4.41",
"tailwind-merge": "^2.2.2",
"tailwindcss-animate": "^1.0.7",
+ "valtio": "^2.1.2",
"zod": "^3.24.1"
},
"devDependencies": {
diff --git a/prisma/migrations/20250118220020_stream_infov1/migration.sql b/prisma/migrations/20250118220020_stream_infov1/migration.sql
new file mode 100644
index 0000000..f3f255f
--- /dev/null
+++ b/prisma/migrations/20250118220020_stream_infov1/migration.sql
@@ -0,0 +1,15 @@
+-- CreateTable
+CREATE TABLE "StreamInfo" (
+ "id" TEXT NOT NULL,
+ "username" TEXT NOT NULL,
+ "title" TEXT NOT NULL,
+ "thumbnail" TEXT NOT NULL,
+ "viewers" INTEGER NOT NULL,
+ "category" TEXT NOT NULL,
+ "startedAt" TIMESTAMP(3) NOT NULL,
+
+ CONSTRAINT "StreamInfo_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "StreamInfo_username_key" ON "StreamInfo"("username");
diff --git a/prisma/migrations/20250118223753_add_is_live/migration.sql b/prisma/migrations/20250118223753_add_is_live/migration.sql
new file mode 100644
index 0000000..95aa300
--- /dev/null
+++ b/prisma/migrations/20250118223753_add_is_live/migration.sql
@@ -0,0 +1,8 @@
+/*
+ Warnings:
+
+ - Added the required column `isLive` to the `StreamInfo` table without a default value. This is not possible if the table is not empty.
+
+*/
+-- AlterTable
+ALTER TABLE "StreamInfo" ADD COLUMN "isLive" BOOLEAN NOT NULL;
diff --git a/prisma/migrations/20250124215305_owned_by_stream_info/migration.sql b/prisma/migrations/20250124215305_owned_by_stream_info/migration.sql
new file mode 100644
index 0000000..85a7e62
--- /dev/null
+++ b/prisma/migrations/20250124215305_owned_by_stream_info/migration.sql
@@ -0,0 +1,11 @@
+/*
+ Warnings:
+
+ - Added the required column `userId` to the `StreamInfo` table without a default value. This is not possible if the table is not empty.
+
+*/
+-- AlterTable
+ALTER TABLE "StreamInfo" ADD COLUMN "userId" TEXT NOT NULL;
+
+-- AddForeignKey
+ALTER TABLE "StreamInfo" ADD CONSTRAINT "StreamInfo_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 2d73c2d..a58d79c 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -19,6 +19,7 @@ model User {
pfpUrl String
username String @unique
sessions Session[]
+ streams StreamInfo[]
}
model Session {
@@ -26,4 +27,18 @@ model Session {
userId String
expiresAt DateTime
user User @relation(references: [id], fields: [userId], onDelete: Cascade)
+}
+
+model StreamInfo {
+ id String @id @default(cuid())
+ username String @unique
+ title String
+ thumbnail String
+ viewers Int
+ category String
+ startedAt DateTime
+ isLive Boolean
+
+ ownedBy User @relation(fields: [userId], references: [id])
+ userId String
}
\ No newline at end of file
diff --git a/src/app/(protected)/[username]/page.tsx b/src/app/(protected)/[username]/page.tsx
index de54a65..57015b4 100644
--- a/src/app/(protected)/[username]/page.tsx
+++ b/src/app/(protected)/[username]/page.tsx
@@ -1,8 +1,16 @@
import LiveStream from "@/components/app/Livestream/Livestream";
+import prisma from "@/lib/db";
export default async function Page({ params }: { params: Promise<{ username: string }> }) {
const { username } = await params;
+ const streamInfo = await prisma.streamInfo.findUnique({
+ where: { username },
+ include: { ownedBy: true },
+ });
+ if (!streamInfo) {
+ return
Stream not found
;
+ }
return (
-
+
);
}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 797a15f..2699fc1 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -8,6 +8,8 @@ import { Toaster } from '@/components/ui/sonner';
import { ThemeProvider } from '@/lib/providers/ThemeProvider';
import { SidebarProvider } from '@/components/ui/sidebar';
import Sidebar from '@/components/app/Sidebar/Sidebar';
+import { cn } from '@/lib/utils';
+import EditLivestream from '@/components/app/EditLivestream/EditLivestream';
const inter = Inter({ subsets: ['latin'] });
@@ -24,7 +26,7 @@ export default async function RootLayout({
const sessionData = await validateRequest();
return (
-
+
-
+ {/* this promise is ugly but i'm lazy to fix the type errors */}
+ )}/>
{/* pt-16 for navbar height */}
diff --git a/src/components/app/EditLivestream/EditLivestream.tsx b/src/components/app/EditLivestream/EditLivestream.tsx
new file mode 100644
index 0000000..21826e2
--- /dev/null
+++ b/src/components/app/EditLivestream/EditLivestream.tsx
@@ -0,0 +1,63 @@
+import { Button } from '@/components/ui/button';
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+} from '@/components/ui/dialog';
+import { validateRequest } from '@/lib/auth';
+import prisma from '@/lib/db';
+import { roomService } from '@/lib/services/livekit';
+import { UniversalForm } from '../UniversalForm/UniversalForm';
+import { editStreamInfo } from '@/lib/form/actions';
+
+export default async function EditLivestream() {
+ const { user } = await validateRequest();
+ if ((await prisma.streamInfo.count({ where: { username: user!.username } })) === 0) {
+ const isLive =
+ (await roomService.listRooms()).filter((r) => r.name === user!.username)[0].numPublishers >= 1;
+ await prisma.streamInfo.create({
+ data: {
+ username: user!.username,
+ title: 'Untitled',
+ category: 'Uncategorized',
+ startedAt: new Date(),
+ thumbnail: 'https://placehold.co/150',
+ viewers: 0,
+ isLive,
+ ownedBy: { connect: { username: user!.username } },
+ },
+ });
+ console.log('created');
+ }
+ const streamInfo = await prisma.streamInfo.findUnique({
+ where: { username: user!.username! },
+ });
+ return (
+
+ );
+}
diff --git a/src/components/app/Livestream/Livestream.tsx b/src/components/app/Livestream/Livestream.tsx
index a4b2a39..7332916 100644
--- a/src/components/app/Livestream/Livestream.tsx
+++ b/src/components/app/Livestream/Livestream.tsx
@@ -5,15 +5,16 @@ import { useEffect, useState } from 'react';
import StreamPlayer from '../StreamPlayer/StreamPlayer';
import UserInfoCard from '../UserInfoCard/UserInfoCard';
import ChatPanel from '../ChatPanel/ChatPanel';
+import type { StreamInfo, User } from '@prisma/client';
-export default function LiveStream({ username }: { username: string }) {
+export default function LiveStream(props: Props) {
const [token, setToken] = useState('');
useEffect(() => {
- fetch(`/api/livekit/viewerToken?room=${username}`)
+ fetch(`/api/livekit/viewerToken?room=${props.username}`)
.then((res) => res.json())
.then((data) => setToken(data.token));
- }, [username]);
+ }, [props.username]);
if (!token) return Loading...
;
@@ -22,10 +23,15 @@ export default function LiveStream({ username }: { username: string }) {
);
}
+
+interface Props {
+ username: string;
+ streamInfo: StreamInfo & { ownedBy: User };
+}
\ No newline at end of file
diff --git a/src/components/app/NavBar/NavBar.tsx b/src/components/app/NavBar/NavBar.tsx
index 3867111..03edb6a 100644
--- a/src/components/app/NavBar/NavBar.tsx
+++ b/src/components/app/NavBar/NavBar.tsx
@@ -1,4 +1,4 @@
-'use client';
+'use client'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { Button } from '@/components/ui/button';
@@ -19,9 +19,7 @@ import { ThemeSwitcher } from '../ThemeSwitcher/ThemeSwitcher';
import { Slack } from 'lucide-react';
import { SidebarTrigger } from '@/components/ui/sidebar';
-export const links = [
- { href: '/srizan', name: 'test stream' },
-];
+export const links = [{ href: '/srizan', name: 'test stream' }];
function NavbarLinks() {
return (
@@ -35,12 +33,12 @@ function NavbarLinks() {
);
}
-export default function Navbar() {
+export default function Navbar(props: Props) {
const { user } = useSession();
return (
<>