User supabase structure
This commit is contained in:
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -10,6 +10,7 @@ import { Label } from "@/components/ui/label";
|
|||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
|
import { registerUser } from "@/actions/user";
|
||||||
|
|
||||||
export default function CreateAccount() {
|
export default function CreateAccount() {
|
||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
@@ -58,8 +59,6 @@ export default function CreateAccount() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const signup = async () => {
|
const signup = async () => {
|
||||||
localStorage.removeItem("chat-messages");
|
|
||||||
localStorage.removeItem("server-messages");
|
|
||||||
setFeedback(undefined);
|
setFeedback(undefined);
|
||||||
const validationError = validateInput();
|
const validationError = validateInput();
|
||||||
if (validationError) {
|
if (validationError) {
|
||||||
@@ -69,16 +68,8 @@ export default function CreateAccount() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const { data } = await axios.post("/api/user", {
|
const response = await registerUser(username, email, password);
|
||||||
username,
|
|
||||||
password,
|
|
||||||
email,
|
|
||||||
});
|
|
||||||
const response = data as {
|
|
||||||
message: string;
|
|
||||||
email_sent: boolean;
|
|
||||||
user_id: string;
|
|
||||||
};
|
|
||||||
if (response.email_sent) {
|
if (response.email_sent) {
|
||||||
toast.info(
|
toast.info(
|
||||||
"We sent you a verification email. Please verify to continue."
|
"We sent you a verification email. Please verify to continue."
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Input } from "@/components/ui/input";
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
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 };
|
type Feedback = { kind: "error" | "info"; message: string };
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ export default function Login() {
|
|||||||
const login = async () => {
|
const login = async () => {
|
||||||
setFeedback(undefined);
|
setFeedback(undefined);
|
||||||
try {
|
try {
|
||||||
const res = await loginServer(email, password);
|
await loginUser(email, password);
|
||||||
|
|
||||||
setFeedback({
|
setFeedback({
|
||||||
kind: "info",
|
kind: "info",
|
||||||
|
|||||||
Reference in New Issue
Block a user