@omersx/bemms 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (335) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +203 -2
  3. package/drizzle.config.ts +11 -0
  4. package/next.config.ts +51 -0
  5. package/package.json +99 -3
  6. package/postcss.config.mjs +7 -0
  7. package/public/hospital_demo_devices.csv +32 -0
  8. package/public/icons/icon-192.png +0 -0
  9. package/public/icons/icon-512.png +0 -0
  10. package/public/icons/icon-maskable-512.png +0 -0
  11. package/public/manifest.webmanifest +31 -0
  12. package/public/sw.js +177 -0
  13. package/src/app/(auth)/layout.tsx +20 -0
  14. package/src/app/(auth)/login/page.tsx +135 -0
  15. package/src/app/(dashboard)/admin/audit-logs/page.tsx +178 -0
  16. package/src/app/(dashboard)/admin/data/page.tsx +37 -0
  17. package/src/app/(dashboard)/admin/departments/[deptId]/edit/page.tsx +206 -0
  18. package/src/app/(dashboard)/admin/departments/[deptId]/page.tsx +71 -0
  19. package/src/app/(dashboard)/admin/departments/new/page.tsx +6 -0
  20. package/src/app/(dashboard)/admin/departments/page.tsx +6 -0
  21. package/src/app/(dashboard)/admin/general/page.tsx +374 -0
  22. package/src/app/(dashboard)/admin/hospitals/[hospitalId]/edit/page.tsx +304 -0
  23. package/src/app/(dashboard)/admin/hospitals/[hospitalId]/page.tsx +94 -0
  24. package/src/app/(dashboard)/admin/hospitals/new/page.tsx +302 -0
  25. package/src/app/(dashboard)/admin/hospitals/page.tsx +6 -0
  26. package/src/app/(dashboard)/admin/layout.tsx +49 -0
  27. package/src/app/(dashboard)/admin/organizations/[orgId]/edit/page.tsx +172 -0
  28. package/src/app/(dashboard)/admin/organizations/[orgId]/page.tsx +82 -0
  29. package/src/app/(dashboard)/admin/organizations/new/page.tsx +150 -0
  30. package/src/app/(dashboard)/admin/organizations/page.tsx +6 -0
  31. package/src/app/(dashboard)/admin/page.tsx +258 -0
  32. package/src/app/(dashboard)/admin/roles/page.tsx +153 -0
  33. package/src/app/(dashboard)/admin/settings/page.tsx +69 -0
  34. package/src/app/(dashboard)/admin/users/[userId]/edit/page.tsx +153 -0
  35. package/src/app/(dashboard)/admin/users/[userId]/page.tsx +317 -0
  36. package/src/app/(dashboard)/admin/users/invite/page.tsx +3 -0
  37. package/src/app/(dashboard)/admin/users/new/page.tsx +5 -0
  38. package/src/app/(dashboard)/admin/users/page.tsx +23 -0
  39. package/src/app/(dashboard)/dashboard/page.tsx +462 -0
  40. package/src/app/(dashboard)/departments/[deptId]/page.tsx +39 -0
  41. package/src/app/(dashboard)/departments/new/page.tsx +330 -0
  42. package/src/app/(dashboard)/departments/page.tsx +52 -0
  43. package/src/app/(dashboard)/devices/[id]/edit/page.tsx +131 -0
  44. package/src/app/(dashboard)/devices/[id]/page.tsx +408 -0
  45. package/src/app/(dashboard)/devices/[id]/qr/page.tsx +54 -0
  46. package/src/app/(dashboard)/devices/new/page.tsx +382 -0
  47. package/src/app/(dashboard)/devices/page.tsx +80 -0
  48. package/src/app/(dashboard)/engineering-team/page.tsx +41 -0
  49. package/src/app/(dashboard)/layout.tsx +43 -0
  50. package/src/app/(dashboard)/maintenance/checklists/page.tsx +57 -0
  51. package/src/app/(dashboard)/maintenance/page.tsx +231 -0
  52. package/src/app/(dashboard)/maintenance/plans/page.tsx +142 -0
  53. package/src/app/(dashboard)/maintenance/tasks/[id]/page.tsx +997 -0
  54. package/src/app/(dashboard)/maintenance/tasks/page.tsx +119 -0
  55. package/src/app/(dashboard)/more/page.tsx +310 -0
  56. package/src/app/(dashboard)/my-department/page.tsx +151 -0
  57. package/src/app/(dashboard)/notifications/notification-list.tsx +103 -0
  58. package/src/app/(dashboard)/notifications/page.tsx +59 -0
  59. package/src/app/(dashboard)/profile/page.tsx +27 -0
  60. package/src/app/(dashboard)/reports/costs/page.tsx +127 -0
  61. package/src/app/(dashboard)/reports/history/page.tsx +105 -0
  62. package/src/app/(dashboard)/reports/inventory/page.tsx +116 -0
  63. package/src/app/(dashboard)/reports/maintenance/page.tsx +136 -0
  64. package/src/app/(dashboard)/reports/page.tsx +120 -0
  65. package/src/app/(dashboard)/reports/tickets/page.tsx +139 -0
  66. package/src/app/(dashboard)/reports/workload/page.tsx +135 -0
  67. package/src/app/(dashboard)/rounds/[id]/page.tsx +197 -0
  68. package/src/app/(dashboard)/rounds/history/page.tsx +82 -0
  69. package/src/app/(dashboard)/rounds/page.tsx +107 -0
  70. package/src/app/(dashboard)/scan/[code]/page.tsx +154 -0
  71. package/src/app/(dashboard)/scan/page.tsx +73 -0
  72. package/src/app/(dashboard)/team/page.tsx +42 -0
  73. package/src/app/(dashboard)/tickets/[id]/page.tsx +465 -0
  74. package/src/app/(dashboard)/tickets/create/page.tsx +722 -0
  75. package/src/app/(dashboard)/tickets/page.tsx +55 -0
  76. package/src/app/(dashboard)/tickets/triage/page.tsx +161 -0
  77. package/src/app/api/admin/data/export/route.ts +316 -0
  78. package/src/app/api/auth/[...nextauth]/route.ts +3 -0
  79. package/src/app/api/health/route.ts +46 -0
  80. package/src/app/api/notifications/sse/route.ts +91 -0
  81. package/src/app/api/notifications/subscribe/route.ts +54 -0
  82. package/src/app/api/notifications/vapid-key/route.ts +7 -0
  83. package/src/app/api/reports/export/route.ts +102 -0
  84. package/src/app/api/tickets/[id]/attachments/route.ts +129 -0
  85. package/src/app/api/tickets/[id]/live-sync/route.ts +52 -0
  86. package/src/app/error.tsx +54 -0
  87. package/src/app/globals.css +89 -0
  88. package/src/app/layout.tsx +59 -0
  89. package/src/app/not-found.tsx +32 -0
  90. package/src/app/page.tsx +5 -0
  91. package/src/components/admin/add-department-user-dialog.tsx +759 -0
  92. package/src/components/admin/add-engineer-dialog.tsx +773 -0
  93. package/src/components/admin/add-user-type-dialog.tsx +89 -0
  94. package/src/components/admin/audit-log-export.tsx +113 -0
  95. package/src/components/admin/audit-log-filters.tsx +255 -0
  96. package/src/components/admin/audit-log-table.tsx +383 -0
  97. package/src/components/admin/data-management/danger-zone.tsx +301 -0
  98. package/src/components/admin/data-management/data-management-tabs.tsx +61 -0
  99. package/src/components/admin/data-management/export-center.tsx +301 -0
  100. package/src/components/admin/data-management/import-wizard.tsx +558 -0
  101. package/src/components/admin/settings-forms/features-form.tsx +115 -0
  102. package/src/components/admin/settings-forms/health-panel.tsx +182 -0
  103. package/src/components/admin/settings-forms/localization-form.tsx +203 -0
  104. package/src/components/admin/settings-forms/retention-form.tsx +164 -0
  105. package/src/components/admin/settings-forms/security-form.tsx +186 -0
  106. package/src/components/admin/system-settings-tabs.tsx +88 -0
  107. package/src/components/admin/user-role-dialog.tsx +293 -0
  108. package/src/components/admin/user-status-dialog.tsx +166 -0
  109. package/src/components/admin/users-page-client.tsx +514 -0
  110. package/src/components/dashboard/action-buttons.tsx +93 -0
  111. package/src/components/dashboard/admin-alerts.tsx +86 -0
  112. package/src/components/dashboard/availability-alerts.tsx +65 -0
  113. package/src/components/dashboard/maintenance-due-list.tsx +87 -0
  114. package/src/components/dashboard/round-widget.tsx +110 -0
  115. package/src/components/dashboard/stat-card.tsx +38 -0
  116. package/src/components/dashboard/ticket-list-compact.tsx +86 -0
  117. package/src/components/departments/department-cards-view.tsx +244 -0
  118. package/src/components/departments/department-detail-view.tsx +467 -0
  119. package/src/components/departments/department-visuals.tsx +190 -0
  120. package/src/components/departments/my-department-view.tsx +333 -0
  121. package/src/components/devices/change-status-dialog.tsx +146 -0
  122. package/src/components/devices/device-action-buttons.tsx +125 -0
  123. package/src/components/devices/device-availability-banner.tsx +59 -0
  124. package/src/components/devices/device-badges.tsx +55 -0
  125. package/src/components/devices/device-documents-tab.tsx +93 -0
  126. package/src/components/devices/device-maintenance-tab.tsx +113 -0
  127. package/src/components/devices/device-mini-qr.tsx +109 -0
  128. package/src/components/devices/device-qr-card.tsx +187 -0
  129. package/src/components/devices/device-signatures-tab.tsx +607 -0
  130. package/src/components/devices/device-tickets-tab.tsx +139 -0
  131. package/src/components/devices/device-timelines.tsx +124 -0
  132. package/src/components/devices/qr-camera-scanner.tsx +167 -0
  133. package/src/components/devices/qr-code-display.tsx +139 -0
  134. package/src/components/devices/quick-add-category-dialog.tsx +135 -0
  135. package/src/components/devices/quick-add-manufacturer-dialog.tsx +212 -0
  136. package/src/components/devices/transfer-device-dialog.tsx +190 -0
  137. package/src/components/layout/header.tsx +80 -0
  138. package/src/components/layout/mobile-nav.tsx +91 -0
  139. package/src/components/layout/more-item-badge.tsx +15 -0
  140. package/src/components/layout/nav-badge.tsx +72 -0
  141. package/src/components/layout/sidebar.tsx +297 -0
  142. package/src/components/maintenance/maintenance-badges.tsx +579 -0
  143. package/src/components/maintenance/maintenance-nav.tsx +107 -0
  144. package/src/components/maintenance/parts-costs-manager.tsx +909 -0
  145. package/src/components/maintenance/signature-card.tsx +413 -0
  146. package/src/components/maintenance/task-action-bar.tsx +955 -0
  147. package/src/components/notifications/notification-bell.tsx +367 -0
  148. package/src/components/notifications/notification-item.tsx +93 -0
  149. package/src/components/notifications/notification-preferences.tsx +182 -0
  150. package/src/components/profile/user-profile-view.tsx +626 -0
  151. package/src/components/providers/nav-counts-provider.tsx +235 -0
  152. package/src/components/providers/session-provider.tsx +7 -0
  153. package/src/components/providers/theme-provider.tsx +124 -0
  154. package/src/components/pwa/install-prompt.tsx +82 -0
  155. package/src/components/pwa/sw-register.tsx +43 -0
  156. package/src/components/reports/export-button.tsx +62 -0
  157. package/src/components/reports/filter-chips.tsx +47 -0
  158. package/src/components/reports/summary-cards.tsx +40 -0
  159. package/src/components/reports/transparency-header.tsx +54 -0
  160. package/src/components/rounds/department-visit-sheet.tsx +199 -0
  161. package/src/components/rounds/mention-textarea.tsx +187 -0
  162. package/src/components/rounds/round-calendar.tsx +233 -0
  163. package/src/components/rounds/round-department-list.tsx +281 -0
  164. package/src/components/rounds/round-history-client.tsx +218 -0
  165. package/src/components/rounds/start-round-card.tsx +184 -0
  166. package/src/components/shared/confirm-dialog.tsx +67 -0
  167. package/src/components/shared/data-table.tsx +104 -0
  168. package/src/components/shared/page-header.tsx +20 -0
  169. package/src/components/shared/sign-out-button.tsx +52 -0
  170. package/src/components/shared/status-badge.tsx +42 -0
  171. package/src/components/shared/table-search.tsx +55 -0
  172. package/src/components/signatures/sign-action-dialog.tsx +253 -0
  173. package/src/components/signatures/signature-history.tsx +121 -0
  174. package/src/components/signatures/signature-status-panel.tsx +164 -0
  175. package/src/components/team/department-coverage.tsx +141 -0
  176. package/src/components/team/edit-engineer-dialog.tsx +242 -0
  177. package/src/components/team/engineer-card.tsx +180 -0
  178. package/src/components/team/engineer-details-dialog.tsx +432 -0
  179. package/src/components/team/schedule-calendar.tsx +204 -0
  180. package/src/components/team/staff-engineer-team-view.tsx +368 -0
  181. package/src/components/team/team-header-stats.tsx +88 -0
  182. package/src/components/team/team-page-client.tsx +216 -0
  183. package/src/components/theme/theme-selector-card.tsx +63 -0
  184. package/src/components/theme/theme-toggle.tsx +65 -0
  185. package/src/components/tickets/staff-status-label.tsx +58 -0
  186. package/src/components/tickets/staff-ticket-card.tsx +109 -0
  187. package/src/components/tickets/staff-ticket-progress-tracker.tsx +405 -0
  188. package/src/components/tickets/staff-tickets-view.tsx +182 -0
  189. package/src/components/tickets/ticket-action-buttons.tsx +873 -0
  190. package/src/components/tickets/ticket-auto-refresh.tsx +197 -0
  191. package/src/components/tickets/ticket-badges.tsx +43 -0
  192. package/src/components/tickets/ticket-card.tsx +197 -0
  193. package/src/components/tickets/ticket-cards-view.tsx +395 -0
  194. package/src/components/tickets/ticket-comment-section.tsx +684 -0
  195. package/src/components/tickets/ticket-dispatch-status.tsx +184 -0
  196. package/src/components/tickets/ticket-list-auto-refresh.tsx +55 -0
  197. package/src/components/tickets/ticket-reporter-profile.tsx +235 -0
  198. package/src/components/tickets/ticket-signatures-panel.tsx +32 -0
  199. package/src/components/tickets/ticket-timeline.tsx +131 -0
  200. package/src/components/tickets/ticket-triage-panel.tsx +124 -0
  201. package/src/components/tickets/tickets-nav.tsx +107 -0
  202. package/src/components/ui/avatar.tsx +43 -0
  203. package/src/components/ui/badge.tsx +34 -0
  204. package/src/components/ui/button.tsx +58 -0
  205. package/src/components/ui/card.tsx +77 -0
  206. package/src/components/ui/checkbox.tsx +31 -0
  207. package/src/components/ui/dialog.tsx +123 -0
  208. package/src/components/ui/dropdown-menu.tsx +126 -0
  209. package/src/components/ui/form.tsx +179 -0
  210. package/src/components/ui/input.tsx +24 -0
  211. package/src/components/ui/label.tsx +27 -0
  212. package/src/components/ui/popover.tsx +34 -0
  213. package/src/components/ui/progress.tsx +36 -0
  214. package/src/components/ui/scroll-area.tsx +47 -0
  215. package/src/components/ui/select.tsx +160 -0
  216. package/src/components/ui/separator.tsx +25 -0
  217. package/src/components/ui/sheet.tsx +131 -0
  218. package/src/components/ui/switch.tsx +30 -0
  219. package/src/components/ui/table.tsx +121 -0
  220. package/src/components/ui/tabs.tsx +62 -0
  221. package/src/components/ui/textarea.tsx +23 -0
  222. package/src/components/ui/tooltip.tsx +27 -0
  223. package/src/lib/actions/__tests__/devices.test.ts +176 -0
  224. package/src/lib/actions/__tests__/signatures.test.ts +303 -0
  225. package/src/lib/actions/__tests__/tickets.test.ts +243 -0
  226. package/src/lib/actions/audit-logs.ts +298 -0
  227. package/src/lib/actions/checklists.ts +429 -0
  228. package/src/lib/actions/dashboard.ts +358 -0
  229. package/src/lib/actions/data-management.ts +723 -0
  230. package/src/lib/actions/departments.ts +369 -0
  231. package/src/lib/actions/device-categories.ts +117 -0
  232. package/src/lib/actions/devices.ts +748 -0
  233. package/src/lib/actions/engineer-rounds.ts +973 -0
  234. package/src/lib/actions/engineers.ts +285 -0
  235. package/src/lib/actions/hospitals.ts +148 -0
  236. package/src/lib/actions/locations.ts +115 -0
  237. package/src/lib/actions/maintenance-plans.ts +316 -0
  238. package/src/lib/actions/maintenance-tasks.ts +415 -0
  239. package/src/lib/actions/manufacturers.ts +132 -0
  240. package/src/lib/actions/nav-counts.ts +144 -0
  241. package/src/lib/actions/notifications.ts +136 -0
  242. package/src/lib/actions/organizations.ts +99 -0
  243. package/src/lib/actions/qr.ts +147 -0
  244. package/src/lib/actions/report-history.ts +77 -0
  245. package/src/lib/actions/reports.ts +192 -0
  246. package/src/lib/actions/roles.ts +32 -0
  247. package/src/lib/actions/signature-auth.ts +377 -0
  248. package/src/lib/actions/signatures.ts +532 -0
  249. package/src/lib/actions/system-settings.ts +274 -0
  250. package/src/lib/actions/tickets.ts +1445 -0
  251. package/src/lib/actions/users.ts +740 -0
  252. package/src/lib/audit/index.ts +103 -0
  253. package/src/lib/auth/__tests__/rbac.test.ts +33 -0
  254. package/src/lib/auth/index.ts +338 -0
  255. package/src/lib/auth/password.ts +10 -0
  256. package/src/lib/auth/rbac.ts +103 -0
  257. package/src/lib/auth/types.ts +57 -0
  258. package/src/lib/constants/departments.ts +16 -0
  259. package/src/lib/constants/manufacturers.ts +32 -0
  260. package/src/lib/db/index.ts +23 -0
  261. package/src/lib/db/schema/audit-logs.ts +42 -0
  262. package/src/lib/db/schema/departments.ts +39 -0
  263. package/src/lib/db/schema/device-categories.ts +38 -0
  264. package/src/lib/db/schema/devices.ts +195 -0
  265. package/src/lib/db/schema/engineer-profiles.ts +63 -0
  266. package/src/lib/db/schema/engineer-rounds.ts +115 -0
  267. package/src/lib/db/schema/enums.ts +148 -0
  268. package/src/lib/db/schema/hospitals.ts +34 -0
  269. package/src/lib/db/schema/index.ts +24 -0
  270. package/src/lib/db/schema/locations.ts +46 -0
  271. package/src/lib/db/schema/maintenance-plans.ts +99 -0
  272. package/src/lib/db/schema/maintenance-records.ts +161 -0
  273. package/src/lib/db/schema/maintenance-tasks.ts +196 -0
  274. package/src/lib/db/schema/manufacturers.ts +60 -0
  275. package/src/lib/db/schema/notifications.ts +48 -0
  276. package/src/lib/db/schema/organizations.ts +24 -0
  277. package/src/lib/db/schema/report-history.ts +28 -0
  278. package/src/lib/db/schema/roles.ts +59 -0
  279. package/src/lib/db/schema/sessions.ts +46 -0
  280. package/src/lib/db/schema/signature-events.ts +48 -0
  281. package/src/lib/db/schema/signature-policies.ts +60 -0
  282. package/src/lib/db/schema/signatures.ts +87 -0
  283. package/src/lib/db/schema/tickets.ts +169 -0
  284. package/src/lib/db/schema/user-assignments.ts +85 -0
  285. package/src/lib/db/schema/users.ts +39 -0
  286. package/src/lib/db/seed.ts +131 -0
  287. package/src/lib/logger/__tests__/logger.test.ts +154 -0
  288. package/src/lib/logger/formatters.ts +159 -0
  289. package/src/lib/logger/index.ts +184 -0
  290. package/src/lib/logger/types.ts +48 -0
  291. package/src/lib/notifications/create.ts +71 -0
  292. package/src/lib/notifications/dispatcher.ts +490 -0
  293. package/src/lib/notifications/index.ts +7 -0
  294. package/src/lib/notifications/push-sender.ts +128 -0
  295. package/src/lib/notifications/push.ts +64 -0
  296. package/src/lib/notifications/triggers.ts +166 -0
  297. package/src/lib/utils/__tests__/crypto.test.ts +30 -0
  298. package/src/lib/utils/__tests__/export.test.ts +55 -0
  299. package/src/lib/utils/__tests__/nav-badge.test.ts +147 -0
  300. package/src/lib/utils/__tests__/staff-status.test.ts +50 -0
  301. package/src/lib/utils/attestations.ts +19 -0
  302. package/src/lib/utils/crypto.ts +18 -0
  303. package/src/lib/utils/csv-parser.ts +181 -0
  304. package/src/lib/utils/export.ts +45 -0
  305. package/src/lib/utils/nav-badge.ts +225 -0
  306. package/src/lib/utils/sound.ts +152 -0
  307. package/src/lib/utils/staff-status.ts +115 -0
  308. package/src/lib/utils.ts +6 -0
  309. package/src/lib/validators/__tests__/auth.test.ts +127 -0
  310. package/src/lib/validators/__tests__/data-management.test.ts +182 -0
  311. package/src/lib/validators/__tests__/devices-profile.test.ts +129 -0
  312. package/src/lib/validators/__tests__/devices.test.ts +98 -0
  313. package/src/lib/validators/__tests__/engineer-rounds.test.ts +170 -0
  314. package/src/lib/validators/__tests__/maintenance.test.ts +178 -0
  315. package/src/lib/validators/__tests__/signatures.test.ts +154 -0
  316. package/src/lib/validators/__tests__/system-settings.test.ts +119 -0
  317. package/src/lib/validators/__tests__/tickets.test.ts +176 -0
  318. package/src/lib/validators/__tests__/users.test.ts +92 -0
  319. package/src/lib/validators/auth.ts +32 -0
  320. package/src/lib/validators/data-management.ts +67 -0
  321. package/src/lib/validators/departments.ts +14 -0
  322. package/src/lib/validators/devices.ts +94 -0
  323. package/src/lib/validators/engineer-rounds.ts +70 -0
  324. package/src/lib/validators/hospitals.ts +17 -0
  325. package/src/lib/validators/locations.ts +15 -0
  326. package/src/lib/validators/maintenance.ts +211 -0
  327. package/src/lib/validators/organizations.ts +11 -0
  328. package/src/lib/validators/reports.ts +31 -0
  329. package/src/lib/validators/signatures.ts +49 -0
  330. package/src/lib/validators/system-settings.ts +55 -0
  331. package/src/lib/validators/tickets.ts +125 -0
  332. package/src/lib/validators/users.ts +43 -0
  333. package/src/middleware.ts +45 -0
  334. package/tailwind.config.ts +76 -0
  335. package/tsconfig.json +28 -0
