diff --git a/client/src/features/admin/components/AdminLayout.tsx b/client/src/features/admin/components/AdminLayout.tsx index 064ad1b..60f984e 100644 --- a/client/src/features/admin/components/AdminLayout.tsx +++ b/client/src/features/admin/components/AdminLayout.tsx @@ -1,5 +1,5 @@ -import React from "react"; -import { Outlet, NavLink, useNavigate } from "react-router-dom"; +import React, { useState, useEffect, useRef } from "react"; +import { Outlet, NavLink, useNavigate, useLocation } from "react-router-dom"; import { useAuthStore } from "../../../store/authStore"; import { motion } from "framer-motion"; @@ -16,6 +16,18 @@ import { export const AdminLayout: React.FC = () => { const { user, logout } = useAuthStore(); const navigate = useNavigate(); + const location = useLocation(); + + // State engine managing navigation sidebar width expansion configuration matching the reference dashboard + const [sidebarExpanded, setSidebarExpanded] = useState(false); + const mainScrollContainerRef = useRef(null); + + // Handle immediate viewport layout reset on route change + useEffect(() => { + if (mainScrollContainerRef.current) { + mainScrollContainerRef.current.scrollTop = 0; + } + }, [location.pathname]); const handleSignOut = () => { logout(); @@ -27,123 +39,148 @@ export const AdminLayout: React.FC = () => { name: "Admin Dashboard", path: "/admin/dashboard", icon: LayoutDashboard, - color: "text-blue-600", }, { name: "Manage Users", path: "/admin/users", icon: Users, - color: "text-amber-700", }, { name: "Manage Librarians", path: "/admin/librarians", icon: ShieldAlert, - color: "text-rose-600", }, ]; return ( -
- {/* Sidebar Navigation - Warm Archival Minimalist Layout (Matching 72 width) */} - - {/* Main Structural Area */} -
- {/* Header Frame - Formatted with identical Height h-22 and Side Padding */} -
-
-

- Admin Dashboard -

-

- Core directory controls and active network administration + {/* User Identity Matrix */} +

+
+

+ ROLE: {user?.role || "ADMIN"}

-
-
-

- ROLE:{" "} - - {user?.role || "ADMIN"} - -

-
+
+ +
+
+
- {/* User Profile Avatar Frame */} -
- -
+ {/* Main Structural Application Framework Split */} +
+ + {/* Persistent Left Icon/Expanded Navigation Sidebar Tracking Shell */} + +
+ {/* Navigation Routing Links */} +
- - {/* Content View Injection Portal using your clean transition specs */} -
+ {/* Action Area Sidebar Footer */} +
+ +
+ + + {/* Workspace Canvas Container Block */} +
+
); -}; +}; \ No newline at end of file diff --git a/client/src/features/admin/components/DeleteLibrarianProfile.tsx b/client/src/features/admin/components/DeleteLibrarianProfile.tsx index 9a2b0a4..e659f37 100644 --- a/client/src/features/admin/components/DeleteLibrarianProfile.tsx +++ b/client/src/features/admin/components/DeleteLibrarianProfile.tsx @@ -18,27 +18,27 @@ export const DeleteLibrarianProfile: React.FC = ({ if (!isOpen) return null; return ( -
+
{/* Container: Matches the clean off-white base with soft linen-amber border */} -
+
{/* Header: Crisp text-base alignment with deep slate-ink tone */} -

+

Revoke Administrative Access

{/* Main Paragraph: Structured at text-sm slate-600 for high editorial legibility */} -

+

Are you completely confident about stripping{" "} - + "{librarianName}" {" "} of all administrative privileges and access layers?

{/* Callout Block: Shipped with premium cream/rose warning surface tokens */} -
- +
+ ⚠️ Critical Reminder: This action completely cleanses their system profile registry. They @@ -48,13 +48,13 @@ export const DeleteLibrarianProfile: React.FC = ({
{/* Modal Action Footers - Crisp Touchpoints */} -
+
{/* Cancel/Abort Button */} @@ -64,7 +64,7 @@ export const DeleteLibrarianProfile: React.FC = ({ type="button" onClick={onConfirm} disabled={isPending} - className="px-4 py-3 bg-slate-900 hover:bg-slate-800 text-amber-50 rounded-xl transition-all cursor-pointer shadow-sm disabled:bg-slate-700 disabled:cursor-not-allowed min-w-32.5 text-center" + className="px-5 py-2.5 bg-[#2B6CB0] hover:bg-[#1A365D] text-white rounded-full transition-all cursor-pointer shadow-sm disabled:opacity-50 disabled:cursor-not-allowed text-center" > {isPending ? "Revoking..." : "Confirm Deletion"} diff --git a/client/src/features/admin/components/DeleteUserModal.tsx b/client/src/features/admin/components/DeleteUserModal.tsx index 3a9c70f..49bccf0 100644 --- a/client/src/features/admin/components/DeleteUserModal.tsx +++ b/client/src/features/admin/components/DeleteUserModal.tsx @@ -18,26 +18,26 @@ export const DeleteUserModal: React.FC = ({ if (!isOpen) return null; return ( -
- {/* Container: Matches the clean off-white base with soft linen-amber border */} -
+
+ {/* Container: Changed to match the exact reference modal layout theme tokens */} +
- {/* Header: Crisp text-base alignment with deep slate-ink tone */} -

+ {/* Header: Shifted to match institutional branding header typography rules */} +

Confirm User Account Purge

- {/* Main Paragraph: Structured at text-sm slate-600 for high editorial legibility */} -

+ {/* Main Paragraph: Styled using identical text-color mappings for high editorial legibility */} +

Are you sure you want to completely delete the system profile record for{" "} - "{userName}"{" "} + "{userName}"{" "} from the library management core engine?

- {/* Callout Block: Shipped with premium cream/rose warning surface tokens */} -
- + {/* Callout Block: Shipped with premium cream/rose warning surfaces matching reference specs */} +
+ ⚠️ Irreversible Action: This process instantly flushes out their system user registry @@ -46,14 +46,14 @@ export const DeleteUserModal: React.FC = ({
- {/* Modal Action Footers - Crisp Touchpoints */} -
+ {/* Modal Action Footers - Crisp Touchpoints Matching Reference Layout */} +
{/* Cancel Button */} @@ -63,7 +63,7 @@ export const DeleteUserModal: React.FC = ({ type="button" onClick={onConfirm} disabled={isPending} - className="px-4 py-3 bg-slate-900 hover:bg-slate-800 text-amber-50 rounded-xl transition-all cursor-pointer shadow-sm disabled:bg-slate-700 disabled:cursor-not-allowed min-w-30 text-center" + className="px-5 py-2.5 bg-[#2B6CB0] hover:bg-[#1A365D] text-white rounded-full transition-all cursor-pointer shadow-sm disabled:opacity-50 disabled:cursor-not-allowed tracking-wide text-center" > {isPending ? "Purging Files..." : "Confirm Delete"} diff --git a/client/src/features/admin/components/LibrarianModal.tsx b/client/src/features/admin/components/LibrarianModal.tsx index e4f588b..86c2689 100644 --- a/client/src/features/admin/components/LibrarianModal.tsx +++ b/client/src/features/admin/components/LibrarianModal.tsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { X, User, Mail, Lock, Phone, ShieldCheck } from "lucide-react"; +import { User, Mail, Lock, Phone, ShieldCheck } from "lucide-react"; import { toast } from "sonner"; import { axiosClient } from "../../../api/axiosClient"; import { useMutation, useQueryClient } from "@tanstack/react-query"; @@ -24,18 +24,18 @@ interface LibrarianModalProps { isOpen: boolean; onClose: () => void; librarianToEdit?: UserRecord | null; + onSaveSuccess?: () => void; // ✨ Added callback hook } export const LibrarianModal: React.FC = ({ isOpen, onClose, librarianToEdit, + onSaveSuccess, }) => { const queryClient = useQueryClient(); const isEditMode = !!librarianToEdit; - // 💡 FIXED: Initialize state directly from props. - // Combined with the unique layout `key`, this renders cleanly without a useEffect loop. const [name, setName] = useState(librarianToEdit?.name || ""); const [gmail, setGmail] = useState(librarianToEdit?.gmail || ""); const [password, setPassword] = useState(""); @@ -77,6 +77,7 @@ export const LibrarianModal: React.FC = ({ ); queryClient.invalidateQueries({ queryKey: ["adminUsersMasterFeed"] }); handleResetAndClose(); + if (onSaveSuccess) onSaveSuccess(); // ✨ Return immediately to dashboard page }, onError: (error: AxiosError) => { toast.error( @@ -143,15 +144,14 @@ export const LibrarianModal: React.FC = ({ if (!isOpen) return null; return ( -
-
- {/* Header Layout Block */} -
+
+
+
-

+

{isEditMode ? "Modify Librarian Details" : "Add New Librarian"}

-

+

{isEditMode ? "Adjust system operational parameters" : "All fields below are strictly required"} @@ -160,156 +160,127 @@ export const LibrarianModal: React.FC = ({

- {/* Input Form Fields Wrapper */} -
- {/* Name Field */} -
-