@burdenoff/microfe-movethewheels 2026.930.5 → 2026.1010.1

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 (373) hide show
  1. package/dist/MoveTheWheelsRoot.js +177 -102
  2. package/dist/MoveTheWheelsRoutes.js +55 -11
  3. package/dist/_virtual/_rolldown/runtime.js +1 -1
  4. package/dist/components/ContainerEvidencePicker.js +143 -0
  5. package/dist/components/FreeTimeAgreementForm.js +496 -0
  6. package/dist/components/ReturnInstructionForm.js +108 -0
  7. package/dist/components/ReuseControls.js +91 -0
  8. package/dist/components/ReusePermissionForm.js +114 -0
  9. package/dist/components/ReuseProposalForm.js +455 -0
  10. package/dist/components/ReuseSourceFields.js +78 -0
  11. package/dist/components/consolidation/ConsolidationHistory.js +244 -0
  12. package/dist/components/consolidation/ConsolidationLotEditor.js +133 -0
  13. package/dist/components/consolidation/ConsolidationManifestWorkbench.js +143 -0
  14. package/dist/components/consolidation/ConsolidationPlanForm.js +172 -0
  15. package/dist/components/consolidation/ConsolidationPlanWorkbench.js +321 -0
  16. package/dist/components/consolidation/ConsolidationReportForm.js +94 -0
  17. package/dist/components/consolidation/ConsolidationReportsWorkbench.js +195 -0
  18. package/dist/components/consolidation/ConsolidationSummary.js +76 -0
  19. package/dist/components/consolidation/OriginalConsolidationHistory.js +112 -0
  20. package/dist/components/freight-cost/FreightDraftForm.js +213 -0
  21. package/dist/components/freight-cost/FreightFields.js +70 -0
  22. package/dist/components/freight-cost/FreightFxEditor.js +90 -0
  23. package/dist/components/freight-cost/FreightHistory.js +164 -0
  24. package/dist/components/freight-cost/FreightLineEditor.js +191 -0
  25. package/dist/components/freight-cost/FreightScopeEditor.js +72 -0
  26. package/dist/components/freight-cost/FreightTotals.js +66 -0
  27. package/dist/components/logistics-procedure/ProcedureDecisionForm.js +197 -0
  28. package/dist/components/logistics-procedure/ProcedureFields.js +31 -0
  29. package/dist/components/logistics-procedure/ProcedureHistory.js +177 -0
  30. package/dist/components/logistics-procedure/ProcedurePolicyForm.js +227 -0
  31. package/dist/components/logistics-procedure/ProcedurePolicyWorkbench.js +155 -0
  32. package/dist/components/logistics-procedure/ProcedureReviewWorkbench.js +221 -0
  33. package/dist/components/logistics-procedure/ProcedureRunWorkbench.js +190 -0
  34. package/dist/components/logistics-procedure/ProcedureSubjectPicker.js +130 -0
  35. package/dist/components/pending-pick/PendingPickDraft.js +84 -0
  36. package/dist/components/pending-pick/PendingPickHistory.js +113 -0
  37. package/dist/components/pending-pick/PickCapture.js +166 -0
  38. package/dist/components/pending-pick/PickLineSelection.js +111 -0
  39. package/dist/components/stock-binding/StockAssessmentDraft.js +48 -0
  40. package/dist/components/stock-binding/StockAssessmentHistory.js +61 -0
  41. package/dist/components/stock-binding/StockAssessmentSummary.js +199 -0
  42. package/dist/components/stock-binding/StockFactForm.js +232 -0
  43. package/dist/components/stock-observation/StockIssueForm.js +148 -0
  44. package/dist/components/stock-observation/StockIssueHistory.js +116 -0
  45. package/dist/components/stock-observation/StockIssueReadPanel.js +70 -0
  46. package/dist/components/trip-utilization/TripReportForm.js +118 -0
  47. package/dist/components/trip-utilization/TripReportHistory.js +54 -0
  48. package/dist/components/trip-utilization/TripReportSummary.js +216 -0
  49. package/dist/components/trip-utilization/TripSegmentFields.js +166 -0
  50. package/dist/generated/consolidation-operations.d.ts +1060 -0
  51. package/dist/generated/container-condition-operations.d.ts +868 -0
  52. package/dist/generated/container-operations.d.ts +356 -0
  53. package/dist/generated/empty-reuse-operations.d.ts +1578 -0
  54. package/dist/generated/free-time-operations.d.ts +938 -0
  55. package/dist/generated/freight-cost-operations.d.ts +716 -0
  56. package/dist/generated/logistics-procedure-operations.d.ts +938 -0
  57. package/dist/generated/pending-pick-operations.d.ts +1969 -0
  58. package/dist/generated/stock-binding-operations.d.ts +930 -0
  59. package/dist/generated/stock-observation-operations.d.ts +476 -0
  60. package/dist/generated/trip-utilization-operations.d.ts +651 -0
  61. package/dist/generated/wspace-operations.d.ts +143 -50
  62. package/dist/hooks/useConsolidationAction.js +119 -0
  63. package/dist/hooks/useContainerCondition.js +105 -0
  64. package/dist/hooks/useContainerLifecycle.js +192 -0
  65. package/dist/hooks/useEmptyReuseAction.js +45 -0
  66. package/dist/hooks/useFreightRecoveryAction.js +117 -0
  67. package/dist/hooks/useProcedureAction.js +119 -0
  68. package/dist/hooks/useProcedureSelection.js +53 -0
  69. package/dist/hooks/useReuseRecoveryAction.js +116 -0
  70. package/dist/movethewheels/components/ContainerEvidencePicker.d.ts +10 -0
  71. package/dist/movethewheels/components/FreeTimeAgreementForm.d.ts +14 -0
  72. package/dist/movethewheels/components/ReturnInstructionForm.d.ts +8 -0
  73. package/dist/movethewheels/components/ReuseControls.d.ts +42 -0
  74. package/dist/movethewheels/components/ReusePermissionForm.d.ts +9 -0
  75. package/dist/movethewheels/components/ReuseProposalForm.d.ts +11 -0
  76. package/dist/movethewheels/components/ReuseSourceFields.d.ts +9 -0
  77. package/dist/movethewheels/components/consolidation/ConsolidationHistory.d.ts +13 -0
  78. package/dist/movethewheels/components/consolidation/ConsolidationLotEditor.d.ts +6 -0
  79. package/dist/movethewheels/components/consolidation/ConsolidationManifestWorkbench.d.ts +8 -0
  80. package/dist/movethewheels/components/consolidation/ConsolidationPlanForm.d.ts +8 -0
  81. package/dist/movethewheels/components/consolidation/ConsolidationPlanWorkbench.d.ts +5 -0
  82. package/dist/movethewheels/components/consolidation/ConsolidationReportForm.d.ts +9 -0
  83. package/dist/movethewheels/components/consolidation/ConsolidationReportsWorkbench.d.ts +7 -0
  84. package/dist/movethewheels/components/consolidation/ConsolidationSummary.d.ts +6 -0
  85. package/dist/movethewheels/components/consolidation/OriginalConsolidationHistory.d.ts +8 -0
  86. package/dist/movethewheels/components/freight-cost/FreightDraftForm.d.ts +8 -0
  87. package/dist/movethewheels/components/freight-cost/FreightFields.d.ts +23 -0
  88. package/dist/movethewheels/components/freight-cost/FreightFxEditor.d.ts +6 -0
  89. package/dist/movethewheels/components/freight-cost/FreightHistory.d.ts +5 -0
  90. package/dist/movethewheels/components/freight-cost/FreightLineEditor.d.ts +8 -0
  91. package/dist/movethewheels/components/freight-cost/FreightScopeEditor.d.ts +6 -0
  92. package/dist/movethewheels/components/freight-cost/FreightTotals.d.ts +6 -0
  93. package/dist/movethewheels/components/logistics-procedure/ProcedureDecisionForm.d.ts +20 -0
  94. package/dist/movethewheels/components/logistics-procedure/ProcedureFields.d.ts +17 -0
  95. package/dist/movethewheels/components/logistics-procedure/ProcedureHistory.d.ts +7 -0
  96. package/dist/movethewheels/components/logistics-procedure/ProcedurePolicyForm.d.ts +10 -0
  97. package/dist/movethewheels/components/logistics-procedure/ProcedurePolicyWorkbench.d.ts +5 -0
  98. package/dist/movethewheels/components/logistics-procedure/ProcedureReviewWorkbench.d.ts +5 -0
  99. package/dist/movethewheels/components/logistics-procedure/ProcedureRunWorkbench.d.ts +6 -0
  100. package/dist/movethewheels/components/logistics-procedure/ProcedureSubjectPicker.d.ts +7 -0
  101. package/dist/movethewheels/components/pending-pick/PendingPickDraft.d.ts +16 -0
  102. package/dist/movethewheels/components/pending-pick/PendingPickHistory.d.ts +5 -0
  103. package/dist/movethewheels/components/pending-pick/PickCapture.d.ts +6 -0
  104. package/dist/movethewheels/components/pending-pick/PickLineSelection.d.ts +17 -0
  105. package/dist/movethewheels/components/stock-binding/StockAssessmentDraft.d.ts +13 -0
  106. package/dist/movethewheels/components/stock-binding/StockAssessmentHistory.d.ts +18 -0
  107. package/dist/movethewheels/components/stock-binding/StockAssessmentSummary.d.ts +9 -0
  108. package/dist/movethewheels/components/stock-binding/StockFactForm.d.ts +6 -0
  109. package/dist/movethewheels/components/stock-observation/StockIssueForm.d.ts +7 -0
  110. package/dist/movethewheels/components/stock-observation/StockIssueHistory.d.ts +7 -0
  111. package/dist/movethewheels/components/stock-observation/StockIssueReadPanel.d.ts +5 -0
  112. package/dist/movethewheels/components/trip-utilization/TripReportForm.d.ts +6 -0
  113. package/dist/movethewheels/components/trip-utilization/TripReportHistory.d.ts +14 -0
  114. package/dist/movethewheels/components/trip-utilization/TripReportSummary.d.ts +5 -0
  115. package/dist/movethewheels/components/trip-utilization/TripSegmentFields.d.ts +9 -0
  116. package/dist/movethewheels/hooks/useConsolidationAction.d.ts +19 -0
  117. package/dist/movethewheels/hooks/useContainerCondition.d.ts +21 -0
  118. package/dist/movethewheels/hooks/useContainerLifecycle.d.ts +40 -0
  119. package/dist/movethewheels/hooks/useEmptyReuseAction.d.ts +14 -0
  120. package/dist/movethewheels/hooks/useFreightRecoveryAction.d.ts +23 -0
  121. package/dist/movethewheels/hooks/useProcedureAction.d.ts +18 -0
  122. package/dist/movethewheels/hooks/useProcedureSelection.d.ts +51 -0
  123. package/dist/movethewheels/hooks/useReuseRecoveryAction.d.ts +18 -0
  124. package/dist/movethewheels/pages/ConsolidationPage.d.ts +1 -0
  125. package/dist/movethewheels/pages/ContainerConditionPage.d.ts +1 -0
  126. package/dist/movethewheels/pages/ContainersPage.d.ts +2 -0
  127. package/dist/movethewheels/pages/EmptyReusePage.d.ts +1 -0
  128. package/dist/movethewheels/pages/FreeTimePage.d.ts +1 -0
  129. package/dist/movethewheels/pages/FreightEstimatePage.d.ts +1 -0
  130. package/dist/movethewheels/pages/LogisticsProceduresPage.d.ts +1 -0
  131. package/dist/movethewheels/pages/PendingPickPage.d.ts +1 -0
  132. package/dist/movethewheels/pages/StockBindingPage.d.ts +1 -0
  133. package/dist/movethewheels/pages/StockObservationsPage.d.ts +1 -0
  134. package/dist/movethewheels/pages/TripUtilizationPage.d.ts +1 -0
  135. package/dist/movethewheels/utils/consolidationHistoryTarget.d.ts +12 -0
  136. package/dist/movethewheels/utils/consolidationInput.d.ts +15 -0
  137. package/dist/movethewheels/utils/consolidationLot.d.ts +3 -0
  138. package/dist/movethewheels/utils/consolidationPins.d.ts +20 -0
  139. package/dist/movethewheels/utils/consolidationRecovery.d.ts +5 -0
  140. package/dist/movethewheels/utils/consolidationReportHead.d.ts +5 -0
  141. package/dist/movethewheels/utils/freeTimeDate.d.ts +1 -0
  142. package/dist/movethewheels/utils/freightAcknowledgement.d.ts +2 -0
  143. package/dist/movethewheels/utils/freightDraft.d.ts +36 -0
  144. package/dist/movethewheels/utils/freightRecovery.d.ts +5 -0
  145. package/dist/movethewheels/utils/graphqlClient.d.ts +2 -1
  146. package/dist/movethewheels/utils/pendingPickDraft.d.ts +8 -0
  147. package/dist/movethewheels/utils/procedureInput.d.ts +18 -0
  148. package/dist/movethewheels/utils/procedureRecovery.d.ts +5 -0
  149. package/dist/movethewheels/utils/reuseAttempt.d.ts +7 -0
  150. package/dist/movethewheels/utils/reuseForm.d.ts +6 -0
  151. package/dist/movethewheels/utils/reuseRecovery.d.ts +26 -0
  152. package/dist/movethewheels/utils/stockBindingForm.d.ts +23 -0
  153. package/dist/movethewheels/utils/stockBindingLabels.d.ts +10 -0
  154. package/dist/movethewheels/utils/stockObservationForm.d.ts +5 -0
  155. package/dist/movethewheels/utils/tripDraftContext.d.ts +25 -0
  156. package/dist/movethewheels/utils/tripUtilizationForm.d.ts +6 -0
  157. package/dist/node_modules/@react-leaflet/core/lib/component.js +5 -5
  158. package/dist/node_modules/fast-equals/dist/es/index.js +87 -74
  159. package/dist/node_modules/leaflet/dist/leaflet-src.js +8 -5
  160. package/dist/node_modules/lodash/_Stack.js +2 -1
  161. package/dist/node_modules/lucide-react/dist/esm/icons/clipboard-list.js +35 -0
  162. package/dist/node_modules/lucide-react/dist/esm/icons/repeat-2.js +22 -0
  163. package/dist/node_modules/react-leaflet/lib/MapContainer.js +3 -3
  164. package/dist/node_modules/react-smooth/es6/Animate.js +2 -2
  165. package/dist/node_modules/recharts/es6/cartesian/Area.js +13 -13
  166. package/dist/node_modules/recharts/es6/cartesian/Bar.js +9 -9
  167. package/dist/node_modules/recharts/es6/cartesian/Brush.js +12 -12
  168. package/dist/node_modules/recharts/es6/cartesian/CartesianAxis.js +7 -7
  169. package/dist/node_modules/recharts/es6/cartesian/CartesianGrid.js +13 -13
  170. package/dist/node_modules/recharts/es6/cartesian/ErrorBar.js +4 -4
  171. package/dist/node_modules/recharts/es6/cartesian/Line.js +10 -10
  172. package/dist/node_modules/recharts/es6/cartesian/ReferenceArea.js +3 -3
  173. package/dist/node_modules/recharts/es6/cartesian/ReferenceDot.js +3 -3
  174. package/dist/node_modules/recharts/es6/cartesian/ReferenceLine.js +4 -4
  175. package/dist/node_modules/recharts/es6/cartesian/XAxis.js +3 -3
  176. package/dist/node_modules/recharts/es6/cartesian/YAxis.js +3 -3
  177. package/dist/node_modules/recharts/es6/chart/AccessibilityManager.js +1 -1
  178. package/dist/node_modules/recharts/es6/chart/generateCategoricalChart.js +22 -22
  179. package/dist/node_modules/recharts/es6/component/Cursor.js +1 -1
  180. package/dist/node_modules/recharts/es6/component/DefaultLegendContent.js +11 -11
  181. package/dist/node_modules/recharts/es6/component/DefaultTooltipContent.js +6 -6
  182. package/dist/node_modules/recharts/es6/component/Label.js +14 -14
  183. package/dist/node_modules/recharts/es6/component/LabelList.js +6 -6
  184. package/dist/node_modules/recharts/es6/component/Legend.js +5 -5
  185. package/dist/node_modules/recharts/es6/component/ResponsiveContainer.js +3 -3
  186. package/dist/node_modules/recharts/es6/component/Text.js +2 -2
  187. package/dist/node_modules/recharts/es6/component/Tooltip.js +3 -3
  188. package/dist/node_modules/recharts/es6/component/TooltipBoundingBox.js +2 -2
  189. package/dist/node_modules/recharts/es6/container/Layer.js +2 -2
  190. package/dist/node_modules/recharts/es6/container/Surface.js +2 -2
  191. package/dist/node_modules/recharts/es6/context/chartLayoutContext.js +2 -2
  192. package/dist/node_modules/recharts/es6/polar/Pie.js +13 -13
  193. package/dist/node_modules/recharts/es6/polar/PolarAngleAxis.js +8 -8
  194. package/dist/node_modules/recharts/es6/polar/PolarRadiusAxis.js +6 -6
  195. package/dist/node_modules/recharts/es6/shape/Cross.js +1 -1
  196. package/dist/node_modules/recharts/es6/shape/Curve.js +1 -1
  197. package/dist/node_modules/recharts/es6/shape/Dot.js +1 -1
  198. package/dist/node_modules/recharts/es6/shape/Polygon.js +4 -4
  199. package/dist/node_modules/recharts/es6/shape/Rectangle.js +4 -4
  200. package/dist/node_modules/recharts/es6/shape/Sector.js +1 -1
  201. package/dist/node_modules/recharts/es6/shape/Symbols.js +1 -1
  202. package/dist/node_modules/recharts/es6/shape/Trapezoid.js +4 -4
  203. package/dist/node_modules/recharts/es6/util/ActiveShapeUtils.js +9 -9
  204. package/dist/node_modules/recharts/es6/util/BarUtils.js +1 -1
  205. package/dist/node_modules/recharts/es6/util/CartesianUtils.js +1 -1
  206. package/dist/node_modules/recharts/es6/util/PolarUtils.js +1 -1
  207. package/dist/node_modules/recharts/es6/util/ReactUtils.js +2 -2
  208. package/dist/node_modules/recharts/es6/util/ReduceCSSCalc.js +1 -1
  209. package/dist/node_modules/recharts/es6/util/types.js +1 -1
  210. package/dist/node_modules/{react-is → recharts/node_modules/react-is}/cjs/react-is.development.js +2 -2
  211. package/dist/node_modules/{react-is → recharts/node_modules/react-is}/cjs/react-is.production.min.js +2 -2
  212. package/dist/node_modules/{react-is → recharts/node_modules/react-is}/index.js +2 -2
  213. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +97 -18
  214. package/dist/node_modules/zustand/esm/middleware.js +2 -2
  215. package/dist/pages/ConsolidationPage.js +76 -0
  216. package/dist/pages/ContainerConditionPage.js +972 -0
  217. package/dist/pages/ContainersPage.js +522 -0
  218. package/dist/pages/EmptyReusePage.js +777 -0
  219. package/dist/pages/FreeTimePage.js +657 -0
  220. package/dist/pages/FreightEstimatePage.js +284 -0
  221. package/dist/pages/LogisticsProceduresPage.js +100 -0
  222. package/dist/pages/PendingPickPage.js +155 -0
  223. package/dist/pages/StockBindingPage.js +236 -0
  224. package/dist/pages/StockObservationsPage.js +168 -0
  225. package/dist/pages/TripUtilizationPage.js +227 -0
  226. package/dist/src/generated/consolidation-operations.js +505 -0
  227. package/dist/src/generated/container-condition-operations.js +208 -0
  228. package/dist/src/generated/container-operations.js +101 -0
  229. package/dist/src/generated/empty-reuse-operations.js +749 -0
  230. package/dist/src/generated/free-time-operations.js +235 -0
  231. package/dist/src/generated/freight-cost-operations.js +325 -0
  232. package/dist/src/generated/logistics-procedure-operations.js +362 -0
  233. package/dist/src/generated/pending-pick-operations.js +1128 -0
  234. package/dist/src/generated/stock-binding-operations.js +175 -0
  235. package/dist/src/generated/stock-observation-operations.js +93 -0
  236. package/dist/src/generated/trip-utilization-operations.js +140 -0
  237. package/dist/src/generated/wspace-operations.js +708 -0
  238. package/dist/utils/consolidationHistoryTarget.js +27 -0
  239. package/dist/utils/consolidationInput.js +21 -0
  240. package/dist/utils/consolidationLot.js +29 -0
  241. package/dist/utils/consolidationPins.js +13 -0
  242. package/dist/utils/consolidationRecovery.js +40 -0
  243. package/dist/utils/consolidationReportHead.js +18 -0
  244. package/dist/utils/freeTimeDate.js +26 -0
  245. package/dist/utils/freightAcknowledgement.js +8 -0
  246. package/dist/utils/freightDraft.js +125 -0
  247. package/dist/utils/freightRecovery.js +36 -0
  248. package/dist/utils/graphqlClient.js +28 -28
  249. package/dist/utils/pendingPickDraft.js +46 -0
  250. package/dist/utils/procedureInput.js +43 -0
  251. package/dist/utils/procedureRecovery.js +42 -0
  252. package/dist/utils/reuseAttempt.js +20 -0
  253. package/dist/utils/reuseForm.js +25 -0
  254. package/dist/utils/reuseRecovery.js +71 -0
  255. package/dist/utils/stockBindingForm.js +142 -0
  256. package/dist/utils/stockBindingLabels.js +23 -0
  257. package/dist/utils/stockObservationForm.js +55 -0
  258. package/dist/utils/tripDraftContext.js +19 -0
  259. package/dist/utils/tripUtilizationForm.js +60 -0
  260. package/package.json +19 -5
  261. package/src/generated/consolidation-operations.ts +1138 -0
  262. package/src/generated/container-condition-operations.ts +771 -0
  263. package/src/generated/container-operations.ts +376 -0
  264. package/src/generated/empty-reuse-operations.ts +1648 -0
  265. package/src/generated/free-time-operations.ts +814 -0
  266. package/src/generated/freight-cost-operations.ts +753 -0
  267. package/src/generated/logistics-procedure-operations.ts +1047 -0
  268. package/src/generated/pending-pick-operations.ts +1508 -0
  269. package/src/generated/stock-binding-operations.ts +631 -0
  270. package/src/generated/stock-observation-operations.ts +373 -0
  271. package/src/generated/trip-utilization-operations.ts +500 -0
  272. package/src/generated/wspace-operations.ts +116 -0
  273. package/src/movethewheels/MoveTheWheelsRoot.tsx +79 -0
  274. package/src/movethewheels/MoveTheWheelsRoutes.tsx +22 -0
  275. package/src/movethewheels/components/ContainerEvidencePicker.tsx +146 -0
  276. package/src/movethewheels/components/FreeTimeAgreementForm.tsx +483 -0
  277. package/src/movethewheels/components/ReturnInstructionForm.tsx +102 -0
  278. package/src/movethewheels/components/ReuseControls.tsx +138 -0
  279. package/src/movethewheels/components/ReusePermissionForm.tsx +123 -0
  280. package/src/movethewheels/components/ReuseProposalForm.tsx +484 -0
  281. package/src/movethewheels/components/ReuseSourceFields.tsx +80 -0
  282. package/src/movethewheels/components/consolidation/ConsolidationHistory.tsx +159 -0
  283. package/src/movethewheels/components/consolidation/ConsolidationLotEditor.tsx +144 -0
  284. package/src/movethewheels/components/consolidation/ConsolidationManifestWorkbench.tsx +168 -0
  285. package/src/movethewheels/components/consolidation/ConsolidationPlanForm.tsx +185 -0
  286. package/src/movethewheels/components/consolidation/ConsolidationPlanWorkbench.tsx +395 -0
  287. package/src/movethewheels/components/consolidation/ConsolidationReportForm.tsx +124 -0
  288. package/src/movethewheels/components/consolidation/ConsolidationReportsWorkbench.tsx +233 -0
  289. package/src/movethewheels/components/consolidation/ConsolidationSummary.tsx +84 -0
  290. package/src/movethewheels/components/consolidation/OriginalConsolidationHistory.tsx +133 -0
  291. package/src/movethewheels/components/freight-cost/FreightDraftForm.tsx +224 -0
  292. package/src/movethewheels/components/freight-cost/FreightFields.tsx +91 -0
  293. package/src/movethewheels/components/freight-cost/FreightFxEditor.tsx +98 -0
  294. package/src/movethewheels/components/freight-cost/FreightHistory.tsx +91 -0
  295. package/src/movethewheels/components/freight-cost/FreightLineEditor.tsx +192 -0
  296. package/src/movethewheels/components/freight-cost/FreightScopeEditor.tsx +64 -0
  297. package/src/movethewheels/components/freight-cost/FreightTotals.tsx +68 -0
  298. package/src/movethewheels/components/logistics-procedure/ProcedureDecisionForm.tsx +204 -0
  299. package/src/movethewheels/components/logistics-procedure/ProcedureFields.tsx +43 -0
  300. package/src/movethewheels/components/logistics-procedure/ProcedureHistory.tsx +102 -0
  301. package/src/movethewheels/components/logistics-procedure/ProcedurePolicyForm.tsx +226 -0
  302. package/src/movethewheels/components/logistics-procedure/ProcedurePolicyWorkbench.tsx +174 -0
  303. package/src/movethewheels/components/logistics-procedure/ProcedureReviewWorkbench.tsx +278 -0
  304. package/src/movethewheels/components/logistics-procedure/ProcedureRunWorkbench.tsx +292 -0
  305. package/src/movethewheels/components/logistics-procedure/ProcedureSubjectPicker.tsx +111 -0
  306. package/src/movethewheels/components/pending-pick/PendingPickDraft.tsx +82 -0
  307. package/src/movethewheels/components/pending-pick/PendingPickHistory.tsx +93 -0
  308. package/src/movethewheels/components/pending-pick/PickCapture.tsx +70 -0
  309. package/src/movethewheels/components/pending-pick/PickLineSelection.tsx +130 -0
  310. package/src/movethewheels/components/stock-binding/StockAssessmentDraft.tsx +52 -0
  311. package/src/movethewheels/components/stock-binding/StockAssessmentHistory.tsx +56 -0
  312. package/src/movethewheels/components/stock-binding/StockAssessmentSummary.tsx +108 -0
  313. package/src/movethewheels/components/stock-binding/StockFactForm.tsx +186 -0
  314. package/src/movethewheels/components/stock-observation/StockIssueForm.tsx +103 -0
  315. package/src/movethewheels/components/stock-observation/StockIssueHistory.tsx +96 -0
  316. package/src/movethewheels/components/stock-observation/StockIssueReadPanel.tsx +72 -0
  317. package/src/movethewheels/components/trip-utilization/TripReportForm.tsx +116 -0
  318. package/src/movethewheels/components/trip-utilization/TripReportHistory.tsx +51 -0
  319. package/src/movethewheels/components/trip-utilization/TripReportSummary.tsx +127 -0
  320. package/src/movethewheels/components/trip-utilization/TripSegmentFields.tsx +118 -0
  321. package/src/movethewheels/hooks/useConsolidationAction.ts +196 -0
  322. package/src/movethewheels/hooks/useContainerCondition.ts +129 -0
  323. package/src/movethewheels/hooks/useContainerLifecycle.ts +291 -0
  324. package/src/movethewheels/hooks/useEmptyReuseAction.ts +72 -0
  325. package/src/movethewheels/hooks/useFreightRecoveryAction.ts +201 -0
  326. package/src/movethewheels/hooks/useProcedureAction.ts +196 -0
  327. package/src/movethewheels/hooks/useProcedureSelection.ts +75 -0
  328. package/src/movethewheels/hooks/useReuseRecoveryAction.ts +192 -0
  329. package/src/movethewheels/pages/ConsolidationPage.tsx +70 -0
  330. package/src/movethewheels/pages/ContainerConditionPage.tsx +959 -0
  331. package/src/movethewheels/pages/ContainersPage.tsx +490 -0
  332. package/src/movethewheels/pages/EmptyReusePage.tsx +823 -0
  333. package/src/movethewheels/pages/FreeTimePage.tsx +720 -0
  334. package/src/movethewheels/pages/FreightEstimatePage.tsx +353 -0
  335. package/src/movethewheels/pages/LogisticsProceduresPage.tsx +86 -0
  336. package/src/movethewheels/pages/PendingPickPage.tsx +226 -0
  337. package/src/movethewheels/pages/StockBindingPage.tsx +299 -0
  338. package/src/movethewheels/pages/StockObservationsPage.tsx +181 -0
  339. package/src/movethewheels/pages/TripUtilizationPage.tsx +315 -0
  340. package/src/movethewheels/utils/consolidationHistoryTarget.ts +39 -0
  341. package/src/movethewheels/utils/consolidationInput.ts +70 -0
  342. package/src/movethewheels/utils/consolidationLot.ts +24 -0
  343. package/src/movethewheels/utils/consolidationPins.ts +52 -0
  344. package/src/movethewheels/utils/consolidationRecovery.ts +88 -0
  345. package/src/movethewheels/utils/consolidationReportHead.ts +29 -0
  346. package/src/movethewheels/utils/freeTimeDate.ts +31 -0
  347. package/src/movethewheels/utils/freightAcknowledgement.ts +31 -0
  348. package/src/movethewheels/utils/freightDraft.ts +170 -0
  349. package/src/movethewheels/utils/freightRecovery.ts +79 -0
  350. package/src/movethewheels/utils/graphqlClient.ts +14 -5
  351. package/src/movethewheels/utils/pendingPickDraft.ts +61 -0
  352. package/src/movethewheels/utils/procedureInput.ts +98 -0
  353. package/src/movethewheels/utils/procedureRecovery.ts +92 -0
  354. package/src/movethewheels/utils/reuseAttempt.ts +29 -0
  355. package/src/movethewheels/utils/reuseForm.ts +30 -0
  356. package/src/movethewheels/utils/reuseRecovery.ts +151 -0
  357. package/src/movethewheels/utils/stockBindingForm.ts +209 -0
  358. package/src/movethewheels/utils/stockBindingLabels.ts +41 -0
  359. package/src/movethewheels/utils/stockObservationForm.ts +73 -0
  360. package/src/movethewheels/utils/tripDraftContext.ts +61 -0
  361. package/src/movethewheels/utils/tripUtilizationForm.ts +105 -0
  362. package/src/operations/condition/container-condition.graphql +41 -0
  363. package/src/operations/consolidation/consolidation.graphql +490 -0
  364. package/src/operations/container/container-lifecycle.graphql +80 -0
  365. package/src/operations/empty-reuse/empty-reuse.graphql +737 -0
  366. package/src/operations/free-time/free-time.graphql +47 -0
  367. package/src/operations/freight-cost/freight.graphql +6 -0
  368. package/src/operations/logistics-procedure/procedure.graphql +15 -0
  369. package/src/operations/pending-pick/pending-pick.graphql +1122 -0
  370. package/src/operations/stock-binding/stock-binding.graphql +160 -0
  371. package/src/operations/stock-observation/stock-observation.graphql +20 -0
  372. package/src/operations/trip-utilization/trip-utilization.graphql +126 -0
  373. package/src/operations/wspace/container-evidence.graphql +6 -0
