diff --git a/guardian-admin-dashboard/src/components/dashboard/DashboardSummaryCards.css b/guardian-admin-dashboard/src/components/dashboard/DashboardSummaryCards.css new file mode 100644 index 000000000..51f3d1079 --- /dev/null +++ b/guardian-admin-dashboard/src/components/dashboard/DashboardSummaryCards.css @@ -0,0 +1,135 @@ +.dsc-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 1rem; + margin-bottom: 2rem; +} + +.dsc-card { + background: #4fa0c8 !important; + border: 1px solid var(--dsc-accent-color); + border-radius: 12px; + padding: 1.25rem 1.25rem 1rem; + display: flex; + flex-direction: column; + gap: 0.5rem; + position: relative; + overflow: hidden; + transition: transform 0.2s ease, box-shadow 0.2s ease; + cursor: default; +} + +.dsc-card::before { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 3px; + border-radius: 12px 12px 0 0; + background: var(--dsc-accent-color); + opacity: 0.85; +} + +.dsc-card:hover { + transform: translateY(-2px); + box-shadow: 0 8px 24px #4fa0c8; +} +.dsc-card-header { + display: flex; + align-items: center; + gap: 0.6rem; +} + +.dsc-icon-wrap { + width: 34px; + height: 34px; + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + background: var(--dsc-accent-bg); + color: var(--dsc-accent-color); + flex-shrink: 0; +} + +.dsc-label { + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.06em; + color: #ffffff; +} + +.dsc-value { + font-size: 2rem; + font-weight: 700; + color: #ffffff; + line-height: 1; + margin-top: 0.25rem; + letter-spacing: -0.02em; +} + +.dsc-suffix { + font-size: 1rem; + font-weight: 500; + color: rgba(255, 255, 255, 0.75); + margin-left: 2px; +} +.dsc-description { + font-size: 0.72rem; + color: rgba(255, 255, 255, 0.7); + margin: 0; +} + +.dsc-card.accent { + --dsc-accent-color: white; + --dsc-accent-bg: #4fa0c8; +} + +.dsc-card.dsc-skeleton { + pointer-events: none; +} + +.dsc-skeleton-icon { + width: 34px; + height: 34px; + border-radius: 8px; + background: #4fa0c8 !important; + animation: dsc-pulse 1.4s ease-in-out infinite; +} + +.dsc-skeleton-line { + height: 10px; + border-radius: 4px; + background: #4fa0c8 !important; + animation: dsc-pulse 1.4s ease-in-out infinite; +} + +.dsc-skeleton-line.short { width: 50%; } +.dsc-skeleton-line.long { width: 35%; height: 28px; margin-top: 0.5rem; } + +@keyframes dsc-pulse { + 0%, 100% { opacity: 0.4; } + 50% { opacity: 0.9; } +} + +.dsc-error { + padding: 1rem 1.25rem; + background: rgba(251, 113, 133, 0.1); + border: 1px solid rgba(251, 113, 133, 0.25); + border-radius: 10px; + color: #fb7185; + font-size: 0.85rem; + margin-bottom: 1.5rem; +} + +@media (max-width: 640px) { + .dsc-grid { + grid-template-columns: repeat(2, 1fr); + } + + .dsc-value { + font-size: 1.6rem; + } +} \ No newline at end of file diff --git a/guardian-admin-dashboard/src/components/dashboard/DashboardSummaryCards.jsx b/guardian-admin-dashboard/src/components/dashboard/DashboardSummaryCards.jsx new file mode 100644 index 000000000..0a0826413 --- /dev/null +++ b/guardian-admin-dashboard/src/components/dashboard/DashboardSummaryCards.jsx @@ -0,0 +1,123 @@ +import { motion } from "framer-motion"; +import { + Users, + UserCheck, + Stethoscope, + ClipboardList, + CheckCircle2, + Clock, + TrendingUp, +} from "lucide-react"; +import "./DashboardSummaryCards.css" + +const CARD_CONFIG = [ + { + key: "totalPatients", + label: "Total Patients", + icon: Stethoscope, + accent: "accent-teal", + description: "All registered patients", + }, + { + key: "totalActivePatients", + label: "Active Patients", + icon: UserCheck, + accent: "accent-green", + description: "Currently active", + }, + { + key: "totalStaff", + label: "Care Staff", + icon: Users, + accent: "accent-blue", + description: "Organisation staff", + }, + { + key: "totalTasks", + label: "Total Tasks", + icon: ClipboardList, + accent: "accent-purple", + description: "All assigned tasks", + }, + { + key: "completedTasks", + label: "Completed Tasks", + icon: CheckCircle2, + accent: "accent-emerald", + description: "Successfully completed", + }, + { + key: "pendingTasks", + label: "Pending Tasks", + icon: Clock, + accent: "accent-amber", + description: "Awaiting completion", + }, + { + key: "taskCompletionRate", + label: "Completion Rate", + icon: TrendingUp, + accent: "accent-rose", + description: "Tasks completed (%)", + suffix: "%", + }, +]; + +export default function DashboardSummaryCards({ summary, loading, error }) { + if (loading) { + return ( +
+ {CARD_CONFIG.map((card) => ( +
+
+
+
+
+ ))} +
+ ); + } + + if (error) { + return ( +
+

⚠ Could not load summary: {error}

+
+ ); + } + + if (!summary) return null; + + return ( +
+ {CARD_CONFIG.map((card, i) => { + const Icon = card.icon; + const value = summary[card.key] ?? "—"; + + return ( + +
+
+ +
+ {card.label} +
+
+ {value} + {card.suffix && value !== "—" && ( + {card.suffix} + )} +
+

{card.description}

+
+ ); + })} +
+ ); +} \ No newline at end of file diff --git a/guardian-admin-dashboard/src/pages/DashboardHome.jsx b/guardian-admin-dashboard/src/pages/DashboardHome.jsx index 4d90bf364..53e5456ed 100644 --- a/guardian-admin-dashboard/src/pages/DashboardHome.jsx +++ b/guardian-admin-dashboard/src/pages/DashboardHome.jsx @@ -1,10 +1,48 @@ +import { useEffect, useState } from "react"; import { motion } from "framer-motion"; import StatCard from "../components/dashboard/StatCard"; import { DASHBOARD_STATS } from "../utils/constants"; import { ArrowRight, Building2, Users, ShieldAlert, FileBarChart2 } from "lucide-react"; import { Link } from "react-router-dom"; +import axios from "axios"; +import DashboardSummaryCards from "../components/dashboard/DashboardSummaryCards"; export default function DashboardHome() { + const [summary, setSummary] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(""); + + useEffect(() => { + const fetchSummary = async () => { + try { + const token = localStorage.getItem("guardian_admin_token"); + + const response = await axios.get( + "https://guardian-backend-git-fix-cors-patelrudra2306-5873s-projects.vercel.app/api/v1/admin/dashboard-summary", + { + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + Accept: "application/json", + }, + withCredentials: false, + } + ); + setSummary(response.data); + } catch (err) { + setError( + err?.response?.data?.message || + err?.message || + "Failed to load dashboard summary." + ); + } finally { + setLoading(false); + } + }; + + fetchSummary(); + }, []); + return (
-
+ + + {/*
{DASHBOARD_STATS.map((item) => ( ))} -
+
*/}

Upcoming modules

-
Alerts & Monitoring
-
Staff Administration
-
Organisation Workflows
-
Reports & Analytics diff --git a/guardian-admin-dashboard/src/utils/storage.js b/guardian-admin-dashboard/src/utils/storage.js index a650fb135..db6d7b553 100644 --- a/guardian-admin-dashboard/src/utils/storage.js +++ b/guardian-admin-dashboard/src/utils/storage.js @@ -5,7 +5,8 @@ export function setAuthToken(token) { } export function getAuthToken() { - return localStorage.getItem(STORAGE_KEYS.token); + const token = localStorage.getItem(STORAGE_KEYS.token); + return token; } export function removeAuthToken() {