@omersx/bemms 0.0.0-stage → 0.1.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,231 @@
1
+ import { listMaintenanceTasks } from "@/lib/actions/maintenance-tasks"
2
+ import { PageHeader } from "@/components/shared/page-header"
3
+ import { DataTable } from "@/components/shared/data-table"
4
+ import { MaintenanceNav } from "@/components/maintenance/maintenance-nav"
5
+ import {
6
+ MaintenanceStatusBadge,
7
+ MaintenanceTypeBadge,
8
+ } from "@/components/maintenance/maintenance-badges"
9
+ import { Button } from "@/components/ui/button"
10
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
11
+ import {
12
+ Activity,
13
+ AlertTriangle,
14
+ Calendar,
15
+ CheckCircle2,
16
+ ClipboardCheck,
17
+ Clock,
18
+ Plus,
19
+ ArrowRight,
20
+ } from "lucide-react"
21
+ import Link from "next/link"
22
+
23
+ export default async function MaintenanceDashboardPage() {
24
+ const result = await listMaintenanceTasks({ page: 1, pageSize: 50 })
25
+ const tasks = result?.success && Array.isArray(result.data) ? result.data : []
26
+
27
+ // Calculate KPI metrics from maintenance tasks
28
+ const inProgressCount = tasks.filter(
29
+ (t: any) => t.statusCode === "in_progress"
30
+ ).length
31
+
32
+ const awaitingReviewCount = tasks.filter(
33
+ (t: any) =>
34
+ t.statusCode === "awaiting_review" ||
35
+ t.statusCode === "work_complete" ||
36
+ t.statusCode === "awaiting_release"
37
+ ).length
38
+
39
+ const now = new Date()
40
+ const sevenDaysFromNow = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
41
+
42
+ const dueSoonOrOverdueCount = tasks.filter((t: any) => {
43
+ if (t.statusCode === "closed" || t.statusCode === "cancelled") return false
44
+ if (!t.dueDate) return false
45
+ const due = new Date(t.dueDate)
46
+ return due <= sevenDaysFromNow
47
+ }).length
48
+
49
+ const closedThisMonthCount = tasks.filter((t: any) => {
50
+ if (t.statusCode !== "closed") return false
51
+ const taskDate = t.completedAt ? new Date(t.completedAt) : new Date(t.updatedAt)
52
+ return (
53
+ taskDate.getMonth() === now.getMonth() &&
54
+ taskDate.getFullYear() === now.getFullYear()
55
+ )
56
+ }).length
57
+
58
+ const columns = [
59
+ {
60
+ key: "taskNumber",
61
+ header: "Task #",
62
+ render: (item: any) => (
63
+ <Link
64
+ href={`/maintenance/tasks/${item.id}`}
65
+ className="text-primary hover:underline font-mono text-sm font-medium"
66
+ >
67
+ {item.taskNumber}
68
+ </Link>
69
+ ),
70
+ },
71
+ {
72
+ key: "title",
73
+ header: "Title",
74
+ render: (item: any) => (
75
+ <Link
76
+ href={`/maintenance/tasks/${item.id}`}
77
+ className="font-medium hover:underline line-clamp-1"
78
+ >
79
+ {item.title}
80
+ </Link>
81
+ ),
82
+ },
83
+ {
84
+ key: "device",
85
+ header: "Device",
86
+ render: (item: any) => (
87
+ <div>
88
+ <span className="text-sm font-medium">
89
+ {item.device?.name || "No device"}
90
+ </span>
91
+ {item.device?.assetNumber && (
92
+ <span className="text-xs text-muted-foreground block">
93
+ Asset: {item.device.assetNumber}
94
+ </span>
95
+ )}
96
+ </div>
97
+ ),
98
+ },
99
+ {
100
+ key: "maintenanceType",
101
+ header: "Type",
102
+ render: (item: any) => (
103
+ <MaintenanceTypeBadge type={item.maintenanceType} />
104
+ ),
105
+ },
106
+ {
107
+ key: "statusCode",
108
+ header: "Status",
109
+ render: (item: any) => (
110
+ <MaintenanceStatusBadge status={item.statusCode} showIcon />
111
+ ),
112
+ },
113
+ {
114
+ key: "assignee",
115
+ header: "Assignee",
116
+ render: (item: any) => (
117
+ <span className="text-sm">
118
+ {item.assignedEngineer?.fullName || "Unassigned"}
119
+ </span>
120
+ ),
121
+ },
122
+ {
123
+ key: "dueDate",
124
+ header: "Due Date",
125
+ render: (item: any) => (
126
+ <span className="text-xs text-muted-foreground">
127
+ {item.dueDate ? new Date(item.dueDate).toLocaleDateString() : "—"}
128
+ </span>
129
+ ),
130
+ },
131
+ ]
132
+
133
+ return (
134
+ <div className="space-y-6">
135
+ <PageHeader
136
+ title="Maintenance"
137
+ description="Manage maintenance tasks, PM schedules, and work orders"
138
+ />
139
+
140
+ <MaintenanceNav />
141
+
142
+ <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
143
+ <Card>
144
+ <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
145
+ <CardTitle className="text-sm font-medium">
146
+ Tasks In Progress
147
+ </CardTitle>
148
+ <Activity className="h-4 w-4 text-indigo-500" />
149
+ </CardHeader>
150
+ <CardContent>
151
+ <div className="text-2xl font-bold">{inProgressCount}</div>
152
+ <p className="text-xs text-muted-foreground mt-1">
153
+ Active maintenance work
154
+ </p>
155
+ </CardContent>
156
+ </Card>
157
+
158
+ <Card>
159
+ <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
160
+ <CardTitle className="text-sm font-medium">
161
+ Awaiting Review
162
+ </CardTitle>
163
+ <Clock className="h-4 w-4 text-purple-500" />
164
+ </CardHeader>
165
+ <CardContent>
166
+ <div className="text-2xl font-bold">{awaitingReviewCount}</div>
167
+ <p className="text-xs text-muted-foreground mt-1">
168
+ Pending review / sign-off
169
+ </p>
170
+ </CardContent>
171
+ </Card>
172
+
173
+ <Card>
174
+ <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
175
+ <CardTitle className="text-sm font-medium">
176
+ Due Soon / Overdue
177
+ </CardTitle>
178
+ <AlertTriangle className="h-4 w-4 text-amber-500" />
179
+ </CardHeader>
180
+ <CardContent>
181
+ <div className="text-2xl font-bold">{dueSoonOrOverdueCount}</div>
182
+ <p className="text-xs text-muted-foreground mt-1">
183
+ Due within 7 days or past due
184
+ </p>
185
+ </CardContent>
186
+ </Card>
187
+
188
+ <Card>
189
+ <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
190
+ <CardTitle className="text-sm font-medium">
191
+ Closed This Month
192
+ </CardTitle>
193
+ <CheckCircle2 className="h-4 w-4 text-emerald-500" />
194
+ </CardHeader>
195
+ <CardContent>
196
+ <div className="text-2xl font-bold">{closedThisMonthCount}</div>
197
+ <p className="text-xs text-muted-foreground mt-1">
198
+ Completed work orders
199
+ </p>
200
+ </CardContent>
201
+ </Card>
202
+ </div>
203
+
204
+ <div className="space-y-4">
205
+ <div className="flex items-center justify-between">
206
+ <div>
207
+ <h2 className="text-lg font-semibold tracking-tight">Recent Tasks</h2>
208
+ <p className="text-sm text-muted-foreground">
209
+ Latest maintenance requests and scheduled work
210
+ </p>
211
+ </div>
212
+ <Link href="/maintenance/tasks">
213
+ <Button variant="ghost" size="sm">
214
+ View All Tasks
215
+ <ArrowRight className="w-4 h-4 ml-1" />
216
+ </Button>
217
+ </Link>
218
+ </div>
219
+
220
+ <DataTable
221
+ data={tasks.slice(0, 10)}
222
+ columns={columns}
223
+ searchable={true}
224
+ searchKey="title"
225
+ searchPlaceholder="Search maintenance tasks..."
226
+ />
227
+ </div>
228
+ </div>
229
+ )
230
+ }
231
+
@@ -0,0 +1,142 @@
1
+ import { PageHeader } from "@/components/shared/page-header"
2
+ import { MaintenanceNav } from "@/components/maintenance/maintenance-nav"
3
+ import {
4
+ MaintenancePlanStatusBadge,
5
+ DueStateBadge,
6
+ } from "@/components/maintenance/maintenance-badges"
7
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
8
+ import { Button } from "@/components/ui/button"
9
+ import {
10
+ Calendar,
11
+ Clock,
12
+ Info,
13
+ Monitor,
14
+ Plus,
15
+ RotateCw,
16
+ User,
17
+ Wrench,
18
+ } from "lucide-react"
19
+ import Link from "next/link"
20
+
21
+ export default async function MaintenancePlansPage() {
22
+ // Sample structure demonstration for PM plans until listMaintenancePlans with device joins is available
23
+ const samplePlans = [
24
+ {
25
+ id: "pm-plan-1",
26
+ title: "Quarterly Defibrillator Safety & Calibration",
27
+ deviceName: "Zoll R Series Defibrillator",
28
+ deviceAsset: "ASSET-2024-001",
29
+ department: "Emergency Department",
30
+ frequency: "Every 3 Months",
31
+ nextDueDate: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toLocaleDateString(),
32
+ status: "active",
33
+ dueState: "scheduled",
34
+ assignedEngineer: "Alex Taylor (Lead Biomed)",
35
+ calculationMethod: "fixed_calendar",
36
+ },
37
+ {
38
+ id: "pm-plan-2",
39
+ title: "Semi-Annual Anesthesia Machine PM & Vaporizer Check",
40
+ deviceName: "Mindray A7 Anesthesia System",
41
+ deviceAsset: "ASSET-2024-042",
42
+ department: "Surgical Suite 3",
43
+ frequency: "Every 6 Months",
44
+ nextDueDate: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000).toLocaleDateString(),
45
+ status: "active",
46
+ dueState: "due_soon",
47
+ assignedEngineer: "Sarah Jenkins (Senior CE)",
48
+ calculationMethod: "completion_based",
49
+ },
50
+ {
51
+ id: "pm-plan-3",
52
+ title: "Annual Infusion Pump Electrical Safety Testing",
53
+ deviceName: "Alaris 8100 Infusion Pump",
54
+ deviceAsset: "ASSET-2024-108",
55
+ department: "ICU Ward B",
56
+ frequency: "Every 12 Months",
57
+ nextDueDate: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toLocaleDateString(),
58
+ status: "active",
59
+ dueState: "overdue",
60
+ assignedEngineer: "David Chen (Biomed Tech II)",
61
+ calculationMethod: "fixed_calendar",
62
+ },
63
+ ]
64
+
65
+ return (
66
+ <div className="space-y-6">
67
+ <PageHeader
68
+ title="Preventive Maintenance Plans"
69
+ description="Configure automated recurring PM schedules, calibration cycles, and maintenance routines"
70
+ >
71
+ <Link href="/maintenance/plans/new">
72
+ <Button>
73
+ <Plus className="w-4 h-4 mr-2" />
74
+ New Plan
75
+ </Button>
76
+ </Link>
77
+ </PageHeader>
78
+
79
+ <MaintenanceNav />
80
+
81
+ <Card className="border-blue-200 bg-blue-50/50 dark:border-blue-900/50 dark:bg-blue-950/20">
82
+ <CardContent className="flex items-start gap-4 p-4">
83
+ <Info className="h-5 w-5 text-blue-600 dark:text-blue-400 mt-0.5 shrink-0" />
84
+ <div className="space-y-1">
85
+ <h3 className="text-sm font-semibold text-blue-900 dark:text-blue-200">
86
+ Database Synchronization Active
87
+ </h3>
88
+ <p className="text-xs text-blue-800 dark:text-blue-300">
89
+ PM Plans will be loaded from the database. Automated background schedules trigger task creation according to specified lead time days and recurrence calculations.
90
+ </p>
91
+ </div>
92
+ </CardContent>
93
+ </Card>
94
+
95
+ <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
96
+ {samplePlans.map((plan) => (
97
+ <Card key={plan.id} className="flex flex-col justify-between hover:shadow-md transition-shadow">
98
+ <CardHeader className="pb-3">
99
+ <div className="flex items-start justify-between gap-2">
100
+ <CardTitle className="text-base font-semibold line-clamp-2">
101
+ {plan.title}
102
+ </CardTitle>
103
+ <MaintenancePlanStatusBadge status={plan.status} />
104
+ </div>
105
+ <CardDescription className="flex items-center gap-1.5 text-xs">
106
+ <Monitor className="w-3.5 h-3.5" />
107
+ <span>{plan.deviceName}</span>
108
+ <span className="text-muted-foreground font-mono">({plan.deviceAsset})</span>
109
+ </CardDescription>
110
+ </CardHeader>
111
+
112
+ <CardContent className="space-y-3 text-sm flex-1">
113
+ <div className="grid grid-cols-2 gap-2 text-xs pt-2 border-t border-border">
114
+ <div className="space-y-1">
115
+ <span className="text-muted-foreground flex items-center gap-1">
116
+ <RotateCw className="w-3 h-3" /> Frequency
117
+ </span>
118
+ <span className="font-medium text-foreground">{plan.frequency}</span>
119
+ </div>
120
+ <div className="space-y-1">
121
+ <span className="text-muted-foreground flex items-center gap-1">
122
+ <Calendar className="w-3 h-3" /> Next Due Date
123
+ </span>
124
+ <span className="font-medium text-foreground">{plan.nextDueDate}</span>
125
+ </div>
126
+ </div>
127
+
128
+ <div className="flex items-center justify-between pt-2 border-t border-border text-xs">
129
+ <div className="flex items-center gap-1 text-muted-foreground">
130
+ <User className="w-3.5 h-3.5" />
131
+ <span className="truncate max-w-[140px]">{plan.assignedEngineer}</span>
132
+ </div>
133
+ <DueStateBadge dueState={plan.dueState} showIcon />
134
+ </div>
135
+ </CardContent>
136
+ </Card>
137
+ ))}
138
+ </div>
139
+ </div>
140
+ )
141
+ }
142
+