From 3391a14643edb733a9d40d4d87f510a3c59a31c4 Mon Sep 17 00:00:00 2001 From: S M Fahim Hossen Date: Sun, 5 Oct 2025 17:03:50 +0600 Subject: [PATCH 1/2] update --- package-lock.json | 63 ++++++++++++++++- package.json | 4 +- src/App.tsx | 2 + src/pages/Login.tsx | 8 ++- src/pages/Signup.tsx | 55 +++++++++++---- src/stores/authStore.ts | 150 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 260 insertions(+), 22 deletions(-) create mode 100644 src/stores/authStore.ts diff --git a/package-lock.json b/package-lock.json index d131e9c..e45beb3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,11 +18,13 @@ "lucide-react": "^0.544.0", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-hot-toast": "^2.6.0", "react-router": "^7.9.3", "react-router-dom": "^7.9.3", "recharts": "^3.2.1", "tailwind-merge": "^3.3.1", - "tailwindcss": "^4.1.13" + "tailwindcss": "^4.1.13", + "zustand": "^5.0.8" }, "devDependencies": { "@eslint/js": "^9.36.0", @@ -2924,8 +2926,8 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/d3-array": { "version": "3.2.4", @@ -3557,6 +3559,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/goober": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.18.tgz", + "integrity": "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==", + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -4346,6 +4357,23 @@ "react": "^19.1.1" } }, + "node_modules/react-hot-toast": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.6.0.tgz", + "integrity": "sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg==", + "license": "MIT", + "dependencies": { + "csstype": "^3.1.3", + "goober": "^2.1.16" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, "node_modules/react-is": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz", @@ -5181,6 +5209,35 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zustand": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.8.tgz", + "integrity": "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index 8057b79..3d610c2 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,13 @@ "lucide-react": "^0.544.0", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-hot-toast": "^2.6.0", "react-router": "^7.9.3", "react-router-dom": "^7.9.3", "recharts": "^3.2.1", "tailwind-merge": "^3.3.1", - "tailwindcss": "^4.1.13" + "tailwindcss": "^4.1.13", + "zustand": "^5.0.8" }, "devDependencies": { "@eslint/js": "^9.36.0", diff --git a/src/App.tsx b/src/App.tsx index e5e9639..9461200 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,6 +6,7 @@ import DashboardLayout from "./components/layouts/DashboardLayouts"; import Overview from "./pages/Overview"; import Referrals from "./pages/Referrals"; import Earnings from "./pages/Earnings"; +import { Toaster } from "react-hot-toast"; const App: React.FC = () => { return ( @@ -21,6 +22,7 @@ const App: React.FC = () => { } /> + ); }; diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index 03c243a..c93ecfc 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -1,12 +1,14 @@ import React, { useState } from "react"; import { TrendingUp, Mail, Lock, ArrowRight } from "lucide-react"; import { useNavigate } from "react-router"; +import { useAuthStore } from "@/stores/authStore"; const Login: React.FC = () => { const [form, setForm] = useState({ email: "", password: "" }); const [error, setError] = useState(""); const [isLoading, setIsLoading] = useState(false); const navigate = useNavigate(); + const { login } = useAuthStore(); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); @@ -15,12 +17,12 @@ const Login: React.FC = () => { } setIsLoading(true); setError(""); + const result = await login(form.email, form.password); - // Simulate API call - setTimeout(() => { + if (result.success) { setIsLoading(false); navigate("/dashboard/overview"); - }, 1000); + } }; return ( diff --git a/src/pages/Signup.tsx b/src/pages/Signup.tsx index e5c9cf2..98ffcef 100644 --- a/src/pages/Signup.tsx +++ b/src/pages/Signup.tsx @@ -7,6 +7,9 @@ import { ArrowRight, User, } from "lucide-react"; +import { useNavigate } from "react-router-dom"; +import { useAuthStore } from "@/stores/authStore"; +import toast from "react-hot-toast"; const Signup: React.FC = () => { const [form, setForm] = useState({ @@ -15,28 +18,48 @@ const Signup: React.FC = () => { password: "", confirm: "", }); - const [error, setError] = useState(""); - const [isLoading, setIsLoading] = useState(false); + const [localError, setLocalError] = useState(""); + const navigate = useNavigate(); + + const { register, isLoading, error: storeError } = useAuthStore(); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - if (!form.email || !form.password || !form.confirm) { - return setError("All fields are required"); + + if (!form.name || !form.email || !form.password || !form.confirm) { + return setLocalError("All fields are required"); } if (form.password !== form.confirm) { - return setError("Passwords do not match"); + return setLocalError("Passwords do not match"); } if (form.password.length < 8) { - return setError("Password must be at least 8 characters"); + return setLocalError("Password must be at least 8 characters"); } - setIsLoading(true); - setError(""); + setLocalError(""); - setTimeout(() => { - setIsLoading(false); - alert("Account created successfully! Redirecting to login..."); - }, 1200); + // Split name into first and last name + const nameParts = form.name.trim().split(" "); + const firstName = nameParts[0]; + const lastName = nameParts.slice(1).join(" "); + + // Call Zustand register action + const result = await register({ + email: form.email, + first_name: firstName, + last_name: lastName || undefined, + password: form.password, + role: "affiliate", + }); + + if (result.success) { + // Redirect to login after successful registration + toast("Account created successfully! Please log in."); + navigate("/login"); + } else { + // Display error from API + setLocalError(result.error || "Registration failed"); + } }; const passwordStrength = @@ -48,6 +71,8 @@ const Signup: React.FC = () => { : "strong" : null; + const displayError = localError || storeError; + return (
{/* Left Side - Branding */} @@ -139,9 +164,9 @@ const Signup: React.FC = () => {

- {error && ( + {displayError && (
-

{error}

+

{displayError}

)} @@ -262,7 +287,7 @@ const Signup: React.FC = () => {