initialize foundational styles, dashboard layout, and hospital network module

This commit is contained in:
2026-08-29 15:22:36 +05:30
parent f2a2994e08
commit 4873b360fc
5 changed files with 729 additions and 315 deletions
+40 -39
View File
@@ -9,45 +9,46 @@
} }
:root { :root {
/* Brand Colors */ /* Brand Colors — Cream-compatible blue palette */
--primary-50: #eef6ff; --primary-50: #fcfbfa;
--primary-100: #d9ecff; --primary-100: #f7f5f0;
--primary-200: #bcdcff; --primary-200: #f1ebd8;
--primary-300: #8ec5fe; --primary-300: #e2d3af;
--primary-400: #5aa5fb; --primary-400: #d0c098;
--primary-500: #3b82f6; --primary-500: #2563eb;
--primary-600: #2563eb; --primary-600: #1d4ed8;
--primary-700: #1d4ed8; --primary-700: #1e3a8a;
--primary-800: #1e40af; --primary-800: #172554;
--primary-900: #1e3a8a; --primary-900: #0f172a;
--teal-400: #2dd4bf; /* Cream-compatible teal palette */
--teal-500: #14b8a6; --teal-400: #0d9488;
--teal-600: #0d9488; --teal-500: #0f766e;
--teal-600: #115e59;
/* Dark palette */ /* Cream & White surface palette (was Dark palette) */
--dark-900: #050d1a; --dark-900: #faf7f0; /* Page Background (soft creamy ivory) */
--dark-800: #0a1628; --dark-800: #ffffff; /* Primary Card/Sidebar surface (crisp white) */
--dark-700: #0f2040; --dark-700: #f5eedc; /* Darker cream for borders / card hovers */
--dark-600: #162a52; --dark-600: #eae1cc; /* Soft warm beige for borders/inputs */
--dark-500: #1e3a6e; --dark-500: #d5c8ab; /* Deep beige for inactive borders/dividers */
/* Neutrals */ /* Neutrals — soft dark brown/charcoal for text (was light neutrals) */
--gray-50: #f8fafc; --gray-50: #1e1b18; /* Body/Primary Text (soft espresso) */
--gray-100: #f1f5f9; --gray-100: #29241f; /* Primary titles */
--gray-200: #e2e8f0; --gray-200: #3b342c; /* Secondary text */
--gray-300: #cbd5e1; --gray-300: #52493e; /* Medium description text */
--gray-400: #94a3b8; --gray-400: #6f6354; /* Muted text */
--gray-500: #64748b; --gray-500: #887b6a; /* Placeholders */
--gray-600: #475569; --gray-600: #a29584; /* Soft dividers */
--gray-700: #334155; --gray-700: #c1b5a5;
--gray-800: #1e293b; --gray-800: #e2dbcd;
--gray-900: #0f172a; --gray-900: #f3efe3;
/* Semantic */ /* Semantic */
--danger: #ef4444; --danger: #ef4444;
--success: #22c55e; --success: #16a34a;
--warning: #f59e0b; --warning: #d97706;
/* Typography */ /* Typography */
--font-primary: 'Plus Jakarta Sans', 'Inter', system-ui, sans-serif; --font-primary: 'Plus Jakarta Sans', 'Inter', system-ui, sans-serif;
@@ -60,12 +61,12 @@
--radius-xl: 24px; --radius-xl: 24px;
--radius-full: 9999px; --radius-full: 9999px;
/* Shadows */ /* Shadows — soft warm ambient shadows */
--shadow-sm: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); --shadow-sm: 0 2px 4px rgba(47, 43, 36, 0.04), 0 1px 2px rgba(47, 43, 36, 0.03);
--shadow-md: 0 4px 16px rgba(0,0,0,0.25); --shadow-md: 0 6px 16px rgba(47, 43, 36, 0.06);
--shadow-lg: 0 10px 40px rgba(0,0,0,0.35); --shadow-lg: 0 12px 32px rgba(47, 43, 36, 0.08);
--shadow-glow: 0 0 40px rgba(59, 130, 246, 0.4); --shadow-glow: 0 0 30px rgba(37, 99, 235, 0.1);
--shadow-teal: 0 0 30px rgba(20, 184, 166, 0.3); --shadow-teal: 0 0 30px rgba(13, 148, 136, 0.08);
} }
html { html {
+70 -63
View File
@@ -15,7 +15,7 @@
.sidebar { .sidebar {
width: 280px; width: 280px;
background: var(--dark-800); background: var(--dark-800);
border-right: 1px solid rgba(255, 255, 255, 0.05); border-right: 1px solid var(--dark-600);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
@@ -29,7 +29,7 @@
align-items: center; align-items: center;
gap: 12px; gap: 12px;
padding: 8px 12px 24px 12px; padding: 8px 12px 24px 12px;
border-bottom: 1px solid rgba(255, 255, 255, 0.05); border-bottom: 1px solid var(--dark-600);
} }
.logo-icon-wrapper { .logo-icon-wrapper {
@@ -51,7 +51,7 @@
.logo-brand { .logo-brand {
font-size: 18px; font-size: 18px;
font-weight: 800; font-weight: 800;
color: #fff; color: var(--gray-50);
letter-spacing: -0.02em; letter-spacing: -0.02em;
} }
@@ -97,8 +97,8 @@
} }
.nav-item:hover { .nav-item:hover {
color: #fff; color: var(--gray-50);
background: rgba(255, 255, 255, 0.03); background: rgba(0, 0, 0, 0.02);
} }
.nav-item:hover svg { .nav-item:hover svg {
@@ -106,10 +106,10 @@
} }
.nav-item.active { .nav-item.active {
color: #fff; color: var(--primary-600);
background: linear-gradient(135deg, rgba(37, 99, 235, 0.15) 0%, rgba(20, 184, 166, 0.05) 100%); background: linear-gradient(135deg, rgba(37, 99, 235, 0.08) 0%, rgba(20, 184, 166, 0.02) 100%);
border: 1px solid rgba(37, 99, 235, 0.25); border: 1px solid rgba(37, 99, 235, 0.15);
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.1); box-shadow: 0 4px 12px rgba(37, 99, 235, 0.05);
} }
.nav-item.active svg { .nav-item.active svg {
@@ -118,7 +118,7 @@
} }
.sidebar-footer { .sidebar-footer {
border-top: 1px solid rgba(255, 255, 255, 0.05); border-top: 1px solid var(--dark-600);
padding-top: 20px; padding-top: 20px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -153,7 +153,7 @@
.user-name { .user-name {
font-size: 14px; font-size: 14px;
font-weight: 700; font-weight: 700;
color: #fff; color: var(--gray-50);
} }
.user-role { .user-role {
@@ -198,9 +198,9 @@
/* ── Topbar ── */ /* ── Topbar ── */
.topbar { .topbar {
height: 70px; height: 70px;
background: rgba(10, 22, 40, 0.5); background: var(--dark-800);
backdrop-filter: blur(8px); backdrop-filter: blur(8px);
border-bottom: 1px solid rgba(255, 255, 255, 0.05); border-bottom: 1px solid var(--dark-700);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
@@ -220,8 +220,8 @@
gap: 8px; gap: 8px;
font-size: 12.5px; font-size: 12.5px;
color: var(--gray-400); color: var(--gray-400);
background: rgba(255, 255, 255, 0.03); background: var(--dark-900);
border: 1px solid rgba(255, 255, 255, 0.06); border: 1px solid var(--dark-600);
padding: 6px 12px; padding: 6px 12px;
border-radius: var(--radius-full); border-radius: var(--radius-full);
} }
@@ -256,8 +256,8 @@
gap: 8px; gap: 8px;
font-size: 12px; font-size: 12px;
color: var(--gray-400); color: var(--gray-400);
background: rgba(255, 255, 255, 0.03); background: var(--dark-900);
border: 1px solid rgba(255, 255, 255, 0.05); border: 1px solid var(--dark-600);
padding: 6px 12px; padding: 6px 12px;
border-radius: var(--radius-full); border-radius: var(--radius-full);
} }
@@ -286,7 +286,7 @@
.pane-title { .pane-title {
font-size: 26px; font-size: 26px;
font-weight: 800; font-weight: 800;
color: #fff; color: var(--gray-50);
letter-spacing: -0.02em; letter-spacing: -0.02em;
} }
@@ -326,8 +326,8 @@
} }
.metric-card { .metric-card {
background: rgba(255, 255, 255, 0.03); background: var(--dark-800);
border: 1px solid rgba(255, 255, 255, 0.06); border: 1px solid var(--dark-600);
border-radius: var(--radius-lg); border-radius: var(--radius-lg);
padding: 24px; padding: 24px;
display: flex; display: flex;
@@ -355,8 +355,8 @@
.glow-yellow .card-glass-glow { background: var(--warning); } .glow-yellow .card-glass-glow { background: var(--warning); }
.metric-card:hover { .metric-card:hover {
background: rgba(255, 255, 255, 0.05); background: var(--dark-700);
border-color: rgba(255, 255, 255, 0.12); border-color: var(--dark-500);
transform: translateY(-2px); transform: translateY(-2px);
} }
@@ -374,7 +374,7 @@
.metric-value { .metric-value {
font-size: 36px; font-size: 36px;
font-weight: 800; font-weight: 800;
color: #fff; color: var(--gray-50);
margin: 12px 0 6px 0; margin: 12px 0 6px 0;
letter-spacing: -0.03em; letter-spacing: -0.03em;
} }
@@ -392,8 +392,8 @@
} }
.detail-panel { .detail-panel {
background: rgba(10, 22, 40, 0.4); background: var(--dark-800);
border: 1px solid rgba(255, 255, 255, 0.05); border: 1px solid var(--dark-600);
border-radius: var(--radius-lg); border-radius: var(--radius-lg);
padding: 24px; padding: 24px;
} }
@@ -401,7 +401,7 @@
.panel-title { .panel-title {
font-size: 16px; font-size: 16px;
font-weight: 700; font-weight: 700;
color: #fff; color: var(--gray-100);
margin-bottom: 20px; margin-bottom: 20px;
} }
@@ -416,8 +416,8 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
background: rgba(255, 255, 255, 0.02); background: var(--dark-900);
border: 1px solid rgba(255, 255, 255, 0.06); border: 1px solid var(--dark-600);
padding: 14px 18px; padding: 14px 18px;
border-radius: var(--radius-md); border-radius: var(--radius-md);
} }
@@ -431,7 +431,7 @@
.pinger-name { .pinger-name {
font-size: 13.5px; font-size: 13.5px;
font-weight: 600; font-weight: 600;
color: #fff; color: var(--gray-50);
} }
.pinger-value { .pinger-value {
@@ -474,7 +474,7 @@
.kpi-num { .kpi-num {
font-size: 22px; font-size: 22px;
font-weight: 800; font-weight: 800;
color: #fff; color: var(--gray-50);
} }
.kpi-label { .kpi-label {
@@ -497,7 +497,10 @@
padding: 14px 16px; padding: 14px 16px;
border-radius: var(--radius-md); border-radius: var(--radius-md);
border-left: 4px solid transparent; border-left: 4px solid transparent;
background: rgba(255, 255, 255, 0.02); background: var(--dark-900);
border-top: 1px solid var(--dark-600);
border-right: 1px solid var(--dark-600);
border-bottom: 1px solid var(--dark-600);
} }
.alert-critical { .alert-critical {
@@ -533,9 +536,9 @@
} }
.resolve-btn { .resolve-btn {
background: rgba(255, 255, 255, 0.06); background: var(--dark-800);
border: 1px solid rgba(255, 255, 255, 0.1); border: 1px solid var(--dark-600);
color: var(--gray-300); color: var(--gray-200);
padding: 6px 12px; padding: 6px 12px;
border-radius: var(--radius-sm); border-radius: var(--radius-sm);
font-size: 12px; font-size: 12px;
@@ -575,13 +578,13 @@
font-weight: 700; font-weight: 700;
color: var(--gray-500); color: var(--gray-500);
text-transform: uppercase; text-transform: uppercase;
border-bottom: 1px solid rgba(255, 255, 255, 0.05); border-bottom: 1px solid var(--dark-600);
} }
.telemetry-table td { .telemetry-table td {
padding: 16px; padding: 16px;
font-size: 13.5px; font-size: 13.5px;
border-bottom: 1px solid rgba(255, 255, 255, 0.03); border-bottom: 1px solid var(--dark-700);
} }
.hr-badge { .hr-badge {
@@ -609,12 +612,12 @@
} }
.status-indicator-tag { .status-indicator-tag {
background: rgba(255, 255, 255, 0.03); background: var(--dark-700);
border: 1px solid rgba(255, 255, 255, 0.08); border: 1px solid var(--dark-600);
padding: 4px 10px; padding: 4px 10px;
border-radius: var(--radius-full); border-radius: var(--radius-full);
font-size: 11px; font-size: 11px;
color: var(--gray-400); color: var(--gray-300);
} }
/* ── Admin Provisioning & Roster Cards ── */ /* ── Admin Provisioning & Roster Cards ── */
@@ -625,20 +628,22 @@
} }
.cg-card { .cg-card {
background: rgba(255, 255, 255, 0.02); background: var(--dark-800);
border: 1px solid rgba(255, 255, 255, 0.05); border: 1px solid var(--dark-600);
border-radius: var(--radius-lg); border-radius: var(--radius-lg);
padding: 20px; padding: 20px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 16px; gap: 16px;
transition: all 0.25s ease; transition: all 0.25s ease;
box-shadow: var(--shadow-sm);
} }
.cg-card:hover { .cg-card:hover {
background: rgba(255, 255, 255, 0.04); background: var(--dark-700);
border-color: rgba(59, 130, 246, 0.2); border-color: var(--primary-400);
transform: translateY(-2px); transform: translateY(-2px);
box-shadow: var(--shadow-md);
} }
.cg-header { .cg-header {
@@ -651,8 +656,8 @@
width: 48px; width: 48px;
height: 48px; height: 48px;
border-radius: 50%; border-radius: 50%;
background: rgba(59, 130, 246, 0.15); background: rgba(59, 130, 246, 0.1);
color: var(--primary-300); color: var(--primary-600);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -663,7 +668,7 @@
.cg-name { .cg-name {
font-size: 15px; font-size: 15px;
font-weight: 700; font-weight: 700;
color: #fff; color: var(--gray-50);
} }
.cg-role { .cg-role {
@@ -673,8 +678,8 @@
} }
.cg-body { .cg-body {
border-top: 1px solid rgba(255, 255, 255, 0.05); border-top: 1px solid var(--dark-600);
border-bottom: 1px solid rgba(255, 255, 255, 0.05); border-bottom: 1px solid var(--dark-600);
padding: 12px 0; padding: 12px 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -753,8 +758,8 @@
/* ── Settings Options List ── */ /* ── Settings Options List ── */
.settings-options-list { .settings-options-list {
background: rgba(255, 255, 255, 0.02); background: var(--dark-800);
border: 1px solid rgba(255, 255, 255, 0.05); border: 1px solid var(--dark-600);
border-radius: var(--radius-lg); border-radius: var(--radius-lg);
padding: 8px 0; padding: 8px 0;
max-width: 100%; max-width: 100%;
@@ -765,7 +770,7 @@
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 20px 24px; padding: 20px 24px;
border-bottom: 1px solid rgba(255, 255, 255, 0.03); border-bottom: 1px solid var(--dark-700);
} }
.setting-row:last-child { .setting-row:last-child {
@@ -782,7 +787,7 @@
.setting-label { .setting-label {
font-size: 14px; font-size: 14px;
font-weight: 700; font-weight: 700;
color: #fff; color: var(--gray-100);
} }
.setting-description { .setting-description {
@@ -809,7 +814,7 @@
position: absolute; position: absolute;
cursor: pointer; cursor: pointer;
inset: 0; inset: 0;
background-color: rgba(255, 255, 255, 0.1); background-color: var(--dark-700);
transition: .3s; transition: .3s;
border-radius: 24px; border-radius: 24px;
} }
@@ -854,10 +859,12 @@ input:checked + .slider:before {
.modal-content { .modal-content {
background: var(--dark-800); background: var(--dark-800);
border: 1px solid rgba(255, 255, 255, 0.08); border: 1px solid var(--dark-600);
border-radius: var(--radius-lg); border-radius: var(--radius-lg);
width: 100%; width: 100%;
max-width: 480px; max-width: 480px;
max-height: 90vh;
overflow-y: auto;
padding: 28px; padding: 28px;
box-shadow: var(--shadow-lg); box-shadow: var(--shadow-lg);
animation: modalSlideUp 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); animation: modalSlideUp 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
@@ -878,7 +885,7 @@ input:checked + .slider:before {
.modal-header h3 { .modal-header h3 {
font-size: 18px; font-size: 18px;
font-weight: 800; font-weight: 800;
color: #fff; color: var(--gray-50);
} }
.close-btn { .close-btn {
@@ -891,7 +898,7 @@ input:checked + .slider:before {
} }
.close-btn:hover { .close-btn:hover {
color: #fff; color: var(--gray-100);
} }
.modal-form { .modal-form {
@@ -914,11 +921,11 @@ input:checked + .slider:before {
.form-group input, .form-group input,
.form-group select { .form-group select {
background: rgba(255, 255, 255, 0.04); background: var(--dark-900);
border: 1px solid rgba(255, 255, 255, 0.08); border: 1px solid var(--dark-600);
border-radius: var(--radius-md); border-radius: var(--radius-md);
padding: 12px; padding: 12px;
color: #fff; color: var(--gray-50);
font-size: 13.5px; font-size: 13.5px;
font-family: var(--font-primary); font-family: var(--font-primary);
outline: none; outline: none;
@@ -940,7 +947,7 @@ input:checked + .slider:before {
.cancel-btn { .cancel-btn {
background: none; background: none;
border: 1px solid rgba(255, 255, 255, 0.08); border: 1px solid var(--dark-600);
color: var(--gray-300); color: var(--gray-300);
padding: 10px 18px; padding: 10px 18px;
border-radius: var(--radius-md); border-radius: var(--radius-md);
@@ -949,8 +956,8 @@ input:checked + .slider:before {
} }
.cancel-btn:hover { .cancel-btn:hover {
background: rgba(255, 255, 255, 0.03); background: var(--dark-700);
color: #fff; color: var(--gray-100);
} }
.submit-btn { .submit-btn {
@@ -1000,7 +1007,7 @@ input:checked + .slider:before {
width: 100%; width: 100%;
height: auto; height: auto;
border-right: none; border-right: none;
border-bottom: 1px solid rgba(255, 255, 255, 0.05); border-bottom: 1px solid var(--dark-600);
} }
.nav-menu { .nav-menu {
flex-direction: row; flex-direction: row;
+90 -46
View File
@@ -23,18 +23,19 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 16px; gap: 16px;
background: rgba(10, 22, 40, 0.6); background: var(--dark-800);
border: 1px solid rgba(255, 255, 255, 0.05); border: 1px solid var(--dark-600);
border-radius: var(--radius-md); border-radius: var(--radius-md);
padding: 16px 20px; padding: 16px 20px;
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: var(--shadow-sm);
} }
.analytics-card:hover { .analytics-card:hover {
transform: translateY(-2px); transform: translateY(-2px);
border-color: rgba(59, 130, 246, 0.2); border-color: rgba(59, 130, 246, 0.2);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); box-shadow: var(--shadow-md);
} }
.analytics-card.glow-card { .analytics-card.glow-card {
@@ -83,7 +84,7 @@
.card-val { .card-val {
font-size: 24px; font-size: 24px;
font-weight: 800; font-weight: 800;
color: #fff; color: var(--gray-50);
line-height: 1.2; line-height: 1.2;
} }
@@ -108,7 +109,7 @@
width: 320px; width: 320px;
flex-shrink: 0; flex-shrink: 0;
background: var(--dark-800); background: var(--dark-800);
border: 1px solid rgba(255, 255, 255, 0.05); border: 1px solid var(--dark-600);
border-radius: var(--radius-md); border-radius: var(--radius-md);
padding: 16px; padding: 16px;
display: flex; display: flex;
@@ -119,7 +120,7 @@
.section-pane-title { .section-pane-title {
font-size: 15px; font-size: 15px;
font-weight: 700; font-weight: 700;
color: #fff; color: var(--gray-50);
} }
.header-search-row { .header-search-row {
@@ -168,10 +169,10 @@
.search-input-wrap input { .search-input-wrap input {
width: 100%; width: 100%;
background: var(--dark-900); background: var(--dark-900);
border: 1px solid rgba(255, 255, 255, 0.08); border: 1px solid var(--dark-600);
border-radius: 8px; border-radius: 8px;
padding: 8px 10px 8px 32px; padding: 8px 10px 8px 32px;
color: #fff; color: var(--gray-50);
font-size: 13px; font-size: 13px;
transition: all 0.2s; transition: all 0.2s;
} }
@@ -192,8 +193,8 @@
} }
.group-item-card { .group-item-card {
background: rgba(255, 255, 255, 0.02); background: var(--dark-900);
border: 1px solid rgba(255, 255, 255, 0.04); border: 1px solid var(--dark-600);
border-radius: 8px; border-radius: 8px;
padding: 12px; padding: 12px;
cursor: pointer; cursor: pointer;
@@ -201,14 +202,14 @@
} }
.group-item-card:hover { .group-item-card:hover {
background: rgba(255, 255, 255, 0.04); background: var(--dark-700);
border-color: rgba(255, 255, 255, 0.1); border-color: var(--dark-500);
} }
.group-item-card.selected { .group-item-card.selected {
background: rgba(59, 130, 246, 0.08); background: rgba(59, 130, 246, 0.06);
border-color: var(--primary-500); border-color: var(--primary-500);
box-shadow: 0 0 12px rgba(59, 130, 246, 0.1); box-shadow: 0 0 12px rgba(59, 130, 246, 0.05);
} }
.group-item-header { .group-item-header {
@@ -221,12 +222,12 @@
.group-name { .group-name {
font-size: 13.5px; font-size: 13.5px;
font-weight: 700; font-weight: 700;
color: #fff; color: var(--gray-50);
} }
.group-badge { .group-badge {
font-size: 10.5px; font-size: 10.5px;
background: rgba(255, 255, 255, 0.06); background: var(--dark-600);
color: var(--gray-300); color: var(--gray-300);
padding: 2px 6px; padding: 2px 6px;
border-radius: 4px; border-radius: 4px;
@@ -269,7 +270,7 @@
} }
.icon-link-btn:hover { .icon-link-btn:hover {
color: #fff; color: var(--primary-600);
text-decoration: underline; text-decoration: underline;
} }
@@ -285,9 +286,10 @@
.network-main-content { .network-main-content {
flex-grow: 1; flex-grow: 1;
background: var(--dark-800); background: var(--dark-800);
border: 1px solid rgba(255, 255, 255, 0.05); border: 1px solid var(--dark-600);
border-radius: var(--radius-md); border-radius: var(--radius-md);
padding: 20px; padding: 20px;
box-shadow: var(--shadow-sm);
} }
.group-details-pane { .group-details-pane {
@@ -301,14 +303,14 @@
justify-content: space-between; justify-content: space-between;
align-items: flex-start; align-items: flex-start;
gap: 20px; gap: 20px;
border-bottom: 1px solid rgba(255, 255, 255, 0.05); border-bottom: 1px solid var(--dark-600);
padding-bottom: 16px; padding-bottom: 16px;
} }
.group-title-label { .group-title-label {
font-size: 20px; font-size: 20px;
font-weight: 800; font-weight: 800;
color: #fff; color: var(--gray-50);
letter-spacing: -0.01em; letter-spacing: -0.01em;
} }
@@ -344,8 +346,8 @@
} }
.hospital-detail-card { .hospital-detail-card {
background: rgba(255, 255, 255, 0.02); background: var(--dark-900);
border: 1px solid rgba(255, 255, 255, 0.05); border: 1px solid var(--dark-600);
border-radius: var(--radius-md); border-radius: var(--radius-md);
padding: 16px; padding: 16px;
display: flex; display: flex;
@@ -357,8 +359,8 @@
.hospital-detail-card:hover { .hospital-detail-card:hover {
transform: translateY(-2px); transform: translateY(-2px);
border-color: rgba(20, 184, 166, 0.25); border-color: var(--teal-500);
background: rgba(255, 255, 255, 0.03); background: var(--dark-700);
} }
.hospital-card-header { .hospital-card-header {
@@ -371,7 +373,7 @@
.hospital-card-name { .hospital-card-name {
font-size: 14.5px; font-size: 14.5px;
font-weight: 700; font-weight: 700;
color: #fff; color: var(--gray-50);
line-height: 1.3; line-height: 1.3;
} }
@@ -401,7 +403,7 @@
gap: 4px; gap: 4px;
font-size: 12px; font-size: 12px;
color: var(--gray-400); color: var(--gray-400);
border-bottom: 1px solid rgba(255, 255, 255, 0.04); border-bottom: 1px solid var(--dark-600);
padding-bottom: 12px; padding-bottom: 12px;
} }
@@ -422,8 +424,8 @@
.m-stat { .m-stat {
font-size: 10.5px; font-size: 10.5px;
background: rgba(255, 255, 255, 0.04); background: var(--dark-600);
color: var(--gray-300); color: var(--gray-100);
padding: 2px 6px; padding: 2px 6px;
border-radius: 4px; border-radius: 4px;
font-weight: 500; font-weight: 500;
@@ -436,8 +438,8 @@
.mini-action-btn { .mini-action-btn {
background: none; background: none;
border: 1px solid rgba(255, 255, 255, 0.15); border: 1px solid var(--dark-500);
color: var(--gray-300); color: var(--gray-200);
font-size: 11px; font-size: 11px;
padding: 4px 8px; padding: 4px 8px;
border-radius: 4px; border-radius: 4px;
@@ -446,9 +448,9 @@
} }
.mini-action-btn:hover { .mini-action-btn:hover {
background: rgba(255, 255, 255, 0.08); background: var(--dark-700);
color: #fff; color: var(--gray-100);
border-color: rgba(255, 255, 255, 0.3); border-color: var(--dark-500);
} }
.mini-action-btn.danger:hover { .mini-action-btn.danger:hover {
@@ -489,7 +491,7 @@
text-align: center; text-align: center;
padding: 40px; padding: 40px;
color: var(--gray-400); color: var(--gray-400);
border: 1px dashed rgba(255, 255, 255, 0.08); border: 1px dashed var(--dark-500);
border-radius: var(--radius-md); border-radius: var(--radius-md);
font-size: 13.5px; font-size: 13.5px;
} }
@@ -498,9 +500,11 @@
.modal-wide .modal-content { .modal-wide .modal-content {
max-width: 900px; max-width: 900px;
width: 90%; width: 90%;
max-height: 90vh;
overflow-y: auto;
background: var(--dark-800); background: var(--dark-800);
border: 1px solid rgba(255, 255, 255, 0.08); border: 1px solid var(--dark-600);
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.4); box-shadow: var(--shadow-lg);
} }
.modal-super-title { .modal-super-title {
@@ -545,7 +549,7 @@
background: var(--dark-900); background: var(--dark-900);
padding: 3px; padding: 3px;
border-radius: 6px; border-radius: 6px;
border: 1px solid rgba(255, 255, 255, 0.05); border: 1px solid var(--dark-600);
} }
.roster-tab-btn { .roster-tab-btn {
@@ -561,13 +565,13 @@
} }
.roster-tab-btn:hover { .roster-tab-btn:hover {
color: #fff; color: var(--gray-100);
} }
.roster-tab-btn.active { .roster-tab-btn.active {
background: var(--primary-600); background: var(--primary-600);
color: #fff; color: #fff;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); box-shadow: var(--shadow-sm);
} }
.roster-action-group { .roster-action-group {
@@ -579,9 +583,9 @@
.roster-dropdown { .roster-dropdown {
background: var(--dark-900); background: var(--dark-900);
border: 1px solid rgba(255, 255, 255, 0.08); border: 1px solid var(--dark-600);
border-radius: 8px; border-radius: 8px;
color: #fff; color: var(--gray-50);
padding: 7px 12px; padding: 7px 12px;
font-size: 12.5px; font-size: 12.5px;
outline: none; outline: none;
@@ -594,7 +598,7 @@
/* Roster Table Styling */ /* Roster Table Styling */
.roster-table-container { .roster-table-container {
border: 1px solid rgba(255, 255, 255, 0.05); border: 1px solid var(--dark-600);
border-radius: 8px; border-radius: 8px;
overflow: hidden; overflow: hidden;
max-height: 380px; max-height: 380px;
@@ -619,7 +623,7 @@
} }
.staff-cell-name { .staff-cell-name {
color: #fff; color: var(--gray-50);
font-size: 13px; font-size: 13px;
} }
@@ -683,11 +687,51 @@
.cancel-btn { .cancel-btn {
background: none; background: none;
border: 1px solid rgba(255, 255, 255, 0.1); border: 1px solid var(--dark-600);
color: var(--gray-300); color: var(--gray-300);
} }
.cancel-btn:hover { .cancel-btn:hover {
background: rgba(255, 255, 255, 0.05); background: var(--dark-700);
color: #fff; color: var(--gray-100);
}
/* ── TWO-COLUMN FORM LAYOUT ── */
.form-grid-two-col {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
align-items: start;
}
.form-column {
display: flex;
flex-direction: column;
gap: 14px;
}
.form-section-title {
font-size: 13.5px;
font-weight: 600;
color: var(--primary-600);
border-bottom: 1px solid var(--dark-600);
padding-bottom: 6px;
margin-top: 0;
margin-bottom: 8px;
}
.form-info-box {
background: var(--dark-900);
border-left: 3px solid var(--teal-500);
padding: 10px;
border-radius: var(--radius-sm);
font-size: 11.5px;
color: var(--gray-300);
line-height: 1.5;
margin-top: 6px;
}
.form-actions-grid-span {
grid-column: span 2;
margin-top: 10px;
} }
+394 -32
View File
@@ -67,7 +67,29 @@ export default function HospitalNetwork({ notify }) {
// Form States // Form States
const [groupForm, setGroupForm] = useState({ name: '', hq: '', established: '', description: '' }) const [groupForm, setGroupForm] = useState({ name: '', hq: '', established: '', description: '' })
const [hospitalForm, setHospitalForm] = useState({ name: '', city: '', beds: '', phone: '', email: '', address: '', rating: '5.0' }) const [hospitalForm, setHospitalForm] = useState({
name: '',
reg_no: '',
beds: '50',
phone: '',
email: '',
address: '',
city: '',
state: '',
zip: '',
country: 'India',
website: '',
logoUrl: 'https://example.com/primecare-logo.png',
logoPath: '/uploads/logos/primecare-medical-center.png',
specialities: 'Cardiology, Neurology, Urology, Orthopedics, Emergency Medicine',
adminFirstName: '',
adminLastName: '',
adminEmail: '',
adminMobile: '',
adminCountryCode: '+91',
adminPassword: '',
adminUsername: '',
})
const [staffForm, setStaffForm] = useState({ type: 'doctor', name: '', specialty: '', role: 'Registered Nurse', experience: '1 Yr', certification: '', status: 'On Duty', phone: '', email: '' }) const [staffForm, setStaffForm] = useState({ type: 'doctor', name: '', specialty: '', role: 'Registered Nurse', experience: '1 Yr', certification: '', status: 'On Duty', phone: '', email: '' })
// Synchronize with LocalStorage // Synchronize with LocalStorage
@@ -97,6 +119,20 @@ export default function HospitalNetwork({ notify }) {
fetchedGroups = groupsRes fetchedGroups = groupsRes
} }
// Normalize backend shape → frontend shape
// Backend uses additional_info.city for HQ, reg_no as identifier, no established/description fields
fetchedGroups = fetchedGroups.map(g => {
const info = g.additional_info
? (typeof g.additional_info === 'string' ? JSON.parse(g.additional_info) : g.additional_info)
: {}
return {
...g,
hq: g.hq || (info.city && info.state ? `${info.city}, ${info.state}` : info.city || info.hq || 'N/A'),
established: g.established || (g.created_at ? g.created_at.substring(0, 4) : 'N/A'),
description: g.description || info.website || `Reg No: ${g.reg_no || 'N/A'}`,
}
})
if (fetchedGroups.length > 0) { if (fetchedGroups.length > 0) {
setGroups(fetchedGroups) setGroups(fetchedGroups)
// Automatically select the first fetched group ID // Automatically select the first fetched group ID
@@ -114,6 +150,22 @@ export default function HospitalNetwork({ notify }) {
} else if (Array.isArray(hospitalsRes)) { } else if (Array.isArray(hospitalsRes)) {
fetchedHospitals = hospitalsRes fetchedHospitals = hospitalsRes
} }
fetchedHospitals = fetchedHospitals.map(h => {
const info = h.additional_info
? (typeof h.additional_info === 'string' ? JSON.parse(h.additional_info) : h.additional_info)
: {}
return {
...h,
city: h.city || info.city || 'N/A',
beds: h.beds || info.beds || 50,
phone: h.phone || info.phone || 'N/A',
email: h.email || info.contact_email || info.email || 'N/A',
address: h.address || info.address || 'N/A',
rating: h.rating || info.rating || '5.0'
}
})
if (fetchedHospitals.length > 0) { if (fetchedHospitals.length > 0) {
setHospitals(fetchedHospitals) setHospitals(fetchedHospitals)
} }
@@ -173,7 +225,7 @@ export default function HospitalNetwork({ notify }) {
const filteredGroups = useMemo(() => { const filteredGroups = useMemo(() => {
return groups.filter(g => return groups.filter(g =>
g.name.toLowerCase().includes(groupQuery.toLowerCase()) || g.name.toLowerCase().includes(groupQuery.toLowerCase()) ||
g.hq.toLowerCase().includes(groupQuery.toLowerCase()) (g.hq || '').toLowerCase().includes(groupQuery.toLowerCase())
) )
}, [groups, groupQuery]) }, [groups, groupQuery])
@@ -285,18 +337,66 @@ export default function HospitalNetwork({ notify }) {
setModalType('hospital') setModalType('hospital')
if (mode === 'edit' && item) { if (mode === 'edit' && item) {
setEditItem(item) setEditItem(item)
const info = item.additional_info
? (typeof item.additional_info === 'string' ? JSON.parse(item.additional_info) : item.additional_info)
: {}
const logo = item.logo
? (typeof item.logo === 'string' ? JSON.parse(item.logo) : item.logo)
: {}
const specialities = item.hospital_speciality && Array.isArray(item.hospital_speciality)
? item.hospital_speciality.map(s => s.speciality || s).join(', ')
: (item.hospitalSpeciality && Array.isArray(item.hospitalSpeciality)
? item.hospitalSpeciality.map(s => s.speciality || s).join(', ')
: 'Cardiology, Neurology, Urology, Orthopedics, Emergency Medicine')
setHospitalForm({ setHospitalForm({
name: item.name, name: item.name || '',
city: item.city, reg_no: item.reg_no || '',
beds: item.beds, beds: item.beds || info.beds || '50',
phone: item.phone, phone: item.phone || info.phone || '',
email: item.email, email: item.email || info.contact_email || info.email || '',
address: item.address, address: item.address || info.address || '',
rating: item.rating city: item.city || info.city || '',
state: info.state || '',
zip: info.zip || '',
country: info.country || 'India',
website: info.website || '',
logoUrl: logo.url || 'https://example.com/primecare-logo.png',
logoPath: logo.path || '/uploads/logos/primecare-medical-center.png',
specialities: specialities,
adminFirstName: item.primaryStaff?.user?.first_name || '',
adminLastName: item.primaryStaff?.user?.last_name || '',
adminEmail: item.primaryStaff?.user?.email || '',
adminMobile: item.primaryStaff?.user?.mobile || '',
adminCountryCode: item.primaryStaff?.user?.country_code || '+91',
adminPassword: '',
adminUsername: item.primaryStaff?.user?.username || '',
}) })
} else { } else {
setEditItem(null) setEditItem(null)
setHospitalForm({ name: '', city: '', beds: '', phone: '', email: '', address: '', rating: '5.0' }) setHospitalForm({
name: '',
reg_no: '',
beds: '50',
phone: '',
email: '',
address: '',
city: '',
state: '',
zip: '',
country: 'India',
website: '',
logoUrl: 'https://example.com/primecare-logo.png',
logoPath: '/uploads/logos/primecare-medical-center.png',
specialities: 'Cardiology, Neurology, Urology, Orthopedics, Emergency Medicine',
adminFirstName: '',
adminLastName: '',
adminEmail: '',
adminMobile: '',
adminCountryCode: '+91',
adminPassword: '',
adminUsername: '',
})
} }
} }
@@ -304,20 +404,100 @@ export default function HospitalNetwork({ notify }) {
e.preventDefault() e.preventDefault()
if (!hospitalForm.name.trim()) return notify('Hospital Name is required', true) if (!hospitalForm.name.trim()) return notify('Hospital Name is required', true)
try {
if (modalMode === 'create') { if (modalMode === 'create') {
const newHospital = { const payload = {
id: 'H' + Date.now().toString().slice(-4), name: hospitalForm.name,
groupId: selectedGroupId, group_id: parseInt(selectedGroupId) || null,
...hospitalForm, reg_no: hospitalForm.reg_no,
beds: parseInt(hospitalForm.beds) || 50 additional_info: {
contact_email: hospitalForm.email,
phone: hospitalForm.phone,
address: hospitalForm.address,
city: hospitalForm.city,
state: hospitalForm.state,
zip: hospitalForm.zip,
country: hospitalForm.country,
website: hospitalForm.website,
beds: parseInt(hospitalForm.beds) || 50,
rating: '5.0'
},
logo: {
url: hospitalForm.logoUrl,
path: hospitalForm.logoPath
},
hospital_speciality: hospitalForm.specialities.split(',').map(s => s.trim()).filter(Boolean),
user: {
role: 'hospital',
first_name: hospitalForm.adminFirstName,
last_name: hospitalForm.adminLastName,
email: hospitalForm.adminEmail,
mobile: hospitalForm.adminMobile,
country_code: hospitalForm.adminCountryCode,
password: hospitalForm.adminPassword,
gender: 'male',
dob: '1980-01-01',
username: hospitalForm.adminUsername || (hospitalForm.adminFirstName.toLowerCase() + '_' + hospitalForm.adminLastName.toLowerCase()),
timezone_id: 1,
is_2fa: 1
}
}
const res = await adminService.hospitalNetwork.saveHospital(payload)
if (res?.success || res?.status === 201) {
notify(`Hospital "${hospitalForm.name}" created successfully.`)
await syncWithApi()
} else {
notify(res?.message || 'Failed to create hospital', true)
} }
setHospitals(prev => [...prev, newHospital])
notify(`Hospital "${hospitalForm.name}" added to group.`)
} else if (modalMode === 'edit' && editItem) { } else if (modalMode === 'edit' && editItem) {
setHospitals(prev => prev.map(h => h.id === editItem.id ? { ...h, ...hospitalForm, beds: parseInt(hospitalForm.beds) || 50 } : h)) const payload = {
notify(`Hospital "${hospitalForm.name}" updated.`) id: editItem.id,
name: hospitalForm.name,
group_id: parseInt(selectedGroupId) || null,
reg_no: hospitalForm.reg_no,
additional_info: {
contact_email: hospitalForm.email,
phone: hospitalForm.phone,
address: hospitalForm.address,
city: hospitalForm.city,
state: hospitalForm.state,
zip: hospitalForm.zip,
country: hospitalForm.country,
website: hospitalForm.website,
beds: parseInt(hospitalForm.beds) || 50,
rating: editItem.rating || '5.0'
},
logo: {
url: hospitalForm.logoUrl,
path: hospitalForm.logoPath
},
hospital_speciality: hospitalForm.specialities.split(',').map(s => s.trim()).filter(Boolean),
user: {
id: editItem.primaryStaff?.user?.id || editItem.user_id,
role: 'hospital',
first_name: hospitalForm.adminFirstName,
last_name: hospitalForm.adminLastName,
email: hospitalForm.adminEmail,
mobile: hospitalForm.adminMobile,
country_code: hospitalForm.adminCountryCode,
username: hospitalForm.adminUsername || (hospitalForm.adminFirstName.toLowerCase() + '_' + hospitalForm.adminLastName.toLowerCase()),
...(hospitalForm.adminPassword ? { password: hospitalForm.adminPassword } : {})
}
}
const res = await adminService.hospitalNetwork.saveHospital(payload)
if (res?.success || res?.status === 200) {
notify(`Hospital "${hospitalForm.name}" updated successfully.`)
await syncWithApi()
} else {
notify(res?.message || 'Failed to update hospital', true)
}
} }
setModalType(null) setModalType(null)
} catch (err) {
notify(err.message || 'An error occurred during submission', true)
}
} }
const handleDeleteHospital = (hospitalId, name) => { const handleDeleteHospital = (hospitalId, name) => {
@@ -467,7 +647,7 @@ export default function HospitalNetwork({ notify }) {
<div className="network-left-sidebar"> <div className="network-left-sidebar">
<div className="pane-header"> <div className="pane-header">
<div className="header-search-row"> <div className="header-search-row">
<h3 className="section-pane-title">Provider Groups</h3> <h3 className="section-pane-title">Hospital Groups</h3>
<button className="add-mini-btn" title="Create New Hospital Group" onClick={() => handleOpenGroupModal('create')}> <button className="add-mini-btn" title="Create New Hospital Group" onClick={() => handleOpenGroupModal('create')}>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
<line x1="12" y1="5" x2="12" y2="19" /> <line x1="12" y1="5" x2="12" y2="19" />
@@ -788,7 +968,7 @@ export default function HospitalNetwork({ notify }) {
{/* ── DYNAMIC ADD / EDIT MODALS ── */} {/* ── DYNAMIC ADD / EDIT MODALS ── */}
{modalType && ( {modalType && (
<div className="modal-overlay modal-front" onClick={() => setModalType(null)}> <div className={`modal-overlay modal-front ${modalType === 'hospital' ? 'modal-wide' : ''}`} onClick={() => setModalType(null)}>
<div className="modal-content" onClick={(e) => e.stopPropagation()}> <div className="modal-content" onClick={(e) => e.stopPropagation()}>
<div className="modal-header"> <div className="modal-header">
<h3> <h3>
@@ -852,26 +1032,31 @@ export default function HospitalNetwork({ notify }) {
{/* 2. Hospital Form */} {/* 2. Hospital Form */}
{modalType === 'hospital' && ( {modalType === 'hospital' && (
<form onSubmit={handleHospitalSubmit} className="modal-form"> <form onSubmit={handleHospitalSubmit} className="modal-form form-grid-two-col">
{/* Column 1: Facility Info */}
<div className="form-column">
<h4 className="form-section-title">Facility Details</h4>
<div className="form-group"> <div className="form-group">
<label>Facility Name *</label> <label>Facility Name *</label>
<input <input
type="text" type="text"
required required
placeholder="e.g., City Medical Clinic Center" placeholder="e.g., PrimeCare Medical Center"
value={hospitalForm.name} value={hospitalForm.name}
onChange={(e) => setHospitalForm(prev => ({ ...prev, name: e.target.value }))} onChange={(e) => setHospitalForm(prev => ({ ...prev, name: e.target.value }))}
/> />
</div> </div>
<div className="form-row-double"> <div className="form-row-double">
<div className="form-group"> <div className="form-group">
<label>City *</label> <label>Registration Number *</label>
<input <input
type="text" type="text"
required required
placeholder="e.g., Boston" placeholder="e.g., HOSP-369258147"
value={hospitalForm.city} value={hospitalForm.reg_no}
onChange={(e) => setHospitalForm(prev => ({ ...prev, city: e.target.value }))} onChange={(e) => setHospitalForm(prev => ({ ...prev, reg_no: e.target.value }))}
/> />
</div> </div>
<div className="form-group"> <div className="form-group">
@@ -884,12 +1069,13 @@ export default function HospitalNetwork({ notify }) {
/> />
</div> </div>
</div> </div>
<div className="form-row-double"> <div className="form-row-double">
<div className="form-group"> <div className="form-group">
<label>Contact Phone</label> <label>Contact Phone</label>
<input <input
type="text" type="text"
placeholder="e.g., +1 (555) 123-4567" placeholder="e.g., 1800-321-6547"
value={hospitalForm.phone} value={hospitalForm.phone}
onChange={(e) => setHospitalForm(prev => ({ ...prev, phone: e.target.value }))} onChange={(e) => setHospitalForm(prev => ({ ...prev, phone: e.target.value }))}
/> />
@@ -898,24 +1084,200 @@ export default function HospitalNetwork({ notify }) {
<label>Public Email Address</label> <label>Public Email Address</label>
<input <input
type="email" type="email"
placeholder="e.g., contact@hospital.com" placeholder="e.g., info@primecare.com"
value={hospitalForm.email} value={hospitalForm.email}
onChange={(e) => setHospitalForm(prev => ({ ...prev, email: e.target.value }))} onChange={(e) => setHospitalForm(prev => ({ ...prev, email: e.target.value }))}
/> />
</div> </div>
</div> </div>
<div className="form-group"> <div className="form-group">
<label>Complete Street Address</label> <label>Complete Street Address</label>
<input <input
type="text" type="text"
placeholder="e.g., 400 Beacon Dr, Boston, MA" placeholder="e.g., 214 Lakeview Medical Avenue"
value={hospitalForm.address} value={hospitalForm.address}
onChange={(e) => setHospitalForm(prev => ({ ...prev, address: e.target.value }))} onChange={(e) => setHospitalForm(prev => ({ ...prev, address: e.target.value }))}
/> />
</div> </div>
<div className="form-actions">
<div className="form-row-double">
<div className="form-group">
<label>City *</label>
<input
type="text"
required
placeholder="e.g., Hyderabad"
value={hospitalForm.city}
onChange={(e) => setHospitalForm(prev => ({ ...prev, city: e.target.value }))}
/>
</div>
<div className="form-group">
<label>State / Province</label>
<input
type="text"
placeholder="e.g., Telangana"
value={hospitalForm.state}
onChange={(e) => setHospitalForm(prev => ({ ...prev, state: e.target.value }))}
/>
</div>
</div>
<div className="form-row-double">
<div className="form-group">
<label>ZIP / Postal Code</label>
<input
type="text"
placeholder="e.g., 500001"
value={hospitalForm.zip}
onChange={(e) => setHospitalForm(prev => ({ ...prev, zip: e.target.value }))}
/>
</div>
<div className="form-group">
<label>Country</label>
<input
type="text"
placeholder="e.g., India"
value={hospitalForm.country}
onChange={(e) => setHospitalForm(prev => ({ ...prev, country: e.target.value }))}
/>
</div>
</div>
<div className="form-group">
<label>Website URL</label>
<input
type="url"
placeholder="e.g., https://www.primecare.com"
value={hospitalForm.website}
onChange={(e) => setHospitalForm(prev => ({ ...prev, website: e.target.value }))}
/>
</div>
<div className="form-row-double">
<div className="form-group">
<label>Logo URL</label>
<input
type="text"
placeholder="URL to logo image"
value={hospitalForm.logoUrl}
onChange={(e) => setHospitalForm(prev => ({ ...prev, logoUrl: e.target.value }))}
/>
</div>
<div className="form-group">
<label>Logo Path</label>
<input
type="text"
placeholder="Server upload path"
value={hospitalForm.logoPath}
onChange={(e) => setHospitalForm(prev => ({ ...prev, logoPath: e.target.value }))}
/>
</div>
</div>
<div className="form-group">
<label>Hospital Specialities (comma separated)</label>
<input
type="text"
placeholder="Cardiology, Neurology, Urology"
value={hospitalForm.specialities}
onChange={(e) => setHospitalForm(prev => ({ ...prev, specialities: e.target.value }))}
/>
</div>
</div>
{/* Column 2: Admin Account Credentials */}
<div className="form-column">
<h4 className="form-section-title">Administrator Account</h4>
<div className="form-row-double">
<div className="form-group">
<label>First Name *</label>
<input
type="text"
required
placeholder="e.g., David"
value={hospitalForm.adminFirstName}
onChange={(e) => setHospitalForm(prev => ({ ...prev, adminFirstName: e.target.value }))}
/>
</div>
<div className="form-group">
<label>Last Name *</label>
<input
type="text"
required
placeholder="e.g., Wilson"
value={hospitalForm.adminLastName}
onChange={(e) => setHospitalForm(prev => ({ ...prev, adminLastName: e.target.value }))}
/>
</div>
</div>
<div className="form-group">
<label>Admin Email *</label>
<input
type="email"
required
placeholder="e.g., david.wilson@primecare.com"
value={hospitalForm.adminEmail}
onChange={(e) => setHospitalForm(prev => ({ ...prev, adminEmail: e.target.value }))}
/>
</div>
<div className="form-row-double">
<div className="form-group">
<label>Country Code</label>
<input
type="text"
placeholder="e.g., +91"
value={hospitalForm.adminCountryCode}
onChange={(e) => setHospitalForm(prev => ({ ...prev, adminCountryCode: e.target.value }))}
/>
</div>
<div className="form-group">
<label>Mobile Number *</label>
<input
type="text"
required
placeholder="e.g., 9123456780"
value={hospitalForm.adminMobile}
onChange={(e) => setHospitalForm(prev => ({ ...prev, adminMobile: e.target.value }))}
/>
</div>
</div>
<div className="form-group">
<label>Username *</label>
<input
type="text"
required
placeholder="e.g., dwilson_primecare"
value={hospitalForm.adminUsername}
onChange={(e) => setHospitalForm(prev => ({ ...prev, adminUsername: e.target.value }))}
/>
</div>
<div className="form-group">
<label>Password {modalMode === 'create' ? '*' : '(Leave blank to keep current)'}</label>
<input
type="password"
required={modalMode === 'create'}
placeholder="e.g., PrimeCare@2026"
value={hospitalForm.adminPassword}
onChange={(e) => setHospitalForm(prev => ({ ...prev, adminPassword: e.target.value }))}
/>
</div>
<div className="form-info-box">
<p>💡 Setting up an Administrator Account registers this user as the primary contact and grants them control to manage this facility.</p>
</div>
<div className="form-actions form-actions-grid-span">
<button type="button" className="action-btn cancel-btn" onClick={() => setModalType(null)}>Cancel</button> <button type="button" className="action-btn cancel-btn" onClick={() => setModalType(null)}>Cancel</button>
<button type="submit" className="action-btn-primary">Save Facility</button> <button type="submit" className="action-btn-primary">
{modalMode === 'create' ? 'Create Facility' : 'Save Changes'}
</button>
</div>
</div> </div>
</form> </form>
)} )}
+19 -19
View File
@@ -133,7 +133,7 @@
font-weight: 800; font-weight: 800;
line-height: 1.1; line-height: 1.1;
letter-spacing: -0.03em; letter-spacing: -0.03em;
color: #fff; color: var(--gray-50);
} }
.hero-title-accent { .hero-title-accent {
@@ -158,8 +158,8 @@
.stat-card { .stat-card {
flex: 1; flex: 1;
background: rgba(255,255,255,0.04); background: rgba(255,255,255,0.65);
border: 1px solid rgba(255,255,255,0.08); border: 1px solid var(--dark-600);
border-radius: var(--radius-md); border-radius: var(--radius-md);
padding: 18px 14px; padding: 18px 14px;
display: flex; display: flex;
@@ -176,7 +176,7 @@
.stat-value { .stat-value {
font-size: 22px; font-size: 22px;
font-weight: 700; font-weight: 700;
color: #fff; color: var(--gray-50);
letter-spacing: -0.02em; letter-spacing: -0.02em;
} }
@@ -216,8 +216,8 @@
.hero-icon-center { .hero-icon-center {
position: relative; position: relative;
z-index: 1; z-index: 1;
background: rgba(15, 32, 64, 0.8); background: rgba(255, 255, 255, 0.9);
border: 1px solid rgba(59,130,246,0.3); border: 1px solid rgba(59,130,246,0.2);
border-radius: 50%; border-radius: 50%;
width: 80px; height: 80px; width: 80px; height: 80px;
display: flex; display: flex;
@@ -245,10 +245,10 @@
padding: 40px 48px; padding: 40px 48px;
position: relative; position: relative;
z-index: 2; z-index: 2;
background: rgba(10, 22, 40, 0.7); background: rgba(255, 255, 255, 0.55);
backdrop-filter: blur(20px); backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
border-left: 1px solid rgba(255,255,255,0.06); border-left: 1px solid var(--dark-600);
opacity: 0; opacity: 0;
transform: translateX(30px); transform: translateX(30px);
transition: opacity 0.7s ease 0.15s, transform 0.7s ease 0.15s; transition: opacity 0.7s ease 0.15s, transform 0.7s ease 0.15s;
@@ -300,7 +300,7 @@
.card-title { .card-title {
font-size: 26px; font-size: 26px;
font-weight: 800; font-weight: 800;
color: #fff; color: var(--gray-50);
letter-spacing: -0.02em; letter-spacing: -0.02em;
} }
@@ -326,7 +326,7 @@
content: ''; content: '';
flex: 1; flex: 1;
height: 1px; height: 1px;
background: rgba(255,255,255,0.07); background: var(--dark-600);
} }
/* Error banner */ /* Error banner */
@@ -391,13 +391,13 @@
.field-input { .field-input {
width: 100%; width: 100%;
height: 48px; height: 48px;
background: rgba(255,255,255,0.04); background: rgba(255,255,255,0.8);
border: 1px solid rgba(255,255,255,0.1); border: 1px solid var(--dark-600);
border-radius: var(--radius-md); border-radius: var(--radius-md);
padding: 0 48px 0 46px; padding: 0 48px 0 46px;
font-size: 14px; font-size: 14px;
font-family: var(--font-primary); font-family: var(--font-primary);
color: #fff; color: var(--gray-50);
transition: border-color 0.25s, background 0.25s, box-shadow 0.25s; transition: border-color 0.25s, background 0.25s, box-shadow 0.25s;
outline: none; outline: none;
} }
@@ -413,8 +413,8 @@
} }
.field-input:hover:not(:focus) { .field-input:hover:not(:focus) {
border-color: rgba(255,255,255,0.18); border-color: var(--dark-500);
background: rgba(255,255,255,0.06); background: rgba(255,255,255,0.95);
} }
/* Password toggle */ /* Password toggle */
@@ -461,9 +461,9 @@
.custom-check { .custom-check {
width: 18px; width: 18px;
height: 18px; height: 18px;
border: 1.5px solid rgba(255,255,255,0.2); border: 1.5px solid var(--dark-500);
border-radius: 5px; border-radius: 5px;
background: rgba(255,255,255,0.04); background: #ffffff;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@@ -586,7 +586,7 @@
} }
.demo-hint .hint-icon { font-size: 14px; flex-shrink: 0; margin-top: 1px; } .demo-hint .hint-icon { font-size: 14px; flex-shrink: 0; margin-top: 1px; }
.demo-hint strong { color: var(--primary-300); font-weight: 600; } .demo-hint strong { color: var(--primary-600); font-weight: 600; }
/* ── Security badge ── */ /* ── Security badge ── */
.security-badge { .security-badge {
@@ -615,7 +615,7 @@
padding: 40px 28px 32px; padding: 40px 28px 32px;
min-height: auto; min-height: auto;
border-left: none; border-left: none;
border-bottom: 1px solid rgba(255,255,255,0.06); border-bottom: 1px solid var(--dark-600);
} }
.hero-graphic { display: none; } .hero-graphic { display: none; }