@@ -0,0 +1,959 @@
1
+ import { useState, type FormEvent, type ReactNode } from 'react';
2
+ import { ShieldCheck } from 'lucide-react';
3
+ import { PageLayout } from '../components/PageLayout';
4
+ import { Button, Input } from '../components/ui';
5
+ import {
6
+ ContainerEvidencePicker,
7
+ type SelectedEvidence,
8
+ } from '../components/ContainerEvidencePicker';
9
+ import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
10
+ import { useConditionAction, useConditionQuery } from '../hooks/useContainerCondition';
11
+ import {
12
+ ConditionContainersDocument,
13
+ ConditionInspectionsDocument,
14
+ ConditionHoldsDocument,
15
+ ConditionQualificationsDocument,
16
+ ConditionDefectsDocument,
17
+ ConditionRepairsDocument,
18
+ ConditionReleasesDocument,
19
+ RecordInspectionDocument,
20
+ CreateConditionHoldDocument,
21
+ RecordConditionRepairDocument,
22
+ SubmitInspectorQualificationDocument,
23
+ ReviewInspectorQualificationDocument,
24
+ RevokeInspectorQualificationDocument,
25
+ ReleaseConditionHoldDocument,
26
+ type ConditionContainersQuery,
27
+ type ConditionInspectionsQuery,
28
+ type ConditionHoldsQuery,
29
+ type ConditionQualificationsQuery,
30
+ type ConditionDefectsQuery,
31
+ type ConditionRepairsQuery,
32
+ type ConditionReleasesQuery,
33
+ type MtwContainerExaminationScheme,
34
+ type MtwContainerCargoCategory,
35
+ type MtwContainerSuitability,
36
+ type MtwContainerDefectSeverity,
37
+ type MtwContainerQualificationScope,
38
+ } from '../../generated/container-condition-operations';
39
+
40
+ const box = 'space-y-4 rounded-xl border bg-bg-surface p-5';
41
+ const selectStyle = 'mt-1 w-full rounded-md border p-2 text-sm';
42
+ const actions = [
43
+ 'inspection',
44
+ 'hold',
45
+ 'repair',
46
+ 'qualification',
47
+ 'review',
48
+ 'revoke',
49
+ 'release',
50
+ ] as const;
51
+ type Action = (typeof actions)[number];
52
+ const actionNames: Record<Action, string> = {
53
+ inspection: 'Record inspection',
54
+ hold: 'Place operational hold',
55
+ repair: 'Record repair',
56
+ qualification: 'Submit my qualification',
57
+ review: 'Review issuer qualification',
58
+ revoke: 'Revoke qualification',
59
+ release: 'Release hold',
60
+ };
61
+ const scopes: MtwContainerQualificationScope[] = [
62
+ 'PES_EXAMINATION',
63
+ 'ACEP_EXAMINATION',
64
+ 'DRY_CARGO',
65
+ 'REEFER_CARGO',
66
+ 'FOOD_GRADE_CARGO',
67
+ 'PEST_CARGO',
68
+ 'DANGEROUS_CARGO',
69
+ ];
70
+ const readable = (value: string) => value.replaceAll('_', ' ').toLowerCase();
71
+ const time = (value: string) => new Date(value).toLocaleString();
72
+
73
+ function Field({
74
+ label,
75
+ name,
76
+ type = 'text',
77
+ maxLength = 255,
78
+ required = true,
79
+ }: {
80
+ label: string;
81
+ name: string;
82
+ type?: string;
83
+ maxLength?: number;
84
+ required?: boolean;
85
+ }) {
86
+ return (
87
+ <label className="block text-sm">
88
+ {label}
89
+ <Input
90
+ name={name}
91
+ type={type}
92
+ required={required}
93
+ maxLength={maxLength}
94
+ step={type === 'datetime-local' ? 1 : undefined}
95
+ className="mt-1"
96
+ />
97
+ </label>
98
+ );
99
+ }
100
+ function Selector({
101
+ label,
102
+ value,
103
+ onChange,
104
+ children,
105
+ }: {
106
+ label: string;
107
+ value: string;
108
+ onChange: (value: string) => void;
109
+ children: ReactNode;
110
+ }) {
111
+ return (
112
+ <label className="block text-sm">
113
+ {label}
114
+ <select
115
+ aria-label={label}
116
+ className={selectStyle}
117
+ value={value}
118
+ onChange={(event) => onChange(event.target.value)}
119
+ >
120
+ {children}
121
+ </select>
122
+ </label>
123
+ );
124
+ }
125
+ function Pages({
126
+ offset,
127
+ setOffset,
128
+ hasMore,
129
+ loading,
130
+ label,
131
+ }: {
132
+ offset: number;
133
+ setOffset: (value: number) => void;
134
+ hasMore?: boolean;
135
+ loading: boolean;
136
+ label: string;
137
+ }) {
138
+ return (
139
+ <div className="flex flex-wrap gap-2">
140
+ <Button
141
+ type="button"
142
+ variant="outline"
143
+ disabled={offset === 0 || loading}
144
+ onClick={() => setOffset(Math.max(0, offset - 25))}
145
+ >
146
+ Previous {label}
147
+ </Button>
148
+ <Button
149
+ type="button"
150
+ variant="outline"
151
+ disabled={!hasMore || loading || offset >= 10000}
152
+ onClick={() => setOffset(offset + 25)}
153
+ >
154
+ Next {label}
155
+ </Button>
156
+ </div>
157
+ );
158
+ }
159
+
160
+ export default function ContainerConditionPage() {
161
+ const { workspaceId, currentUser, tenantId, apiGatewayUrl } = useMoveTheWheels();
162
+ return (
163
+ <ConditionWorkbench
164
+ key={`${workspaceId ?? ''}:${currentUser?.id ?? ''}:${tenantId ?? ''}:${apiGatewayUrl ?? ''}`}
165
+ />
166
+ );
167
+ }
168
+ function ConditionWorkbench() {
169
+ const [containerId, setContainerId] = useState('');
170
+ const [offset, setOffset] = useState(0);
171
+ const query = useConditionQuery<ConditionContainersQuery>(ConditionContainersDocument, {
172
+ pagination: { limit: 25, offset },
173
+ });
174
+ return (
175
+ <PageLayout
176
+ title="Container condition"
177
+ subtitle="Recorded examinations, repairs and qualified hold release"
178
+ icon={<ShieldCheck size={24} />}
179
+ >
180
+ <div className="space-y-6">
181
+ <p className="rounded-lg border p-4 text-sm">
182
+ Operational records support a human decision. MoveTheWheels does not issue CSC approval,
183
+ verify an issuer automatically, or certify fitness for carriage. A repair never releases a
184
+ hold by itself.
185
+ </p>
186
+ <section className={box}>
187
+ <h2 className="text-lg font-semibold">Choose equipment</h2>
188
+ {query.error && <p role="alert">{query.error}</p>}
189
+ {query.loading && <p role="status">Loading containers…</p>}
190
+ <Selector label="Container" value={containerId} onChange={setContainerId}>
191
+ <option value="">Choose a container</option>
192
+ {query.data?.mtwContainerPage.items.map((row) => (
193
+ <option key={row.id} value={row.id}>
194
+ {row.containerNumber} — {readable(row.equipmentType)}
195
+ </option>
196
+ ))}
197
+ </Selector>
198
+ <Pages
199
+ offset={offset}
200
+ loading={query.loading}
201
+ hasMore={query.data?.mtwContainerPage.hasMore}
202
+ label="containers"
203
+ setOffset={(value) => {
204
+ setOffset(value);
205
+ setContainerId('');
206
+ }}
207
+ />
208
+ </section>
209
+ {containerId && <ConditionRecords key={containerId} containerId={containerId} />}
210
+ </div>
211
+ </PageLayout>
212
+ );
213
+ }
214
+ function ConditionRecords({ containerId }: { containerId: string }) {
215
+ const { currentUser } = useMoveTheWheels();
216
+ const task = useConditionAction();
217
+ const [action, setAction] = useState<Action>('inspection');
218
+ const [holdId, setHoldId] = useState('');
219
+ const [inspectionId, setInspectionId] = useState('');
220
+ const [qualificationId, setQualificationId] = useState('');
221
+ const [scheme, setScheme] = useState<MtwContainerExaminationScheme>('PES');
222
+ const [cargo, setCargo] = useState<MtwContainerCargoCategory>('DRY');
223
+ const [suitability, setSuitability] = useState<MtwContainerSuitability>('REVIEW_REQUIRED');
224
+ const [evidence, setEvidence] = useState<SelectedEvidence[]>([]);
225
+ const [selectedDefects, setSelectedDefects] = useState<string[]>([]);
226
+ const [selectedScopes, setSelectedScopes] = useState<MtwContainerQualificationScope[]>([]);
227
+ const [defects, setDefects] = useState<
228
+ Array<{ code: string; severity: MtwContainerDefectSeverity; details: string }>
229
+ >([]);
230
+ const [validationError, setValidationError] = useState<string | null>(null);
231
+ const [inspectionOffset, setInspectionOffset] = useState(0);
232
+ const [viewInspectionId, setViewInspectionId] = useState('');
233
+ const [defectOffset, setDefectOffset] = useState(0);
234
+ const [holdOffset, setHoldOffset] = useState(0);
235
+ const [qualificationOffset, setQualificationOffset] = useState(0);
236
+ const [repairOffset, setRepairOffset] = useState(0);
237
+ const [historyHoldId, setHistoryHoldId] = useState('');
238
+ const [releaseOffset, setReleaseOffset] = useState(0);
239
+ const inspections = useConditionQuery<ConditionInspectionsQuery>(
240
+ ConditionInspectionsDocument,
241
+ { containerId, pagination: { limit: 25, offset: inspectionOffset } },
242
+ task.revision
243
+ );
244
+ const inspectionDefects = useConditionQuery<ConditionDefectsQuery>(
245
+ ConditionDefectsDocument,
246
+ viewInspectionId
247
+ ? { inspectionId: viewInspectionId, pagination: { limit: 25, offset: defectOffset } }
248
+ : null,
249
+ task.revision
250
+ );
251
+ const holds = useConditionQuery<ConditionHoldsQuery>(
252
+ ConditionHoldsDocument,
253
+ { containerId, pagination: { limit: 25, offset: holdOffset } },
254
+ task.revision
255
+ );
256
+ const qualifications = useConditionQuery<ConditionQualificationsQuery>(
257
+ ConditionQualificationsDocument,
258
+ { pagination: { limit: 25, offset: qualificationOffset } },
259
+ task.revision
260
+ );
261
+ const hold = holds.data?.mtwContainerHoldPage.items.find((item) => item.id === holdId);
262
+ const qualification = qualifications.data?.mtwContainerQualificationPage.items.find(
263
+ (item) => item.id === qualificationId
264
+ );
265
+ const heldDefects = useConditionQuery<ConditionDefectsQuery>(
266
+ ConditionDefectsDocument,
267
+ hold?.inspectionId
268
+ ? { inspectionId: hold.inspectionId, pagination: { limit: 25, offset: 0 } }
269
+ : null,
270
+ task.revision
271
+ );
272
+ const repairs = useConditionQuery<ConditionRepairsQuery>(
273
+ ConditionRepairsDocument,
274
+ historyHoldId
275
+ ? { holdId: historyHoldId, pagination: { limit: 25, offset: repairOffset } }
276
+ : null,
277
+ task.revision
278
+ );
279
+ const releases = useConditionQuery<ConditionReleasesQuery>(
280
+ ConditionReleasesDocument,
281
+ { containerId, pagination: { limit: 25, offset: releaseOffset } },
282
+ task.revision
283
+ );
284
+
285
+ const save = async (event: FormEvent<HTMLFormElement>) => {
286
+ event.preventDefault();
287
+ setValidationError(null);
288
+ const fields = new FormData(event.currentTarget);
289
+ const text = (name: string) => String(fields.get(name) ?? '').trim();
290
+ const instant = (name: string) => {
291
+ const date = new Date(text(name));
292
+ if (!Number.isFinite(date.getTime())) throw new Error('Enter a valid date and time.');
293
+ return date.toISOString();
294
+ };
295
+ const proof = evidence.map(({ fileId, versionId }) => ({ fileId, versionId }));
296
+ try {
297
+ if (action !== 'revoke' && proof.length === 0)
298
+ throw new Error('Choose at least one exact evidence version.');
299
+ if (action === 'inspection')
300
+ await task.run(
301
+ RecordInspectionDocument,
302
+ {
303
+ containerId,
304
+ inspectedAt: instant('inspectedAt'),
305
+ templateVersion: text('templateVersion'),
306
+ examinationScheme: scheme,
307
+ cscPlateVersionId: text('cscPlateVersionId'),
308
+ examinationVersionId: text('examinationVersionId'),
309
+ nextExaminationAt: scheme === 'PES' ? instant('nextExaminationAt') : undefined,
310
+ acepReference: scheme === 'ACEP' ? text('acepReference') : undefined,
311
+ cargoCategory: cargo,
312
+ suitability,
313
+ evidence: proof,
314
+ defects,
315
+ resolvedDefectIds: selectedDefects,
316
+ },
317
+ 'Inspection recorded. Severe defects create a hold.'
318
+ );
319
+ if (action === 'hold')
320
+ await task.run(
321
+ CreateConditionHoldDocument,
322
+ { containerId, reason: text('reason'), heldAt: instant('heldAt'), evidence: proof },
323
+ 'Operational hold recorded.'
324
+ );
325
+ if (action === 'repair') {
326
+ if (!hold || hold.status !== 'OPEN') throw new Error('Choose an open hold.');
327
+ await task.run(
328
+ RecordConditionRepairDocument,
329
+ {
330
+ holdId: hold.id,
331
+ expectedVersion: hold.version,
332
+ completedAt: instant('completedAt'),
333
+ workDescription: text('workDescription'),
334
+ defectIds: selectedDefects,
335
+ evidence: proof,
336
+ },
337
+ 'Repair recorded. The hold remains open.'
338
+ );
339
+ }
340
+ if (action === 'qualification' && selectedScopes.length === 0)
341
+ throw new Error('Choose at least one examination or cargo scope.');
342
+ if (action === 'qualification')
343
+ await task.run(
344
+ SubmitInspectorQualificationDocument,
345
+ {
346
+ issuerName: text('issuerName'),
347
+ credentialReference: text('credentialReference'),
348
+ validFrom: instant('validFrom'),
349
+ validUntil: instant('validUntil'),
350
+ scopes: selectedScopes,
351
+ evidence: proof,
352
+ },
353
+ 'Qualification submitted for a separate human review.'
354
+ );
355
+ if (action === 'review') {
356
+ if (!qualification || qualification.subjectActorId === currentUser?.id)
357
+ throw new Error('Choose a qualification submitted by another human.');
358
+ await task.run(
359
+ ReviewInspectorQualificationDocument,
360
+ {
361
+ qualificationId: qualification.id,
362
+ expectedVersion: qualification.version,
363
+ issuerConfirmationReference: text('issuerConfirmationReference'),
364
+ reviewNote: text('reviewNote'),
365
+ evidence: proof,
366
+ },
367
+ 'Human issuer review recorded.'
368
+ );
369
+ }
370
+ if (action === 'revoke') {
371
+ if (!qualification) throw new Error('Choose a qualification.');
372
+ await task.run(
373
+ RevokeInspectorQualificationDocument,
374
+ {
375
+ qualificationId: qualification.id,
376
+ expectedVersion: qualification.version,
377
+ reason: text('reason'),
378
+ },
379
+ 'Qualification revoked.'
380
+ );
381
+ }
382
+ if (action === 'release') {
383
+ if (!hold || hold.status !== 'OPEN' || !qualification || !inspectionId)
384
+ throw new Error(
385
+ 'Choose an open hold, current inspection and your reviewed qualification.'
386
+ );
387
+ await task.run(
388
+ ReleaseConditionHoldDocument,
389
+ {
390
+ holdId: hold.id,
391
+ expectedVersion: hold.version,
392
+ inspectionId,
393
+ qualificationId: qualification.id,
394
+ resolutionReview: text('resolutionReview'),
395
+ evidence: proof,
396
+ },
397
+ 'Qualified release decision recorded. Other open holds still apply.'
398
+ );
399
+ }
400
+ } catch (failure) {
401
+ setValidationError(failure instanceof Error ? failure.message : 'Check the record fields.');
402
+ }
403
+ };
404
+
405
+ return (
406
+ <div className="space-y-6">
407
+ <section className={box}>
408
+ <h2 className="text-lg font-semibold">Condition history</h2>
409
+ {inspections.error && <p role="alert">Inspections unavailable: {inspections.error}</p>}
410
+ {inspections.loading && <p role="status">Loading inspections…</p>}
411
+ <ul className="space-y-2">
412
+ {inspections.data?.mtwContainerInspectionPage.items.map((row) => (
413
+ <li key={row.id} className="rounded border p-3 text-sm">
414
+ {time(row.inspectedAt)} — {readable(row.suitability)}, {row.examinationScheme},{' '}
415
+ {readable(row.cargoCategory)}. {row.defectCount} defects, {row.severeDefectCount}{' '}
416
+ severe. Template {row.templateVersion}.
417
+ </li>
418
+ ))}
419
+ </ul>
420
+ <Pages
421
+ offset={inspectionOffset}
422
+ setOffset={(value) => {
423
+ setInspectionOffset(value);
424
+ setInspectionId('');
425
+ setViewInspectionId('');
426
+ setDefectOffset(0);
427
+ }}
428
+ hasMore={inspections.data?.mtwContainerInspectionPage.hasMore}
429
+ loading={inspections.loading}
430
+ label="inspections"
431
+ />
432
+ {inspections.data && inspections.data.mtwContainerInspectionPage.items.length === 0 && (
433
+ <p>No inspections recorded on this page.</p>
434
+ )}
435
+ <Selector
436
+ label="Inspect recorded defects"
437
+ value={viewInspectionId}
438
+ onChange={(value) => {
439
+ setViewInspectionId(value);
440
+ setDefectOffset(0);
441
+ }}
442
+ >
443
+ <option value="">Choose an inspection</option>
444
+ {inspections.data?.mtwContainerInspectionPage.items.map((row) => (
445
+ <option key={row.id} value={row.id}>
446
+ {time(row.inspectedAt)} — {readable(row.suitability)} — {row.templateVersion}
447
+ </option>
448
+ ))}
449
+ </Selector>
450
+ {viewInspectionId && (
451
+ <div className="space-y-2">
452
+ {inspectionDefects.error && <p role="alert">{inspectionDefects.error}</p>}
453
+ {inspectionDefects.loading && <p role="status">Loading recorded defects…</p>}
454
+ <ul className="space-y-2">
455
+ {inspectionDefects.data?.mtwContainerDefectPage.items.map((row) => (
456
+ <li key={row.id} className="rounded border p-3 text-sm">
457
+ {row.code} — {readable(row.severity)} — {row.details}
458
+ </li>
459
+ ))}
460
+ </ul>
461
+ {inspectionDefects.data?.mtwContainerDefectPage.items.length === 0 && (
462
+ <p>No defects were recorded in this inspection.</p>
463
+ )}
464
+ <Pages
465
+ offset={defectOffset}
466
+ setOffset={setDefectOffset}
467
+ hasMore={inspectionDefects.data?.mtwContainerDefectPage.hasMore}
468
+ loading={inspectionDefects.loading}
469
+ label="defects"
470
+ />
471
+ </div>
472
+ )}
473
+ {holds.error && <p role="alert">Holds unavailable: {holds.error}</p>}
474
+ <ul className="space-y-2">
475
+ {holds.data?.mtwContainerHoldPage.items.map((row) => (
476
+ <li key={row.id} className="rounded border p-3 text-sm">
477
+ {readable(row.status)} — {row.reason} — {time(row.heldAt)}. Revision {row.version}.
478
+ </li>
479
+ ))}
480
+ </ul>
481
+ <Pages
482
+ offset={holdOffset}
483
+ setOffset={(value) => {
484
+ setHoldOffset(value);
485
+ setHoldId('');
486
+ setSelectedDefects([]);
487
+ }}
488
+ hasMore={holds.data?.mtwContainerHoldPage.hasMore}
489
+ loading={holds.loading}
490
+ label="holds"
491
+ />
492
+ </section>
493
+ <section className={box}>
494
+ <h2 className="text-lg font-semibold">Record a decision or event</h2>
495
+ <Selector
496
+ label="Action"
497
+ value={action}
498
+ onChange={(value) => {
499
+ if (actions.some((item) => item === value)) {
500
+ const next = actions.find((item) => item === value);
501
+ if (next) setAction(next);
502
+ }
503
+ setQualificationId('');
504
+ setEvidence([]);
505
+ setSelectedDefects([]);
506
+ setValidationError(null);
507
+ task.resetFeedback();
508
+ }}
509
+ >
510
+ {actions.map((value) => (
511
+ <option key={value} value={value}>
512
+ {actionNames[value]}
513
+ </option>
514
+ ))}
515
+ </Selector>
516
+ {validationError && <p role="alert">{validationError}</p>}
517
+ {task.error && <p role="alert">{task.error}</p>}
518
+ {task.notice && <p role="status">{task.notice}</p>}
519
+ {task.hasPendingAttempt && (
520
+ <div className="space-y-2 rounded border p-3 text-sm">
521
+ <p>
522
+ A failed response may still have committed. An unchanged retry preserves its original
523
+ request and revision. Check history before discarding the attempt to start another.
524
+ </p>
525
+ <Button
526
+ type="button"
527
+ variant="outline"
528
+ disabled={task.busy}
529
+ onClick={task.discardAttempt}
530
+ >
531
+ Discard failed attempt
532
+ </Button>
533
+ </div>
534
+ )}
535
+ <form
536
+ key={action}
537
+ onSubmit={(event) => {
538
+ void save(event);
539
+ }}
540
+ className="space-y-4"
541
+ >
542
+ {['inspection', 'repair', 'release'].includes(action) && (
543
+ <Selector
544
+ label="Hold being addressed"
545
+ value={holdId}
546
+ onChange={(value) => {
547
+ setHoldId(value);
548
+ setSelectedDefects([]);
549
+ setRepairOffset(0);
550
+ }}
551
+ >
552
+ <option value="">Choose a hold (optional for a new inspection)</option>
553
+ {holds.data?.mtwContainerHoldPage.items
554
+ .filter((row) => row.status === 'OPEN')
555
+ .map((row) => (
556
+ <option key={row.id} value={row.id}>
557
+ {row.reason} — {time(row.heldAt)}
558
+ </option>
559
+ ))}
560
+ </Selector>
561
+ )}
562
+ {action === 'inspection' && (
563
+ <>
564
+ <Field label="Actual inspection time" name="inspectedAt" type="datetime-local" />
565
+ <Field label="Inspection template version" name="templateVersion" maxLength={120} />
566
+ <Selector
567
+ label="Recorded examination scheme"
568
+ value={scheme}
569
+ onChange={(value) => setScheme(value === 'ACEP' ? 'ACEP' : 'PES')}
570
+ >
571
+ <option value="PES">Periodic examination (PES)</option>
572
+ <option value="ACEP">Approved continuous examination programme (ACEP)</option>
573
+ </Selector>
574
+ {scheme === 'PES' ? (
575
+ <Field
576
+ label="Recorded next examination due"
577
+ name="nextExaminationAt"
578
+ type="datetime-local"
579
+ />
580
+ ) : (
581
+ <Field label="Recorded ACEP programme reference" name="acepReference" />
582
+ )}
583
+ <Selector
584
+ label="Cargo category"
585
+ value={cargo}
586
+ onChange={(value) => {
587
+ const match = (
588
+ ['DRY', 'REEFER', 'FOOD_GRADE', 'PEST', 'DANGEROUS'] as const
589
+ ).find((item) => item === value);
590
+ if (match) setCargo(match);
591
+ }}
592
+ >
593
+ {['DRY', 'REEFER', 'FOOD_GRADE', 'PEST', 'DANGEROUS'].map((value) => (
594
+ <option key={value} value={value}>
595
+ {readable(value)}
596
+ </option>
597
+ ))}
598
+ </Selector>
599
+ <Selector
600
+ label="Recorded suitability"
601
+ value={suitability}
602
+ onChange={(value) => {
603
+ const match = (['ACCEPTABLE', 'REJECTED', 'REVIEW_REQUIRED'] as const).find(
604
+ (item) => item === value
605
+ );
606
+ if (match) setSuitability(match);
607
+ }}
608
+ >
609
+ {['ACCEPTABLE', 'REJECTED', 'REVIEW_REQUIRED'].map((value) => (
610
+ <option key={value} value={value}>
611
+ {readable(value)}
612
+ </option>
613
+ ))}
614
+ </Selector>
615
+ <fieldset className="space-y-3">
616
+ <legend>Defects found (up to 20)</legend>
617
+ {defects.map((defect, index) => (
618
+ <div key={index} className="space-y-2 rounded border p-3">
619
+ <label className="block text-sm">
620
+ Defect code
621
+ <Input
622
+ required
623
+ maxLength={120}
624
+ value={defect.code}
625
+ onChange={(event) =>
626
+ setDefects(
627
+ defects.map((row, position) =>
628
+ position === index ? { ...row, code: event.target.value } : row
629
+ )
630
+ )
631
+ }
632
+ />
633
+ </label>
634
+ <Selector
635
+ label={`Defect ${index + 1} severity`}
636
+ value={defect.severity}
637
+ onChange={(value) => {
638
+ const match = (['MINOR', 'MAJOR', 'SEVERE'] as const).find(
639
+ (item) => item === value
640
+ );
641
+ if (match)
642
+ setDefects(
643
+ defects.map((row, position) =>
644
+ position === index ? { ...row, severity: match } : row
645
+ )
646
+ );
647
+ }}
648
+ >
649
+ {['MINOR', 'MAJOR', 'SEVERE'].map((value) => (
650
+ <option key={value} value={value}>
651
+ {readable(value)}
652
+ </option>
653
+ ))}
654
+ </Selector>
655
+ <label className="block text-sm">
656
+ Defect details
657
+ <Input
658
+ required
659
+ maxLength={2000}
660
+ value={defect.details}
661
+ onChange={(event) =>
662
+ setDefects(
663
+ defects.map((row, position) =>
664
+ position === index ? { ...row, details: event.target.value } : row
665
+ )
666
+ )
667
+ }
668
+ />
669
+ </label>
670
+ <Button
671
+ type="button"
672
+ variant="outline"
673
+ onClick={() =>
674
+ setDefects(defects.filter((_, position) => position !== index))
675
+ }
676
+ >
677
+ Remove defect
678
+ </Button>
679
+ </div>
680
+ ))}
681
+ <Button
682
+ type="button"
683
+ variant="outline"
684
+ disabled={defects.length >= 20}
685
+ onClick={() =>
686
+ setDefects([...defects, { code: '', severity: 'MINOR', details: '' }])
687
+ }
688
+ >
689
+ Add defect
690
+ </Button>
691
+ </fieldset>
692
+ </>
693
+ )}
694
+ {action === 'hold' && (
695
+ <>
696
+ <Field label="Operational hold reason" name="reason" maxLength={2000} />
697
+ <Field label="Actual hold time" name="heldAt" type="datetime-local" />
698
+ </>
699
+ )}
700
+ {action === 'repair' && (
701
+ <>
702
+ <Field
703
+ label="Actual repair completion time"
704
+ name="completedAt"
705
+ type="datetime-local"
706
+ />
707
+ <Field label="Repair work performed" name="workDescription" maxLength={2000} />
708
+ <p className="text-sm">Recording repair evidence leaves the hold open.</p>
709
+ </>
710
+ )}
711
+ {['inspection', 'repair'].includes(action) && hold?.inspectionId && (
712
+ <fieldset className="space-y-2">
713
+ <legend>
714
+ {action === 'inspection'
715
+ ? 'Held defects explicitly resolved by this examination'
716
+ : 'Held defects addressed by this repair'}
717
+ </legend>
718
+ {heldDefects.error && <p role="alert">{heldDefects.error}</p>}
719
+ {heldDefects.data?.mtwContainerDefectPage.items
720
+ .filter((defect) => hold.defectIds.includes(defect.id))
721
+ .map((defect) => (
722
+ <label key={defect.id} className="flex gap-2 text-sm">
723
+ <input
724
+ type="checkbox"
725
+ checked={selectedDefects.includes(defect.id)}
726
+ onChange={() =>
727
+ setSelectedDefects(
728
+ selectedDefects.includes(defect.id)
729
+ ? selectedDefects.filter((id) => id !== defect.id)
730
+ : [...selectedDefects, defect.id]
731
+ )
732
+ }
733
+ />
734
+ {defect.code} — {defect.details}
735
+ </label>
736
+ ))}
737
+ </fieldset>
738
+ )}
739
+ {action === 'qualification' && (
740
+ <>
741
+ <p className="text-sm">
742
+ This submission belongs to you. Another authorized human must record issuer
743
+ confirmation.
744
+ </p>
745
+ <Field label="Credential issuer" name="issuerName" />
746
+ <Field label="Credential reference" name="credentialReference" />
747
+ <Field label="Qualification valid from" name="validFrom" type="datetime-local" />
748
+ <Field label="Qualification valid until" name="validUntil" type="datetime-local" />
749
+ <fieldset className="space-y-2">
750
+ <legend>Examination and cargo scopes</legend>
751
+ {scopes.map((scope) => (
752
+ <label key={scope} className="flex gap-2 text-sm">
753
+ <input
754
+ type="checkbox"
755
+ checked={selectedScopes.includes(scope)}
756
+ onChange={() =>
757
+ setSelectedScopes(
758
+ selectedScopes.includes(scope)
759
+ ? selectedScopes.filter((value) => value !== scope)
760
+ : [...selectedScopes, scope]
761
+ )
762
+ }
763
+ />
764
+ {readable(scope)}
765
+ </label>
766
+ ))}
767
+ </fieldset>
768
+ </>
769
+ )}
770
+ {['review', 'revoke', 'release'].includes(action) && (
771
+ <Selector label="Qualification" value={qualificationId} onChange={setQualificationId}>
772
+ <option value="">Choose a qualification</option>
773
+ {qualifications.data?.mtwContainerQualificationPage.items.map((row) => (
774
+ <option
775
+ key={row.id}
776
+ value={row.id}
777
+ disabled={
778
+ action === 'review'
779
+ ? row.status !== 'SUBMITTED' || row.subjectActorId === currentUser?.id
780
+ : action === 'release'
781
+ ? row.status !== 'HUMAN_REVIEWED' || row.subjectActorId !== currentUser?.id
782
+ : row.status === 'REVOKED'
783
+ }
784
+ >
785
+ {row.issuerName} — {row.credentialReference} — {readable(row.status)}
786
+ </option>
787
+ ))}
788
+ </Selector>
789
+ )}
790
+ {action === 'review' && (
791
+ <>
792
+ <Field label="Issuer confirmation reference" name="issuerConfirmationReference" />
793
+ <Field label="Human review notes" name="reviewNote" maxLength={2000} />
794
+ <p className="text-sm">
795
+ Record what you independently confirmed with the issuer. Software does not validate
796
+ the credential automatically.
797
+ </p>
798
+ </>
799
+ )}
800
+ {action === 'revoke' && (
801
+ <Field label="Revocation reason" name="reason" maxLength={2000} />
802
+ )}
803
+ {action === 'release' && (
804
+ <>
805
+ <Selector label="Release inspection" value={inspectionId} onChange={setInspectionId}>
806
+ <option value="">Choose a current inspection</option>
807
+ {inspections.data?.mtwContainerInspectionPage.items.map((row) => (
808
+ <option
809
+ key={row.id}
810
+ value={row.id}
811
+ disabled={row.suitability !== 'ACCEPTABLE' || row.severeDefectCount !== 0}
812
+ >
813
+ {time(row.inspectedAt)} — {readable(row.suitability)} —{' '}
814
+ {readable(row.cargoCategory)}
815
+ </option>
816
+ ))}
817
+ </Selector>
818
+ <Field
819
+ label="Explicit hold resolution review"
820
+ name="resolutionReview"
821
+ maxLength={2000}
822
+ />
823
+ <p className="text-sm">
824
+ The server checks current qualification, resolved defects, inspection chronology and
825
+ exact evidence. A newer conflicting inspection blocks release.
826
+ </p>
827
+ </>
828
+ )}
829
+ {action !== 'revoke' && (
830
+ <ContainerEvidencePicker value={evidence} onChange={setEvidence} />
831
+ )}
832
+ {action === 'inspection' && (
833
+ <fieldset className="space-y-3 rounded-lg border p-4">
834
+ <legend>Identify examination evidence</legend>
835
+ <p className="text-sm">
836
+ Identify which selected version contains the CSC plate and which contains the
837
+ examination record. A combined document can serve both roles. These are your
838
+ recorded classifications; the software does not certify their contents.
839
+ </p>
840
+ {[
841
+ ['cscPlateVersionId', 'CSC plate evidence'],
842
+ ['examinationVersionId', 'Examination document evidence'],
843
+ ].map(([name, label]) => (
844
+ <label key={name} className="block text-sm">
845
+ {label}
846
+ <select
847
+ name={name}
848
+ aria-label={label}
849
+ required
850
+ className={selectStyle}
851
+ defaultValue=""
852
+ >
853
+ <option value="">Choose a selected evidence version</option>
854
+ {evidence.map((item) => (
855
+ <option key={item.versionId} value={item.versionId}>
856
+ {item.label}
857
+ </option>
858
+ ))}
859
+ </select>
860
+ </label>
861
+ ))}
862
+ </fieldset>
863
+ )}
864
+ <Button type="submit" disabled={task.busy}>
865
+ {task.busy ? 'Saving…' : actionNames[action]}
866
+ </Button>
867
+ </form>
868
+ </section>
869
+ <section className={box}>
870
+ <h2 className="text-lg font-semibold">Qualifications</h2>
871
+ {qualifications.error && (
872
+ <p role="alert">
873
+ Qualification records are unavailable for your current access: {qualifications.error}
874
+ </p>
875
+ )}
876
+ <ul className="space-y-2">
877
+ {qualifications.data?.mtwContainerQualificationPage.items.map((row) => (
878
+ <li key={row.id} className="rounded border p-3 text-sm">
879
+ {row.issuerName} — {row.credentialReference} — {readable(row.status)}. Valid{' '}
880
+ {time(row.validFrom)} to {time(row.validUntil)}. Scopes:{' '}
881
+ {row.scopes.map(readable).join(', ')}.{' '}
882
+ {row.subjectActorId === currentUser?.id
883
+ ? 'Your qualification.'
884
+ : 'Another inspector.'}
885
+ </li>
886
+ ))}
887
+ </ul>
888
+ <Pages
889
+ offset={qualificationOffset}
890
+ setOffset={(value) => {
891
+ setQualificationOffset(value);
892
+ setQualificationId('');
893
+ }}
894
+ hasMore={qualifications.data?.mtwContainerQualificationPage.hasMore}
895
+ loading={qualifications.loading}
896
+ label="qualifications"
897
+ />
898
+ </section>
899
+ <section className={box}>
900
+ <h2 className="text-lg font-semibold">Inspect repair history</h2>
901
+ <Selector
902
+ label="History hold"
903
+ value={historyHoldId}
904
+ onChange={(value) => {
905
+ setHistoryHoldId(value);
906
+ setRepairOffset(0);
907
+ }}
908
+ >
909
+ <option value="">Choose a recorded hold</option>
910
+ {holds.data?.mtwContainerHoldPage.items.map((row) => (
911
+ <option key={row.id} value={row.id}>
912
+ {readable(row.status)} — {row.reason} — {time(row.heldAt)}
913
+ </option>
914
+ ))}
915
+ </Selector>
916
+ </section>
917
+ {historyHoldId && (
918
+ <section className={box}>
919
+ <h2 className="text-lg font-semibold">Repair history for selected hold</h2>
920
+ {repairs.error && <p role="alert">{repairs.error}</p>}
921
+ <ul className="space-y-2">
922
+ {repairs.data?.mtwContainerRepairPage.items.map((row) => (
923
+ <li key={row.id} className="rounded border p-3 text-sm">
924
+ {time(row.completedAt)} — {row.workDescription}. Evidence: {row.evidence.length}{' '}
925
+ versions.
926
+ </li>
927
+ ))}
928
+ </ul>
929
+ <Pages
930
+ offset={repairOffset}
931
+ setOffset={setRepairOffset}
932
+ hasMore={repairs.data?.mtwContainerRepairPage.hasMore}
933
+ loading={repairs.loading}
934
+ label="repairs"
935
+ />
936
+ </section>
937
+ )}
938
+ <section className={box}>
939
+ <h2 className="text-lg font-semibold">Release decision history</h2>
940
+ {releases.error && <p role="alert">{releases.error}</p>}
941
+ <ul className="space-y-2">
942
+ {releases.data?.mtwContainerReleaseDecisionPage.items.map((row) => (
943
+ <li key={row.id} className="rounded border p-3 text-sm">
944
+ {time(row.decidedAt)} — {row.resolutionReview}. Evidence: {row.evidence.length}{' '}
945
+ versions.
946
+ </li>
947
+ ))}
948
+ </ul>
949
+ <Pages
950
+ offset={releaseOffset}
951
+ setOffset={setReleaseOffset}
952
+ hasMore={releases.data?.mtwContainerReleaseDecisionPage.hasMore}
953
+ loading={releases.loading}
954
+ label="decisions"
955
+ />
956
+ </section>
957
+ </div>
958
+ );
959
+ }