@hed-hog/operations 0.0.330 → 0.0.331

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 (281) hide show
  1. package/README.md +5 -5
  2. package/dist/controllers/operations-collaborators.controller.d.ts +7 -216
  3. package/dist/controllers/operations-collaborators.controller.d.ts.map +1 -1
  4. package/dist/controllers/operations-contracts.controller.d.ts +6 -6
  5. package/dist/controllers/operations-projects.controller.d.ts +25 -0
  6. package/dist/controllers/operations-projects.controller.d.ts.map +1 -1
  7. package/dist/controllers/operations-projects.controller.js +48 -0
  8. package/dist/controllers/operations-projects.controller.js.map +1 -1
  9. package/dist/controllers/operations-reports.controller.d.ts +1 -1
  10. package/dist/controllers/operations-tasks.controller.d.ts +34 -9
  11. package/dist/controllers/operations-tasks.controller.d.ts.map +1 -1
  12. package/dist/controllers/operations-tasks.controller.js +43 -32
  13. package/dist/controllers/operations-tasks.controller.js.map +1 -1
  14. package/dist/controllers/operations-timesheets.controller.d.ts +9 -9
  15. package/dist/dashboard/components/DashboardLayout.d.ts +30 -0
  16. package/dist/dashboard/components/DashboardLayout.d.ts.map +1 -0
  17. package/dist/dashboard/components/DashboardLayout.js +87 -0
  18. package/dist/dashboard/components/DashboardLayout.js.map +1 -0
  19. package/dist/dashboard/components/widget-registry.d.ts +23 -0
  20. package/dist/dashboard/components/widget-registry.d.ts.map +1 -0
  21. package/dist/dashboard/components/widget-registry.js +245 -0
  22. package/dist/dashboard/components/widget-registry.js.map +1 -0
  23. package/dist/dashboard/hooks/useDashboardData.d.ts +20 -0
  24. package/dist/dashboard/hooks/useDashboardData.d.ts.map +1 -0
  25. package/dist/dashboard/hooks/useDashboardData.js +24 -0
  26. package/dist/dashboard/hooks/useDashboardData.js.map +1 -0
  27. package/dist/dashboard/types/widgets.types.d.ts +233 -0
  28. package/dist/dashboard/types/widgets.types.d.ts.map +1 -0
  29. package/dist/dashboard/types/widgets.types.js +6 -0
  30. package/dist/dashboard/types/widgets.types.js.map +1 -0
  31. package/dist/dashboard/widgets/CapacityDistribution.d.ts +23 -0
  32. package/dist/dashboard/widgets/CapacityDistribution.d.ts.map +1 -0
  33. package/dist/dashboard/widgets/CapacityDistribution.js +11 -0
  34. package/dist/dashboard/widgets/CapacityDistribution.js.map +1 -0
  35. package/dist/dashboard/widgets/EffortByProject.d.ts +22 -0
  36. package/dist/dashboard/widgets/EffortByProject.d.ts.map +1 -0
  37. package/dist/dashboard/widgets/EffortByProject.js +11 -0
  38. package/dist/dashboard/widgets/EffortByProject.js.map +1 -0
  39. package/dist/dashboard/widgets/HeadcountByArea.d.ts +24 -0
  40. package/dist/dashboard/widgets/HeadcountByArea.d.ts.map +1 -0
  41. package/dist/dashboard/widgets/HeadcountByArea.js +11 -0
  42. package/dist/dashboard/widgets/HeadcountByArea.js.map +1 -0
  43. package/dist/dashboard/widgets/ManagedProjectsStatus.d.ts +18 -0
  44. package/dist/dashboard/widgets/ManagedProjectsStatus.d.ts.map +1 -0
  45. package/dist/dashboard/widgets/ManagedProjectsStatus.js +12 -0
  46. package/dist/dashboard/widgets/ManagedProjectsStatus.js.map +1 -0
  47. package/dist/dashboard/widgets/MyHoursPeriodKpi.d.ts +22 -0
  48. package/dist/dashboard/widgets/MyHoursPeriodKpi.d.ts.map +1 -0
  49. package/dist/dashboard/widgets/MyHoursPeriodKpi.js +12 -0
  50. package/dist/dashboard/widgets/MyHoursPeriodKpi.js.map +1 -0
  51. package/dist/dashboard/widgets/MyOpenRequestsKpi.d.ts +19 -0
  52. package/dist/dashboard/widgets/MyOpenRequestsKpi.d.ts.map +1 -0
  53. package/dist/dashboard/widgets/MyOpenRequestsKpi.js +17 -0
  54. package/dist/dashboard/widgets/MyOpenRequestsKpi.js.map +1 -0
  55. package/dist/dashboard/widgets/MyPendingRequestsList.d.ts +23 -0
  56. package/dist/dashboard/widgets/MyPendingRequestsList.d.ts.map +1 -0
  57. package/dist/dashboard/widgets/MyPendingRequestsList.js +14 -0
  58. package/dist/dashboard/widgets/MyPendingRequestsList.js.map +1 -0
  59. package/dist/dashboard/widgets/MyProjectAllocationsKpi.d.ts +22 -0
  60. package/dist/dashboard/widgets/MyProjectAllocationsKpi.d.ts.map +1 -0
  61. package/dist/dashboard/widgets/MyProjectAllocationsKpi.js +11 -0
  62. package/dist/dashboard/widgets/MyProjectAllocationsKpi.js.map +1 -0
  63. package/dist/dashboard/widgets/MyQuickActions.d.ts +23 -0
  64. package/dist/dashboard/widgets/MyQuickActions.d.ts.map +1 -0
  65. package/dist/dashboard/widgets/MyQuickActions.js +18 -0
  66. package/dist/dashboard/widgets/MyQuickActions.js.map +1 -0
  67. package/dist/dashboard/widgets/MyRelevantDeadlines.d.ts +23 -0
  68. package/dist/dashboard/widgets/MyRelevantDeadlines.d.ts.map +1 -0
  69. package/dist/dashboard/widgets/MyRelevantDeadlines.js +22 -0
  70. package/dist/dashboard/widgets/MyRelevantDeadlines.js.map +1 -0
  71. package/dist/dashboard/widgets/MyTimesheetStatusKpi.d.ts +17 -0
  72. package/dist/dashboard/widgets/MyTimesheetStatusKpi.d.ts.map +1 -0
  73. package/dist/dashboard/widgets/MyTimesheetStatusKpi.js +11 -0
  74. package/dist/dashboard/widgets/MyTimesheetStatusKpi.js.map +1 -0
  75. package/dist/dashboard/widgets/MyWeeklyJourney.d.ts +21 -0
  76. package/dist/dashboard/widgets/MyWeeklyJourney.d.ts.map +1 -0
  77. package/dist/dashboard/widgets/MyWeeklyJourney.js +19 -0
  78. package/dist/dashboard/widgets/MyWeeklyJourney.js.map +1 -0
  79. package/dist/dashboard/widgets/PortfolioCostsKpi.d.ts +19 -0
  80. package/dist/dashboard/widgets/PortfolioCostsKpi.d.ts.map +1 -0
  81. package/dist/dashboard/widgets/PortfolioCostsKpi.js +12 -0
  82. package/dist/dashboard/widgets/PortfolioCostsKpi.js.map +1 -0
  83. package/dist/dashboard/widgets/PortfolioEffortKpi.d.ts +18 -0
  84. package/dist/dashboard/widgets/PortfolioEffortKpi.d.ts.map +1 -0
  85. package/dist/dashboard/widgets/PortfolioEffortKpi.js +8 -0
  86. package/dist/dashboard/widgets/PortfolioEffortKpi.js.map +1 -0
  87. package/dist/dashboard/widgets/PortfolioProjectsKpi.d.ts +22 -0
  88. package/dist/dashboard/widgets/PortfolioProjectsKpi.d.ts.map +1 -0
  89. package/dist/dashboard/widgets/PortfolioProjectsKpi.js +56 -0
  90. package/dist/dashboard/widgets/PortfolioProjectsKpi.js.map +1 -0
  91. package/dist/dashboard/widgets/PortfolioRiskKpi.d.ts +19 -0
  92. package/dist/dashboard/widgets/PortfolioRiskKpi.d.ts.map +1 -0
  93. package/dist/dashboard/widgets/PortfolioRiskKpi.js +11 -0
  94. package/dist/dashboard/widgets/PortfolioRiskKpi.js.map +1 -0
  95. package/dist/dashboard/widgets/ProjectStatusOverview.d.ts +19 -0
  96. package/dist/dashboard/widgets/ProjectStatusOverview.d.ts.map +1 -0
  97. package/dist/dashboard/widgets/ProjectStatusOverview.js +18 -0
  98. package/dist/dashboard/widgets/ProjectStatusOverview.js.map +1 -0
  99. package/dist/dashboard/widgets/StrategicDeadlines.d.ts +24 -0
  100. package/dist/dashboard/widgets/StrategicDeadlines.d.ts.map +1 -0
  101. package/dist/dashboard/widgets/StrategicDeadlines.js +22 -0
  102. package/dist/dashboard/widgets/StrategicDeadlines.js.map +1 -0
  103. package/dist/dashboard/widgets/TeamApprovalQueue.d.ts +24 -0
  104. package/dist/dashboard/widgets/TeamApprovalQueue.d.ts.map +1 -0
  105. package/dist/dashboard/widgets/TeamApprovalQueue.js +12 -0
  106. package/dist/dashboard/widgets/TeamApprovalQueue.js.map +1 -0
  107. package/dist/dashboard/widgets/TeamCapacityKpi.d.ts +18 -0
  108. package/dist/dashboard/widgets/TeamCapacityKpi.d.ts.map +1 -0
  109. package/dist/dashboard/widgets/TeamCapacityKpi.js +19 -0
  110. package/dist/dashboard/widgets/TeamCapacityKpi.js.map +1 -0
  111. package/dist/dashboard/widgets/TeamHeadcountKpi.d.ts +22 -0
  112. package/dist/dashboard/widgets/TeamHeadcountKpi.d.ts.map +1 -0
  113. package/dist/dashboard/widgets/TeamHeadcountKpi.js +56 -0
  114. package/dist/dashboard/widgets/TeamHeadcountKpi.js.map +1 -0
  115. package/dist/dashboard/widgets/TeamHoursKpi.d.ts +19 -0
  116. package/dist/dashboard/widgets/TeamHoursKpi.d.ts.map +1 -0
  117. package/dist/dashboard/widgets/TeamHoursKpi.js +13 -0
  118. package/dist/dashboard/widgets/TeamHoursKpi.js.map +1 -0
  119. package/dist/dashboard/widgets/TeamPendingApprovalsKpi.d.ts +20 -0
  120. package/dist/dashboard/widgets/TeamPendingApprovalsKpi.d.ts.map +1 -0
  121. package/dist/dashboard/widgets/TeamPendingApprovalsKpi.js +11 -0
  122. package/dist/dashboard/widgets/TeamPendingApprovalsKpi.js.map +1 -0
  123. package/dist/dashboard/widgets/TeamUtilizationOverview.d.ts +18 -0
  124. package/dist/dashboard/widgets/TeamUtilizationOverview.d.ts.map +1 -0
  125. package/dist/dashboard/widgets/TeamUtilizationOverview.js +17 -0
  126. package/dist/dashboard/widgets/TeamUtilizationOverview.js.map +1 -0
  127. package/dist/dashboard/widgets/TeamWorkloadAlerts.d.ts +24 -0
  128. package/dist/dashboard/widgets/TeamWorkloadAlerts.d.ts.map +1 -0
  129. package/dist/dashboard/widgets/TeamWorkloadAlerts.js +19 -0
  130. package/dist/dashboard/widgets/TeamWorkloadAlerts.js.map +1 -0
  131. package/dist/dashboard/widgets/index.d.ts +24 -0
  132. package/dist/dashboard/widgets/index.d.ts.map +1 -0
  133. package/dist/dashboard/widgets/index.js +54 -0
  134. package/dist/dashboard/widgets/index.js.map +1 -0
  135. package/dist/dto/create-collaborator.dto.d.ts +0 -1
  136. package/dist/dto/create-collaborator.dto.d.ts.map +1 -1
  137. package/dist/dto/create-collaborator.dto.js +0 -6
  138. package/dist/dto/create-collaborator.dto.js.map +1 -1
  139. package/dist/index.d.ts +2 -0
  140. package/dist/index.d.ts.map +1 -1
  141. package/dist/index.js +2 -0
  142. package/dist/index.js.map +1 -1
  143. package/dist/operations.controller.d.ts +42 -0
  144. package/dist/operations.controller.d.ts.map +1 -1
  145. package/dist/operations.service.d.ts +182 -268
  146. package/dist/operations.service.d.ts.map +1 -1
  147. package/dist/operations.service.js +2147 -1337
  148. package/dist/operations.service.js.map +1 -1
  149. package/dist/operations.service.spec.js +345 -174
  150. package/dist/operations.service.spec.js.map +1 -1
  151. package/hedhog/data/dashboard_component.yaml +66 -0
  152. package/hedhog/data/dashboard_item.yaml +25 -25
  153. package/hedhog/data/route.yaml +61 -0
  154. package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +39 -99
  155. package/hedhog/frontend/app/_components/collaborator-picker.tsx.ejs +158 -0
  156. package/hedhog/frontend/app/_components/my-project-summary-screen.tsx.ejs +314 -116
  157. package/hedhog/frontend/app/_components/project-assignments-tab.tsx.ejs +434 -449
  158. package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +289 -412
  159. package/hedhog/frontend/app/_components/project-file-attachments.tsx.ejs +371 -0
  160. package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +426 -374
  161. package/hedhog/frontend/app/_components/task-detail-sheet.tsx.ejs +803 -581
  162. package/hedhog/frontend/app/_components/task-file-attachments.tsx.ejs +4 -1
  163. package/hedhog/frontend/app/_components/task-form-fields.tsx.ejs +406 -0
  164. package/hedhog/frontend/app/_components/task-form-sheet.tsx.ejs +629 -784
  165. package/hedhog/frontend/app/_components/task-info-display.tsx.ejs +137 -0
  166. package/hedhog/frontend/app/_components/timesheet-entry-create-sheet.tsx.ejs +306 -0
  167. package/hedhog/frontend/app/_lib/api.ts.ejs +480 -476
  168. package/hedhog/frontend/app/_lib/types.ts.ejs +66 -5
  169. package/hedhog/frontend/app/_lib/utils/format.ts.ejs +0 -2
  170. package/hedhog/frontend/app/_lib/utils/task-ui.ts.ejs +43 -0
  171. package/hedhog/frontend/app/approvals/page.tsx.ejs +6 -1
  172. package/hedhog/frontend/app/collaborator-types/page.tsx.ejs +6 -1
  173. package/hedhog/frontend/app/collaborators/page.tsx.ejs +59 -8
  174. package/hedhog/frontend/app/contracts/page.tsx.ejs +29 -8
  175. package/hedhog/frontend/app/dashboard/widgets/CapacityDistribution.tsx.ejs +84 -0
  176. package/hedhog/frontend/app/dashboard/widgets/EffortByProject.tsx.ejs +85 -0
  177. package/hedhog/frontend/app/dashboard/widgets/HeadcountByArea.tsx.ejs +101 -0
  178. package/hedhog/frontend/app/dashboard/widgets/ManagedProjectsStatus.tsx.ejs +113 -0
  179. package/hedhog/frontend/app/dashboard/widgets/MyHoursPeriodKpi.tsx.ejs +87 -0
  180. package/hedhog/frontend/app/dashboard/widgets/MyOpenRequestsKpi.tsx.ejs +97 -0
  181. package/hedhog/frontend/app/dashboard/widgets/MyPendingRequestsList.tsx.ejs +99 -0
  182. package/hedhog/frontend/app/dashboard/widgets/MyProjectAllocationsKpi.tsx.ejs +78 -0
  183. package/hedhog/frontend/app/dashboard/widgets/MyQuickActions.tsx.ejs +130 -0
  184. package/hedhog/frontend/app/dashboard/widgets/MyRelevantDeadlines.tsx.ejs +144 -0
  185. package/hedhog/frontend/app/dashboard/widgets/MyTimesheetStatusKpi.tsx.ejs +78 -0
  186. package/hedhog/frontend/app/dashboard/widgets/MyWeeklyJourney.tsx.ejs +99 -0
  187. package/hedhog/frontend/app/dashboard/widgets/PortfolioCostsKpi.tsx.ejs +112 -0
  188. package/hedhog/frontend/app/dashboard/widgets/PortfolioEffortKpi.tsx.ejs +93 -0
  189. package/hedhog/frontend/app/dashboard/widgets/PortfolioProjectsKpi.tsx.ejs +96 -0
  190. package/hedhog/frontend/app/dashboard/widgets/PortfolioRiskKpi.tsx.ejs +115 -0
  191. package/hedhog/frontend/app/dashboard/widgets/ProjectStatusOverview.tsx.ejs +120 -0
  192. package/hedhog/frontend/app/dashboard/widgets/StrategicDeadlines.tsx.ejs +146 -0
  193. package/hedhog/frontend/app/dashboard/widgets/TeamApprovalQueue.tsx.ejs +108 -0
  194. package/hedhog/frontend/app/dashboard/widgets/TeamCapacityKpi.tsx.ejs +97 -0
  195. package/hedhog/frontend/app/dashboard/widgets/TeamHeadcountKpi.tsx.ejs +100 -0
  196. package/hedhog/frontend/app/dashboard/widgets/TeamHoursKpi.tsx.ejs +104 -0
  197. package/hedhog/frontend/app/dashboard/widgets/TeamPendingApprovalsKpi.tsx.ejs +110 -0
  198. package/hedhog/frontend/app/dashboard/widgets/TeamUtilizationOverview.tsx.ejs +115 -0
  199. package/hedhog/frontend/app/dashboard/widgets/TeamWorkloadAlerts.tsx.ejs +117 -0
  200. package/hedhog/frontend/app/dashboard/widgets/index.ts.ejs +26 -0
  201. package/hedhog/frontend/app/departments/page.tsx.ejs +6 -1
  202. package/hedhog/frontend/app/my-projects/page.tsx.ejs +14 -10
  203. package/hedhog/frontend/app/my-tasks/page.tsx.ejs +328 -105
  204. package/hedhog/frontend/app/project-cost-categories/page.tsx.ejs +58 -52
  205. package/hedhog/frontend/app/project-cost-types/page.tsx.ejs +58 -51
  206. package/hedhog/frontend/app/projects/page.tsx.ejs +376 -30
  207. package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +6 -1
  208. package/hedhog/frontend/app/time-off/page.tsx.ejs +6 -1
  209. package/hedhog/frontend/app/timesheets/page.tsx.ejs +10 -4
  210. package/hedhog/frontend/messages/en.json +238 -46
  211. package/hedhog/frontend/messages/operations/en.json +61 -52
  212. package/hedhog/frontend/messages/operations/pt.json +59 -43
  213. package/hedhog/frontend/messages/pt.json +238 -46
  214. package/hedhog/frontend/widgets/capacity-distribution.tsx.ejs +17 -0
  215. package/hedhog/frontend/widgets/effort-by-project.tsx.ejs +17 -0
  216. package/hedhog/frontend/widgets/headcount-by-area.tsx.ejs +17 -0
  217. package/hedhog/frontend/widgets/index.ts.ejs +25 -0
  218. package/hedhog/frontend/widgets/managed-projects-status.tsx.ejs +17 -0
  219. package/hedhog/frontend/widgets/my-hours-period-kpi.tsx.ejs +17 -0
  220. package/hedhog/frontend/widgets/my-open-requests-kpi.tsx.ejs +17 -0
  221. package/hedhog/frontend/widgets/my-pending-requests-list.tsx.ejs +17 -0
  222. package/hedhog/frontend/widgets/my-project-allocations-kpi.tsx.ejs +17 -0
  223. package/hedhog/frontend/widgets/my-quick-actions.tsx.ejs +17 -0
  224. package/hedhog/frontend/widgets/my-relevant-deadlines.tsx.ejs +17 -0
  225. package/hedhog/frontend/widgets/my-timesheet-status-kpi.tsx.ejs +17 -0
  226. package/hedhog/frontend/widgets/my-weekly-journey.tsx.ejs +17 -0
  227. package/hedhog/frontend/widgets/portfolio-costs-kpi.tsx.ejs +17 -0
  228. package/hedhog/frontend/widgets/portfolio-effort-kpi.tsx.ejs +17 -0
  229. package/hedhog/frontend/widgets/portfolio-projects-kpi.tsx.ejs +17 -0
  230. package/hedhog/frontend/widgets/portfolio-risk-kpi.tsx.ejs +17 -0
  231. package/hedhog/frontend/widgets/project-status-overview.tsx.ejs +17 -0
  232. package/hedhog/frontend/widgets/shared-operations-widget.tsx.ejs +170 -0
  233. package/hedhog/frontend/widgets/strategic-deadlines.tsx.ejs +17 -0
  234. package/hedhog/frontend/widgets/team-approval-queue.tsx.ejs +17 -0
  235. package/hedhog/frontend/widgets/team-capacity-kpi.tsx.ejs +17 -0
  236. package/hedhog/frontend/widgets/team-headcount-kpi.tsx.ejs +17 -0
  237. package/hedhog/frontend/widgets/team-hours-kpi.tsx.ejs +17 -0
  238. package/hedhog/frontend/widgets/team-pending-approvals-kpi.tsx.ejs +17 -0
  239. package/hedhog/frontend/widgets/team-utilization-overview.tsx.ejs +17 -0
  240. package/hedhog/frontend/widgets/team-workload-alerts.tsx.ejs +17 -0
  241. package/hedhog/table/operations_collaborator.yaml +8 -13
  242. package/hedhog/table/operations_project.yaml +1 -1
  243. package/hedhog/table/operations_project_file.yaml +23 -0
  244. package/hedhog/table/operations_task.yaml +76 -69
  245. package/hedhog/table/operations_task_activity.yaml +51 -0
  246. package/package.json +6 -5
  247. package/src/controllers/operations-projects.controller.ts +41 -8
  248. package/src/controllers/operations-tasks.controller.ts +156 -166
  249. package/src/dashboard/README.md +214 -0
  250. package/src/dashboard/components/DashboardLayout.tsx +131 -0
  251. package/src/dashboard/components/widget-registry.ts +255 -0
  252. package/src/dashboard/hooks/useDashboardData.ts +29 -0
  253. package/src/dashboard/types/widgets.types.ts +237 -0
  254. package/src/dashboard/widgets/CapacityDistribution.tsx +56 -0
  255. package/src/dashboard/widgets/EffortByProject.tsx +51 -0
  256. package/src/dashboard/widgets/HeadcountByArea.tsx +57 -0
  257. package/src/dashboard/widgets/ManagedProjectsStatus.tsx +53 -0
  258. package/src/dashboard/widgets/MyHoursPeriodKpi.tsx +87 -0
  259. package/src/dashboard/widgets/MyOpenRequestsKpi.tsx +51 -0
  260. package/src/dashboard/widgets/MyPendingRequestsList.tsx +63 -0
  261. package/src/dashboard/widgets/MyProjectAllocationsKpi.tsx +57 -0
  262. package/src/dashboard/widgets/MyQuickActions.tsx +62 -0
  263. package/src/dashboard/widgets/MyRelevantDeadlines.tsx +84 -0
  264. package/src/dashboard/widgets/MyTimesheetStatusKpi.tsx +65 -0
  265. package/src/dashboard/widgets/MyWeeklyJourney.tsx +57 -0
  266. package/src/dashboard/widgets/PortfolioCostsKpi.tsx +48 -0
  267. package/src/dashboard/widgets/PortfolioEffortKpi.tsx +41 -0
  268. package/src/dashboard/widgets/PortfolioRiskKpi.tsx +50 -0
  269. package/src/dashboard/widgets/ProjectStatusOverview.tsx +52 -0
  270. package/src/dashboard/widgets/StrategicDeadlines.tsx +93 -0
  271. package/src/dashboard/widgets/TeamApprovalQueue.tsx +70 -0
  272. package/src/dashboard/widgets/TeamCapacityKpi.tsx +50 -0
  273. package/src/dashboard/widgets/TeamHoursKpi.tsx +51 -0
  274. package/src/dashboard/widgets/TeamPendingApprovalsKpi.tsx +53 -0
  275. package/src/dashboard/widgets/TeamUtilizationOverview.tsx +62 -0
  276. package/src/dashboard/widgets/TeamWorkloadAlerts.tsx +81 -0
  277. package/src/dashboard/widgets/index.ts +26 -0
  278. package/src/dto/create-collaborator.dto.ts +4 -11
  279. package/src/index.ts +3 -0
  280. package/src/operations.service.spec.ts +988 -764
  281. package/src/operations.service.ts +4277 -2535
