@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,626 @@
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { useRouter } from 'next/navigation';
5
+ import { toast } from 'sonner';
6
+ import { updateCurrentUserProfile, DepartmentStaffProfile } from '@/lib/actions/users';
7
+ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
8
+ import { Button } from '@/components/ui/button';
9
+ import { Input } from '@/components/ui/input';
10
+ import { Label } from '@/components/ui/label';
11
+ import { Badge } from '@/components/ui/badge';
12
+ import { Avatar, AvatarFallback } from '@/components/ui/avatar';
13
+ import {
14
+ User,
15
+ Phone,
16
+ Mail,
17
+ Building2,
18
+ Briefcase,
19
+ IdCard,
20
+ TicketCheck,
21
+ CheckCircle,
22
+ Save,
23
+ Loader2,
24
+ Stethoscope,
25
+ ShieldCheck,
26
+ Wrench,
27
+ Clock,
28
+ Calendar,
29
+ PhoneCall,
30
+ CalendarDays,
31
+ Radio,
32
+ Moon,
33
+ Edit,
34
+ LogOut,
35
+ } from 'lucide-react';
36
+ import Link from 'next/link';
37
+ import { cn } from '@/lib/utils';
38
+ import { updateEngineerDutyStatus } from '@/lib/actions/engineers';
39
+ import { EditEngineerDialog } from '@/components/team/edit-engineer-dialog';
40
+ import { SignOutButton } from '@/components/shared/sign-out-button';
41
+
42
+ interface UserProfileViewProps {
43
+ profile: DepartmentStaffProfile;
44
+ }
45
+
46
+ const COMMON_SPECIALTIES = [
47
+ 'Staff Nurse',
48
+ 'Charge Nurse',
49
+ 'ICU Specialist',
50
+ 'Operating Theatre Nurse',
51
+ 'Ward Medical Officer',
52
+ 'Clinical Consultant',
53
+ 'Department Head / Supervisor',
54
+ 'Dialysis Technician',
55
+ ];
56
+
57
+ export function UserProfileView({ profile }: UserProfileViewProps) {
58
+ const router = useRouter();
59
+ const [editing, setEditing] = useState(false);
60
+ const [loading, setLoading] = useState(false);
61
+
62
+ // Form states
63
+ const [fullName, setFullName] = useState(profile.fullName || '');
64
+ const [jobTitle, setJobTitle] = useState(profile.jobTitle || '');
65
+ const [phone, setPhone] = useState(profile.phone || '');
66
+ const [employeeIdentifier, setEmployeeIdentifier] = useState(profile.employeeIdentifier || '');
67
+
68
+ // Engineer state
69
+ const isEngineer = profile.roles.some((r) =>
70
+ ['BIOMED_ENG', 'BIOMED_TECH', 'BIOMED_MGR', 'SYS_ADMIN'].includes(r)
71
+ ) || Boolean(profile.engineerProfile);
72
+
73
+ const [dutyStatus, setDutyStatus] = useState<string>(
74
+ profile.engineerProfile?.dutyStatus || 'on_duty'
75
+ );
76
+ const [updatingDuty, setUpdatingDuty] = useState(false);
77
+ const [editScheduleOpen, setEditScheduleOpen] = useState(false);
78
+
79
+ const handleDutyStatusChange = async (newStatus: any) => {
80
+ if (!profile.engineerProfile?.id) return;
81
+ setUpdatingDuty(true);
82
+ try {
83
+ const res = await updateEngineerDutyStatus(profile.engineerProfile.id, newStatus);
84
+ if (res.success) {
85
+ setDutyStatus(newStatus);
86
+ const labels: Record<string, string> = {
87
+ on_duty: 'On Duty',
88
+ on_call: 'On Call',
89
+ in_maintenance: 'In Maintenance',
90
+ off_duty: 'Off Duty',
91
+ };
92
+ toast.success(`Duty status updated to ${labels[newStatus] || newStatus}`);
93
+ router.refresh();
94
+ } else {
95
+ toast.error(res.error || 'Failed to update duty status');
96
+ }
97
+ } catch {
98
+ toast.error('An error occurred');
99
+ } finally {
100
+ setUpdatingDuty(false);
101
+ }
102
+ };
103
+
104
+ const initials = profile.fullName
105
+ .split(' ')
106
+ .map((n) => n[0])
107
+ .join('')
108
+ .substring(0, 2)
109
+ .toUpperCase();
110
+
111
+ const handleSave = async (e: React.FormEvent) => {
112
+ e.preventDefault();
113
+ setLoading(true);
114
+
115
+ try {
116
+ const res = await updateCurrentUserProfile({
117
+ fullName: fullName.trim(),
118
+ jobTitle: jobTitle.trim() || undefined,
119
+ phone: phone.trim() || undefined,
120
+ employeeIdentifier: employeeIdentifier.trim() || undefined,
121
+ });
122
+
123
+ if (res.success) {
124
+ toast.success('Profile updated successfully');
125
+ setEditing(false);
126
+ router.refresh();
127
+ } else {
128
+ toast.error(res.error || 'Failed to update profile');
129
+ }
130
+ } catch (err: any) {
131
+ toast.error(err.message || 'An error occurred');
132
+ } finally {
133
+ setLoading(false);
134
+ }
135
+ };
136
+
137
+ return (
138
+ <div className="space-y-6">
139
+ {/* ── 1. Identity & Overview Card ───────────────────────────────── */}
140
+ <Card className="border shadow-sm overflow-hidden">
141
+ <div className="bg-gradient-to-r from-primary/10 via-primary/5 to-transparent p-6 border-b">
142
+ <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
143
+ <div className="flex items-center gap-4">
144
+ <Avatar className="h-16 w-16 border-2 border-background shadow-sm">
145
+ <AvatarFallback className="bg-primary text-primary-foreground text-xl font-bold">
146
+ {initials}
147
+ </AvatarFallback>
148
+ </Avatar>
149
+ <div className="space-y-1">
150
+ <div className="flex items-center gap-2 flex-wrap">
151
+ <h2 className="text-xl font-bold text-foreground">{profile.fullName}</h2>
152
+ {profile.roles.map((r) => (
153
+ <Badge key={r} variant="secondary" className="text-[10px] font-semibold">
154
+ {r.replace(/_/g, ' ')}
155
+ </Badge>
156
+ ))}
157
+ </div>
158
+ <p className="text-sm text-muted-foreground flex items-center gap-1.5 font-medium">
159
+ <Stethoscope className="w-4 h-4 text-primary" />
160
+ {profile.jobTitle || 'Clinical Staff Member'}
161
+ </p>
162
+ <p className="text-xs text-muted-foreground">
163
+ {profile.departmentName ? `${profile.departmentName} · ` : ''}
164
+ {profile.hospitalName || 'Assigned Hospital'}
165
+ </p>
166
+ </div>
167
+ </div>
168
+
169
+ <Button
170
+ variant={editing ? 'outline' : 'default'}
171
+ size="sm"
172
+ onClick={() => setEditing(!editing)}
173
+ className="shrink-0"
174
+ >
175
+ {editing ? 'Cancel' : 'Edit Contact & Title'}
176
+ </Button>
177
+ </div>
178
+ </div>
179
+
180
+ {/* Quick Contact & Scope Strip */}
181
+ <CardContent className="p-4 grid sm:grid-cols-3 gap-3 text-xs bg-card">
182
+ <div className="flex items-center gap-2.5 p-2.5 rounded-lg bg-muted/40 border">
183
+ <Phone className="w-4 h-4 text-primary shrink-0" />
184
+ <div className="truncate">
185
+ <span className="block text-[10px] text-muted-foreground font-semibold uppercase">
186
+ Contact Phone / Ext.
187
+ </span>
188
+ <span className="font-medium text-foreground truncate">
189
+ {profile.phone || 'Not set (add phone)'}
190
+ </span>
191
+ </div>
192
+ </div>
193
+
194
+ <div className="flex items-center gap-2.5 p-2.5 rounded-lg bg-muted/40 border">
195
+ <Mail className="w-4 h-4 text-primary shrink-0" />
196
+ <div className="truncate">
197
+ <span className="block text-[10px] text-muted-foreground font-semibold uppercase">
198
+ Official Email
199
+ </span>
200
+ <span className="font-medium text-foreground truncate">{profile.email}</span>
201
+ </div>
202
+ </div>
203
+
204
+ <div className="flex items-center gap-2.5 p-2.5 rounded-lg bg-muted/40 border">
205
+ <IdCard className="w-4 h-4 text-primary shrink-0" />
206
+ <div className="truncate">
207
+ <span className="block text-[10px] text-muted-foreground font-semibold uppercase">
208
+ Staff Badge / Extension
209
+ </span>
210
+ <span className="font-medium text-foreground truncate">
211
+ {profile.employeeIdentifier || 'Not registered'}
212
+ </span>
213
+ </div>
214
+ </div>
215
+ </CardContent>
216
+ </Card>
217
+
218
+ {/* ── 2. Edit Profile Form (When Editing) ────────────────────────── */}
219
+ {editing ? (
220
+ <Card className="border-2 border-primary/20 shadow-md">
221
+ <CardHeader className="pb-3">
222
+ <CardTitle className="text-base flex items-center gap-2">
223
+ <User className="w-4 h-4 text-primary" />
224
+ Update Clinical Contact Details
225
+ </CardTitle>
226
+ <p className="text-xs text-muted-foreground">
227
+ This information is visible to biomedical engineers when you report equipment problems.
228
+ </p>
229
+ </CardHeader>
230
+ <CardContent className="space-y-4">
231
+ <div className="flex items-start gap-2.5 p-3 rounded-xl bg-blue-50/70 dark:bg-blue-950/20 border border-blue-200 dark:border-blue-900 text-xs text-blue-900 dark:text-blue-200">
232
+ <ShieldCheck className="w-4 h-4 text-blue-600 dark:text-blue-400 shrink-0 mt-0.5" />
233
+ <div>
234
+ <span className="font-semibold">Hospital & Department are pre-assigned:</span>
235
+ <p className="text-[11px] text-blue-800/80 dark:text-blue-300/80 mt-0.5">
236
+ You are registered under <strong>{profile.departmentName || 'Your Department'}</strong> at <strong>{profile.hospitalName || 'Your Hospital'}</strong>. No hospital or department entry is required. You only need to verify your name, clinical speciality, and direct phone so engineers can contact you.
237
+ </p>
238
+ </div>
239
+ </div>
240
+
241
+ <form onSubmit={handleSave} className="space-y-4">
242
+ <div>
243
+ <Label htmlFor="fullName" className="text-xs font-semibold">
244
+ Full Display Name *
245
+ </Label>
246
+ <Input
247
+ id="fullName"
248
+ value={fullName}
249
+ onChange={(e) => setFullName(e.target.value)}
250
+ placeholder="e.g. Dr. Sarah Al-Mansoor"
251
+ required
252
+ className="mt-1 text-sm"
253
+ />
254
+ </div>
255
+
256
+ <div>
257
+ <Label htmlFor="jobTitle" className="text-xs font-semibold">
258
+ Clinical Job Title / Speciality *
259
+ </Label>
260
+ <Input
261
+ id="jobTitle"
262
+ value={jobTitle}
263
+ onChange={(e) => setJobTitle(e.target.value)}
264
+ placeholder="e.g. Senior Charge Nurse - Intensive Care"
265
+ className="mt-1 text-sm"
266
+ />
267
+ <div className="flex flex-wrap gap-1.5 mt-2">
268
+ <span className="text-[10px] text-muted-foreground self-center mr-1">Suggestions:</span>
269
+ {COMMON_SPECIALTIES.map((spec) => (
270
+ <button
271
+ key={spec}
272
+ type="button"
273
+ onClick={() => setJobTitle(spec)}
274
+ className="text-[10px] px-2 py-0.5 rounded-md border bg-muted/40 hover:bg-primary/10 hover:text-primary transition"
275
+ >
276
+ {spec}
277
+ </button>
278
+ ))}
279
+ </div>
280
+ </div>
281
+
282
+ <div className="grid sm:grid-cols-2 gap-4">
283
+ <div>
284
+ <Label htmlFor="phone" className="text-xs font-semibold">
285
+ Direct Contact Phone / Mobile
286
+ </Label>
287
+ <Input
288
+ id="phone"
289
+ value={phone}
290
+ onChange={(e) => setPhone(e.target.value)}
291
+ placeholder="e.g. +966 50 123 4567"
292
+ className="mt-1 text-sm"
293
+ />
294
+ <p className="text-[11px] text-muted-foreground mt-1">
295
+ Used by technicians to call you for urgent device triage.
296
+ </p>
297
+ </div>
298
+
299
+ <div>
300
+ <Label htmlFor="employeeIdentifier" className="text-xs font-semibold">
301
+ Hospital Extension / Ward Bleep
302
+ </Label>
303
+ <Input
304
+ id="employeeIdentifier"
305
+ value={employeeIdentifier}
306
+ onChange={(e) => setEmployeeIdentifier(e.target.value)}
307
+ placeholder="e.g. Ext. 3120 (Nurse Station Bed 4)"
308
+ className="mt-1 text-sm"
309
+ />
310
+ <p className="text-[11px] text-muted-foreground mt-1">
311
+ Your ward extension or internal bleep number.
312
+ </p>
313
+ </div>
314
+ </div>
315
+
316
+ <div className="flex justify-end gap-2 pt-2 border-t">
317
+ <Button type="button" variant="outline" size="sm" onClick={() => setEditing(false)}>
318
+ Cancel
319
+ </Button>
320
+ <Button type="submit" size="sm" disabled={loading} className="gap-1.5">
321
+ {loading ? (
322
+ <>
323
+ <Loader2 className="w-3.5 h-3.5 animate-spin" />
324
+ Saving...
325
+ </>
326
+ ) : (
327
+ <>
328
+ <Save className="w-3.5 h-3.5" />
329
+ Save Profile
330
+ </>
331
+ )}
332
+ </Button>
333
+ </div>
334
+ </form>
335
+ </CardContent>
336
+ </Card>
337
+ ) : null}
338
+
339
+ {/* ── 2.5 Biomedical Engineer Duty Status & Schedule Card ─────────── */}
340
+ {isEngineer && profile.engineerProfile && (
341
+ <Card className="border shadow-sm border-blue-200 dark:border-blue-900 bg-blue-50/20 dark:bg-blue-950/10">
342
+ <CardHeader className="pb-3 border-b border-blue-100 dark:border-blue-900/40">
343
+ <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3">
344
+ <div className="space-y-1">
345
+ <CardTitle className="text-base flex items-center gap-2 text-foreground">
346
+ <Wrench className="w-4 h-4 text-blue-600 dark:text-blue-400" />
347
+ Biomedical Engineer Duty Status &amp; Schedule
348
+ </CardTitle>
349
+ <p className="text-xs text-muted-foreground">
350
+ Your live duty availability, on-call days, and hospital working hours.
351
+ </p>
352
+ </div>
353
+ <Button
354
+ variant="outline"
355
+ size="sm"
356
+ className="gap-1.5 text-xs bg-background"
357
+ onClick={() => setEditScheduleOpen(true)}
358
+ >
359
+ <Edit className="w-3.5 h-3.5" />
360
+ Edit My Schedule
361
+ </Button>
362
+ </div>
363
+ </CardHeader>
364
+ <CardContent className="pt-4 space-y-4">
365
+ {/* Quick 1-Click Duty Status Switcher */}
366
+ <div className="space-y-2">
367
+ <Label className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">
368
+ Current Duty Availability
369
+ </Label>
370
+ <div className="grid grid-cols-2 sm:grid-cols-4 gap-2">
371
+ {[
372
+ { id: 'on_duty', label: 'On Duty', desc: 'In Hospital', color: 'border-emerald-500 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300' },
373
+ { id: 'on_call', label: 'On Call', desc: 'Emergency 24/7', color: 'border-amber-500 bg-amber-500/10 text-amber-700 dark:text-amber-300' },
374
+ { id: 'in_maintenance', label: 'In Maintenance', desc: 'Active Workshop', color: 'border-blue-500 bg-blue-500/10 text-blue-700 dark:text-blue-300' },
375
+ { id: 'off_duty', label: 'Off Duty', desc: 'Resting / Off', color: 'border-slate-400 bg-muted text-muted-foreground' },
376
+ ].map((item) => {
377
+ const isActive = dutyStatus === item.id;
378
+ return (
379
+ <button
380
+ key={item.id}
381
+ type="button"
382
+ disabled={updatingDuty}
383
+ onClick={() => handleDutyStatusChange(item.id)}
384
+ className={cn(
385
+ 'p-2.5 rounded-xl border text-left transition-all relative cursor-pointer',
386
+ isActive
387
+ ? `${item.color} ring-2 ring-primary/30 font-semibold shadow-xs`
388
+ : 'border-border/70 hover:bg-muted/40 text-muted-foreground'
389
+ )}
390
+ >
391
+ <div className="flex items-center justify-between">
392
+ <span className="text-xs font-bold">{item.label}</span>
393
+ {isActive && (
394
+ <span className="relative flex h-2 w-2">
395
+ <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75"></span>
396
+ <span className="relative inline-flex rounded-full h-2 w-2 bg-primary"></span>
397
+ </span>
398
+ )}
399
+ </div>
400
+ <span className="text-[10px] block opacity-80 mt-0.5">{item.desc}</span>
401
+ </button>
402
+ );
403
+ })}
404
+ </div>
405
+ </div>
406
+
407
+ {/* Schedule Details Grid */}
408
+ <div className="grid sm:grid-cols-3 gap-3 text-xs pt-2">
409
+ <div className="p-3 rounded-xl border bg-card space-y-1">
410
+ <span className="text-[10px] text-muted-foreground font-semibold uppercase flex items-center gap-1">
411
+ <Clock className="w-3 h-3 text-primary" /> Shift Hours
412
+ </span>
413
+ <p className="font-semibold text-foreground">
414
+ {profile.engineerProfile.shiftHours || '08:00 AM - 04:00 PM'}
415
+ </p>
416
+ </div>
417
+
418
+ <div className="p-3 rounded-xl border bg-card space-y-1">
419
+ <span className="text-[10px] text-muted-foreground font-semibold uppercase flex items-center gap-1">
420
+ <Calendar className="w-3 h-3 text-primary" /> Working Days
421
+ </span>
422
+ <div className="flex flex-wrap gap-1 pt-0.5">
423
+ {(profile.engineerProfile.workingDays || ['Sun', 'Mon', 'Tue', 'Wed', 'Thu']).map((day) => (
424
+ <Badge key={day} variant="secondary" className="text-[10px] px-1.5 py-0 font-medium">
425
+ {day}
426
+ </Badge>
427
+ ))}
428
+ </div>
429
+ </div>
430
+
431
+ <div className="p-3 rounded-xl border bg-card space-y-1">
432
+ <span className="text-[10px] text-muted-foreground font-semibold uppercase flex items-center gap-1">
433
+ <PhoneCall className="w-3 h-3 text-amber-500" /> On-Call Days
434
+ </span>
435
+ <div className="flex flex-wrap gap-1 pt-0.5">
436
+ {(profile.engineerProfile.onCallDays && profile.engineerProfile.onCallDays.length > 0) ? (
437
+ profile.engineerProfile.onCallDays.map((day) => (
438
+ <Badge key={day} className="bg-amber-500/15 text-amber-700 dark:text-amber-300 border-amber-300 dark:border-amber-800 text-[10px] px-1.5 py-0 font-medium">
439
+ {day}
440
+ </Badge>
441
+ ))
442
+ ) : (
443
+ <span className="text-muted-foreground italic text-[11px]">None assigned</span>
444
+ )}
445
+ </div>
446
+ </div>
447
+ </div>
448
+
449
+ {/* Contact & Specialization */}
450
+ <div className="grid sm:grid-cols-2 gap-3 text-xs">
451
+ <div className="p-3 rounded-xl border bg-card space-y-1">
452
+ <span className="text-[10px] text-muted-foreground font-semibold uppercase">
453
+ Technical Specialization
454
+ </span>
455
+ <p className="font-medium text-foreground">
456
+ {profile.engineerProfile.specialization || 'General Biomedical Engineering'}
457
+ </p>
458
+ </div>
459
+ <div className="p-3 rounded-xl border bg-card space-y-1">
460
+ <span className="text-[10px] text-muted-foreground font-semibold uppercase">
461
+ Direct Mobile / Extension
462
+ </span>
463
+ <p className="font-medium text-foreground">
464
+ {profile.engineerProfile.mobileNumber || profile.phone || 'No mobile'} · Ext: {profile.engineerProfile.extension || profile.employeeIdentifier || '—'}
465
+ </p>
466
+ </div>
467
+ </div>
468
+
469
+ {/* Quick Link to Team Duty Calendar */}
470
+ <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2 pt-2 border-t border-border/60 text-xs">
471
+ <span className="text-muted-foreground">
472
+ View whole hospital biomedical engineering team duty roster:
473
+ </span>
474
+ <Button asChild variant="outline" size="sm" className="gap-1.5 text-xs">
475
+ <Link href="/team">
476
+ <CalendarDays className="w-3.5 h-3.5 text-primary" />
477
+ Hospital Duty Roster &amp; Calendar →
478
+ </Link>
479
+ </Button>
480
+ </div>
481
+ </CardContent>
482
+ </Card>
483
+ )}
484
+
485
+ {/* Edit Engineer Dialog for Schedule */}
486
+ {isEngineer && profile.engineerProfile && (
487
+ <EditEngineerDialog
488
+ engineer={{
489
+ id: profile.engineerProfile.id,
490
+ userId: profile.id,
491
+ fullName: profile.fullName,
492
+ email: profile.email,
493
+ avatarUrl: profile.avatarUrl,
494
+ jobTitle: profile.engineerProfile.jobTitle,
495
+ specialization: profile.engineerProfile.specialization,
496
+ extension: profile.engineerProfile.extension,
497
+ mobileNumber: profile.engineerProfile.mobileNumber,
498
+ dutyStatus: profile.engineerProfile.dutyStatus as any,
499
+ shiftHours: profile.engineerProfile.shiftHours,
500
+ workingDays: profile.engineerProfile.workingDays,
501
+ onCallDays: profile.engineerProfile.onCallDays,
502
+ coveredDepartmentIds: profile.engineerProfile.coveredDepartmentIds,
503
+ coveredDepartments: [],
504
+ emergencyPriority: 'first_responder',
505
+ notes: profile.engineerProfile.notes,
506
+ hospitalName: profile.hospitalName,
507
+ activeTicketsCount: profile.activeTicketsCount,
508
+ activeMaintenanceCount: 0,
509
+ assignedDevicesCount: 0,
510
+ }}
511
+ open={editScheduleOpen}
512
+ onOpenChange={setEditScheduleOpen}
513
+ onSuccess={() => router.refresh()}
514
+ />
515
+ )}
516
+
517
+ {/* ── 3. Department & Hospital Assignment Card ──────────────────── */}
518
+ <Card className="border shadow-sm">
519
+ <CardHeader className="pb-3">
520
+ <div className="flex items-center justify-between">
521
+ <CardTitle className="text-base flex items-center gap-2">
522
+ <Building2 className="w-4 h-4 text-primary" />
523
+ Hospital & Department Scope
524
+ </CardTitle>
525
+ <Badge variant="outline" className="text-[10px] text-green-700 dark:text-green-400 border-green-300 dark:border-green-800 bg-green-50/50 dark:bg-green-950/20 font-medium">
526
+ 🔒 Pre-assigned & Verified
527
+ </Badge>
528
+ </div>
529
+ <p className="text-xs text-muted-foreground mt-1">
530
+ Pre-assigned by Hospital Administration. Clinical staff do not need to configure or enter hospital locations.
531
+ </p>
532
+ </CardHeader>
533
+ <CardContent className="space-y-4">
534
+ <div className="grid sm:grid-cols-2 gap-4 text-sm">
535
+ <div className="p-3.5 rounded-xl border bg-muted/20 space-y-1">
536
+ <span className="text-xs text-muted-foreground font-semibold uppercase tracking-wider">
537
+ Assigned Hospital
538
+ </span>
539
+ <p className="font-bold text-foreground text-base">
540
+ {profile.hospitalName || 'General Hospital'}
541
+ </p>
542
+ </div>
543
+
544
+ <div className="p-3.5 rounded-xl border bg-muted/20 space-y-1">
545
+ <span className="text-xs text-muted-foreground font-semibold uppercase tracking-wider">
546
+ Primary Clinical Department
547
+ </span>
548
+ <p className="font-bold text-foreground text-base">
549
+ {profile.departmentName || 'All Assigned Departments'}
550
+ </p>
551
+ </div>
552
+ </div>
553
+
554
+ <div className="flex items-start gap-2.5 p-3 rounded-xl bg-muted/40 border text-xs text-muted-foreground">
555
+ <ShieldCheck className="w-4 h-4 text-primary shrink-0 mt-0.5" />
556
+ <div>
557
+ <span className="font-medium text-foreground">Zero-Config Clinical Routing:</span>
558
+ <p className="text-[11px] mt-0.5">
559
+ Whenever you report a problem or scan an asset, BEMMS automatically connects your report to {profile.departmentName || 'your department'} without requiring any hospital or department codes.
560
+ </p>
561
+ </div>
562
+ </div>
563
+
564
+ <div className="flex flex-col sm:flex-row items-center justify-between gap-3 pt-3 border-t text-xs text-muted-foreground">
565
+ <div className="flex items-center gap-2">
566
+ <CheckCircle className="w-4 h-4 text-green-600 shrink-0" />
567
+ <span>
568
+ Authorized to view equipment and report issues for {profile.departmentName || 'your department'}.
569
+ </span>
570
+ </div>
571
+ <Button asChild variant="outline" size="sm" className="text-xs self-start sm:self-auto">
572
+ <Link href="/my-department">View Department Equipment →</Link>
573
+ </Button>
574
+ </div>
575
+ </CardContent>
576
+ </Card>
577
+
578
+ {/* ── 4. My Reported Activity Card ──────────────────────────────── */}
579
+ <Card className="border shadow-sm">
580
+ <CardHeader className="pb-3">
581
+ <CardTitle className="text-base flex items-center gap-2">
582
+ <TicketCheck className="w-4 h-4 text-primary" />
583
+ My Helpdesk Activity
584
+ </CardTitle>
585
+ </CardHeader>
586
+ <CardContent className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
587
+ <div className="space-y-1">
588
+ <p className="text-sm font-semibold text-foreground">
589
+ {profile.activeTicketsCount > 0
590
+ ? `${profile.activeTicketsCount} active ticket(s) currently open`
591
+ : 'No active tickets currently open'}
592
+ </p>
593
+ <p className="text-xs text-muted-foreground">
594
+ Track real-time repair progress, spare parts arrivals, and engineer assignments.
595
+ </p>
596
+ </div>
597
+
598
+ <Button asChild size="sm" className="shrink-0">
599
+ <Link href="/tickets">View My Tickets</Link>
600
+ </Button>
601
+ </CardContent>
602
+ </Card>
603
+
604
+ {/* ── 5. Account Session & Sign Out Card ────────────────────────── */}
605
+ <Card className="border shadow-sm border-destructive/20 bg-destructive/5 dark:bg-destructive/10">
606
+ <CardContent className="p-4 sm:p-5 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
607
+ <div className="space-y-1">
608
+ <h3 className="font-semibold text-sm text-foreground flex items-center gap-2">
609
+ <LogOut className="w-4 h-4 text-destructive" />
610
+ Sign Out of Session
611
+ </h3>
612
+ <p className="text-xs text-muted-foreground">
613
+ End your active session on this device. You will need to enter your credentials again to log back in.
614
+ </p>
615
+ </div>
616
+ <SignOutButton
617
+ variant="destructive"
618
+ size="sm"
619
+ label="Log out"
620
+ className="shrink-0"
621
+ />
622
+ </CardContent>
623
+ </Card>
624
+ </div>
625
+ );
626
+ }