diff --git a/package-lock.json b/package-lock.json
index 904f900..826e02b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -74,6 +74,7 @@
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.3",
@@ -2308,6 +2309,7 @@
"integrity": "sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ==",
"devOptional": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"undici-types": "~7.12.0"
}
@@ -2318,6 +2320,7 @@
"integrity": "sha512-+kLxJpaJzXybyDyFXYADyP1cznTO8HSuBpenGlnKOAkH4hyNINiywvXS/tGJhsrGGP/gM185RA3xpjY0Yg4erA==",
"devOptional": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"csstype": "^3.0.2"
}
@@ -2328,6 +2331,7 @@
"integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==",
"devOptional": true,
"license": "MIT",
+ "peer": true,
"peerDependencies": {
"@types/react": "^19.0.0"
}
@@ -2384,6 +2388,7 @@
"integrity": "sha512-EHrrEsyhOhxYt8MTg4zTF+DJMuNBzWwgvvOYNj/zm1vnaD/IC5zCXFehZv94Piqa2cRFfXrTFxIvO95L7Qc/cw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.44.1",
"@typescript-eslint/types": "8.44.1",
@@ -2636,6 +2641,7 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -2766,6 +2772,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.8.3",
"caniuse-lite": "^1.0.30001741",
@@ -2920,7 +2927,8 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/d3-array": {
"version": "3.2.4",
@@ -3189,6 +3197,7 @@
"integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -4373,6 +4382,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz",
"integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -4382,6 +4392,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz",
"integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"scheduler": "^0.26.0"
},
@@ -4418,6 +4429,7 @@
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/use-sync-external-store": "^0.0.6",
"use-sync-external-store": "^1.4.0"
@@ -4584,7 +4596,8 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/redux-thunk": {
"version": "3.1.0",
@@ -4865,6 +4878,7 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -4933,6 +4947,7 @@
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"dev": true,
"license": "Apache-2.0",
+ "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -5092,6 +5107,7 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-7.1.7.tgz",
"integrity": "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.5.0",
@@ -5183,6 +5199,7 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
diff --git a/src/App.tsx b/src/App.tsx
index 7bec0b6..a512f4c 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,5 +1,5 @@
import React from "react";
-import { BrowserRouter, Routes, Route} from "react-router-dom";
+import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
import Login from "./pages/Login";
import Signup from "./pages/Signup";
import DashboardLayout from "./components/layouts/DashboardLayouts";
@@ -8,21 +8,27 @@ import Referrals from "./pages/Referrals";
import Earnings from "./pages/Earnings";
import { Toaster } from "react-hot-toast";
import Landing from "./pages/Landing";
+import ProtectedRoute from "./components/ProtectedRoute";
const App: React.FC = () => {
return (
-
+ } />
} />
} />
- } />
- }>
- } />
- } />
- } />
+ {/* Protected Dashboard Routes - Only for affiliates */}
+ }>
+ }>
+ } />
+ } />
+ } />
+
+
+ {/* Catch all - redirect to landing */}
+ } />
diff --git a/src/components/ProtectedRoute.tsx b/src/components/ProtectedRoute.tsx
new file mode 100644
index 0000000..9f89876
--- /dev/null
+++ b/src/components/ProtectedRoute.tsx
@@ -0,0 +1,44 @@
+import { Navigate, Outlet } from "react-router-dom";
+
+const ProtectedRoute = () => {
+ const token = localStorage.getItem("aff-token");
+ const userStr = localStorage.getItem("aff-user");
+
+ if (!token) {
+ return ;
+ }
+
+ if (userStr) {
+ try {
+ const user = JSON.parse(userStr);
+
+ if (user.role !== "affiliate") {
+ return (
+
+
+
+ Access Denied
+
+
+ This dashboard is only accessible to affiliates.
+
+
+
+ );
+ }
+ } catch (error) {
+ console.error("Error parsing user data:", error);
+
+ localStorage.removeItem("aff-token");
+ localStorage.removeItem("aff-user");
+ return ;
+ }
+ } else {
+ // No user data, redirect to login
+ return ;
+ }
+
+ return ;
+};
+
+export default ProtectedRoute;
diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx
index 710d570..e832b90 100644
--- a/src/components/Sidebar.tsx
+++ b/src/components/Sidebar.tsx
@@ -1,4 +1,4 @@
-import React from "react";
+import React, { useEffect } from "react";
import {
Sidebar,
SidebarContent,
@@ -12,10 +12,27 @@ import {
} from "@/components/ui/sidebar";
import { LayoutDashboard, Users, DollarSign, LogOut } from "lucide-react";
import { Link, useLocation } from "react-router-dom";
+import { useUserStore } from "@/stores/userStore";
+import { useAuthStore } from "@/stores/authStore";
const AppSidebar: React.FC = () => {
const { pathname } = useLocation();
+ const { user, fetchUser } = useUserStore();
+ const { logout } = useAuthStore();
+
+ useEffect(() => {
+ // Get user ID from localStorage
+ const userStr = localStorage.getItem("aff-user");
+
+ if (userStr) {
+ const userData = JSON.parse(userStr);
+ if (userData.id) {
+ fetchUser(userData.id);
+ }
+ }
+ }, [fetchUser]);
+
const links = [
{ name: "Overview", path: "/dashboard/overview", icon: LayoutDashboard },
{ name: "Referrals", path: "/dashboard/referrals", icon: Users },
@@ -89,7 +106,10 @@ const AppSidebar: React.FC = () => {
asChild
className="hover:bg-red-50 text-red-600 transition-colors bg-white"
>
-