@@ -0,0 +1,204 @@
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
5
+ import { Badge } from '@/components/ui/badge';
6
+ import { Button } from '@/components/ui/button';
7
+ import { Calendar as CalendarIcon, Clock, PhoneCall, Radio, ChevronLeft, ChevronRight, User } from 'lucide-react';
8
+ import { EngineerTeamMember } from '@/lib/actions/engineers';
9
+
10
+ interface ScheduleCalendarProps {
11
+ engineers: EngineerTeamMember[];
12
+ }
13
+
14
+ const DAYS_OF_WEEK = [
15
+ { key: 'Sun', label: 'Sunday', arabic: 'الأحد' },
16
+ { key: 'Mon', label: 'Monday', arabic: 'الاثنين' },
17
+ { key: 'Tue', label: 'Tuesday', arabic: 'الثلاثاء' },
18
+ { key: 'Wed', label: 'Wednesday', arabic: 'الأربعاء' },
19
+ { key: 'Thu', label: 'Thursday', arabic: 'الخميس' },
20
+ { key: 'Fri', label: 'Friday', arabic: 'الجمعة' },
21
+ { key: 'Sat', label: 'Saturday', arabic: 'السبت' },
22
+ ];
23
+
24
+ export function ScheduleCalendar({ engineers }: ScheduleCalendarProps) {
25
+ // Current day of the week
26
+ const todayIndex = new Date().getDay(); // 0 is Sunday
27
+ const todayKey = DAYS_OF_WEEK[todayIndex].key;
28
+
29
+ const [selectedDay, setSelectedDay] = useState<string>(todayKey);
30
+
31
+ return (
32
+ <div className="space-y-6">
33
+ {/* Overview Banner */}
34
+ <Card className="bg-gradient-to-r from-primary/10 via-primary/5 to-transparent border-primary/20">
35
+ <CardHeader className="pb-3">
36
+ <div className="flex items-center justify-between">
37
+ <div className="space-y-1">
38
+ <CardTitle className="text-lg flex items-center gap-2">
39
+ <CalendarIcon className="w-5 h-5 text-primary" />
40
+ Hospital Biomedical Duty Roster & On-Call Schedule
41
+ </CardTitle>
42
+ <CardDescription>
43
+ Regular clinical engineering coverage hours: Sunday to Thursday (08:00 AM – 04:00 PM). Emergency on-call is active 24/7.
44
+ </CardDescription>
45
+ </div>
46
+ <Badge variant="outline" className="bg-background/80 text-xs gap-1.5 py-1 px-2.5 font-medium">
47
+ <Clock className="w-3.5 h-3.5 text-primary" />
48
+ Standard Shift: 8 hrs
49
+ </Badge>
50
+ </div>
51
+ </CardHeader>
52
+ </Card>
53
+
54
+ {/* Day Selector Pills */}
55
+ <div className="grid grid-cols-2 sm:grid-cols-4 lg:grid-cols-7 gap-2.5">
56
+ {DAYS_OF_WEEK.map((day) => {
57
+ const isToday = day.key === todayKey;
58
+ const isSelected = day.key === selectedDay;
59
+ const onDutyCount = engineers.filter((e) => e.workingDays.includes(day.key)).length;
60
+ const onCallCount = engineers.filter((e) => e.onCallDays.includes(day.key)).length;
61
+
62
+ return (
63
+ <button
64
+ key={day.key}
65
+ onClick={() => setSelectedDay(day.key)}
66
+ className={`p-3 rounded-xl border text-center transition-all flex flex-col items-center justify-between min-h-[90px] relative ${
67
+ isSelected
68
+ ? 'border-primary bg-primary text-primary-foreground shadow-md'
69
+ : isToday
70
+ ? 'border-emerald-500/50 bg-emerald-50/50 dark:bg-emerald-950/20 text-foreground'
71
+ : 'border-border/60 bg-card hover:border-primary/40 text-foreground'
72
+ }`}
73
+ >
74
+ {isToday && (
75
+ <span
76
+ className={`absolute -top-2 left-1/2 -translate-x-1/2 text-[9px] px-1.5 py-0.2 rounded-full font-bold uppercase tracking-wider ${
77
+ isSelected ? 'bg-background text-primary' : 'bg-emerald-600 text-white'
78
+ }`}
79
+ >
80
+ Today
81
+ </span>
82
+ )}
83
+ <span className={`text-xs font-semibold ${isSelected ? 'text-primary-foreground' : 'text-muted-foreground'}`}>
84
+ {day.key}
85
+ </span>
86
+ <span className="text-sm font-bold my-1">{day.label.slice(0, 3)}</span>
87
+
88
+ <div className="flex items-center gap-1.5 text-[10px] mt-1">
89
+ {onDutyCount > 0 && (
90
+ <span
91
+ className={`px-1.5 py-0.5 rounded font-medium ${
92
+ isSelected ? 'bg-primary-foreground/20 text-primary-foreground' : 'bg-emerald-500/15 text-emerald-700 dark:text-emerald-400'
93
+ }`}
94
+ >
95
+ 🟢 {onDutyCount}
96
+ </span>
97
+ )}
98
+ {onCallCount > 0 && (
99
+ <span
100
+ className={`px-1.5 py-0.5 rounded font-medium ${
101
+ isSelected ? 'bg-primary-foreground/20 text-primary-foreground' : 'bg-amber-500/15 text-amber-700 dark:text-amber-400'
102
+ }`}
103
+ >
104
+ 📞 {onCallCount}
105
+ </span>
106
+ )}
107
+ </div>
108
+ </button>
109
+ );
110
+ })}
111
+ </div>
112
+
113
+ {/* Selected Day Roster Details */}
114
+ <Card className="border-border/70 shadow-sm">
115
+ <CardHeader className="pb-3 border-b bg-muted/20">
116
+ <div className="flex items-center justify-between">
117
+ <div>
118
+ <CardTitle className="text-base flex items-center gap-2">
119
+ <span>{DAYS_OF_WEEK.find((d) => d.key === selectedDay)?.label} Roster</span>
120
+ <span className="text-xs text-muted-foreground font-normal">
121
+ ({DAYS_OF_WEEK.find((d) => d.key === selectedDay)?.arabic})
122
+ </span>
123
+ {selectedDay === todayKey && (
124
+ <Badge className="bg-emerald-500 text-white text-[10px] ml-2">Active Today</Badge>
125
+ )}
126
+ </CardTitle>
127
+ <CardDescription className="text-xs mt-0.5">
128
+ Engineers scheduled for hospital on-site duty and emergency on-call rotation.
129
+ </CardDescription>
130
+ </div>
131
+ </div>
132
+ </CardHeader>
133
+
134
+ <CardContent className="p-0 divide-y divide-border/60">
135
+ {engineers.map((eng) => {
136
+ const isWorking = eng.workingDays.includes(selectedDay);
137
+ const isOnCall = eng.onCallDays.includes(selectedDay);
138
+
139
+ return (
140
+ <div key={eng.id} className="p-4 flex flex-col sm:flex-row sm:items-center justify-between gap-4 hover:bg-muted/10 transition-colors">
141
+ <div className="flex items-center gap-3">
142
+ <div className="w-10 h-10 rounded-full bg-primary/10 text-primary font-bold flex items-center justify-center shrink-0 border border-primary/20">
143
+ {eng.fullName.replace('Eng. ', '').split(' ').map((n) => n[0]).join('').slice(0, 2)}
144
+ </div>
145
+ <div>
146
+ <div className="flex items-center gap-2">
147
+ <h4 className="font-semibold text-sm">{eng.fullName}</h4>
148
+ <Badge variant="outline" className="text-[10px] py-0 px-1.5 font-normal">
149
+ {eng.jobTitle}
150
+ </Badge>
151
+ </div>
152
+ <p className="text-xs text-muted-foreground mt-0.5">{eng.specialization}</p>
153
+ <div className="flex items-center gap-3 mt-1 text-xs text-muted-foreground">
154
+ {eng.extension && (
155
+ <span>Ext: <strong className="text-foreground">{eng.extension}</strong></span>
156
+ )}
157
+ {eng.mobileNumber && (
158
+ <span>Mobile: <strong className="text-foreground">{eng.mobileNumber}</strong></span>
159
+ )}
160
+ </div>
161
+ </div>
162
+ </div>
163
+
164
+ <div className="flex items-center gap-3 shrink-0 self-end sm:self-center">
165
+ {isWorking ? (
166
+ <div className="text-right">
167
+ <Badge className="bg-emerald-500/15 text-emerald-700 dark:text-emerald-400 border-emerald-500/30 gap-1.5 font-medium">
168
+ <Radio className="w-3 h-3 text-emerald-500" />
169
+ On-Site Duty ({eng.shiftHours || '08:00 - 16:00'})
170
+ </Badge>
171
+ <p className="text-[11px] text-muted-foreground mt-0.5">Hospital Workshop & Wards</p>
172
+ </div>
173
+ ) : isOnCall ? (
174
+ <div className="text-right">
175
+ <Badge className="bg-amber-500/15 text-amber-700 dark:text-amber-400 border-amber-500/30 gap-1.5 font-medium">
176
+ <PhoneCall className="w-3 h-3 text-amber-500 animate-pulse" />
177
+ Emergency On-Call (24h)
178
+ </Badge>
179
+ <p className="text-[11px] text-muted-foreground mt-0.5">Urgent response within 30 min</p>
180
+ </div>
181
+ ) : (
182
+ <Badge variant="outline" className="text-muted-foreground gap-1.5">
183
+ Off Duty / Rest
184
+ </Badge>
185
+ )}
186
+
187
+ {eng.mobileNumber && (
188
+ <Button asChild size="sm" variant="outline" className="h-8 gap-1.5 text-xs">
189
+ <a href={`tel:${eng.mobileNumber}`}>
190
+ <PhoneCall className="w-3.5 h-3.5 text-primary" />
191
+ Call
192
+ </a>
193
+ </Button>
194
+ )}
195
+ </div>
196
+ </div>
197
+ );
198
+ })}
199
+ </CardContent>
200
+ </Card>
201
+ </div>
202
+ );
203
+ }
204
+
@@ -0,0 +1,368 @@
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { Card, CardContent } from '@/components/ui/card';
5
+ import { Badge } from '@/components/ui/badge';
6
+ import { Avatar, AvatarFallback } from '@/components/ui/avatar';
7
+ import {
8
+ Phone,
9
+ Mail,
10
+ Clock,
11
+ CheckCircle,
12
+ AlertCircle,
13
+ Calendar,
14
+ Wrench,
15
+ Moon,
16
+ } from 'lucide-react';
17
+ import { cn } from '@/lib/utils';
18
+
19
+ interface EngineerInfo {
20
+ id: string;
21
+ userId: string;
22
+ fullName: string;
23
+ email: string;
24
+ avatarUrl: string | null;
25
+ jobTitle: string;
26
+ specialization: string | null;
27
+ extension: string | null;
28
+ mobileNumber: string | null;
29
+ dutyStatus: string;
30
+ shiftHours: string | null;
31
+ workingDays: string[];
32
+ onCallDays: string[];
33
+ coveredDepartments: { id: string; name: string; code: string }[];
34
+ hospitalName: string | null;
35
+ activeTicketsCount: number;
36
+ activeMaintenanceCount: number;
37
+ assignedDevicesCount: number;
38
+ }
39
+
40
+ interface StaffEngineerTeamViewProps {
41
+ engineers: EngineerInfo[];
42
+ }
43
+
44
+ const DAYS_OF_WEEK = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
45
+
46
+ const DUTY_STATUS_CONFIG: Record<
47
+ string,
48
+ {
49
+ label: string;
50
+ color: string;
51
+ bgColor: string;
52
+ borderColor: string;
53
+ icon: typeof CheckCircle;
54
+ }
55
+ > = {
56
+ on_duty: {
57
+ label: 'On Duty',
58
+ color: 'text-green-700 dark:text-green-300',
59
+ bgColor: 'bg-green-50 dark:bg-green-950/30',
60
+ borderColor: 'border-green-200 dark:border-green-800',
61
+ icon: CheckCircle,
62
+ },
63
+ on_call: {
64
+ label: 'On Call',
65
+ color: 'text-blue-700 dark:text-blue-300',
66
+ bgColor: 'bg-blue-50 dark:bg-blue-950/30',
67
+ borderColor: 'border-blue-200 dark:border-blue-800',
68
+ icon: Phone,
69
+ },
70
+ in_maintenance: {
71
+ label: 'In Maintenance',
72
+ color: 'text-amber-700 dark:text-amber-300',
73
+ bgColor: 'bg-amber-50 dark:bg-amber-950/30',
74
+ borderColor: 'border-amber-200 dark:border-amber-800',
75
+ icon: Wrench,
76
+ },
77
+ off_duty: {
78
+ label: 'Off Duty',
79
+ color: 'text-gray-500 dark:text-gray-400',
80
+ bgColor: 'bg-gray-50 dark:bg-gray-900/30',
81
+ borderColor: 'border-gray-200 dark:border-gray-700',
82
+ icon: Moon,
83
+ },
84
+ };
85
+
86
+ export function StaffEngineerTeamView({ engineers }: StaffEngineerTeamViewProps) {
87
+ const [filter, setFilter] = useState<'all' | 'available'>('all');
88
+
89
+ const availableEngineers = engineers.filter(
90
+ (e) => e.dutyStatus === 'on_duty' || e.dutyStatus === 'on_call'
91
+ );
92
+ const filteredEngineers =
93
+ filter === 'available' ? availableEngineers : engineers;
94
+
95
+ const todayIndex = new Date().getDay();
96
+ const todayName = DAYS_OF_WEEK[todayIndex];
97
+
98
+ return (
99
+ <div className="space-y-5">
100
+ {/* Summary Strip */}
101
+ <div className="flex items-center gap-3 flex-wrap">
102
+ <div className="flex items-center gap-2 bg-green-50 dark:bg-green-950/30 border border-green-200 dark:border-green-800 rounded-lg px-3 py-2">
103
+ <CheckCircle className="w-4 h-4 text-green-600 dark:text-green-400" />
104
+ <span className="text-sm font-semibold text-green-700 dark:text-green-300">
105
+ {availableEngineers.length} available today
106
+ </span>
107
+ </div>
108
+ <span className="text-sm text-muted-foreground">
109
+ {engineers.length} total engineers
110
+ </span>
111
+ </div>
112
+
113
+ {/* Filter */}
114
+ <div className="flex gap-2">
115
+ <button
116
+ onClick={() => setFilter('all')}
117
+ className={cn(
118
+ 'text-xs px-3 py-1.5 rounded-full border font-medium transition-colors',
119
+ filter === 'all'
120
+ ? 'bg-primary text-primary-foreground border-primary'
121
+ : 'bg-card text-muted-foreground border-border hover:bg-muted'
122
+ )}
123
+ >
124
+ All ({engineers.length})
125
+ </button>
126
+ <button
127
+ onClick={() => setFilter('available')}
128
+ className={cn(
129
+ 'text-xs px-3 py-1.5 rounded-full border font-medium transition-colors',
130
+ filter === 'available'
131
+ ? 'bg-primary text-primary-foreground border-primary'
132
+ : 'bg-card text-muted-foreground border-border hover:bg-muted'
133
+ )}
134
+ >
135
+ Available Now ({availableEngineers.length})
136
+ </button>
137
+ </div>
138
+
139
+ {/* Engineer Cards */}
140
+ {filteredEngineers.length === 0 ? (
141
+ <div className="text-center py-12 border rounded-lg bg-muted/20">
142
+ <p className="text-muted-foreground text-sm">
143
+ No engineers are currently available.
144
+ </p>
145
+ </div>
146
+ ) : (
147
+ <div className="space-y-4">
148
+ {filteredEngineers.map((eng) => (
149
+ <EngineerCard
150
+ key={eng.id}
151
+ engineer={eng}
152
+ todayName={todayName}
153
+ />
154
+ ))}
155
+ </div>
156
+ )}
157
+ </div>
158
+ );
159
+ }
160
+
161
+ function EngineerCard({
162
+ engineer,
163
+ todayName,
164
+ }: {
165
+ engineer: EngineerInfo;
166
+ todayName: string;
167
+ }) {
168
+ const statusConfig = DUTY_STATUS_CONFIG[engineer.dutyStatus] || DUTY_STATUS_CONFIG.off_duty;
169
+ const StatusIcon = statusConfig.icon;
170
+ const initials = engineer.fullName
171
+ .split(' ')
172
+ .map((n) => n[0])
173
+ .join('')
174
+ .substring(0, 2)
175
+ .toUpperCase();
176
+
177
+ const isAvailable =
178
+ engineer.dutyStatus === 'on_duty' || engineer.dutyStatus === 'on_call';
179
+
180
+ return (
181
+ <Card
182
+ className={cn(
183
+ 'shadow-sm overflow-hidden',
184
+ isAvailable
185
+ ? 'border-green-200 dark:border-green-900'
186
+ : 'opacity-75'
187
+ )}
188
+ >
189
+ {/* Status Banner */}
190
+ <div
191
+ className={cn(
192
+ 'px-4 py-2 flex items-center gap-2 text-xs font-semibold border-b',
193
+ statusConfig.bgColor,
194
+ statusConfig.borderColor,
195
+ statusConfig.color
196
+ )}
197
+ >
198
+ <StatusIcon className="w-3.5 h-3.5" />
199
+ {statusConfig.label}
200
+ {engineer.shiftHours && (
201
+ <span className="text-muted-foreground font-normal ml-auto">
202
+ {engineer.shiftHours}
203
+ </span>
204
+ )}
205
+ </div>
206
+
207
+ <CardContent className="p-4">
208
+ {/* Name and Role */}
209
+ <div className="flex items-start gap-3">
210
+ <Avatar className="h-12 w-12 shrink-0">
211
+ <AvatarFallback
212
+ className={cn(
213
+ 'text-sm font-bold',
214
+ isAvailable
215
+ ? 'bg-primary/10 text-primary'
216
+ : 'bg-muted text-muted-foreground'
217
+ )}
218
+ >
219
+ {initials}
220
+ </AvatarFallback>
221
+ </Avatar>
222
+ <div className="min-w-0 flex-1">
223
+ <h3 className="font-semibold text-base">{engineer.fullName}</h3>
224
+ <p className="text-sm text-muted-foreground">{engineer.jobTitle}</p>
225
+ {engineer.specialization && (
226
+ <p className="text-xs text-muted-foreground mt-0.5">
227
+ {engineer.specialization}
228
+ </p>
229
+ )}
230
+ </div>
231
+ </div>
232
+
233
+ {/* Contact Info */}
234
+ <div className="mt-4 space-y-2">
235
+ {engineer.mobileNumber && (
236
+ <a
237
+ href={`tel:${engineer.mobileNumber}`}
238
+ className="flex items-center gap-2 text-sm text-primary hover:underline min-h-[36px]"
239
+ >
240
+ <Phone className="w-4 h-4 shrink-0" />
241
+ {engineer.mobileNumber}
242
+ </a>
243
+ )}
244
+ {engineer.extension && (
245
+ <div className="flex items-center gap-2 text-sm text-muted-foreground">
246
+ <Phone className="w-4 h-4 shrink-0" />
247
+ Ext. {engineer.extension}
248
+ </div>
249
+ )}
250
+ <a
251
+ href={`mailto:${engineer.email}`}
252
+ className="flex items-center gap-2 text-sm text-primary hover:underline min-h-[36px]"
253
+ >
254
+ <Mail className="w-4 h-4 shrink-0" />
255
+ {engineer.email}
256
+ </a>
257
+ </div>
258
+
259
+ {/* Weekly Schedule Calendar */}
260
+ <div className="mt-4">
261
+ <p className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">
262
+ <Calendar className="w-3.5 h-3.5 inline mr-1" />
263
+ Weekly Schedule
264
+ </p>
265
+ <div className="grid grid-cols-7 gap-1">
266
+ {DAYS_OF_WEEK.map((day) => {
267
+ const isWorkDay = engineer.workingDays.includes(day);
268
+ const isOnCallDay = engineer.onCallDays.includes(day);
269
+ const isToday = day === todayName;
270
+
271
+ return (
272
+ <div
273
+ key={day}
274
+ className={cn(
275
+ 'flex flex-col items-center py-1.5 rounded-lg text-center border',
276
+ isToday && 'ring-2 ring-primary ring-offset-1',
277
+ isWorkDay
278
+ ? 'bg-green-50 dark:bg-green-950/30 border-green-200 dark:border-green-800'
279
+ : isOnCallDay
280
+ ? 'bg-blue-50 dark:bg-blue-950/30 border-blue-200 dark:border-blue-800'
281
+ : 'bg-muted/30 border-border'
282
+ )}
283
+ >
284
+ <span
285
+ className={cn(
286
+ 'text-[10px] font-bold leading-none',
287
+ isToday
288
+ ? 'text-primary'
289
+ : isWorkDay
290
+ ? 'text-green-700 dark:text-green-300'
291
+ : isOnCallDay
292
+ ? 'text-blue-700 dark:text-blue-300'
293
+ : 'text-muted-foreground'
294
+ )}
295
+ >
296
+ {day}
297
+ </span>
298
+ <span className="text-[10px] mt-0.5 leading-none">
299
+ {isWorkDay ? '✓' : isOnCallDay ? '📞' : '—'}
300
+ </span>
301
+ </div>
302
+ );
303
+ })}
304
+ </div>
305
+ <div className="flex items-center gap-3 mt-2 text-[11px] text-muted-foreground">
306
+ <span className="flex items-center gap-1">
307
+ <span className="w-2 h-2 rounded-full bg-green-500 inline-block" />
308
+ Working
309
+ </span>
310
+ <span className="flex items-center gap-1">
311
+ <span className="w-2 h-2 rounded-full bg-blue-500 inline-block" />
312
+ On Call
313
+ </span>
314
+ <span className="flex items-center gap-1">
315
+ <span className="w-2 h-2 rounded-full bg-muted inline-block border" />
316
+ Off
317
+ </span>
318
+ </div>
319
+ </div>
320
+
321
+ {/* Covered Departments */}
322
+ {engineer.coveredDepartments.length > 0 && (
323
+ <div className="mt-4">
324
+ <p className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-1.5">
325
+ Covers Departments
326
+ </p>
327
+ <div className="flex flex-wrap gap-1">
328
+ {engineer.coveredDepartments.map((dept) => (
329
+ <Badge
330
+ key={dept.id}
331
+ variant="secondary"
332
+ className="text-xs"
333
+ >
334
+ {dept.name}
335
+ </Badge>
336
+ ))}
337
+ </div>
338
+ </div>
339
+ )}
340
+
341
+ {/* Current Workload */}
342
+ {(engineer.activeTicketsCount > 0 ||
343
+ engineer.activeMaintenanceCount > 0) && (
344
+ <div className="mt-4 pt-3 border-t border-border">
345
+ <p className="text-xs text-muted-foreground">
346
+ Currently handling:{' '}
347
+ {engineer.activeTicketsCount > 0 && (
348
+ <span className="font-medium text-foreground">
349
+ {engineer.activeTicketsCount} ticket
350
+ {engineer.activeTicketsCount !== 1 ? 's' : ''}
351
+ </span>
352
+ )}
353
+ {engineer.activeTicketsCount > 0 &&
354
+ engineer.activeMaintenanceCount > 0 &&
355
+ ' and '}
356
+ {engineer.activeMaintenanceCount > 0 && (
357
+ <span className="font-medium text-foreground">
358
+ {engineer.activeMaintenanceCount} maintenance task
359
+ {engineer.activeMaintenanceCount !== 1 ? 's' : ''}
360
+ </span>
361
+ )}
362
+ </p>
363
+ </div>
364
+ )}
365
+ </CardContent>
366
+ </Card>
367
+ );
368
+ }
@@ -0,0 +1,88 @@
1
+ 'use client';
2
+
3
+ import { Card } from '@/components/ui/card';
4
+ import { Users, Radio, PhoneCall, Wrench, ShieldCheck, Moon } from 'lucide-react';
5
+
6
+ interface TeamHeaderStatsProps {
7
+ stats: {
8
+ totalEngineers: number;
9
+ onDutyToday: number;
10
+ onCallToday: number;
11
+ inMaintenanceToday: number;
12
+ offDutyToday: number;
13
+ totalActiveWorkOrders: number;
14
+ };
15
+ }
16
+
17
+ export function TeamHeaderStats({ stats }: TeamHeaderStatsProps) {
18
+ return (
19
+ <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-3">
20
+ {/* Total Engineers */}
21
+ <Card className="p-4 bg-card border-border/70 shadow-sm flex items-center justify-between">
22
+ <div>
23
+ <p className="text-xs font-medium text-muted-foreground">Total Team</p>
24
+ <p className="text-2xl font-bold mt-0.5">{stats.totalEngineers}</p>
25
+ <span className="text-[11px] text-muted-foreground">Biomedical Engineers</span>
26
+ </div>
27
+ <div className="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center text-primary">
28
+ <Users className="w-5 h-5" />
29
+ </div>
30
+ </Card>
31
+
32
+ {/* On Duty */}
33
+ <Card className="p-4 bg-emerald-50/50 dark:bg-emerald-950/20 border-emerald-200/60 dark:border-emerald-900/40 shadow-sm flex items-center justify-between">
34
+ <div>
35
+ <p className="text-xs font-medium text-emerald-800 dark:text-emerald-300">On Duty Today</p>
36
+ <div className="flex items-center gap-1.5 mt-0.5">
37
+ <span className="relative flex h-2.5 w-2.5">
38
+ <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
39
+ <span className="relative inline-flex rounded-full h-2.5 w-2.5 bg-emerald-500"></span>
40
+ </span>
41
+ <p className="text-2xl font-bold text-emerald-700 dark:text-emerald-400">{stats.onDutyToday}</p>
42
+ </div>
43
+ <span className="text-[11px] text-emerald-700/80 dark:text-emerald-400/80">In Hospital / Ready</span>
44
+ </div>
45
+ <div className="w-10 h-10 rounded-full bg-emerald-100 dark:bg-emerald-900/50 flex items-center justify-center text-emerald-600 dark:text-emerald-400">
46
+ <Radio className="w-5 h-5" />
47
+ </div>
48
+ </Card>
49
+
50
+ {/* On Call */}
51
+ <Card className="p-4 bg-amber-50/50 dark:bg-amber-950/20 border-amber-200/60 dark:border-amber-900/40 shadow-sm flex items-center justify-between">
52
+ <div>
53
+ <p className="text-xs font-medium text-amber-800 dark:text-amber-300">On-Call Shift</p>
54
+ <p className="text-2xl font-bold text-amber-700 dark:text-amber-400 mt-0.5">{stats.onCallToday}</p>
55
+ <span className="text-[11px] text-amber-700/80 dark:text-amber-400/80">Emergency Responder</span>
56
+ </div>
57
+ <div className="w-10 h-10 rounded-full bg-amber-100 dark:bg-amber-900/50 flex items-center justify-center text-amber-600 dark:text-amber-400">
58
+ <PhoneCall className="w-5 h-5" />
59
+ </div>
60
+ </Card>
61
+
62
+ {/* Active Work Orders */}
63
+ <Card className="p-4 bg-blue-50/50 dark:bg-blue-950/20 border-blue-200/60 dark:border-blue-900/40 shadow-sm flex items-center justify-between">
64
+ <div>
65
+ <p className="text-xs font-medium text-blue-800 dark:text-blue-300">Active Workloads</p>
66
+ <p className="text-2xl font-bold text-blue-700 dark:text-blue-400 mt-0.5">{stats.totalActiveWorkOrders}</p>
67
+ <span className="text-[11px] text-blue-700/80 dark:text-blue-400/80">Open Tasks & Tickets</span>
68
+ </div>
69
+ <div className="w-10 h-10 rounded-full bg-blue-100 dark:bg-blue-900/50 flex items-center justify-center text-blue-600 dark:text-blue-400">
70
+ <Wrench className="w-5 h-5" />
71
+ </div>
72
+ </Card>
73
+
74
+ {/* Off Duty */}
75
+ <Card className="p-4 bg-slate-50 dark:bg-slate-900/40 border-border/70 shadow-sm col-span-2 md:col-span-1 flex items-center justify-between">
76
+ <div>
77
+ <p className="text-xs font-medium text-muted-foreground">Off Duty</p>
78
+ <p className="text-2xl font-bold text-muted-foreground mt-0.5">{stats.offDutyToday}</p>
79
+ <span className="text-[11px] text-muted-foreground">Rest / Post-Call</span>
80
+ </div>
81
+ <div className="w-10 h-10 rounded-full bg-muted flex items-center justify-center text-muted-foreground">
82
+ <Moon className="w-5 h-5" />
83
+ </div>
84
+ </Card>
85
+ </div>
86
+ );
87
+ }
88
+