@@ -0,0 +1,137 @@
1
+ 'use client';
2
+
3
+ import { AlarmClock, Calendar, History, Tag, User } from 'lucide-react';
4
+ import { useTranslations } from 'next-intl';
5
+ import type { ReactNode } from 'react';
6
+ import { formatDate } from '../_lib/utils/format';
7
+ import { formatDurationMinutes, getInitials } from '../_lib/utils/task-ui';
8
+ import type { TaskDetailSheetData } from './task-detail-sheet';
9
+
10
+ type Props = {
11
+ task: TaskDetailSheetData;
12
+ avatarSrc: string | null;
13
+ doingMinutes: number;
14
+ getSettingValue: (key: string) => unknown;
15
+ currentLocaleCode: string;
16
+ footer?: ReactNode;
17
+ };
18
+
19
+ export function TaskInfoDisplay({
20
+ task,
21
+ avatarSrc,
22
+ doingMinutes,
23
+ getSettingValue,
24
+ currentLocaleCode,
25
+ footer,
26
+ }: Props) {
27
+ const commonT = useTranslations('operations.Common');
28
+ const detailT = useTranslations('operations.ProjectDetailsPage');
29
+
30
+ return (
31
+ <div className="flex flex-col gap-5">
32
+ {task.description ? (
33
+ <div>
34
+ <p className="mb-1 text-xs font-medium uppercase tracking-wide text-muted-foreground">
35
+ {detailT('taskForm.descriptionLabel')}
36
+ </p>
37
+ <p className="text-sm leading-relaxed">{task.description}</p>
38
+ </div>
39
+ ) : null}
40
+
41
+ {task.dueDate || task.estimateHours != null ? (
42
+ <div className="grid grid-cols-2 gap-3">
43
+ {task.dueDate ? (
44
+ <div className="flex items-start gap-2 text-sm">
45
+ <Calendar className="mt-0.5 size-4 shrink-0 text-muted-foreground" />
46
+ <div>
47
+ <p className="text-[11px] text-muted-foreground">
48
+ {detailT('taskForm.deadlineLabel')}
49
+ </p>
50
+ <p className="font-medium">
51
+ {formatDate(task.dueDate, getSettingValue, currentLocaleCode)}
52
+ </p>
53
+ </div>
54
+ </div>
55
+ ) : null}
56
+ {task.estimateHours != null ? (
57
+ <div className="flex items-start gap-2 text-sm">
58
+ <AlarmClock className="mt-0.5 size-4 shrink-0 text-muted-foreground" />
59
+ <div>
60
+ <p className="text-[11px] text-muted-foreground">
61
+ {detailT('taskForm.estimateLabel')}
62
+ </p>
63
+ <p className="font-medium">{task.estimateHours}h</p>
64
+ </div>
65
+ </div>
66
+ ) : null}
67
+ </div>
68
+ ) : null}
69
+
70
+ <div className="flex items-start gap-2 text-sm">
71
+ <History className="mt-0.5 size-4 shrink-0 text-muted-foreground" />
72
+ <div>
73
+ <p className="text-[11px] text-muted-foreground">
74
+ {detailT('taskForm.doingTimeLabel')}
75
+ </p>
76
+ <p className="font-medium">{formatDurationMinutes(doingMinutes)}</p>
77
+ </div>
78
+ </div>
79
+
80
+ {task.tags ? (
81
+ <div>
82
+ <div className="mb-1.5 flex items-center gap-1.5 text-xs font-medium uppercase tracking-wide text-muted-foreground">
83
+ <Tag className="size-3" />
84
+ {detailT('taskForm.tagsLabel')}
85
+ </div>
86
+ <div className="flex flex-wrap gap-1.5">
87
+ {task.tags.split(',').map((tag) => (
88
+ <span
89
+ key={tag.trim()}
90
+ className="rounded-md bg-muted px-2 py-0.5 text-xs text-muted-foreground"
91
+ >
92
+ {tag.trim()}
93
+ </span>
94
+ ))}
95
+ </div>
96
+ </div>
97
+ ) : null}
98
+
99
+ {task.assigneeName ? (
100
+ <div>
101
+ <div className="mb-1.5 flex items-center gap-1.5 text-xs font-medium uppercase tracking-wide text-muted-foreground">
102
+ <User className="size-3" />
103
+ {commonT('labels.collaborator')}
104
+ </div>
105
+ <div className="flex items-center gap-2.5">
106
+ <div className="flex size-8 shrink-0 items-center justify-center overflow-hidden rounded-full bg-muted text-xs font-semibold uppercase text-muted-foreground ring-1 ring-border">
107
+ {avatarSrc ? (
108
+ // eslint-disable-next-line @next/next/no-img-element
109
+ <img
110
+ src={avatarSrc}
111
+ alt={task.assigneeName}
112
+ className="size-full object-cover"
113
+ />
114
+ ) : (
115
+ getInitials(task.assigneeName)
116
+ )}
117
+ </div>
118
+ <span className="text-sm">{task.assigneeName}</span>
119
+ </div>
120
+ </div>
121
+ ) : null}
122
+
123
+ {task.projectName || task.projectCode ? (
124
+ <div className="rounded-lg border bg-muted/20 px-3 py-2.5">
125
+ <p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
126
+ {commonT('labels.project')}
127
+ </p>
128
+ <p className="mt-0.5 text-sm font-medium">
129
+ {[task.projectName, task.projectCode].filter(Boolean).join(' • ')}
130
+ </p>
131
+ </div>
132
+ ) : null}
133
+
134
+ {footer ? <div className="border-t pt-5">{footer}</div> : null}
135
+ </div>
136
+ );
137
+ }
@@ -0,0 +1,306 @@
1
+ 'use client';
2
+
3
+ import {
4
+ Form,
5
+ FormControl,
6
+ FormField,
7
+ FormItem,
8
+ FormLabel,
9
+ FormMessage,
10
+ } from '@/components/ui/form';
11
+ import { FormActions } from '@/components/ui/form-actions';
12
+ import { Input } from '@/components/ui/input';
13
+ import {
14
+ Sheet,
15
+ SheetContent,
16
+ SheetDescription,
17
+ SheetHeader,
18
+ SheetTitle,
19
+ } from '@/components/ui/sheet';
20
+ import { Textarea } from '@/components/ui/textarea';
21
+ import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
22
+ import { useApp } from '@hed-hog/next-app-provider';
23
+ import { zodResolver } from '@hookform/resolvers/zod';
24
+ import { Timer } from 'lucide-react';
25
+ import { useTranslations } from 'next-intl';
26
+ import { useEffect, useMemo } from 'react';
27
+ import { useForm } from 'react-hook-form';
28
+ import { z } from 'zod';
29
+
30
+ import { getOperationsErrorMessage, mutateOperations } from '../_lib/api';
31
+ import { trimToNull } from '../_lib/utils/forms';
32
+
33
+ type TimesheetEntryCreateSheetProps = {
34
+ open: boolean;
35
+ onOpenChange: (open: boolean) => void;
36
+ project: {
37
+ id: number;
38
+ label: string;
39
+ projectAssignmentId?: number | null;
40
+ } | null;
41
+ task: {
42
+ id: number;
43
+ label: string;
44
+ } | null;
45
+ onCreated?: () => void;
46
+ };
47
+
48
+ type EntryFormValues = {
49
+ workDate: string;
50
+ duration?: number;
51
+ unit: 'hours' | 'minutes';
52
+ description: string;
53
+ };
54
+
55
+ const getTodayDate = () => {
56
+ const now = new Date();
57
+ return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
58
+ };
59
+
60
+ const buildDefaultValues = (): EntryFormValues => ({
61
+ workDate: getTodayDate(),
62
+ duration: undefined,
63
+ unit: 'hours',
64
+ description: '',
65
+ });
66
+
67
+ const positiveNumberField = (message: string) =>
68
+ z.preprocess(
69
+ (value) => {
70
+ if (value === '' || value === null || value === undefined) {
71
+ return undefined;
72
+ }
73
+
74
+ if (typeof value === 'number') {
75
+ return value;
76
+ }
77
+
78
+ const parsed = Number(value);
79
+ return Number.isNaN(parsed) ? value : parsed;
80
+ },
81
+ z.number({ required_error: message }).positive(message)
82
+ );
83
+
84
+ export function TimesheetEntryCreateSheet({
85
+ open,
86
+ onOpenChange,
87
+ project,
88
+ task,
89
+ onCreated,
90
+ }: TimesheetEntryCreateSheetProps) {
91
+ const t = useTranslations('operations.TimesheetsPage');
92
+ const commonT = useTranslations('operations.Common');
93
+ const { request, showToastHandler } = useApp();
94
+
95
+ const entrySchema = useMemo(
96
+ () =>
97
+ z.object({
98
+ workDate: z.string().min(1, t('messages.requiredFields')),
99
+ duration: positiveNumberField(t('messages.entryValidation')),
100
+ unit: z.enum(['hours', 'minutes']),
101
+ description: z
102
+ .string()
103
+ .trim()
104
+ .max(500, t('sheet.validation.descriptionMaxLength'))
105
+ .optional()
106
+ .or(z.literal('')),
107
+ }),
108
+ [t]
109
+ );
110
+
111
+ const form = useForm<EntryFormValues>({
112
+ resolver: zodResolver(entrySchema),
113
+ defaultValues: buildDefaultValues(),
114
+ });
115
+
116
+ const unitValue = form.watch('unit');
117
+
118
+ useEffect(() => {
119
+ if (!open) {
120
+ form.reset(buildDefaultValues());
121
+ }
122
+ }, [form, open]);
123
+
124
+ const handleSubmit = async (values: EntryFormValues) => {
125
+ if (!project?.id || !task?.id) {
126
+ showToastHandler?.('error', t('messages.requiredFields'));
127
+ return;
128
+ }
129
+
130
+ try {
131
+ await mutateOperations(request, '/operations/timesheet-entries', 'POST', {
132
+ projectId: project.id,
133
+ taskId: task.id,
134
+ workDate: values.workDate,
135
+ duration: values.duration,
136
+ unit: values.unit,
137
+ description: trimToNull(values.description),
138
+ });
139
+
140
+ showToastHandler?.('success', t('messages.saveSuccess'));
141
+ form.reset(buildDefaultValues());
142
+ onOpenChange(false);
143
+ onCreated?.();
144
+ } catch (error) {
145
+ showToastHandler?.(
146
+ 'error',
147
+ getOperationsErrorMessage(error, t('messages.saveError'))
148
+ );
149
+ }
150
+ };
151
+
152
+ const handleOpenChange = (nextOpen: boolean) => {
153
+ if (form.formState.isSubmitting && !nextOpen) {
154
+ return;
155
+ }
156
+
157
+ onOpenChange(nextOpen);
158
+ };
159
+
160
+ return (
161
+ <Sheet open={open} onOpenChange={handleOpenChange}>
162
+ <SheetContent className="flex h-full w-full flex-col gap-0 overflow-hidden p-0 sm:max-w-xl">
163
+ <SheetHeader className="border-b px-4 py-4 text-left">
164
+ <div className="flex items-start gap-3">
165
+ <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-cyan-500/10 text-cyan-600">
166
+ <Timer className="size-5" />
167
+ </div>
168
+
169
+ <div className="space-y-1">
170
+ <SheetTitle>{t('sheet.title')}</SheetTitle>
171
+ <SheetDescription>{t('sheet.description')}</SheetDescription>
172
+ </div>
173
+ </div>
174
+ </SheetHeader>
175
+
176
+ <Form {...form}>
177
+ <form
178
+ onSubmit={form.handleSubmit(handleSubmit)}
179
+ className="flex min-h-0 flex-1 flex-col"
180
+ >
181
+ <div className="flex-1 space-y-4 overflow-y-auto px-4 py-4">
182
+ <div className="rounded-lg border bg-muted/30 p-3">
183
+ <div className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
184
+ {commonT('labels.project')}
185
+ </div>
186
+ <div className="mt-1 text-sm font-medium text-foreground">
187
+ {project?.label ?? commonT('labels.notAssigned')}
188
+ </div>
189
+ </div>
190
+
191
+ <div className="rounded-lg border bg-muted/30 p-3">
192
+ <div className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
193
+ {commonT('labels.task')}
194
+ </div>
195
+ <div className="mt-1 text-sm font-medium text-foreground">
196
+ {task?.label ?? commonT('labels.notAssigned')}
197
+ </div>
198
+ </div>
199
+
200
+ <div className="grid gap-4 md:grid-cols-[1fr_1fr_220px]">
201
+ <FormField
202
+ control={form.control}
203
+ name="workDate"
204
+ render={({ field }) => (
205
+ <FormItem>
206
+ <FormLabel>{commonT('labels.workDate')}</FormLabel>
207
+ <FormControl>
208
+ <Input type="date" {...field} />
209
+ </FormControl>
210
+ <FormMessage />
211
+ </FormItem>
212
+ )}
213
+ />
214
+
215
+ <FormField
216
+ control={form.control}
217
+ name="duration"
218
+ render={({ field }) => (
219
+ <FormItem>
220
+ <FormLabel>{t('sheet.fields.duration')}</FormLabel>
221
+ <FormControl>
222
+ <Input
223
+ type="number"
224
+ min="0"
225
+ step={unitValue === 'minutes' ? '5' : '0.25'}
226
+ placeholder={t('sheet.placeholders.duration')}
227
+ value={field.value ?? ''}
228
+ onChange={(event) => {
229
+ const nextValue = event.target.value;
230
+ field.onChange(
231
+ nextValue === '' ? undefined : Number(nextValue)
232
+ );
233
+ }}
234
+ />
235
+ </FormControl>
236
+ <FormMessage />
237
+ </FormItem>
238
+ )}
239
+ />
240
+
241
+ <FormField
242
+ control={form.control}
243
+ name="unit"
244
+ render={({ field }) => (
245
+ <FormItem>
246
+ <FormLabel>{t('sheet.fields.unit')}</FormLabel>
247
+ <FormControl>
248
+ <ToggleGroup
249
+ type="single"
250
+ value={field.value}
251
+ className="w-full"
252
+ onValueChange={(value) => {
253
+ if (value === 'hours' || value === 'minutes') {
254
+ field.onChange(value);
255
+ }
256
+ }}
257
+ >
258
+ <ToggleGroupItem value="hours" className="flex-1">
259
+ {t('sheet.fields.hours')}
260
+ </ToggleGroupItem>
261
+ <ToggleGroupItem value="minutes" className="flex-1">
262
+ {t('sheet.fields.minutes')}
263
+ </ToggleGroupItem>
264
+ </ToggleGroup>
265
+ </FormControl>
266
+ <FormMessage />
267
+ </FormItem>
268
+ )}
269
+ />
270
+ </div>
271
+
272
+ <FormField
273
+ control={form.control}
274
+ name="description"
275
+ render={({ field }) => (
276
+ <FormItem>
277
+ <FormLabel>{commonT('labels.description')}</FormLabel>
278
+ <FormControl>
279
+ <Textarea
280
+ {...field}
281
+ rows={4}
282
+ placeholder={t('sheet.placeholders.description')}
283
+ />
284
+ </FormControl>
285
+ <FormMessage />
286
+ </FormItem>
287
+ )}
288
+ />
289
+ </div>
290
+
291
+ <FormActions
292
+ sheet
293
+ onCancel={() => onOpenChange(false)}
294
+ cancelLabel={commonT('actions.cancel')}
295
+ submitType="submit"
296
+ submitLabel={commonT('actions.submit')}
297
+ submitDisabled={
298
+ form.formState.isSubmitting || !project?.id || !task?.id
299
+ }
300
+ />
301
+ </form>
302
+ </Form>
303
+ </SheetContent>
304
+ </Sheet>
305
+ );
306
+ }