From 0c5817e42c513115052c901b653d8c1978ff5df1 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Tue, 23 Dec 2025 15:50:14 +0100 Subject: [PATCH] User supabase structure --- src/actions/login-server.ts | 18 ------ src/actions/user.ts | 78 +++++++++++++++++++++++++ src/app/api/user/route.ts | 100 --------------------------------- src/app/auth/CreateAccount.tsx | 15 +---- src/app/auth/Login.tsx | 4 +- 5 files changed, 83 insertions(+), 132 deletions(-) delete mode 100644 src/actions/login-server.ts create mode 100644 src/actions/user.ts delete mode 100644 src/app/api/user/route.ts diff --git a/src/actions/login-server.ts b/src/actions/login-server.ts deleted file mode 100644 index ea358c6..0000000 --- a/src/actions/login-server.ts +++ /dev/null @@ -1,18 +0,0 @@ -"use server"; - -import createClient from "@/actions/supa"; - -export default async function loginServer(email: string, password: string) { - const supabase = await createClient(); - - const { data, error } = await supabase.auth.signInWithPassword({ - email, - password, - }); - - if (error) { - throw new Error(error.message); - } - - return data.user; -} diff --git a/src/actions/user.ts b/src/actions/user.ts new file mode 100644 index 0000000..4d72e63 --- /dev/null +++ b/src/actions/user.ts @@ -0,0 +1,78 @@ +"use server"; + +import createClient from "@/actions/supa"; + +/** + * Register a new user + */ +export async function registerUser( + username: string, + email: string, + password: string +) { + if (!username || !email || !password) { + throw new Error("Missing required fields"); + } + + const supabase = await createClient(); + + // Check if username is already taken + const { data: existing } = await supabase + .from("profiles") + .select("username") + .eq("username", username) + .maybeSingle(); + + if (existing) { + throw new Error("Username already used"); + } + + // Sign up user + const { data: authData, error: authError } = await supabase.auth.signUp({ + email, + password, + }); + + if (authError || !authData.user) { + throw new Error(authError?.message ?? "User registration failed"); + } + + // Insert profile + await supabase.from("profiles").insert({ + id: authData.user.id, + username, + display_name: username, + avatar_url: "", + node_address: "", + }); + + return { + message: "User registered. Please check your email to verify your account.", + user_id: authData.user.id, + email_sent: true, + }; +} + +/** + * Login a user + */ +export async function loginUser(email: string, password: string) { + if (!email || !password) { + throw new Error("Email and password are required"); + } + + const supabase = await createClient(); + + const { data, error } = await supabase.auth.signInWithPassword({ + email, + password, + }); + + if (error || !data.session) { + throw new Error("Invalid credentials"); + } + + const { session } = data; + + return session.user?.id; +} diff --git a/src/app/api/user/route.ts b/src/app/api/user/route.ts deleted file mode 100644 index e6b81b2..0000000 --- a/src/app/api/user/route.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; -import { StatusCodes } from "http-status-codes"; -import { supabase } from "../supa"; - -/** - * POST /api/user - * Register new user - * Body: { username, email, password } - */ -export async function POST(req: NextRequest) { - const { username, email, password } = await req.json(); - - if (!email || !password || !username) - return NextResponse.json( - { message: "Missing required fields" }, - { status: StatusCodes.BAD_REQUEST } - ); - - const { data: existing } = await supabase - .from("profiles") - .select("username") - .eq("username", username) - .maybeSingle(); - - if (existing) - return NextResponse.json( - { message: "Username already used" }, - { status: StatusCodes.CONFLICT } - ); - - const { data: authData, error: authError } = await supabase.auth.signUp({ - email, - password, - }); - - if (authError) - return NextResponse.json( - { message: authError.message }, - { status: StatusCodes.INTERNAL_SERVER_ERROR } - ); - - if (!authData.user) - return NextResponse.json( - { message: "User is null" }, - { status: StatusCodes.INTERNAL_SERVER_ERROR } - ); - - await supabase.from("profiles").insert({ - id: authData.user.id, - username, - display_name: username, - avatar_url: "", - node_address: "", - }); - - return NextResponse.json({ - message: "User registered. Please check your email to verify your account.", - user_id: authData.user?.id, - email_sent: true, - }); -} - -/** - * GET /api/user - * Login user - * Params: { username, password } - */ -export async function GET(req: NextRequest) { - const params = new URL(req.url).searchParams; - const [email, password] = [params.get("email"), params.get("password")]; - - if (!email || !password) - return NextResponse.json( - { message: "Params email and password are required" }, - { status: StatusCodes.BAD_REQUEST } - ); - - const { data, error } = await supabase.auth.signInWithPassword({ - email, - password, - }); - - if (error) - return NextResponse.json( - { message: "Invalid credentials" }, - { status: StatusCodes.UNAUTHORIZED } - ); - - const { session } = data; - const res = NextResponse.json({ - message: "ok", - access_token: session?.access_token, - refresh_token: session?.refresh_token, - user_id: session?.user?.id, - }); - - res.cookies.set("token", session?.access_token ?? "", { httpOnly: true }); - - return res; -} diff --git a/src/app/auth/CreateAccount.tsx b/src/app/auth/CreateAccount.tsx index d1c63a8..6fa1286 100644 --- a/src/app/auth/CreateAccount.tsx +++ b/src/app/auth/CreateAccount.tsx @@ -10,6 +10,7 @@ import { Label } from "@/components/ui/label"; import { toast } from "sonner"; import { useRouter } from "next/navigation"; import Cookies from "js-cookie"; +import { registerUser } from "@/actions/user"; export default function CreateAccount() { const [username, setUsername] = useState(""); @@ -58,8 +59,6 @@ export default function CreateAccount() { }; const signup = async () => { - localStorage.removeItem("chat-messages"); - localStorage.removeItem("server-messages"); setFeedback(undefined); const validationError = validateInput(); if (validationError) { @@ -69,16 +68,8 @@ export default function CreateAccount() { try { setLoading(true); - const { data } = await axios.post("/api/user", { - username, - password, - email, - }); - const response = data as { - message: string; - email_sent: boolean; - user_id: string; - }; + const response = await registerUser(username, email, password); + if (response.email_sent) { toast.info( "We sent you a verification email. Please verify to continue." diff --git a/src/app/auth/Login.tsx b/src/app/auth/Login.tsx index fb20e6c..d3fbc2f 100644 --- a/src/app/auth/Login.tsx +++ b/src/app/auth/Login.tsx @@ -5,7 +5,7 @@ import { Input } from "@/components/ui/input"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import loginServer from "@/actions/login-server"; +import { loginUser } from "@/actions/user"; type Feedback = { kind: "error" | "info"; message: string }; @@ -19,7 +19,7 @@ export default function Login() { const login = async () => { setFeedback(undefined); try { - const res = await loginServer(email, password); + await loginUser(email, password); setFeedback({ kind: "info",