Youtube handle try, not working, user input for it.

This commit is contained in:
EdiFarcas
2025-04-28 15:26:52 +03:00
parent 7f744e1e9f
commit 7c4707d677
6 changed files with 158 additions and 18 deletions
@@ -0,0 +1,16 @@
/*
Warnings:
- You are about to drop the column `youtubeId` on the `User` table. All the data in the column will be lost.
- A unique constraint covering the columns `[youtubeUsername]` on the table `User` will be added. If there are existing duplicate values, this will fail.
*/
-- DropIndex
DROP INDEX "User_youtubeId_key";
-- AlterTable
ALTER TABLE "User" DROP COLUMN "youtubeId",
ADD COLUMN "youtubeUsername" TEXT;
-- CreateIndex
CREATE UNIQUE INDEX "User_youtubeUsername_key" ON "User"("youtubeUsername");
@@ -0,0 +1,16 @@
/*
Warnings:
- A unique constraint covering the columns `[youtubeHandle]` on the table `User` will be added. If there are existing duplicate values, this will fail.
- A unique constraint covering the columns `[youtubeChannelId]` on the table `User` will be added. If there are existing duplicate values, this will fail.
*/
-- AlterTable
ALTER TABLE "User" ADD COLUMN "youtubeChannelId" TEXT,
ADD COLUMN "youtubeHandle" TEXT;
-- CreateIndex
CREATE UNIQUE INDEX "User_youtubeHandle_key" ON "User"("youtubeHandle");
-- CreateIndex
CREATE UNIQUE INDEX "User_youtubeChannelId_key" ON "User"("youtubeChannelId");
+12 -10
View File
@@ -8,16 +8,18 @@ generator client {
}
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
youtubeId String? @unique
coins Int @default(0)
entries Entry[]
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
youtubeUsername String? @unique
youtubeHandle String? @unique
youtubeChannelId String? @unique
coins Int @default(0)
entries Entry[]
}
model Account {
+31 -2
View File
@@ -31,10 +31,39 @@ export const authOptions = {
console.error("Sign-in failed: Missing user, account, or profile data.");
return false;
}
if (account.provider === "google" && account.access_token) {
try {
const { data } = await axios.get("https://www.googleapis.com/youtube/v3/channels", {
params: {
part: "brandingSettings",
mine: "true",
},
headers: {
Authorization: `Bearer ${account.access_token}`,
},
});
const customUrl = data.items?.[0]?.brandingSettings?.channel?.customUrl;
// Create the handle
const youtubeHandle = customUrl ? `@${customUrl.replace(/^.*\//, "")}` : null;
console.log("Fetched YouTube handle:", youtubeHandle);
// Attach ONLY the handle to the user
user.youtubeHandle = youtubeHandle;
} catch (error) {
console.error("Error fetching YouTube handle:", error);
}
}
return true;
},
async session({ session, user }: { session: any; user: { id: string } }) {
session.user.id = user.id; // Attach user ID to the session
async session({ session, user }: { session: any; user: any }) {
session.user.id = user.id;
session.user.youtubeHandle = user.youtubeHandle; // Only attach YouTube handle
return session;
},
},
+25
View File
@@ -0,0 +1,25 @@
import { NextResponse } from "next/server";
import { getServerSession } from "next-auth";
import { authOptions } from "../auth/[...nextauth]/route";
import { db } from "@/lib/db";
export async function POST(req: Request) {
const session = await getServerSession(authOptions);
if (!session?.user?.email) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const { youtubeHandle } = await req.json();
if (!youtubeHandle || typeof youtubeHandle !== "string") {
return NextResponse.json({ error: "Invalid handle" }, { status: 400 });
}
await db.user.update({
where: { email: session.user.email },
data: { youtubeHandle },
});
return NextResponse.json({ success: true });
}
+58 -6
View File
@@ -1,3 +1,6 @@
"use client"; // <-- add this because we will use onChange, onSubmit!
import { useState } from "react";
import { getServerSession } from "next-auth";
import { authOptions } from "../api/auth/[...nextauth]/route";
import { db } from "@/lib/db";
@@ -13,16 +16,43 @@ export default async function ProfilePage() {
const user = await db.user.findUnique({
where: { email: session.user?.email! },
select: {
name: true,
email: true,
coins: true,
},
name: true,
email: true,
coins: true,
youtubeHandle: true,
},
});
if (!user) {
redirect("/api/auth/signin");
}
return <ProfileContent user={user} />;
}
// Create a separate component for the UI part
function ProfileContent({ user }: { user: any }) {
const [youtubeHandle, setYoutubeHandle] = useState(user.youtubeHandle || "");
const [saving, setSaving] = useState(false);
const handleSave = async () => {
setSaving(true);
try {
const res = await fetch("/api/youtube-handle", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ youtubeHandle }),
});
if (!res.ok) throw new Error("Failed to update");
alert("YouTube handle updated successfully!");
} catch (error) {
console.error(error);
alert("Error updating handle.");
} finally {
setSaving(false);
}
};
return (
<div className="min-h-screen bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
<div className="max-w-3xl mx-auto">
@@ -62,6 +92,27 @@ export default async function ProfilePage() {
<p className="font-medium text-gray-500">{user.email}</p>
</div>
</div>
{/* YouTube Handle */}
<div className="flex flex-col space-y-2 p-3 bg-gray-50 rounded-lg">
<label className="text-sm text-black flex items-center">
<span className="text-lg mr-2">📺</span> YouTube Handle
</label>
<input
type="text"
className="p-2 rounded-lg border border-gray-300 focus:outline-none focus:ring-2 focus:ring-purple-600 text-black"
placeholder="@yourhandle"
value={youtubeHandle}
onChange={(e) => setYoutubeHandle(e.target.value)}
/>
<button
onClick={handleSave}
disabled={saving}
className="bg-purple-600 text-white px-4 py-2 rounded-lg mt-2 hover:bg-purple-700 transition-colors disabled:opacity-50"
>
{saving ? "Saving..." : "Save Handle"}
</button>
</div>
</div>
{/* Coins Section */}
@@ -76,7 +127,7 @@ export default async function ProfilePage() {
</div>
<button className="bg-purple-600 text-white px-4 py-2 rounded-lg hover:bg-purple-700 transition-colors">
Add Coins
</button> {/* Add functionality to add coins here */}
</button>
</div>
</div>
</div>
@@ -102,9 +153,10 @@ export default async function ProfilePage() {
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}