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 = () => {