[rewrite] Updated backend structure a bit and started working on registration
This commit is contained in:
1 parent
f0c378b20f
commit
5d12391635
17 files changed
+832
-86
No files matched your search
@@ -0,0 +1,11 @@
|
||||
export class ApiError extends Error {
|
||||
response: string;
|
||||
status: number;
|
||||
|
||||
constructor(message: string, response: string, status: number) {
|
||||
super(message);
|
||||
this.name = "ApiError";
|
||||
this.response = response;
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,16 @@
|
||||
import axios from "axios";
|
||||
|
||||
const API_BASE_URL = "http://localhost:8000";
|
||||
|
||||
export const registerUser = async (userData: {
|
||||
username: string;
|
||||
email: string;
|
||||
phone_number: string;
|
||||
password: string;
|
||||
}) => {
|
||||
const response = await axios.post(`${API_BASE_URL}/user/register`, {
|
||||
...userData,
|
||||
shop_id: 0 // 0 signifies a free account
|
||||
});
|
||||
return response.data;
|
||||
};
|
||||
@@ -2,7 +2,6 @@ import { HTMLAttributes, useState } from "react";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { IconBrandFacebook, IconBrandGithub } from "@tabler/icons-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
@@ -15,22 +14,47 @@ import {
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { PasswordInput } from "@/components/password-input";
|
||||
import { registerUser } from "@/lib/api";
|
||||
import { ApiError } from "@/errors/api-error";
|
||||
|
||||
type SignUpFormProps = HTMLAttributes<HTMLDivElement>;
|
||||
|
||||
const formSchema = z
|
||||
.object({
|
||||
username: z
|
||||
.string()
|
||||
.min(1, { message: "Please enter your username" })
|
||||
.min(3, { message: "Username must be at least 3 characters long" })
|
||||
.max(64, { message: "Username must be less than 64 characters" }),
|
||||
email: z
|
||||
.string()
|
||||
.min(1, { message: "Please enter your email" })
|
||||
.email({ message: "Invalid email address" }),
|
||||
phone_number: z
|
||||
.string()
|
||||
.min(1, { message: "Please enter your phone number" })
|
||||
.min(10, { message: "Phone number must be at least 10 digits" })
|
||||
.max(15, { message: "Phone number cannot be longer than 15 digits" })
|
||||
.regex(/^\+\d{1,3} \d{1,9}$/, { message: "Invalid phone number format" }),
|
||||
password: z
|
||||
.string()
|
||||
.min(1, {
|
||||
message: "Please enter your password"
|
||||
.min(1, { message: "Please enter your password" })
|
||||
.min(8, {
|
||||
message: "Password must be at least 8 characters long"
|
||||
})
|
||||
.min(7, {
|
||||
message: "Password must be at least 7 characters long"
|
||||
.max(128, { message: "Password must be at most 128 characters long" })
|
||||
.refine((password) => /[A-Z]/.test(password), {
|
||||
message: "Password must contain at least one uppercase letter"
|
||||
})
|
||||
.refine((password) => /[a-z]/.test(password), {
|
||||
message: "Password must contain at least one lowercase letter"
|
||||
})
|
||||
.refine((password) => /\d/.test(password), {
|
||||
message: "Password must contain at least one number"
|
||||
})
|
||||
.refine((password) => /[@$!%*?&]/.test(password), {
|
||||
message:
|
||||
"Password must contain at least one special character (@, $, !, %, *, ?, &)"
|
||||
}),
|
||||
confirmPassword: z.string()
|
||||
})
|
||||
@@ -41,24 +65,38 @@ const formSchema = z
|
||||
|
||||
export function SignUpForm({ className, ...props }: SignUpFormProps) {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [successMessage, setSuccessMessage] = useState<string | null>(null);
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
username: "",
|
||||
email: "",
|
||||
phone_number: "",
|
||||
password: "",
|
||||
confirmPassword: ""
|
||||
}
|
||||
});
|
||||
|
||||
function onSubmit(data: z.infer<typeof formSchema>) {
|
||||
async function onSubmit(data: z.infer<typeof formSchema>) {
|
||||
setIsLoading(true);
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(data);
|
||||
setError(null);
|
||||
setSuccessMessage(null);
|
||||
|
||||
setTimeout(() => {
|
||||
try {
|
||||
await registerUser({
|
||||
username: data.username,
|
||||
email: data.email,
|
||||
password: data.password,
|
||||
phone_number: data.phone_number
|
||||
});
|
||||
setSuccessMessage("Account created successfully!");
|
||||
} catch (error: unknown) {
|
||||
setError(error instanceof ApiError ? error.response : "Something went wrong.");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -66,6 +104,19 @@ export function SignUpForm({ className, ...props }: SignUpFormProps) {
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<div className="grid gap-2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="username"
|
||||
render={({ field }) => (
|
||||
<FormItem className="space-y-1">
|
||||
<FormLabel>Username</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="your_username" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
@@ -79,6 +130,19 @@ export function SignUpForm({ className, ...props }: SignUpFormProps) {
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="phone_number"
|
||||
render={({ field }) => (
|
||||
<FormItem className="space-y-1">
|
||||
<FormLabel>Phone Number</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="+1234567890" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
@@ -105,37 +169,13 @@ export function SignUpForm({ className, ...props }: SignUpFormProps) {
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button className="mt-2" disabled={isLoading}>
|
||||
Create Account
|
||||
{error && <p className="text-red-500">{error}</p>}
|
||||
{successMessage && (
|
||||
<p className="text-green-500">{successMessage}</p>
|
||||
)}
|
||||
<Button className="mt-2" type="submit" disabled={isLoading}>
|
||||
{isLoading ? "Creating Account..." : "Create Account"}
|
||||
</Button>
|
||||
|
||||
<div className="relative my-2">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<span className="w-full border-t" />
|
||||
</div>
|
||||
<div className="relative flex justify-center text-xs uppercase">
|
||||
<span className="bg-background px-2 text-muted-foreground">
|
||||
Or continue with
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full"
|
||||
type="button"
|
||||
disabled={isLoading}>
|
||||
<IconBrandGithub className="h-4 w-4" /> GitHub
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full"
|
||||
type="button"
|
||||
disabled={isLoading}>
|
||||
<IconBrandFacebook className="h-4 w-4" /> Facebook
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from "@/components/ui/accordion";
|
||||
import { faqs } from "../data/faq-data";
|
||||
|
||||
export default function FAQ() {
|
||||
export default function Faq() {
|
||||
return (
|
||||
<div className="mt-12 max-w-4xl">
|
||||
<h2 id="faqs" className="mb-6 text-center text-3xl font-bold">
|
||||
|
||||
@@ -2,7 +2,7 @@ import MainNavbar from "@/components/main-navbar";
|
||||
import Features from "./components/features";
|
||||
import Hero from "./components/hero";
|
||||
import Pricing from "./components/pricing";
|
||||
import FAQ from "./components/faq";
|
||||
import Faq from "./components/faq";
|
||||
import CallToAction from "./components/call-to-action";
|
||||
|
||||
export default function MainPage() {
|
||||
@@ -16,7 +16,7 @@ export default function MainPage() {
|
||||
<Hero />
|
||||
<Features />
|
||||
<Pricing />
|
||||
<FAQ />
|
||||
<Faq />
|
||||
<CallToAction />
|
||||
|
||||
{/* [Optional] Consider inserting an image or illustration here to reinforce the platform’s purpose. */}
|
||||
|
||||
Reference in new issue
Block a user