User supabase structure

This commit is contained in:
2025-12-23 15:50:14 +01:00
parent 6d4cbbf03b
commit 0c5817e42c
5 changed files with 83 additions and 132 deletions
-18
View File
@@ -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;
}
+78
View File
@@ -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;
}
-100
View File
@@ -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;
}
+3 -12
View File
@@ -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."
+2 -2
View File
@@ -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",