Skip to content

Commit

Permalink
Merge pull request #12 from hookdeck/feat/support-edits
Browse files Browse the repository at this point in the history
feat: edit the title and description
  • Loading branch information
leggetter committed Aug 18, 2024
2 parents 4d9f3f2 + eadd42b commit 85009be
Show file tree
Hide file tree
Showing 24 changed files with 3,411 additions and 323 deletions.
56 changes: 56 additions & 0 deletions app/actions/vlogs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"use server";

import { VlogItem } from "@/types/VlogItem";
import { createClient } from "@/utils/supabase/server";
import { revalidatePath } from "next/cache";

export async function updateVlog(prevState: any, formData: FormData) {
const supabase = createClient();
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
throw new Error("You must be logged in to update a vlog title");
}

const vlogId = formData.get("vlogId") as string;
const title = formData.get("title") as string;
const description = formData.get("description") as string;

// TODO: validate form data
const updates: { title?: string; description?: string } = {};
if (title) {
updates["title"] = title;
}
if (description) {
updates["description"] = description;
}

const { data, error } = await supabase
.from("videos")
.select("*")
.eq("id", vlogId)
.single();

if (error) {
// TODO: handle error
console.error("Could not find vlog with ID", vlogId);
return;
}

if (data) {
const vlog = data as VlogItem;
const { error } = await supabase
.from("videos")
.update(updates)
.eq("id", vlogId);
if (!error) {
revalidatePath(`/vlogs/${vlog.by_username}/${vlogId}`);
return { updated: true };
} else {
// TODO: handle error
console.error("Error updating vlog title for vlog with ID", vlogId);
return;
}
}
}
3 changes: 1 addition & 2 deletions app/auth/callback/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ export async function GET(request: Request) {
const code = requestUrl.searchParams.get("code");

if (code) {
const cookieStore = cookies();
const supabase = createClient(cookieStore);
const supabase = createClient();
const response = await supabase.auth.exchangeCodeForSession(code);
const user = response.data.user;

Expand Down
16 changes: 12 additions & 4 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { GeistSans } from "geist/font/sans";
import "./globals.css";
import { cookies } from "next/headers";
import type { Metadata } from "next";
import { createClient } from "@/utils/supabase/server";
import AuthButton from "@/components/AuthButton";
import Link from "next/link";
import Image from "next/image";

let defaultUrl = process.env.NEXT_PUBLIC_WEBSITE_URL;
if (!defaultUrl) {
Expand All @@ -28,8 +28,7 @@ export default async function RootLayout({
}: {
children: React.ReactNode;
}) {
const cookieStore = cookies();
const supabase = createClient(cookieStore);
const supabase = createClient();
const user = await supabase.auth.getUser();

return (
Expand All @@ -46,7 +45,16 @@ export default async function RootLayout({
<nav className="w-full flex justify-center border-b border-b-foreground/10 h-16">
<div className="w-full max-w-4xl flex justify-between items-center p-3 text-sm">
<span className="text-2xl">
<Link href="/">SupaVlog</Link>
<Link className="flex flex-row gap-1 items-center" href="/">
<Image
src="/icons/video.svg"
width={24}
height={24}
alt="Video icon"
className="dark:invert"
/>
SupaVlog
</Link>
</span>
{user && <AuthButton />}
</div>
Expand Down
4 changes: 1 addition & 3 deletions app/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { cookies } from "next/headers";
import { createClient } from "@/utils/supabase/server";
import { redirect } from "next/navigation";
import LinkButton from "@/components/LinkButton";
Expand All @@ -13,8 +12,7 @@ export default function Login({

const email = formData.get("email") as string;
const password = formData.get("password") as string;
const cookieStore = cookies();
const supabase = createClient(cookieStore);
const supabase = createClient();

const { error } = await supabase.auth.signInWithPassword({
email,
Expand Down
2 changes: 1 addition & 1 deletion app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default async function Home() {
width={24}
height={24}
alt="Video icon"
className="invert"
className="dark:invert"
/>
Watch the Vlogs
</Link>
Expand Down
5 changes: 2 additions & 3 deletions app/signup/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { headers, cookies } from "next/headers";
import { headers } from "next/headers";
import { createClient } from "@/utils/supabase/server";
import { redirect } from "next/navigation";
import LinkButton from "@/components/LinkButton";
Expand All @@ -16,8 +16,7 @@ export default function Login({
const email = formData.get("email") as string;
const password = formData.get("password") as string;
const username = formData.get("username") as string;
const cookieStore = cookies();
const supabase = createClient(cookieStore);
const supabase = createClient();

const { error } = await supabase.auth.signUp({
email,
Expand Down
58 changes: 33 additions & 25 deletions app/vlogs/[username]/[vlog_id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { Metadata, ResolvingMetadata } from "next";

import { cookies } from "next/headers";
import { createClient } from "@/utils/supabase/server";
import { notFound } from "next/navigation";
import { VlogItem } from "@/types/VlogItem";
Expand All @@ -9,6 +8,8 @@ import RecordAVlogButtonSection from "@/components/RecordAVlogButtonSection";
import Breadcrumb from "@/components/Breadcrumb";
import Link from "next/link";
import DeleteVlogButton from "@/components/DeleteVlogButton";
import VlogTitle from "@/components/VlogTitle";
import VlogDescription from "@/components/VlogDescription";

const serverClient = getClient();

Expand Down Expand Up @@ -43,6 +44,7 @@ const getVlogFromStream = async (vlogId: string): Promise<VlogItem | null> => {
title: callResponse.call.custom.title,
by_username: callResponse.call.created_by.name!,
by_user_id: callResponse.call.created_by.id,
description: callResponse.call.custom.description,
};
}
}
Expand All @@ -56,11 +58,10 @@ const getVlogFromSupabase = async (
let vlog: VlogItem | null = null;

// TODO: can we reduce the duplication of creating two Supabase clients?
const cookieStore = cookies();
const supabase = createClient(cookieStore);
const supabase = createClient();

const joinQuery =
"user_id, url, thumbnail_url, created_at, title, profiles(username)";
"user_id, url, description, thumbnail_url, created_at, title, profiles(username)";
const { data, error } = await supabase
.from("videos")
.select(joinQuery)
Expand All @@ -77,6 +78,7 @@ const getVlogFromSupabase = async (
id: vlogId,
url: recording.url,
thumbnail_url: recording.thumbnail_url,
description: recording.description,
filename: recording.url
? recording.url.substring(recording.url.lastIndexOf("/") + 1)
: null,
Expand All @@ -97,6 +99,7 @@ const getVlog = async (vlogId: string): Promise<VlogItem | null> => {
? await getVlogFromStream(vlogId)
: await getVlogFromSupabase(vlogId);

console.log({ vlog });
return vlog;
};

Expand Down Expand Up @@ -130,10 +133,11 @@ export default async function SingleVlog({ params }: Props) {
vlog?.title || "No title available";

// TODO: can we reduce the duplication of creating two Supabase clients?
const cookieStore = cookies();
const supabase = createClient(cookieStore);
const supabase = createClient();
const currentUser = await supabase.auth.getUser();

const allowEdits = currentUser.data.user?.id === vlog?.by_user_id;

return (
<div className="flex-1 flex flex-col w-full gap-10">
<Breadcrumb structureOverride={navOverride} />
Expand All @@ -142,21 +146,24 @@ export default async function SingleVlog({ params }: Props) {
) : (
<>
<RecordAVlogButtonSection />
<div className="flex-1 flex flex-col w-full justify-center gap-10">
<div className="flex flex-col gap-2">
<h2 className="text-2xl text-center">
{vlog.title || "No title available"}
</h2>
<h3 className="text-lg text-center">
By{" "}
{vlog.by_username ? (
<Link href={`/vlogs/${vlog.by_username}`}>
{vlog.by_username}
</Link>
) : (
"Unknown user"
)}
</h3>
<div className="flex-1 flex flex-col w-full items-center gap-10">
<div className="flex flex-col gap-2 items-center">
<VlogTitle vlog={vlog} allowEdits={allowEdits} />
<div className="flex flex-row items-center gap-2">
<h3 className="text-lg text-center">
By{" "}
{vlog.by_username ? (
<Link href={`/vlogs/${vlog.by_username}`}>
{vlog.by_username}
</Link>
) : (
"Unknown user"
)}
</h3>
<span className="text-sm">
{new Date(vlog.end_time).toLocaleString()}
</span>
</div>
</div>
{vlog.url ? (
<video controls>
Expand All @@ -167,14 +174,15 @@ export default async function SingleVlog({ params }: Props) {
<p>Video is still processing...</p>
</div>
)}

<span>{new Date(vlog.end_time).toLocaleString()}</span>
</div>
{currentUser.data.user?.id === vlog.by_user_id && (
<div className="flex-1 flex flex-col w-full justify-center gap-10">
{allowEdits && (
<div className="flex-1 flex flex-row w-full justify-center gap-10">
<DeleteVlogButton vlogId={vlog.id} username={vlog.by_username} />
</div>
)}
<div className="flex justify-center">
<VlogDescription vlog={vlog} allowEdits={allowEdits} />
</div>
</>
)}
</div>
Expand Down
3 changes: 1 addition & 2 deletions app/vlogs/[username]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ export default async function VlogByUsername({
}: {
params: { username: string };
}) {
const cookieStore = cookies();
const supabase = createClient(cookieStore);
const supabase = createClient();
const {
data: { user },
} = await supabase.auth.getUser();
Expand Down
3 changes: 1 addition & 2 deletions app/vlogs/new/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import Breadcrumb from "@/components/Breadcrumb";
const serverClient = getClient();

export default async function RecordNew() {
const cookieStore = cookies();
const supabase = createClient(cookieStore);
const supabase = createClient();
const {
data: { user },
} = await supabase.auth.getUser();
Expand Down
7 changes: 2 additions & 5 deletions components/AuthButton.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { createClient } from "@/utils/supabase/server";
import Link from "next/link";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";

export default async function AuthButton() {
const cookieStore = cookies();
const supabase = createClient(cookieStore);
const supabase = createClient();

const {
data: { user },
Expand All @@ -14,8 +12,7 @@ export default async function AuthButton() {
const signOut = async () => {
"use server";

const cookieStore = cookies();
const supabase = createClient(cookieStore);
const supabase = createClient();
await supabase.auth.signOut();
return redirect("/login");
};
Expand Down
21 changes: 13 additions & 8 deletions components/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
type ButtonProps =
| React.ButtonHTMLAttributes<HTMLButtonElement>
| {
type?: "primary";
children: React.ReactNode;
className?: string;
};
import { ButtonHTMLAttributes, DetailedHTMLProps } from "react";

type ButtonProps = DetailedHTMLProps<
ButtonHTMLAttributes<HTMLButtonElement>,
HTMLButtonElement
> & {
type?: "primary";
children: React.ReactNode;
className?: string;
};

export default function Button({
children,
Expand All @@ -18,7 +21,9 @@ export default function Button({
type === "primary"
? "bg-blue-700"
: "bg-btn-background hover:bg-btn-background-hover"
} flex items-center group text-sm w-fit ${className}`}
} flex items-center group text-sm w-fit ${
props.disabled && "bg-red-600"
} ${className}`}
{...props}
>
{children}
Expand Down
3 changes: 1 addition & 2 deletions components/RecordAVlogButtonSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import LinkButton from "./LinkButton";
import { createClient } from "@/utils/supabase/server";

export default async function RecordAVlogButtonSection() {
const cookieStore = cookies();
const supabase = createClient(cookieStore);
const supabase = createClient();
const {
data: { user },
} = await supabase.auth.getUser();
Expand Down
Loading

0 comments on commit 85009be

Please sign in to comment.