diff --git a/app/components/dashboard/header.tsx b/app/components/dashboard/header.tsx index 32c7fb0..c6cf7f9 100644 --- a/app/components/dashboard/header.tsx +++ b/app/components/dashboard/header.tsx @@ -5,17 +5,16 @@ import { cn } from "~/lib/utils"; import { Button } from "~/components/ui/button"; import { PanelLeft, - Search, - Bell, + Settings, User, - Moon, - Sun, + Menu, ChevronDown, - Globe, - HelpCircle, + Server, + } from "lucide-react"; +import apiService from "~/lib/api"; interface HeaderProps { onToggleSidebar?: () => void; @@ -32,6 +31,17 @@ export function Header({ const [isProfileMenuOpen, setIsProfileMenuOpen] = useState(false); const [isNotificationOpen, setIsNotificationOpen] = useState(false); + const redirectHandler = async () => { + try { + const getData = await apiService.post('/GenerateSsoCode') + const url = `http://localhost:3000/redirect/${getData.data}`; + // const url = `https://inogen-bpms.pelekan.org/redirect/${getData.data}`; + window.open(url, "_blank"); + } catch (error) { + console.log(error); + } + } + return (
{/* User Menu */}
- +
+ { + user?.id === 2041 && + } + + +
{/* Profile Dropdown */} {isProfileMenuOpen && (
diff --git a/app/components/dashboard/layout.tsx b/app/components/dashboard/layout.tsx index 0d12e7f..adcbb16 100644 --- a/app/components/dashboard/layout.tsx +++ b/app/components/dashboard/layout.tsx @@ -3,6 +3,7 @@ import { cn } from "~/lib/utils"; import { Sidebar } from "./sidebar"; import { Header } from "./header"; import { StrategicAlignmentPopup } from "./strategic-alignment-popup"; +import apiService from "~/lib/api"; interface DashboardLayoutProps { children: React.ReactNode; @@ -27,10 +28,12 @@ export function DashboardLayout({ setIsMobileSidebarOpen(!isMobileSidebarOpen); }; + + return (
{/* Gradient overlay */}
@@ -58,6 +61,7 @@ export function DashboardLayout({ onToggleCollapse={toggleSidebarCollapse} className="h-full flex-shrink-0 relative z-10" onStrategicAlignmentClick={() => setIsStrategicAlignmentPopupOpen(true)} + />
diff --git a/app/components/dashboard/sidebar.tsx b/app/components/dashboard/sidebar.tsx index 172a6dd..75fc0ac 100644 --- a/app/components/dashboard/sidebar.tsx +++ b/app/components/dashboard/sidebar.tsx @@ -15,6 +15,7 @@ import { Settings, Star, Workflow, + DiscAlbum } from "lucide-react"; import React, { useState } from "react"; import { Link, useLocation } from "react-router"; @@ -38,7 +39,7 @@ interface MenuItem { } const menuItems: MenuItem[] = [ - + { id: "dashboard", label: "صفحه اصلی", @@ -106,12 +107,13 @@ const menuItems: MenuItem[] = [ icon: Star, href: "/dashboard/top-innovations", }, - { + { id: "strategic-alignment", label: "میزان انطباق راهبردی", icon: null, href: "#", // This is not a route, it opens a popup }, + ]; const bottomMenuItems: MenuItem[] = [ @@ -206,6 +208,7 @@ export function Sidebar({ const handleClick = () => { if (item.id === "strategic-alignment") { + console.log("test") onStrategicAlignmentClick?.(); } else if (item.id === "logout") { logout(); @@ -214,30 +217,24 @@ export function Sidebar({ } }; - if (item.id === "strategic-alignment") { -return ( - -) + if (item.id === "strategic-alignment") { + return ( + + ) - } + } return (
@@ -293,10 +290,10 @@ return ( "w-full text-right", // Disable pointer cursor when child is active (cannot collapse) item.children && - item.children.some( - (child) => child.href && location.pathname === child.href - ) && - "cursor-not-allowed" + item.children.some( + (child) => child.href && location.pathname === child.href + ) && + "cursor-not-allowed" )} onClick={handleClick} > diff --git a/app/lib/api.ts b/app/lib/api.ts index b26b23c..062c434 100644 --- a/app/lib/api.ts +++ b/app/lib/api.ts @@ -39,6 +39,19 @@ class ApiService { this.token = null; } + private handleSessionExpired(message?: string) { + this.clearToken(); + localStorage.removeItem("auth_token"); + localStorage.removeItem("auth_user"); + try { + sessionStorage.setItem("sessionExpired", "1"); + } catch {} + if (message) { + toast.error(message); + } + window.location.href = "/login"; + } + private async request( endpoint: string, options: RequestInit = {}, @@ -66,6 +79,11 @@ class ApiService { const response = await fetch(url, config); const data: ApiResponse = await response.json(); + if (data.errorCode === 301) { + this.handleSessionExpired("نشست شما منقضی شده است. لطفا دوباره وارد شوید."); + throw new Error(data.message || "Session expired"); + } + // Handle different response states if (!response.ok) { throw new Error( @@ -91,13 +109,7 @@ class ApiService { // Handle authentication errors if (error instanceof Error && error.message.includes("401")) { - this.clearToken(); - localStorage.removeItem("auth_token"); - localStorage.removeItem("auth_user"); - try { - sessionStorage.setItem("sessionExpired", "1"); - } catch {} - window.location.href = "/login"; + this.handleSessionExpired(); throw error; } @@ -128,6 +140,11 @@ class ApiService { const response = await fetch(fullUrl, config); const apiData: ApiResponse = await response.json(); + if (apiData.errorCode === 301) { + this.handleSessionExpired("نشست شما منقضی شده است. لطفا دوباره وارد شوید."); + throw new Error(apiData.message || "Session expired"); + } + if (!response.ok) { throw new Error(apiData?.message || `HTTP error! status: ${response.status}`); } diff --git a/package-lock.json b/package-lock.json index 4340ade..35a0092 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,10 +10,12 @@ "@radix-ui/react-dialog": "^1.1.14", "@radix-ui/react-dropdown-menu": "^2.1.15", "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-popover": "^1.1.15", "@radix-ui/react-progress": "^1.1.7", "@radix-ui/react-select": "^2.2.5", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-tabs": "^1.1.13", + "@radix-ui/react-tooltip": "^1.2.8", "@react-router/node": "^7.7.0", "@react-router/serve": "^7.7.1", "@types/d3": "^7.4.3", @@ -967,6 +969,43 @@ } } }, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", + "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popper": { "version": "1.2.8", "license": "MIT", @@ -1202,6 +1241,40 @@ } } }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", + "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.1", "license": "MIT",