@freighttech/shipment-tracking 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (456) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +25 -0
  3. package/dist/generated/entities/bic_config/index.js +21 -0
  4. package/dist/generated/entities/bic_config/index.js.map +7 -0
  5. package/dist/generated/entities/carrier_config/index.js +27 -0
  6. package/dist/generated/entities/carrier_config/index.js.map +7 -0
  7. package/dist/generated/entities/location_override/index.js +33 -0
  8. package/dist/generated/entities/location_override/index.js.map +7 -0
  9. package/dist/generated/entities/shipment/index.js +73 -0
  10. package/dist/generated/entities/shipment/index.js.map +7 -0
  11. package/dist/generated/entities/ships_go_config/index.js +31 -0
  12. package/dist/generated/entities/ships_go_config/index.js.map +7 -0
  13. package/dist/generated/entities/tracking_event/index.js +101 -0
  14. package/dist/generated/entities/tracking_event/index.js.map +7 -0
  15. package/dist/generated/entities/tracking_job/index.js +47 -0
  16. package/dist/generated/entities/tracking_job/index.js.map +7 -0
  17. package/dist/generated/entities/webhook/index.js +25 -0
  18. package/dist/generated/entities/webhook/index.js.map +7 -0
  19. package/dist/generated/entities/webhook_delivery/index.js +25 -0
  20. package/dist/generated/entities/webhook_delivery/index.js.map +7 -0
  21. package/dist/generated/entities.ids.generated.js +21 -0
  22. package/dist/generated/entities.ids.generated.js.map +7 -0
  23. package/dist/index.js +41 -0
  24. package/dist/index.js.map +7 -0
  25. package/dist/modules/shipment_tracking/acl.js +22 -0
  26. package/dist/modules/shipment_tracking/acl.js.map +7 -0
  27. package/dist/modules/shipment_tracking/api/bic-configs/route.js +176 -0
  28. package/dist/modules/shipment_tracking/api/bic-configs/route.js.map +7 -0
  29. package/dist/modules/shipment_tracking/api/bic-configs/test/route.js +95 -0
  30. package/dist/modules/shipment_tracking/api/bic-configs/test/route.js.map +7 -0
  31. package/dist/modules/shipment_tracking/api/cargo-events/route.js +93 -0
  32. package/dist/modules/shipment_tracking/api/cargo-events/route.js.map +7 -0
  33. package/dist/modules/shipment_tracking/api/carrier-configs/route.js +139 -0
  34. package/dist/modules/shipment_tracking/api/carrier-configs/route.js.map +7 -0
  35. package/dist/modules/shipment_tracking/api/dashboard/ships-map/route.js +177 -0
  36. package/dist/modules/shipment_tracking/api/dashboard/ships-map/route.js.map +7 -0
  37. package/dist/modules/shipment_tracking/api/location-overrides/route.js +179 -0
  38. package/dist/modules/shipment_tracking/api/location-overrides/route.js.map +7 -0
  39. package/dist/modules/shipment_tracking/api/openapi.js +27 -0
  40. package/dist/modules/shipment_tracking/api/openapi.js.map +7 -0
  41. package/dist/modules/shipment_tracking/api/shipments/route.js +192 -0
  42. package/dist/modules/shipment_tracking/api/shipments/route.js.map +7 -0
  43. package/dist/modules/shipment_tracking/api/shipsgo-configs/route.js +185 -0
  44. package/dist/modules/shipment_tracking/api/shipsgo-configs/route.js.map +7 -0
  45. package/dist/modules/shipment_tracking/api/tracking-jobs/route.js +144 -0
  46. package/dist/modules/shipment_tracking/api/tracking-jobs/route.js.map +7 -0
  47. package/dist/modules/shipment_tracking/api/tracking-jobs/sync/route.js +107 -0
  48. package/dist/modules/shipment_tracking/api/tracking-jobs/sync/route.js.map +7 -0
  49. package/dist/modules/shipment_tracking/api/utils.js +12 -0
  50. package/dist/modules/shipment_tracking/api/utils.js.map +7 -0
  51. package/dist/modules/shipment_tracking/api/webhooks/deliveries/route.js +76 -0
  52. package/dist/modules/shipment_tracking/api/webhooks/deliveries/route.js.map +7 -0
  53. package/dist/modules/shipment_tracking/api/webhooks/route.js +135 -0
  54. package/dist/modules/shipment_tracking/api/webhooks/route.js.map +7 -0
  55. package/dist/modules/shipment_tracking/api/webhooks/test/route.js +71 -0
  56. package/dist/modules/shipment_tracking/api/webhooks/test/route.js.map +7 -0
  57. package/dist/modules/shipment_tracking/assets/carriers/cma_cgm.png +0 -0
  58. package/dist/modules/shipment_tracking/assets/carriers/cosco.png +0 -0
  59. package/dist/modules/shipment_tracking/assets/carriers/evergreen.png +0 -0
  60. package/dist/modules/shipment_tracking/assets/carriers/hapag_lloyd.png +0 -0
  61. package/dist/modules/shipment_tracking/assets/carriers/maersk.png +0 -0
  62. package/dist/modules/shipment_tracking/assets/carriers/msc.png +0 -0
  63. package/dist/modules/shipment_tracking/assets/carriers/one.png +0 -0
  64. package/dist/modules/shipment_tracking/assets/carriers/oocl.png +0 -0
  65. package/dist/modules/shipment_tracking/assets/carriers/yang_ming.png +0 -0
  66. package/dist/modules/shipment_tracking/assets/carriers/zim.png +0 -0
  67. package/dist/modules/shipment_tracking/assets/index.js +52 -0
  68. package/dist/modules/shipment_tracking/assets/index.js.map +7 -0
  69. package/dist/modules/shipment_tracking/backend/carrier-configs/page.js +621 -0
  70. package/dist/modules/shipment_tracking/backend/carrier-configs/page.js.map +7 -0
  71. package/dist/modules/shipment_tracking/backend/carrier-configs/page.meta.js +19 -0
  72. package/dist/modules/shipment_tracking/backend/carrier-configs/page.meta.js.map +7 -0
  73. package/dist/modules/shipment_tracking/backend/location-overrides/page.js +198 -0
  74. package/dist/modules/shipment_tracking/backend/location-overrides/page.js.map +7 -0
  75. package/dist/modules/shipment_tracking/backend/location-overrides/page.meta.js +19 -0
  76. package/dist/modules/shipment_tracking/backend/location-overrides/page.meta.js.map +7 -0
  77. package/dist/modules/shipment_tracking/backend/shipment-tracking/page.js +279 -0
  78. package/dist/modules/shipment_tracking/backend/shipment-tracking/page.js.map +7 -0
  79. package/dist/modules/shipment_tracking/backend/shipment-tracking/page.meta.js +19 -0
  80. package/dist/modules/shipment_tracking/backend/shipment-tracking/page.meta.js.map +7 -0
  81. package/dist/modules/shipment_tracking/backend/tracking-jobs/page.js +10 -0
  82. package/dist/modules/shipment_tracking/backend/tracking-jobs/page.js.map +7 -0
  83. package/dist/modules/shipment_tracking/backend/tracking-jobs/page.meta.js +19 -0
  84. package/dist/modules/shipment_tracking/backend/tracking-jobs/page.meta.js.map +7 -0
  85. package/dist/modules/shipment_tracking/backend/webhooks/page.js +198 -0
  86. package/dist/modules/shipment_tracking/backend/webhooks/page.js.map +7 -0
  87. package/dist/modules/shipment_tracking/backend/webhooks/page.meta.js +19 -0
  88. package/dist/modules/shipment_tracking/backend/webhooks/page.meta.js.map +7 -0
  89. package/dist/modules/shipment_tracking/ce.js +52 -0
  90. package/dist/modules/shipment_tracking/ce.js.map +7 -0
  91. package/dist/modules/shipment_tracking/cli.js +229 -0
  92. package/dist/modules/shipment_tracking/cli.js.map +7 -0
  93. package/dist/modules/shipment_tracking/commands/bic-configs.js +66 -0
  94. package/dist/modules/shipment_tracking/commands/bic-configs.js.map +7 -0
  95. package/dist/modules/shipment_tracking/commands/carrier-configs.js +65 -0
  96. package/dist/modules/shipment_tracking/commands/carrier-configs.js.map +7 -0
  97. package/dist/modules/shipment_tracking/commands/index.js +9 -0
  98. package/dist/modules/shipment_tracking/commands/index.js.map +7 -0
  99. package/dist/modules/shipment_tracking/commands/location-overrides.js +93 -0
  100. package/dist/modules/shipment_tracking/commands/location-overrides.js.map +7 -0
  101. package/dist/modules/shipment_tracking/commands/shipments.js +200 -0
  102. package/dist/modules/shipment_tracking/commands/shipments.js.map +7 -0
  103. package/dist/modules/shipment_tracking/commands/shipsgo-configs.js +75 -0
  104. package/dist/modules/shipment_tracking/commands/shipsgo-configs.js.map +7 -0
  105. package/dist/modules/shipment_tracking/commands/tracking-jobs.js +120 -0
  106. package/dist/modules/shipment_tracking/commands/tracking-jobs.js.map +7 -0
  107. package/dist/modules/shipment_tracking/commands/tracking.js +140 -0
  108. package/dist/modules/shipment_tracking/commands/tracking.js.map +7 -0
  109. package/dist/modules/shipment_tracking/commands/webhooks.js +115 -0
  110. package/dist/modules/shipment_tracking/commands/webhooks.js.map +7 -0
  111. package/dist/modules/shipment_tracking/components/CombinedTimestampCell.js +168 -0
  112. package/dist/modules/shipment_tracking/components/CombinedTimestampCell.js.map +7 -0
  113. package/dist/modules/shipment_tracking/components/FacilityLocationInput.js +202 -0
  114. package/dist/modules/shipment_tracking/components/FacilityLocationInput.js.map +7 -0
  115. package/dist/modules/shipment_tracking/components/LocationOverrideDrawer.js +501 -0
  116. package/dist/modules/shipment_tracking/components/LocationOverrideDrawer.js.map +7 -0
  117. package/dist/modules/shipment_tracking/components/ShipmentDetailsDrawer.js +818 -0
  118. package/dist/modules/shipment_tracking/components/ShipmentDetailsDrawer.js.map +7 -0
  119. package/dist/modules/shipment_tracking/components/ShipmentDrawer.js +404 -0
  120. package/dist/modules/shipment_tracking/components/ShipmentDrawer.js.map +7 -0
  121. package/dist/modules/shipment_tracking/components/ShipsGoConfigSection.js +200 -0
  122. package/dist/modules/shipment_tracking/components/ShipsGoConfigSection.js.map +7 -0
  123. package/dist/modules/shipment_tracking/components/TimestampCell.js +108 -0
  124. package/dist/modules/shipment_tracking/components/TimestampCell.js.map +7 -0
  125. package/dist/modules/shipment_tracking/components/TrackingJobDrawer.js +343 -0
  126. package/dist/modules/shipment_tracking/components/TrackingJobDrawer.js.map +7 -0
  127. package/dist/modules/shipment_tracking/components/VesselTrackingMap.js +496 -0
  128. package/dist/modules/shipment_tracking/components/VesselTrackingMap.js.map +7 -0
  129. package/dist/modules/shipment_tracking/components/WebhookDrawer.js +332 -0
  130. package/dist/modules/shipment_tracking/components/WebhookDrawer.js.map +7 -0
  131. package/dist/modules/shipment_tracking/data/entities.js +686 -0
  132. package/dist/modules/shipment_tracking/data/entities.js.map +7 -0
  133. package/dist/modules/shipment_tracking/data/validators.js +434 -0
  134. package/dist/modules/shipment_tracking/data/validators.js.map +7 -0
  135. package/dist/modules/shipment_tracking/di.js +60 -0
  136. package/dist/modules/shipment_tracking/di.js.map +7 -0
  137. package/dist/modules/shipment_tracking/encryption.js +12 -0
  138. package/dist/modules/shipment_tracking/encryption.js.map +7 -0
  139. package/dist/modules/shipment_tracking/events.js +87 -0
  140. package/dist/modules/shipment_tracking/events.js.map +7 -0
  141. package/dist/modules/shipment_tracking/hooks/useVesselTracking.js +137 -0
  142. package/dist/modules/shipment_tracking/hooks/useVesselTracking.js.map +7 -0
  143. package/dist/modules/shipment_tracking/i18n/de.json +327 -0
  144. package/dist/modules/shipment_tracking/i18n/en.json +327 -0
  145. package/dist/modules/shipment_tracking/i18n/es.json +327 -0
  146. package/dist/modules/shipment_tracking/i18n/pl.json +327 -0
  147. package/dist/modules/shipment_tracking/index.js +15 -0
  148. package/dist/modules/shipment_tracking/index.js.map +7 -0
  149. package/dist/modules/shipment_tracking/lib/adapters/cma-cgm.js +66 -0
  150. package/dist/modules/shipment_tracking/lib/adapters/cma-cgm.js.map +7 -0
  151. package/dist/modules/shipment_tracking/lib/adapters/cosco-types.js +1 -0
  152. package/dist/modules/shipment_tracking/lib/adapters/cosco-types.js.map +7 -0
  153. package/dist/modules/shipment_tracking/lib/adapters/cosco.js +236 -0
  154. package/dist/modules/shipment_tracking/lib/adapters/cosco.js.map +7 -0
  155. package/dist/modules/shipment_tracking/lib/adapters/evergreen.js +87 -0
  156. package/dist/modules/shipment_tracking/lib/adapters/evergreen.js.map +7 -0
  157. package/dist/modules/shipment_tracking/lib/adapters/hapag-lloyd.js +68 -0
  158. package/dist/modules/shipment_tracking/lib/adapters/hapag-lloyd.js.map +7 -0
  159. package/dist/modules/shipment_tracking/lib/adapters/index.js +20 -0
  160. package/dist/modules/shipment_tracking/lib/adapters/index.js.map +7 -0
  161. package/dist/modules/shipment_tracking/lib/adapters/maersk.js +84 -0
  162. package/dist/modules/shipment_tracking/lib/adapters/maersk.js.map +7 -0
  163. package/dist/modules/shipment_tracking/lib/adapters/msc.js +170 -0
  164. package/dist/modules/shipment_tracking/lib/adapters/msc.js.map +7 -0
  165. package/dist/modules/shipment_tracking/lib/adapters/zim.js +85 -0
  166. package/dist/modules/shipment_tracking/lib/adapters/zim.js.map +7 -0
  167. package/dist/modules/shipment_tracking/lib/audit-helpers.js +20 -0
  168. package/dist/modules/shipment_tracking/lib/audit-helpers.js.map +7 -0
  169. package/dist/modules/shipment_tracking/lib/auth/base64url.js +8 -0
  170. package/dist/modules/shipment_tracking/lib/auth/base64url.js.map +7 -0
  171. package/dist/modules/shipment_tracking/lib/auth/oauth-client.js +38 -0
  172. package/dist/modules/shipment_tracking/lib/auth/oauth-client.js.map +7 -0
  173. package/dist/modules/shipment_tracking/lib/background.js +15 -0
  174. package/dist/modules/shipment_tracking/lib/background.js.map +7 -0
  175. package/dist/modules/shipment_tracking/lib/bic-api-client.js +106 -0
  176. package/dist/modules/shipment_tracking/lib/bic-api-client.js.map +7 -0
  177. package/dist/modules/shipment_tracking/lib/carrier-adapter.js +17 -0
  178. package/dist/modules/shipment_tracking/lib/carrier-adapter.js.map +7 -0
  179. package/dist/modules/shipment_tracking/lib/current-vessel.js +149 -0
  180. package/dist/modules/shipment_tracking/lib/current-vessel.js.map +7 -0
  181. package/dist/modules/shipment_tracking/lib/dcsa-event-mapping.js +124 -0
  182. package/dist/modules/shipment_tracking/lib/dcsa-event-mapping.js.map +7 -0
  183. package/dist/modules/shipment_tracking/lib/dcsa-event-parser.js +112 -0
  184. package/dist/modules/shipment_tracking/lib/dcsa-event-parser.js.map +7 -0
  185. package/dist/modules/shipment_tracking/lib/dcsa-params.js +16 -0
  186. package/dist/modules/shipment_tracking/lib/dcsa-params.js.map +7 -0
  187. package/dist/modules/shipment_tracking/lib/empty-return.js +48 -0
  188. package/dist/modules/shipment_tracking/lib/empty-return.js.map +7 -0
  189. package/dist/modules/shipment_tracking/lib/location-overrides.js +85 -0
  190. package/dist/modules/shipment_tracking/lib/location-overrides.js.map +7 -0
  191. package/dist/modules/shipment_tracking/lib/location-types.js +59 -0
  192. package/dist/modules/shipment_tracking/lib/location-types.js.map +7 -0
  193. package/dist/modules/shipment_tracking/lib/logger.js +113 -0
  194. package/dist/modules/shipment_tracking/lib/logger.js.map +7 -0
  195. package/dist/modules/shipment_tracking/lib/poi-event-processor.js +183 -0
  196. package/dist/modules/shipment_tracking/lib/poi-event-processor.js.map +7 -0
  197. package/dist/modules/shipment_tracking/lib/poi-nats-config.js +52 -0
  198. package/dist/modules/shipment_tracking/lib/poi-nats-config.js.map +7 -0
  199. package/dist/modules/shipment_tracking/lib/poi-types.js +43 -0
  200. package/dist/modules/shipment_tracking/lib/poi-types.js.map +7 -0
  201. package/dist/modules/shipment_tracking/lib/rate-limiter.js +31 -0
  202. package/dist/modules/shipment_tracking/lib/rate-limiter.js.map +7 -0
  203. package/dist/modules/shipment_tracking/lib/route-extraction.js +187 -0
  204. package/dist/modules/shipment_tracking/lib/route-extraction.js.map +7 -0
  205. package/dist/modules/shipment_tracking/lib/route-inference.js +106 -0
  206. package/dist/modules/shipment_tracking/lib/route-inference.js.map +7 -0
  207. package/dist/modules/shipment_tracking/lib/schedule-generator.js +63 -0
  208. package/dist/modules/shipment_tracking/lib/schedule-generator.js.map +7 -0
  209. package/dist/modules/shipment_tracking/lib/shipsgo-client.js +143 -0
  210. package/dist/modules/shipment_tracking/lib/shipsgo-client.js.map +7 -0
  211. package/dist/modules/shipment_tracking/lib/shipsgo-mapper.js +204 -0
  212. package/dist/modules/shipment_tracking/lib/shipsgo-mapper.js.map +7 -0
  213. package/dist/modules/shipment_tracking/lib/status-machine.js +131 -0
  214. package/dist/modules/shipment_tracking/lib/status-machine.js.map +7 -0
  215. package/dist/modules/shipment_tracking/lib/time-extraction.js +41 -0
  216. package/dist/modules/shipment_tracking/lib/time-extraction.js.map +7 -0
  217. package/dist/modules/shipment_tracking/lib/timestamp-utils.js +100 -0
  218. package/dist/modules/shipment_tracking/lib/timestamp-utils.js.map +7 -0
  219. package/dist/modules/shipment_tracking/lib/vessel-api.js +111 -0
  220. package/dist/modules/shipment_tracking/lib/vessel-api.js.map +7 -0
  221. package/dist/modules/shipment_tracking/lib/vessel-cache.js +50 -0
  222. package/dist/modules/shipment_tracking/lib/vessel-cache.js.map +7 -0
  223. package/dist/modules/shipment_tracking/lib/vessel-extraction.js +13 -0
  224. package/dist/modules/shipment_tracking/lib/vessel-extraction.js.map +7 -0
  225. package/dist/modules/shipment_tracking/lib/webhook-dispatcher.js +62 -0
  226. package/dist/modules/shipment_tracking/lib/webhook-dispatcher.js.map +7 -0
  227. package/dist/modules/shipment_tracking/migrations/Migration20260422161208_shipment_tracking.js +48 -0
  228. package/dist/modules/shipment_tracking/migrations/Migration20260422161208_shipment_tracking.js.map +7 -0
  229. package/dist/modules/shipment_tracking/migrations/Migration20260529120000_shipment_tracking_poi_region_names.js +15 -0
  230. package/dist/modules/shipment_tracking/migrations/Migration20260529120000_shipment_tracking_poi_region_names.js.map +7 -0
  231. package/dist/modules/shipment_tracking/migrations/Migration20260821120000_shipment_tracking_shipsgo.js +47 -0
  232. package/dist/modules/shipment_tracking/migrations/Migration20260821120000_shipment_tracking_shipsgo.js.map +7 -0
  233. package/dist/modules/shipment_tracking/notifications.js +145 -0
  234. package/dist/modules/shipment_tracking/notifications.js.map +7 -0
  235. package/dist/modules/shipment_tracking/services/carrierRegistry.js +24 -0
  236. package/dist/modules/shipment_tracking/services/carrierRegistry.js.map +7 -0
  237. package/dist/modules/shipment_tracking/services/poiNatsService.js +397 -0
  238. package/dist/modules/shipment_tracking/services/poiNatsService.js.map +7 -0
  239. package/dist/modules/shipment_tracking/services/shipsGoProvider.js +163 -0
  240. package/dist/modules/shipment_tracking/services/shipsGoProvider.js.map +7 -0
  241. package/dist/modules/shipment_tracking/services/trackingService.js +1283 -0
  242. package/dist/modules/shipment_tracking/services/trackingService.js.map +7 -0
  243. package/dist/modules/shipment_tracking/services/webhookService.js +263 -0
  244. package/dist/modules/shipment_tracking/services/webhookService.js.map +7 -0
  245. package/dist/modules/shipment_tracking/setup.js +72 -0
  246. package/dist/modules/shipment_tracking/setup.js.map +7 -0
  247. package/dist/modules/shipment_tracking/subscribers/cargo-event-created.js +60 -0
  248. package/dist/modules/shipment_tracking/subscribers/cargo-event-created.js.map +7 -0
  249. package/dist/modules/shipment_tracking/subscribers/dcsa-event-webhook-dispatch.js +58 -0
  250. package/dist/modules/shipment_tracking/subscribers/dcsa-event-webhook-dispatch.js.map +7 -0
  251. package/dist/modules/shipment_tracking/subscribers/poi-event-notification.js +82 -0
  252. package/dist/modules/shipment_tracking/subscribers/poi-event-notification.js.map +7 -0
  253. package/dist/modules/shipment_tracking/subscribers/poi-event-webhook-dispatch.js +53 -0
  254. package/dist/modules/shipment_tracking/subscribers/poi-event-webhook-dispatch.js.map +7 -0
  255. package/dist/modules/shipment_tracking/subscribers/shipment-status-changed.js +28 -0
  256. package/dist/modules/shipment_tracking/subscribers/shipment-status-changed.js.map +7 -0
  257. package/dist/modules/shipment_tracking/subscribers/terminal-event-ingest.js +67 -0
  258. package/dist/modules/shipment_tracking/subscribers/terminal-event-ingest.js.map +7 -0
  259. package/dist/modules/shipment_tracking/subscribers/tracking-job-initial-poll.js +30 -0
  260. package/dist/modules/shipment_tracking/subscribers/tracking-job-initial-poll.js.map +7 -0
  261. package/dist/modules/shipment_tracking/subscribers/tracking-job-webhook-dispatch.js +19 -0
  262. package/dist/modules/shipment_tracking/subscribers/tracking-job-webhook-dispatch.js.map +7 -0
  263. package/dist/modules/shipment_tracking/tables/index.js +6 -0
  264. package/dist/modules/shipment_tracking/tables/index.js.map +7 -0
  265. package/dist/modules/shipment_tracking/tables/tracking_job/table.client.js +284 -0
  266. package/dist/modules/shipment_tracking/tables/tracking_job/table.client.js.map +7 -0
  267. package/dist/modules/shipment_tracking/tables/tracking_job/table.js +36 -0
  268. package/dist/modules/shipment_tracking/tables/tracking_job/table.js.map +7 -0
  269. package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/config.js +25 -0
  270. package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/config.js.map +7 -0
  271. package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/widget.client.js +355 -0
  272. package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/widget.client.js.map +7 -0
  273. package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/widget.js +26 -0
  274. package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/widget.js.map +7 -0
  275. package/dist/types/assets.d.js +1 -0
  276. package/dist/types/assets.d.js.map +7 -0
  277. package/generated/entities/bic_config/index.ts +20 -0
  278. package/generated/entities/carrier_config/index.ts +23 -0
  279. package/generated/entities/location_override/index.ts +26 -0
  280. package/generated/entities/shipment/index.ts +46 -0
  281. package/generated/entities/ships_go_config/index.ts +25 -0
  282. package/generated/entities/tracking_event/index.ts +60 -0
  283. package/generated/entities/tracking_job/index.ts +33 -0
  284. package/generated/entities/webhook/index.ts +22 -0
  285. package/generated/entities/webhook_delivery/index.ts +22 -0
  286. package/generated/entities.ids.generated.ts +47 -0
  287. package/package.json +81 -0
  288. package/src/index.ts +39 -0
  289. package/src/modules/shipment_tracking/__integration__/TC-TRACK-410-shipsgo-config-api.spec.ts +133 -0
  290. package/src/modules/shipment_tracking/__integration__/meta.ts +4 -0
  291. package/src/modules/shipment_tracking/__tests__/empty-return-stop.test.ts +231 -0
  292. package/src/modules/shipment_tracking/__tests__/fixtures/hapag-lloyd-transship-container.json +702 -0
  293. package/src/modules/shipment_tracking/__tests__/fixtures/index.ts +434 -0
  294. package/src/modules/shipment_tracking/__tests__/fixtures/maersk-multi-transship-completed.json +1518 -0
  295. package/src/modules/shipment_tracking/__tests__/fixtures/maersk-transship-intransit.json +558 -0
  296. package/src/modules/shipment_tracking/__tests__/fixtures/msc-direct.json +222 -0
  297. package/src/modules/shipment_tracking/__tests__/fixtures/msc-multi-transship-completed.json +974 -0
  298. package/src/modules/shipment_tracking/__tests__/fixtures/msc-multi.json +4846 -0
  299. package/src/modules/shipment_tracking/__tests__/fixtures/msc-transship.json +409 -0
  300. package/src/modules/shipment_tracking/__tests__/fixtures/poi-events.json +240 -0
  301. package/src/modules/shipment_tracking/__tests__/fixtures/synthetic/index.ts +138 -0
  302. package/src/modules/shipment_tracking/__tests__/fixtures/synthetic-eta-updates.json +288 -0
  303. package/src/modules/shipment_tracking/__tests__/fixtures/synthetic-route-inference.json +201 -0
  304. package/src/modules/shipment_tracking/__tests__/fixtures/synthetic-voyage-progression.json +410 -0
  305. package/src/modules/shipment_tracking/__tests__/shipsgo-air-mapper.test.ts +157 -0
  306. package/src/modules/shipment_tracking/__tests__/shipsgo-client.test.ts +155 -0
  307. package/src/modules/shipment_tracking/__tests__/shipsgo-mapper.test.ts +201 -0
  308. package/src/modules/shipment_tracking/__tests__/shipsgo-poll.test.ts +357 -0
  309. package/src/modules/shipment_tracking/__tests__/shipsgo-provider.test.ts +364 -0
  310. package/src/modules/shipment_tracking/__tests__/trackingService.integration.test.ts +2248 -0
  311. package/src/modules/shipment_tracking/__tests__/webhookPayload.test.ts +151 -0
  312. package/src/modules/shipment_tracking/acl.ts +18 -0
  313. package/src/modules/shipment_tracking/api/bic-configs/route.ts +206 -0
  314. package/src/modules/shipment_tracking/api/bic-configs/test/route.ts +108 -0
  315. package/src/modules/shipment_tracking/api/cargo-events/route.ts +101 -0
  316. package/src/modules/shipment_tracking/api/carrier-configs/route.ts +142 -0
  317. package/src/modules/shipment_tracking/api/dashboard/ships-map/route.ts +246 -0
  318. package/src/modules/shipment_tracking/api/location-overrides/route.ts +185 -0
  319. package/src/modules/shipment_tracking/api/openapi.ts +28 -0
  320. package/src/modules/shipment_tracking/api/shipments/route.ts +197 -0
  321. package/src/modules/shipment_tracking/api/shipsgo-configs/route.ts +215 -0
  322. package/src/modules/shipment_tracking/api/tracking-jobs/route.ts +149 -0
  323. package/src/modules/shipment_tracking/api/tracking-jobs/sync/route.ts +116 -0
  324. package/src/modules/shipment_tracking/api/utils.ts +10 -0
  325. package/src/modules/shipment_tracking/api/webhooks/deliveries/route.ts +82 -0
  326. package/src/modules/shipment_tracking/api/webhooks/route.ts +138 -0
  327. package/src/modules/shipment_tracking/api/webhooks/test/route.ts +84 -0
  328. package/src/modules/shipment_tracking/assets/carriers/cma_cgm.png +0 -0
  329. package/src/modules/shipment_tracking/assets/carriers/cosco.png +0 -0
  330. package/src/modules/shipment_tracking/assets/carriers/evergreen.png +0 -0
  331. package/src/modules/shipment_tracking/assets/carriers/hapag_lloyd.png +0 -0
  332. package/src/modules/shipment_tracking/assets/carriers/maersk.png +0 -0
  333. package/src/modules/shipment_tracking/assets/carriers/msc.png +0 -0
  334. package/src/modules/shipment_tracking/assets/carriers/one.png +0 -0
  335. package/src/modules/shipment_tracking/assets/carriers/oocl.png +0 -0
  336. package/src/modules/shipment_tracking/assets/carriers/yang_ming.png +0 -0
  337. package/src/modules/shipment_tracking/assets/carriers/zim.png +0 -0
  338. package/src/modules/shipment_tracking/assets/index.ts +66 -0
  339. package/src/modules/shipment_tracking/backend/carrier-configs/page.meta.ts +16 -0
  340. package/src/modules/shipment_tracking/backend/carrier-configs/page.tsx +782 -0
  341. package/src/modules/shipment_tracking/backend/location-overrides/page.meta.ts +16 -0
  342. package/src/modules/shipment_tracking/backend/location-overrides/page.tsx +241 -0
  343. package/src/modules/shipment_tracking/backend/shipment-tracking/page.meta.ts +16 -0
  344. package/src/modules/shipment_tracking/backend/shipment-tracking/page.tsx +340 -0
  345. package/src/modules/shipment_tracking/backend/tracking-jobs/page.meta.ts +16 -0
  346. package/src/modules/shipment_tracking/backend/tracking-jobs/page.tsx +16 -0
  347. package/src/modules/shipment_tracking/backend/webhooks/page.meta.ts +16 -0
  348. package/src/modules/shipment_tracking/backend/webhooks/page.tsx +228 -0
  349. package/src/modules/shipment_tracking/ce.ts +48 -0
  350. package/src/modules/shipment_tracking/cli.ts +321 -0
  351. package/src/modules/shipment_tracking/commands/bic-configs.ts +94 -0
  352. package/src/modules/shipment_tracking/commands/carrier-configs.ts +89 -0
  353. package/src/modules/shipment_tracking/commands/index.ts +8 -0
  354. package/src/modules/shipment_tracking/commands/location-overrides.ts +119 -0
  355. package/src/modules/shipment_tracking/commands/shipments.ts +247 -0
  356. package/src/modules/shipment_tracking/commands/shipsgo-configs.ts +101 -0
  357. package/src/modules/shipment_tracking/commands/tracking-jobs.ts +158 -0
  358. package/src/modules/shipment_tracking/commands/tracking.ts +230 -0
  359. package/src/modules/shipment_tracking/commands/webhooks.ts +159 -0
  360. package/src/modules/shipment_tracking/components/CombinedTimestampCell.tsx +236 -0
  361. package/src/modules/shipment_tracking/components/FacilityLocationInput.tsx +235 -0
  362. package/src/modules/shipment_tracking/components/LocationOverrideDrawer.tsx +586 -0
  363. package/src/modules/shipment_tracking/components/ShipmentDetailsDrawer.tsx +1364 -0
  364. package/src/modules/shipment_tracking/components/ShipmentDrawer.tsx +498 -0
  365. package/src/modules/shipment_tracking/components/ShipsGoConfigSection.tsx +266 -0
  366. package/src/modules/shipment_tracking/components/TimestampCell.tsx +146 -0
  367. package/src/modules/shipment_tracking/components/TrackingJobDrawer.tsx +467 -0
  368. package/src/modules/shipment_tracking/components/VesselTrackingMap.tsx +761 -0
  369. package/src/modules/shipment_tracking/components/WebhookDrawer.tsx +434 -0
  370. package/src/modules/shipment_tracking/data/entities.ts +748 -0
  371. package/src/modules/shipment_tracking/data/validators.ts +523 -0
  372. package/src/modules/shipment_tracking/di.ts +73 -0
  373. package/src/modules/shipment_tracking/encryption.ts +17 -0
  374. package/src/modules/shipment_tracking/events.ts +122 -0
  375. package/src/modules/shipment_tracking/hooks/useVesselTracking.ts +297 -0
  376. package/src/modules/shipment_tracking/i18n/de.json +327 -0
  377. package/src/modules/shipment_tracking/i18n/en.json +327 -0
  378. package/src/modules/shipment_tracking/i18n/es.json +327 -0
  379. package/src/modules/shipment_tracking/i18n/pl.json +327 -0
  380. package/src/modules/shipment_tracking/index.ts +13 -0
  381. package/src/modules/shipment_tracking/lib/__tests__/dcsa-event-mapping.test.ts +385 -0
  382. package/src/modules/shipment_tracking/lib/__tests__/dcsa-event-parser.test.ts +398 -0
  383. package/src/modules/shipment_tracking/lib/__tests__/empty-return.test.ts +174 -0
  384. package/src/modules/shipment_tracking/lib/__tests__/poi-event-processor.test.ts +699 -0
  385. package/src/modules/shipment_tracking/lib/__tests__/route-inference.test.ts +402 -0
  386. package/src/modules/shipment_tracking/lib/__tests__/status-machine.test.ts +447 -0
  387. package/src/modules/shipment_tracking/lib/__tests__/time-extraction.test.ts +331 -0
  388. package/src/modules/shipment_tracking/lib/__tests__/timestamp-utils.test.ts +260 -0
  389. package/src/modules/shipment_tracking/lib/__tests__/vessel-api.test.ts +125 -0
  390. package/src/modules/shipment_tracking/lib/__tests__/vessel-extraction.test.ts +108 -0
  391. package/src/modules/shipment_tracking/lib/adapters/cma-cgm.ts +84 -0
  392. package/src/modules/shipment_tracking/lib/adapters/cosco-types.ts +145 -0
  393. package/src/modules/shipment_tracking/lib/adapters/cosco.ts +314 -0
  394. package/src/modules/shipment_tracking/lib/adapters/evergreen.ts +107 -0
  395. package/src/modules/shipment_tracking/lib/adapters/hapag-lloyd.ts +88 -0
  396. package/src/modules/shipment_tracking/lib/adapters/index.ts +18 -0
  397. package/src/modules/shipment_tracking/lib/adapters/maersk.ts +104 -0
  398. package/src/modules/shipment_tracking/lib/adapters/msc.ts +223 -0
  399. package/src/modules/shipment_tracking/lib/adapters/zim.ts +106 -0
  400. package/src/modules/shipment_tracking/lib/audit-helpers.ts +29 -0
  401. package/src/modules/shipment_tracking/lib/auth/base64url.ts +4 -0
  402. package/src/modules/shipment_tracking/lib/auth/oauth-client.ts +53 -0
  403. package/src/modules/shipment_tracking/lib/background.ts +24 -0
  404. package/src/modules/shipment_tracking/lib/bic-api-client.ts +199 -0
  405. package/src/modules/shipment_tracking/lib/carrier-adapter.ts +136 -0
  406. package/src/modules/shipment_tracking/lib/current-vessel.ts +274 -0
  407. package/src/modules/shipment_tracking/lib/dcsa-event-mapping.ts +202 -0
  408. package/src/modules/shipment_tracking/lib/dcsa-event-parser.ts +163 -0
  409. package/src/modules/shipment_tracking/lib/dcsa-params.ts +14 -0
  410. package/src/modules/shipment_tracking/lib/empty-return.ts +122 -0
  411. package/src/modules/shipment_tracking/lib/location-overrides.ts +150 -0
  412. package/src/modules/shipment_tracking/lib/location-types.ts +154 -0
  413. package/src/modules/shipment_tracking/lib/logger.ts +195 -0
  414. package/src/modules/shipment_tracking/lib/poi-event-processor.ts +302 -0
  415. package/src/modules/shipment_tracking/lib/poi-nats-config.ts +134 -0
  416. package/src/modules/shipment_tracking/lib/poi-types.ts +198 -0
  417. package/src/modules/shipment_tracking/lib/rate-limiter.ts +58 -0
  418. package/src/modules/shipment_tracking/lib/route-extraction.ts +439 -0
  419. package/src/modules/shipment_tracking/lib/route-inference.ts +238 -0
  420. package/src/modules/shipment_tracking/lib/schedule-generator.ts +92 -0
  421. package/src/modules/shipment_tracking/lib/shipsgo-client.ts +350 -0
  422. package/src/modules/shipment_tracking/lib/shipsgo-mapper.ts +296 -0
  423. package/src/modules/shipment_tracking/lib/status-machine.ts +230 -0
  424. package/src/modules/shipment_tracking/lib/time-extraction.ts +85 -0
  425. package/src/modules/shipment_tracking/lib/timestamp-utils.ts +244 -0
  426. package/src/modules/shipment_tracking/lib/vessel-api.ts +299 -0
  427. package/src/modules/shipment_tracking/lib/vessel-cache.ts +102 -0
  428. package/src/modules/shipment_tracking/lib/vessel-extraction.ts +39 -0
  429. package/src/modules/shipment_tracking/lib/webhook-dispatcher.ts +93 -0
  430. package/src/modules/shipment_tracking/migrations/.snapshot-open-mercato.json +2914 -0
  431. package/src/modules/shipment_tracking/migrations/Migration20260422161208_shipment_tracking.ts +60 -0
  432. package/src/modules/shipment_tracking/migrations/Migration20260529120000_shipment_tracking_poi_region_names.ts +22 -0
  433. package/src/modules/shipment_tracking/migrations/Migration20260821120000_shipment_tracking_shipsgo.ts +65 -0
  434. package/src/modules/shipment_tracking/notifications.ts +151 -0
  435. package/src/modules/shipment_tracking/services/carrierRegistry.ts +29 -0
  436. package/src/modules/shipment_tracking/services/poiNatsService.ts +526 -0
  437. package/src/modules/shipment_tracking/services/shipsGoProvider.ts +231 -0
  438. package/src/modules/shipment_tracking/services/trackingService.ts +1777 -0
  439. package/src/modules/shipment_tracking/services/webhookService.ts +347 -0
  440. package/src/modules/shipment_tracking/setup.ts +99 -0
  441. package/src/modules/shipment_tracking/subscribers/__tests__/terminal-event-ingest.test.ts +141 -0
  442. package/src/modules/shipment_tracking/subscribers/cargo-event-created.ts +115 -0
  443. package/src/modules/shipment_tracking/subscribers/dcsa-event-webhook-dispatch.ts +115 -0
  444. package/src/modules/shipment_tracking/subscribers/poi-event-notification.ts +144 -0
  445. package/src/modules/shipment_tracking/subscribers/poi-event-webhook-dispatch.ts +94 -0
  446. package/src/modules/shipment_tracking/subscribers/shipment-status-changed.ts +41 -0
  447. package/src/modules/shipment_tracking/subscribers/terminal-event-ingest.ts +109 -0
  448. package/src/modules/shipment_tracking/subscribers/tracking-job-initial-poll.ts +53 -0
  449. package/src/modules/shipment_tracking/subscribers/tracking-job-webhook-dispatch.ts +50 -0
  450. package/src/modules/shipment_tracking/tables/index.ts +4 -0
  451. package/src/modules/shipment_tracking/tables/tracking_job/table.client.tsx +337 -0
  452. package/src/modules/shipment_tracking/tables/tracking_job/table.ts +34 -0
  453. package/src/modules/shipment_tracking/widgets/dashboard/ships-map/config.ts +32 -0
  454. package/src/modules/shipment_tracking/widgets/dashboard/ships-map/widget.client.tsx +448 -0
  455. package/src/modules/shipment_tracking/widgets/dashboard/ships-map/widget.ts +25 -0
  456. package/src/types/assets.d.ts +5 -0
@@ -0,0 +1,496 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { useState, useCallback, useMemo, useEffect } from "react";
5
+ import { GoogleMap, useJsApiLoader, MarkerF, PolylineF, CircleF, InfoWindowF } from "@react-google-maps/api";
6
+ import { Ship, Navigation, Anchor, MapPin, Clock, Building2, Ruler, Info, X } from "lucide-react";
7
+ import { useVesselTracking } from "../hooks/useVesselTracking.js";
8
+ import { Spinner } from "@freighttech/ui/primitives/spinner";
9
+ import { useT, useLocale } from "@open-mercato/shared/lib/i18n/context";
10
+ const containerStyle = {
11
+ width: "100%",
12
+ height: "100%"
13
+ };
14
+ const mapOptions = {
15
+ zoomControl: true,
16
+ mapTypeControl: false,
17
+ scaleControl: false,
18
+ streetViewControl: false,
19
+ rotateControl: false,
20
+ fullscreenControl: false,
21
+ disableDefaultUI: false,
22
+ gestureHandling: "cooperative",
23
+ styles: [
24
+ {
25
+ featureType: "water",
26
+ elementType: "geometry",
27
+ stylers: [{ color: "#bfdbfe" }]
28
+ // Light blue for water
29
+ },
30
+ {
31
+ featureType: "landscape",
32
+ elementType: "geometry",
33
+ stylers: [{ color: "#f5f3ff" }]
34
+ // Light purple for land
35
+ },
36
+ {
37
+ featureType: "road",
38
+ elementType: "geometry",
39
+ stylers: [{ color: "#e0e7ff" }]
40
+ // Light indigo for roads
41
+ }
42
+ ]
43
+ };
44
+ const defaultCenter = { lat: 54.5, lng: 18.5 };
45
+ const MIN_POI_ZOOM = 6;
46
+ const POI_COLORS = {
47
+ PORT: "#2563eb",
48
+ // blue
49
+ TERMINAL: "#059669",
50
+ // emerald
51
+ WAYPOINT: "#d97706",
52
+ // amber
53
+ PORT_GEOMETRIC_CENTER: "#64748b"
54
+ // slate
55
+ };
56
+ function getPoiPrimaryName(poi, locale) {
57
+ if (poi.type === "TERMINAL") {
58
+ return poi.terminalName || poi.portName || poi.city || poi.locode || poi.code;
59
+ }
60
+ if (poi.type === "PORT" || poi.type === "PORT_GEOMETRIC_CENTER") {
61
+ return poi.city || poi.portName || poi.locode || poi.code;
62
+ }
63
+ const region = locale === "pl" ? poi.regionNamePl || poi.regionNameEn : poi.regionNameEn || poi.regionNamePl;
64
+ return region || poi.locode || poi.code;
65
+ }
66
+ function getPoiTypeLabel(type, t) {
67
+ switch (type) {
68
+ case "PORT":
69
+ return t("shipment_tracking.map.poi.port", "Port");
70
+ case "TERMINAL":
71
+ return t("shipment_tracking.map.poi.terminal", "Terminal");
72
+ case "WAYPOINT":
73
+ return t("shipment_tracking.map.poi.waypoint", "Waypoint");
74
+ case "PORT_GEOMETRIC_CENTER":
75
+ return t("shipment_tracking.map.poi.portCenter", "Port center");
76
+ default:
77
+ return type;
78
+ }
79
+ }
80
+ function calculateVesselDimensions(vessel) {
81
+ const dims = vessel?.dimensions;
82
+ if (!dims) {
83
+ return { length: 0, width: 0, hasValidDimensions: false };
84
+ }
85
+ const length = (dims.a ?? 0) + (dims.b ?? 0);
86
+ const width = (dims.c ?? 0) + (dims.d ?? 0);
87
+ const hasValidDimensions = length > 0 && width > 0;
88
+ return { length, width, hasValidDimensions };
89
+ }
90
+ function formatRelativeTime(dateString, t) {
91
+ if (!dateString) return "";
92
+ const date = new Date(dateString);
93
+ if (Number.isNaN(date.getTime())) return "";
94
+ const now = /* @__PURE__ */ new Date();
95
+ const diffMs = now.getTime() - date.getTime();
96
+ const diffMinutes = Math.floor(diffMs / 6e4);
97
+ const diffHours = Math.floor(diffMinutes / 60);
98
+ const diffDays = Math.floor(diffHours / 24);
99
+ if (diffMinutes < 1) {
100
+ return t("shipment_tracking.map.justNow", "Just now");
101
+ }
102
+ if (diffMinutes < 60) {
103
+ return t("shipment_tracking.map.minutesAgo", "{{count}} min ago", { count: diffMinutes });
104
+ }
105
+ if (diffHours < 24) {
106
+ return t("shipment_tracking.map.hoursAgo", "{{count}}h ago", { count: diffHours });
107
+ }
108
+ return t("shipment_tracking.map.daysAgo", "{{count}}d ago", { count: diffDays });
109
+ }
110
+ function VesselInfoCard({
111
+ vessel,
112
+ displayName,
113
+ isPlannedVessel,
114
+ containerStatus,
115
+ currentPort,
116
+ currentLeg,
117
+ t
118
+ }) {
119
+ const { length, width, hasValidDimensions } = calculateVesselDimensions(vessel);
120
+ const lastUpdate = formatRelativeTime(vessel?.updatedAt, t);
121
+ const getVesselStatusDisplay = () => {
122
+ if (vessel?.status === "IN_PORT") {
123
+ return {
124
+ icon: /* @__PURE__ */ jsx(Anchor, { className: "w-3 h-3 text-green-600 dark:text-green-400" }),
125
+ text: vessel.currentPort?.name || t("shipment_tracking.map.inPort", "In Port"),
126
+ color: "text-green-600 dark:text-green-400"
127
+ };
128
+ }
129
+ if (vessel?.status === "AT_SEA") {
130
+ const destination = vessel.lastDestinationPort?.name || vessel.lastDestination;
131
+ return {
132
+ icon: /* @__PURE__ */ jsx(Navigation, { className: "w-3 h-3 text-blue-600 dark:text-blue-400" }),
133
+ text: destination ? t("shipment_tracking.map.atSeaTo", "At Sea -> {{destination}}", { destination }) : t("shipment_tracking.map.atSea", "At Sea"),
134
+ color: "text-blue-600 dark:text-blue-400"
135
+ };
136
+ }
137
+ return {
138
+ icon: /* @__PURE__ */ jsx(Info, { className: "w-3 h-3 text-muted-foreground" }),
139
+ text: t("shipment_tracking.map.unknown", "Unknown"),
140
+ color: "text-muted-foreground"
141
+ };
142
+ };
143
+ const statusDisplay = getVesselStatusDisplay();
144
+ return /* @__PURE__ */ jsxs("div", { className: "bg-card border border-border rounded-l-lg border-r-0 px-3 py-2.5 h-full overflow-y-auto", children: [
145
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 mb-1", children: [
146
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 min-w-0", children: [
147
+ /* @__PURE__ */ jsx(Ship, { className: "w-4 h-4 text-blue-500 dark:text-blue-400 flex-shrink-0" }),
148
+ /* @__PURE__ */ jsx("h2", { className: "font-semibold text-sm truncate text-foreground", children: displayName })
149
+ ] }),
150
+ isPlannedVessel && /* @__PURE__ */ jsx("span", { className: "text-[10px] px-1.5 py-0.5 bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-400 rounded flex-shrink-0", children: t("shipment_tracking.map.planned", "Planned") })
151
+ ] }),
152
+ vessel?.imo && /* @__PURE__ */ jsxs("div", { className: "text-xs text-muted-foreground font-mono mb-2", children: [
153
+ "IMO ",
154
+ vessel.imo
155
+ ] }),
156
+ /* @__PURE__ */ jsxs("div", { className: "border-t border-border pt-2 space-y-1.5", children: [
157
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs", children: [
158
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/70 w-14 flex-shrink-0 truncate", title: t("shipment_tracking.map.status", "Status"), children: t("shipment_tracking.map.status", "Status") }),
159
+ /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-1 ${statusDisplay.color} truncate`, children: [
160
+ statusDisplay.icon,
161
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: statusDisplay.text })
162
+ ] })
163
+ ] }),
164
+ vessel?.shipType && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs", children: [
165
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/70 w-14 flex-shrink-0 truncate", title: t("shipment_tracking.map.type", "Type"), children: t("shipment_tracking.map.type", "Type") }),
166
+ /* @__PURE__ */ jsx("span", { className: "text-foreground truncate", title: vessel.shipType, children: vessel.shipType })
167
+ ] }),
168
+ hasValidDimensions && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs", children: [
169
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/70 w-14 flex-shrink-0 truncate", title: t("shipment_tracking.map.size", "Size"), children: t("shipment_tracking.map.size", "Size") }),
170
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-foreground", children: [
171
+ /* @__PURE__ */ jsx(Ruler, { className: "w-3 h-3 text-muted-foreground" }),
172
+ /* @__PURE__ */ jsxs("span", { children: [
173
+ length,
174
+ "m x ",
175
+ width,
176
+ "m"
177
+ ] })
178
+ ] })
179
+ ] }),
180
+ vessel?.operatorName && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs", children: [
181
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/70 w-14 flex-shrink-0 truncate", title: t("shipment_tracking.map.operator", "Operator"), children: t("shipment_tracking.map.operator", "Operator") }),
182
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-foreground truncate", title: vessel.operatorName, children: [
183
+ /* @__PURE__ */ jsx(Building2, { className: "w-3 h-3 text-muted-foreground flex-shrink-0" }),
184
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: vessel.operatorName })
185
+ ] })
186
+ ] }),
187
+ lastUpdate && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs", children: [
188
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/70 w-14 flex-shrink-0 truncate", title: t("shipment_tracking.map.updated", "Updated"), children: t("shipment_tracking.map.updated", "Updated") }),
189
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-muted-foreground", children: [
190
+ /* @__PURE__ */ jsx(Clock, { className: "w-3 h-3 text-muted-foreground" }),
191
+ /* @__PURE__ */ jsx("span", { children: lastUpdate })
192
+ ] })
193
+ ] })
194
+ ] }),
195
+ containerStatus && containerStatus !== "delivered" && /* @__PURE__ */ jsx("div", { className: "border-t border-border mt-2 pt-2", children: containerStatus === "in_transit" && currentLeg ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs text-blue-600 dark:text-blue-400", children: [
196
+ /* @__PURE__ */ jsx(MapPin, { className: "w-3 h-3" }),
197
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: t("shipment_tracking.map.inTransitTo", "In transit to {{destination}}", {
198
+ destination: currentLeg.toPort
199
+ }) })
200
+ ] }) : containerStatus === "at_port" && currentPort ? /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
201
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs text-green-600 dark:text-green-400", children: [
202
+ /* @__PURE__ */ jsx(MapPin, { className: "w-3 h-3" }),
203
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: t("shipment_tracking.map.containerAtPort", "Container at {{port}}", {
204
+ port: currentPort
205
+ }) })
206
+ ] }),
207
+ isPlannedVessel && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs text-amber-600 dark:text-amber-400", children: [
208
+ /* @__PURE__ */ jsx(Clock, { className: "w-3 h-3" }),
209
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: t("shipment_tracking.map.awaitingVessel", "Awaiting this vessel") })
210
+ ] })
211
+ ] }) : containerStatus === "not_departed" ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs text-amber-600 dark:text-amber-400", children: [
212
+ /* @__PURE__ */ jsx(Clock, { className: "w-3 h-3" }),
213
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: t("shipment_tracking.map.awaitingDeparture", "Awaiting departure") })
214
+ ] }) : null })
215
+ ] });
216
+ }
217
+ function VesselTrackingMap({
218
+ vesselImo,
219
+ vesselName,
220
+ height = "250px",
221
+ autoRefresh = true,
222
+ refreshInterval = 3e4,
223
+ showInfoOverlay = true,
224
+ showPois = true,
225
+ containerStatus,
226
+ currentPort,
227
+ isPlannedVessel = false,
228
+ currentLeg,
229
+ traceFrom
230
+ }) {
231
+ const t = useT();
232
+ const locale = useLocale();
233
+ const { isLoaded, loadError } = useJsApiLoader({
234
+ id: "google-map-script",
235
+ googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY || ""
236
+ });
237
+ const [map, setMap] = useState(null);
238
+ const [zoom, setZoom] = useState(8);
239
+ const [selectedPoi, setSelectedPoi] = useState(null);
240
+ const enablePois = showPois && zoom >= MIN_POI_ZOOM;
241
+ useEffect(() => {
242
+ if (!enablePois) setSelectedPoi(null);
243
+ }, [enablePois]);
244
+ const {
245
+ vessel,
246
+ isVesselLoading,
247
+ vesselError,
248
+ trace,
249
+ isTraceLoading,
250
+ isDebouncing,
251
+ setBounds,
252
+ pois
253
+ } = useVesselTracking(vesselImo, {
254
+ autoRefresh,
255
+ vesselRefreshInterval: refreshInterval,
256
+ boundsDebounceDelay: 500,
257
+ traceLimit: 5e3,
258
+ traceFrom,
259
+ enablePois
260
+ });
261
+ const onMapLoad = useCallback((mapInstance) => {
262
+ setMap(mapInstance);
263
+ }, []);
264
+ const handleMapIdle = useCallback(() => {
265
+ if (!map) return;
266
+ const bounds = map.getBounds();
267
+ if (!bounds) return;
268
+ const currentZoom = map.getZoom();
269
+ if (typeof currentZoom === "number") setZoom(currentZoom);
270
+ const ne = bounds.getNorthEast();
271
+ const sw = bounds.getSouthWest();
272
+ const MARGIN_DEGREES = 0.3;
273
+ setBounds({
274
+ north: Math.min(90, ne.lat() + MARGIN_DEGREES),
275
+ south: Math.max(-90, sw.lat() - MARGIN_DEGREES),
276
+ east: Math.min(180, ne.lng() + MARGIN_DEGREES),
277
+ west: Math.max(-180, sw.lng() - MARGIN_DEGREES)
278
+ });
279
+ }, [map, setBounds]);
280
+ const shipIcon = useMemo(() => {
281
+ if (!isLoaded || typeof window === "undefined") return void 0;
282
+ const google = window.google;
283
+ if (!google) return void 0;
284
+ const heading = vessel?.lastHeading ?? 0;
285
+ const containerShipPath = `
286
+ M 12 2
287
+ L 8 7
288
+ L 8 30
289
+ Q 8 32, 10 32
290
+ L 10 34
291
+ L 14 34
292
+ L 14 32
293
+ Q 16 32, 16 30
294
+ L 16 7
295
+ L 12 2
296
+ Z
297
+ M 10 32
298
+ L 10 36
299
+ L 14 36
300
+ L 14 32
301
+ Z
302
+ `;
303
+ return {
304
+ path: containerShipPath,
305
+ fillColor: "#0f172a",
306
+ // Dark slate hull
307
+ fillOpacity: 0.95,
308
+ strokeColor: "#ffffff",
309
+ strokeWeight: 1.5,
310
+ scale: 1,
311
+ rotation: heading,
312
+ anchor: new google.maps.Point(12, 18)
313
+ // Center point for rotation
314
+ };
315
+ }, [isLoaded, vessel?.lastHeading]);
316
+ const poiDotIcon = useMemo(() => {
317
+ if (!isLoaded || typeof window === "undefined") return null;
318
+ const google = window.google;
319
+ if (!google) return null;
320
+ return (color, selected) => ({
321
+ path: google.maps.SymbolPath.CIRCLE,
322
+ scale: selected ? 6 : 4,
323
+ fillColor: color,
324
+ fillOpacity: 0.95,
325
+ strokeColor: "#ffffff",
326
+ strokeWeight: 1.5
327
+ });
328
+ }, [isLoaded]);
329
+ const infoWindowOptions = useMemo(() => {
330
+ if (!isLoaded || typeof window === "undefined") return void 0;
331
+ const google = window.google;
332
+ if (!google) return void 0;
333
+ return {
334
+ headerDisabled: true,
335
+ pixelOffset: new google.maps.Size(0, -4),
336
+ maxWidth: 260
337
+ };
338
+ }, [isLoaded]);
339
+ const center = useMemo(() => {
340
+ if (vessel?.lastPosition) {
341
+ return { lat: vessel.lastPosition.lat, lng: vessel.lastPosition.lng };
342
+ }
343
+ return defaultCenter;
344
+ }, [vessel?.lastPosition]);
345
+ const tracePath = useMemo(() => {
346
+ if (!trace?.trace) return [];
347
+ return trace.trace.filter((p) => p.lat && p.lng && p.eventType === "POSITION_UPDATE").map((p) => ({ lat: p.lat, lng: p.lng }));
348
+ }, [trace?.trace]);
349
+ if (loadError) {
350
+ return /* @__PURE__ */ jsx("div", { className: "flex w-full", style: { height }, children: /* @__PURE__ */ jsx("div", { className: "w-full flex items-center justify-center bg-muted rounded-lg border border-border", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
351
+ /* @__PURE__ */ jsx(Ship, { className: "w-8 h-8 text-muted-foreground mx-auto mb-2" }),
352
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("shipment_tracking.map.loadError", "Failed to load map") })
353
+ ] }) }) });
354
+ }
355
+ if (!isLoaded || isVesselLoading && !vessel) {
356
+ return /* @__PURE__ */ jsx("div", { className: "flex w-full", style: { height }, children: /* @__PURE__ */ jsx("div", { className: "w-full flex items-center justify-center bg-muted rounded-lg border border-border", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2", children: [
357
+ /* @__PURE__ */ jsx(Spinner, { className: "h-6 w-6" }),
358
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: t("shipment_tracking.map.loading", "Loading map...") })
359
+ ] }) }) });
360
+ }
361
+ if (!vessel && !isVesselLoading) {
362
+ return /* @__PURE__ */ jsx("div", { className: "flex w-full", style: { height }, children: /* @__PURE__ */ jsx("div", { className: "w-full flex items-center justify-center bg-muted rounded-lg border border-border", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
363
+ /* @__PURE__ */ jsx(Ship, { className: "w-8 h-8 text-muted-foreground mx-auto mb-2" }),
364
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: vesselError ? t("shipment_tracking.map.vesselError", "Failed to load vessel data") : t("shipment_tracking.map.vesselNotFound", "Vessel not found") })
365
+ ] }) }) });
366
+ }
367
+ const displayName = vesselName || vessel?.name || "Unknown Vessel";
368
+ return /* @__PURE__ */ jsxs("div", { className: "flex w-full", style: { height }, children: [
369
+ showInfoOverlay && /* @__PURE__ */ jsx("div", { className: "w-1/3 flex-shrink-0", children: /* @__PURE__ */ jsx(
370
+ VesselInfoCard,
371
+ {
372
+ vessel,
373
+ displayName,
374
+ isPlannedVessel,
375
+ containerStatus,
376
+ currentPort,
377
+ currentLeg,
378
+ t
379
+ }
380
+ ) }),
381
+ /* @__PURE__ */ jsxs("div", { className: `relative border border-border overflow-hidden ${showInfoOverlay ? "w-2/3 rounded-r-lg" : "w-full rounded-lg"}`, children: [
382
+ /* @__PURE__ */ jsxs(
383
+ GoogleMap,
384
+ {
385
+ mapContainerStyle: containerStyle,
386
+ center,
387
+ zoom: 8,
388
+ onLoad: onMapLoad,
389
+ onIdle: handleMapIdle,
390
+ options: mapOptions,
391
+ children: [
392
+ vessel?.lastPosition && /* @__PURE__ */ jsx(
393
+ MarkerF,
394
+ {
395
+ position: { lat: vessel.lastPosition.lat, lng: vessel.lastPosition.lng },
396
+ icon: shipIcon,
397
+ title: displayName,
398
+ zIndex: 2e3
399
+ }
400
+ ),
401
+ tracePath.length > 1 && /* @__PURE__ */ jsx(
402
+ PolylineF,
403
+ {
404
+ path: tracePath,
405
+ options: {
406
+ strokeColor: "#8b5cf6",
407
+ // Purple
408
+ strokeOpacity: 0.6,
409
+ strokeWeight: 2,
410
+ geodesic: true
411
+ }
412
+ }
413
+ ),
414
+ enablePois && pois?.map((poi) => {
415
+ const color = POI_COLORS[poi.type] ?? "#64748b";
416
+ const isSelected = selectedPoi?.code === poi.code;
417
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
418
+ /* @__PURE__ */ jsx(
419
+ CircleF,
420
+ {
421
+ center: poi.center,
422
+ radius: poi.radiusMeters,
423
+ options: {
424
+ fillColor: color,
425
+ fillOpacity: isSelected ? 0.2 : 0.08,
426
+ strokeColor: color,
427
+ strokeOpacity: isSelected ? 0.9 : 0.5,
428
+ strokeWeight: 1,
429
+ clickable: false,
430
+ // Smaller circles on top so they aren't buried under large translucent fills
431
+ zIndex: Math.round(1e6 / Math.max(poi.radiusMeters, 1))
432
+ }
433
+ }
434
+ ),
435
+ /* @__PURE__ */ jsx(
436
+ MarkerF,
437
+ {
438
+ position: poi.center,
439
+ icon: poiDotIcon ? poiDotIcon(color, isSelected) : void 0,
440
+ title: getPoiPrimaryName(poi, locale),
441
+ onClick: () => setSelectedPoi(poi),
442
+ zIndex: isSelected ? 1e3 : 500
443
+ }
444
+ )
445
+ ] }, poi.code);
446
+ }),
447
+ selectedPoi && /* @__PURE__ */ jsx(
448
+ InfoWindowF,
449
+ {
450
+ position: selectedPoi.center,
451
+ onCloseClick: () => setSelectedPoi(null),
452
+ options: infoWindowOptions,
453
+ children: /* @__PURE__ */ jsxs("div", { className: "relative min-w-[150px] max-w-[240px] text-slate-800 pr-5", children: [
454
+ /* @__PURE__ */ jsx(
455
+ "button",
456
+ {
457
+ type: "button",
458
+ onClick: () => setSelectedPoi(null),
459
+ "aria-label": t("shipment_tracking.map.close", "Close"),
460
+ className: "absolute top-0 right-0 flex h-5 w-5 items-center justify-center rounded text-slate-400 hover:text-slate-700 hover:bg-slate-100 leading-none",
461
+ children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
462
+ }
463
+ ),
464
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 mb-1", children: [
465
+ /* @__PURE__ */ jsx(
466
+ "span",
467
+ {
468
+ className: "inline-block w-2.5 h-2.5 rounded-full flex-shrink-0",
469
+ style: { backgroundColor: POI_COLORS[selectedPoi.type] ?? "#64748b" }
470
+ }
471
+ ),
472
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium uppercase tracking-wide text-slate-500", children: getPoiTypeLabel(selectedPoi.type, t) })
473
+ ] }),
474
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold leading-tight text-slate-900", children: getPoiPrimaryName(selectedPoi, locale) }),
475
+ selectedPoi.terminalName && selectedPoi.portName && /* @__PURE__ */ jsx("div", { className: "text-xs text-slate-500 mt-0.5", children: selectedPoi.portName }),
476
+ (selectedPoi.city || selectedPoi.country) && /* @__PURE__ */ jsx("div", { className: "text-xs text-slate-500 mt-0.5", children: [selectedPoi.city, selectedPoi.country].filter(Boolean).join(", ") }),
477
+ /* @__PURE__ */ jsx("div", { className: "text-[11px] font-mono text-slate-400 mt-1", children: selectedPoi.locode || selectedPoi.code })
478
+ ] })
479
+ }
480
+ )
481
+ ]
482
+ }
483
+ ),
484
+ (isTraceLoading || isDebouncing) && /* @__PURE__ */ jsx("div", { className: "absolute top-3 right-3 bg-card/95 backdrop-blur-sm rounded-lg shadow-sm px-2 py-1 border border-border", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
485
+ /* @__PURE__ */ jsx("div", { className: "w-3 h-3 border-2 border-blue-400 border-t-transparent rounded-full animate-spin" }),
486
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t("shipment_tracking.map.loadingTrace", "Loading...") })
487
+ ] }) })
488
+ ] })
489
+ ] });
490
+ }
491
+ var VesselTrackingMap_default = VesselTrackingMap;
492
+ export {
493
+ VesselTrackingMap,
494
+ VesselTrackingMap_default as default
495
+ };
496
+ //# sourceMappingURL=VesselTrackingMap.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/shipment_tracking/components/VesselTrackingMap.tsx"],
4
+ "sourcesContent": ["'use client'\n\n/**\n * VesselTrackingMap - Interactive map showing vessel position and trace.\n *\n * Features:\n * - Real-time vessel position with heading-rotated ship icon\n * - Trace polyline limited to viewport bounds (debounced fetch)\n * - Vessel info overlay with status and destination\n * - Auto-refresh vessel position every 30 seconds\n */\n\nimport * as React from 'react'\nimport { useState, useCallback, useMemo, useEffect } from 'react'\nimport { GoogleMap, useJsApiLoader, MarkerF, PolylineF, CircleF, InfoWindowF } from '@react-google-maps/api'\nimport { Ship, Navigation, Anchor, MapPin, Clock, Building2, Ruler, Info, X } from 'lucide-react'\nimport { useVesselTracking } from '../hooks/useVesselTracking'\nimport { Spinner } from '@freighttech/ui/primitives/spinner'\nimport { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'\nimport type { VesselTrackingStatus } from '../lib/current-vessel'\nimport type { VesselInfo, PoiInfo, PoiType } from '../lib/vessel-api'\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype GoogleMapInstance = any\n\nexport interface VesselTrackingMapProps {\n /** Vessel IMO number */\n vesselImo: string | null | undefined\n /** Vessel name (fallback if API doesn't return name) */\n vesselName?: string | null\n /** Map height (CSS value, default: '250px') */\n height?: string\n /** Auto-refresh vessel position (default: true) */\n autoRefresh?: boolean\n /** Vessel refresh interval in ms (default: 30000) */\n refreshInterval?: number\n /** Show vessel info overlay (default: true) */\n showInfoOverlay?: boolean\n /** Show points of interest (ports/terminals/waypoints) as clickable circles (default: true) */\n showPois?: boolean\n /** Container tracking status - affects display messaging */\n containerStatus?: VesselTrackingStatus\n /** Port where container currently is (for at_port/not_departed status) */\n currentPort?: string\n /** Whether this is a planned vessel (not yet carrying the container) */\n isPlannedVessel?: boolean\n /** Current leg info (for in_transit status) */\n currentLeg?: {\n fromPort: string\n toPort: string\n }\n /** Start date for trace (ISO 8601) - limits trace to current leg */\n traceFrom?: string\n}\n\n// \u2500\u2500\u2500 Map Configuration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst containerStyle: React.CSSProperties = {\n width: '100%',\n height: '100%',\n}\n\n// Map options - typed as Record to avoid google namespace dependency at compile time\nconst mapOptions: Record<string, unknown> = {\n zoomControl: true,\n mapTypeControl: false,\n scaleControl: false,\n streetViewControl: false,\n rotateControl: false,\n fullscreenControl: false,\n disableDefaultUI: false,\n gestureHandling: 'cooperative',\n styles: [\n {\n featureType: 'water',\n elementType: 'geometry',\n stylers: [{ color: '#bfdbfe' }], // Light blue for water\n },\n {\n featureType: 'landscape',\n elementType: 'geometry',\n stylers: [{ color: '#f5f3ff' }], // Light purple for land\n },\n {\n featureType: 'road',\n elementType: 'geometry',\n stylers: [{ color: '#e0e7ff' }], // Light indigo for roads\n },\n ],\n}\n\n// Default center: Baltic Sea\nconst defaultCenter = { lat: 54.5, lng: 18.5 }\n\n// Below this zoom the viewport is too large \u2014 too many POIs to be useful or performant,\n// so we skip fetching/drawing them entirely (keeps the map uncluttered when zoomed out).\nconst MIN_POI_ZOOM = 6\n\n// Subtle per-type colors for POI circles. Kept faint (low opacity) so they don't\n// compete with the vessel marker and trace.\nconst POI_COLORS: Record<PoiType, string> = {\n PORT: '#2563eb', // blue\n TERMINAL: '#059669', // emerald\n WAYPOINT: '#d97706', // amber\n PORT_GEOMETRIC_CENTER: '#64748b', // slate\n}\n\n// \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Resolve a POI's human-friendly primary name, following the same per-type fallback the\n * backend uses: terminals prefer the terminal name, ports prefer the city, waypoints use\n * the localized maritime region. Falls back to LOCODE / code when nothing else is set.\n */\nfunction getPoiPrimaryName(poi: PoiInfo, locale: string): string {\n if (poi.type === 'TERMINAL') {\n return poi.terminalName || poi.portName || poi.city || poi.locode || poi.code\n }\n if (poi.type === 'PORT' || poi.type === 'PORT_GEOMETRIC_CENTER') {\n return poi.city || poi.portName || poi.locode || poi.code\n }\n // WAYPOINT \u2014 localized region name\n const region = locale === 'pl'\n ? (poi.regionNamePl || poi.regionNameEn)\n : (poi.regionNameEn || poi.regionNamePl)\n return region || poi.locode || poi.code\n}\n\nfunction getPoiTypeLabel(type: PoiType, t: ReturnType<typeof useT>): string {\n switch (type) {\n case 'PORT':\n return t('shipment_tracking.map.poi.port', 'Port')\n case 'TERMINAL':\n return t('shipment_tracking.map.poi.terminal', 'Terminal')\n case 'WAYPOINT':\n return t('shipment_tracking.map.poi.waypoint', 'Waypoint')\n case 'PORT_GEOMETRIC_CENTER':\n return t('shipment_tracking.map.poi.portCenter', 'Port center')\n default:\n return type\n }\n}\n\n\n/**\n * Calculate vessel dimensions from AIS dimension fields.\n * a = bow to reference, b = reference to stern \u2192 length = a + b\n * c = port to reference, d = reference to starboard \u2192 width = c + d\n */\nfunction calculateVesselDimensions(vessel: VesselInfo | null | undefined): {\n length: number\n width: number\n hasValidDimensions: boolean\n} {\n const dims = vessel?.dimensions\n if (!dims) {\n return { length: 0, width: 0, hasValidDimensions: false }\n }\n const length = (dims.a ?? 0) + (dims.b ?? 0)\n const width = (dims.c ?? 0) + (dims.d ?? 0)\n // Only consider valid if both length and width are positive\n const hasValidDimensions = length > 0 && width > 0\n return { length, width, hasValidDimensions }\n}\n\n/**\n * Format relative time for last update (e.g., \"2 min ago\", \"1 hour ago\").\n */\nfunction formatRelativeTime(dateString: string | null | undefined, t: ReturnType<typeof useT>): string {\n if (!dateString) return ''\n const date = new Date(dateString)\n if (Number.isNaN(date.getTime())) return ''\n\n const now = new Date()\n const diffMs = now.getTime() - date.getTime()\n const diffMinutes = Math.floor(diffMs / 60000)\n const diffHours = Math.floor(diffMinutes / 60)\n const diffDays = Math.floor(diffHours / 24)\n\n if (diffMinutes < 1) {\n return t('shipment_tracking.map.justNow', 'Just now')\n }\n if (diffMinutes < 60) {\n return t('shipment_tracking.map.minutesAgo', '{{count}} min ago', { count: diffMinutes })\n }\n if (diffHours < 24) {\n return t('shipment_tracking.map.hoursAgo', '{{count}}h ago', { count: diffHours })\n }\n return t('shipment_tracking.map.daysAgo', '{{count}}d ago', { count: diffDays })\n}\n\n// \u2500\u2500\u2500 Vessel Info Card \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface VesselInfoCardProps {\n vessel: VesselInfo | null | undefined\n displayName: string\n isPlannedVessel: boolean\n containerStatus?: VesselTrackingStatus\n currentPort?: string\n currentLeg?: { fromPort: string; toPort: string }\n t: ReturnType<typeof useT>\n}\n\nfunction VesselInfoCard({\n vessel,\n displayName,\n isPlannedVessel,\n containerStatus,\n currentPort,\n currentLeg,\n t,\n}: VesselInfoCardProps) {\n const { length, width, hasValidDimensions } = calculateVesselDimensions(vessel)\n const lastUpdate = formatRelativeTime(vessel?.updatedAt, t)\n\n // Determine vessel status display\n const getVesselStatusDisplay = () => {\n if (vessel?.status === 'IN_PORT') {\n return {\n icon: <Anchor className=\"w-3 h-3 text-green-600 dark:text-green-400\" />,\n text: vessel.currentPort?.name || t('shipment_tracking.map.inPort', 'In Port'),\n color: 'text-green-600 dark:text-green-400',\n }\n }\n if (vessel?.status === 'AT_SEA') {\n const destination = vessel.lastDestinationPort?.name || vessel.lastDestination\n return {\n icon: <Navigation className=\"w-3 h-3 text-blue-600 dark:text-blue-400\" />,\n text: destination\n ? t('shipment_tracking.map.atSeaTo', 'At Sea -> {{destination}}', { destination })\n : t('shipment_tracking.map.atSea', 'At Sea'),\n color: 'text-blue-600 dark:text-blue-400',\n }\n }\n return {\n icon: <Info className=\"w-3 h-3 text-muted-foreground\" />,\n text: t('shipment_tracking.map.unknown', 'Unknown'),\n color: 'text-muted-foreground',\n }\n }\n\n const statusDisplay = getVesselStatusDisplay()\n\n return (\n <div className=\"bg-card border border-border rounded-l-lg border-r-0 px-3 py-2.5 h-full overflow-y-auto\">\n {/* Header: Vessel name + planned badge */}\n <div className=\"flex items-center justify-between gap-2 mb-1\">\n <div className=\"flex items-center gap-1.5 min-w-0\">\n <Ship className=\"w-4 h-4 text-blue-500 dark:text-blue-400 flex-shrink-0\" />\n <h2 className=\"font-semibold text-sm truncate text-foreground\">{displayName}</h2>\n </div>\n {isPlannedVessel && (\n <span className=\"text-[10px] px-1.5 py-0.5 bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-400 rounded flex-shrink-0\">\n {t('shipment_tracking.map.planned', 'Planned')}\n </span>\n )}\n </div>\n\n {/* IMO number */}\n {vessel?.imo && (\n <div className=\"text-xs text-muted-foreground font-mono mb-2\">\n IMO {vessel.imo}\n </div>\n )}\n\n {/* Vessel details section */}\n <div className=\"border-t border-border pt-2 space-y-1.5\">\n {/* Status row */}\n <div className=\"flex items-center gap-2 text-xs\">\n <span className=\"text-muted-foreground/70 w-14 flex-shrink-0 truncate\" title={t('shipment_tracking.map.status', 'Status')}>\n {t('shipment_tracking.map.status', 'Status')}\n </span>\n <div className={`flex items-center gap-1 ${statusDisplay.color} truncate`}>\n {statusDisplay.icon}\n <span className=\"truncate\">{statusDisplay.text}</span>\n </div>\n </div>\n\n {/* Ship type row */}\n {vessel?.shipType && (\n <div className=\"flex items-center gap-2 text-xs\">\n <span className=\"text-muted-foreground/70 w-14 flex-shrink-0 truncate\" title={t('shipment_tracking.map.type', 'Type')}>\n {t('shipment_tracking.map.type', 'Type')}\n </span>\n <span className=\"text-foreground truncate\" title={vessel.shipType}>{vessel.shipType}</span>\n </div>\n )}\n\n {/* Size row */}\n {hasValidDimensions && (\n <div className=\"flex items-center gap-2 text-xs\">\n <span className=\"text-muted-foreground/70 w-14 flex-shrink-0 truncate\" title={t('shipment_tracking.map.size', 'Size')}>\n {t('shipment_tracking.map.size', 'Size')}\n </span>\n <div className=\"flex items-center gap-1 text-foreground\">\n <Ruler className=\"w-3 h-3 text-muted-foreground\" />\n <span>{length}m x {width}m</span>\n </div>\n </div>\n )}\n\n {/* Operator row */}\n {vessel?.operatorName && (\n <div className=\"flex items-center gap-2 text-xs\">\n <span className=\"text-muted-foreground/70 w-14 flex-shrink-0 truncate\" title={t('shipment_tracking.map.operator', 'Operator')}>\n {t('shipment_tracking.map.operator', 'Operator')}\n </span>\n <div className=\"flex items-center gap-1 text-foreground truncate\" title={vessel.operatorName}>\n <Building2 className=\"w-3 h-3 text-muted-foreground flex-shrink-0\" />\n <span className=\"truncate\">{vessel.operatorName}</span>\n </div>\n </div>\n )}\n\n {/* Last update row */}\n {lastUpdate && (\n <div className=\"flex items-center gap-2 text-xs\">\n <span className=\"text-muted-foreground/70 w-14 flex-shrink-0 truncate\" title={t('shipment_tracking.map.updated', 'Updated')}>\n {t('shipment_tracking.map.updated', 'Updated')}\n </span>\n <div className=\"flex items-center gap-1 text-muted-foreground\">\n <Clock className=\"w-3 h-3 text-muted-foreground\" />\n <span>{lastUpdate}</span>\n </div>\n </div>\n )}\n </div>\n\n {/* Container status section (when container tracking is active) */}\n {containerStatus && containerStatus !== 'delivered' && (\n <div className=\"border-t border-border mt-2 pt-2\">\n {containerStatus === 'in_transit' && currentLeg ? (\n <div className=\"flex items-center gap-1 text-xs text-blue-600 dark:text-blue-400\">\n <MapPin className=\"w-3 h-3\" />\n <span className=\"truncate\">\n {t('shipment_tracking.map.inTransitTo', 'In transit to {{destination}}', {\n destination: currentLeg.toPort,\n })}\n </span>\n </div>\n ) : containerStatus === 'at_port' && currentPort ? (\n <div className=\"space-y-0.5\">\n <div className=\"flex items-center gap-1 text-xs text-green-600 dark:text-green-400\">\n <MapPin className=\"w-3 h-3\" />\n <span className=\"truncate\">\n {t('shipment_tracking.map.containerAtPort', 'Container at {{port}}', {\n port: currentPort,\n })}\n </span>\n </div>\n {isPlannedVessel && (\n <div className=\"flex items-center gap-1 text-xs text-amber-600 dark:text-amber-400\">\n <Clock className=\"w-3 h-3\" />\n <span className=\"truncate\">\n {t('shipment_tracking.map.awaitingVessel', 'Awaiting this vessel')}\n </span>\n </div>\n )}\n </div>\n ) : containerStatus === 'not_departed' ? (\n <div className=\"flex items-center gap-1 text-xs text-amber-600 dark:text-amber-400\">\n <Clock className=\"w-3 h-3\" />\n <span className=\"truncate\">\n {t('shipment_tracking.map.awaitingDeparture', 'Awaiting departure')}\n </span>\n </div>\n ) : null}\n </div>\n )}\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Main Component \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function VesselTrackingMap({\n vesselImo,\n vesselName,\n height = '250px',\n autoRefresh = true,\n refreshInterval = 30_000,\n showInfoOverlay = true,\n showPois = true,\n containerStatus,\n currentPort,\n isPlannedVessel = false,\n currentLeg,\n traceFrom,\n}: VesselTrackingMapProps) {\n const t = useT()\n const locale = useLocale()\n\n // Load Google Maps API\n const { isLoaded, loadError } = useJsApiLoader({\n id: 'google-map-script',\n googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY || '',\n })\n\n // Map instance reference\n const [map, setMap] = useState<GoogleMapInstance | null>(null)\n // Current zoom (gates POI fetching) and the POI selected for the info window\n const [zoom, setZoom] = useState(8)\n const [selectedPoi, setSelectedPoi] = useState<PoiInfo | null>(null)\n\n // Only fetch POIs once zoomed in enough to keep the count and clutter manageable\n const enablePois = showPois && zoom >= MIN_POI_ZOOM\n\n // Drop the details popup when POIs are hidden (e.g. zoomed out) to avoid an orphan window\n useEffect(() => {\n if (!enablePois) setSelectedPoi(null)\n }, [enablePois])\n\n // Vessel tracking with debounced bounds\n const {\n vessel,\n isVesselLoading,\n vesselError,\n trace,\n isTraceLoading,\n isDebouncing,\n setBounds,\n pois,\n } = useVesselTracking(vesselImo, {\n autoRefresh,\n vesselRefreshInterval: refreshInterval,\n boundsDebounceDelay: 500,\n traceLimit: 5000,\n traceFrom,\n enablePois,\n })\n\n // Handle map load\n const onMapLoad = useCallback((mapInstance: GoogleMapInstance) => {\n setMap(mapInstance)\n }, [])\n\n // Handle map idle (fires after load and after pan/zoom completes)\n const handleMapIdle = useCallback(() => {\n if (!map) return\n const bounds = map.getBounds()\n if (!bounds) return\n\n // Track zoom so POI fetching can be gated on it\n const currentZoom = map.getZoom()\n if (typeof currentZoom === 'number') setZoom(currentZoom)\n\n const ne = bounds.getNorthEast()\n const sw = bounds.getSouthWest()\n\n // Add fixed margin (~30-35km) to fetch trace points outside visible viewport\n // This ensures smooth curves at map edges instead of straight lines\n const MARGIN_DEGREES = 0.3\n\n setBounds({\n north: Math.min(90, ne.lat() + MARGIN_DEGREES),\n south: Math.max(-90, sw.lat() - MARGIN_DEGREES),\n east: Math.min(180, ne.lng() + MARGIN_DEGREES),\n west: Math.max(-180, sw.lng() - MARGIN_DEGREES),\n })\n }, [map, setBounds])\n\n // Create container ship icon with heading rotation\n // Ship silhouette viewed from above: pointed bow (top), wide stern (bottom), bridge at rear\n const shipIcon = useMemo(() => {\n if (!isLoaded || typeof window === 'undefined') return undefined\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const google = (window as any).google\n if (!google) return undefined\n\n const heading = vessel?.lastHeading ?? 0\n\n // Container ship silhouette (top-down view, pointing up/north)\n // Elongated shape with slightly pointed bow - typical container ship proportions\n // Features: tapered bow (not too sharp), narrow hull, bridge at stern\n const containerShipPath = `\n M 12 2\n L 8 7\n L 8 30\n Q 8 32, 10 32\n L 10 34\n L 14 34\n L 14 32\n Q 16 32, 16 30\n L 16 7\n L 12 2\n Z\n M 10 32\n L 10 36\n L 14 36\n L 14 32\n Z\n `\n\n return {\n path: containerShipPath,\n fillColor: '#0f172a', // Dark slate hull\n fillOpacity: 0.95,\n strokeColor: '#ffffff',\n strokeWeight: 1.5,\n scale: 1.0,\n rotation: heading,\n anchor: new google.maps.Point(12, 18), // Center point for rotation\n }\n }, [isLoaded, vessel?.lastHeading])\n\n // Factory for the small clickable POI center dot. Markers live in a higher map pane than\n // circles, so these stay above the translucent circles and are the precise click target \u2014\n // the circles themselves are non-clickable, so overlapping circles never steal a click.\n // Pixel-scaled (not meters), so the dot stays a consistent small size at any zoom.\n const poiDotIcon = useMemo(() => {\n if (!isLoaded || typeof window === 'undefined') return null\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const google = (window as any).google\n if (!google) return null\n return (color: string, selected: boolean) => ({\n path: google.maps.SymbolPath.CIRCLE,\n scale: selected ? 6 : 4,\n fillColor: color,\n fillOpacity: 0.95,\n strokeColor: '#ffffff',\n strokeWeight: 1.5,\n })\n }, [isLoaded])\n\n // Options for the POI info window: drop Google's default header row (the empty top bar +\n // default close button that crowds the content), nudge the bubble just above the center\n // dot, and cap its width. We render our own close button instead.\n const infoWindowOptions = useMemo(() => {\n if (!isLoaded || typeof window === 'undefined') return undefined\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const google = (window as any).google\n if (!google) return undefined\n return {\n headerDisabled: true,\n pixelOffset: new google.maps.Size(0, -4),\n maxWidth: 260,\n }\n }, [isLoaded])\n\n // Center map on vessel position\n const center = useMemo(() => {\n if (vessel?.lastPosition) {\n return { lat: vessel.lastPosition.lat, lng: vessel.lastPosition.lng }\n }\n return defaultCenter\n }, [vessel?.lastPosition])\n\n // Filter trace points to only position updates for cleaner polyline\n const tracePath = useMemo(() => {\n if (!trace?.trace) return []\n return trace.trace\n .filter((p) => p.lat && p.lng && p.eventType === 'POSITION_UPDATE')\n .map((p) => ({ lat: p.lat, lng: p.lng }))\n }, [trace?.trace])\n\n // \u2500\u2500\u2500 Loading State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n if (loadError) {\n return (\n <div className=\"flex w-full\" style={{ height }}>\n <div className=\"w-full flex items-center justify-center bg-muted rounded-lg border border-border\">\n <div className=\"text-center\">\n <Ship className=\"w-8 h-8 text-muted-foreground mx-auto mb-2\" />\n <p className=\"text-sm text-muted-foreground\">\n {t('shipment_tracking.map.loadError', 'Failed to load map')}\n </p>\n </div>\n </div>\n </div>\n )\n }\n\n if (!isLoaded || (isVesselLoading && !vessel)) {\n return (\n <div className=\"flex w-full\" style={{ height }}>\n <div className=\"w-full flex items-center justify-center bg-muted rounded-lg border border-border\">\n <div className=\"flex flex-col items-center gap-2\">\n <Spinner className=\"h-6 w-6\" />\n <span className=\"text-sm text-muted-foreground\">\n {t('shipment_tracking.map.loading', 'Loading map...')}\n </span>\n </div>\n </div>\n </div>\n )\n }\n\n // \u2500\u2500\u2500 No Vessel Data \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n if (!vessel && !isVesselLoading) {\n return (\n <div className=\"flex w-full\" style={{ height }}>\n <div className=\"w-full flex items-center justify-center bg-muted rounded-lg border border-border\">\n <div className=\"text-center\">\n <Ship className=\"w-8 h-8 text-muted-foreground mx-auto mb-2\" />\n <p className=\"text-sm text-muted-foreground\">\n {vesselError\n ? t('shipment_tracking.map.vesselError', 'Failed to load vessel data')\n : t('shipment_tracking.map.vesselNotFound', 'Vessel not found')}\n </p>\n </div>\n </div>\n </div>\n )\n }\n\n // \u2500\u2500\u2500 Map Render \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const displayName = vesselName || vessel?.name || 'Unknown Vessel'\n\n return (\n <div className=\"flex w-full\" style={{ height }}>\n {/* Vessel Info Card - 1/3 width */}\n {showInfoOverlay && (\n <div className=\"w-1/3 flex-shrink-0\">\n <VesselInfoCard\n vessel={vessel}\n displayName={displayName}\n isPlannedVessel={isPlannedVessel}\n containerStatus={containerStatus}\n currentPort={currentPort}\n currentLeg={currentLeg}\n t={t}\n />\n </div>\n )}\n\n {/* Map - 2/3 width (or full if no info overlay) */}\n <div className={`relative border border-border overflow-hidden ${showInfoOverlay ? 'w-2/3 rounded-r-lg' : 'w-full rounded-lg'}`}>\n <GoogleMap\n mapContainerStyle={containerStyle}\n center={center}\n zoom={8}\n onLoad={onMapLoad}\n onIdle={handleMapIdle}\n options={mapOptions}\n >\n {/* Vessel Marker */}\n {vessel?.lastPosition && (\n <MarkerF\n position={{ lat: vessel.lastPosition.lat, lng: vessel.lastPosition.lng }}\n icon={shipIcon}\n title={displayName}\n zIndex={2000}\n />\n )}\n\n {/* Trace Polyline */}\n {tracePath.length > 1 && (\n <PolylineF\n path={tracePath}\n options={{\n strokeColor: '#8b5cf6', // Purple\n strokeOpacity: 0.6,\n strokeWeight: 2,\n geodesic: true,\n }}\n />\n )}\n\n {/* POIs \u2014 faint, non-intrusive circles (visual only) plus a small clickable\n center dot. Making the circles non-clickable means a large translucent circle\n can never swallow clicks for a small port/terminal sitting inside it; the dot\n is always the precise, overlap-resistant click target. */}\n {enablePois && pois?.map((poi) => {\n const color = POI_COLORS[poi.type] ?? '#64748b'\n const isSelected = selectedPoi?.code === poi.code\n return (\n <React.Fragment key={poi.code}>\n <CircleF\n center={poi.center}\n radius={poi.radiusMeters}\n options={{\n fillColor: color,\n fillOpacity: isSelected ? 0.2 : 0.08,\n strokeColor: color,\n strokeOpacity: isSelected ? 0.9 : 0.5,\n strokeWeight: 1,\n clickable: false,\n // Smaller circles on top so they aren't buried under large translucent fills\n zIndex: Math.round(1_000_000 / Math.max(poi.radiusMeters, 1)),\n }}\n />\n <MarkerF\n position={poi.center}\n icon={poiDotIcon ? poiDotIcon(color, isSelected) : undefined}\n title={getPoiPrimaryName(poi, locale)}\n onClick={() => setSelectedPoi(poi)}\n zIndex={isSelected ? 1000 : 500}\n />\n </React.Fragment>\n )\n })}\n\n {/* POI details popup. Position-anchored: rendering InfoWindowF inside MarkerF does\n NOT inject the marker anchor in this version of @react-google-maps/api, which\n throws \"must provide either an anchor or a position\" on open. The pixelOffset in\n infoWindowOptions lifts the bubble just above the center dot. */}\n {selectedPoi && (\n <InfoWindowF\n position={selectedPoi.center}\n onCloseClick={() => setSelectedPoi(null)}\n options={infoWindowOptions}\n >\n <div className=\"relative min-w-[150px] max-w-[240px] text-slate-800 pr-5\">\n {/* Custom close button (Google's default header is disabled) */}\n <button\n type=\"button\"\n onClick={() => setSelectedPoi(null)}\n aria-label={t('shipment_tracking.map.close', 'Close')}\n className=\"absolute top-0 right-0 flex h-5 w-5 items-center justify-center rounded text-slate-400 hover:text-slate-700 hover:bg-slate-100 leading-none\"\n >\n <X className=\"h-3.5 w-3.5\" />\n </button>\n <div className=\"flex items-center gap-1.5 mb-1\">\n <span\n className=\"inline-block w-2.5 h-2.5 rounded-full flex-shrink-0\"\n style={{ backgroundColor: POI_COLORS[selectedPoi.type] ?? '#64748b' }}\n />\n <span className=\"text-[11px] font-medium uppercase tracking-wide text-slate-500\">\n {getPoiTypeLabel(selectedPoi.type, t)}\n </span>\n </div>\n <div className=\"text-sm font-semibold leading-tight text-slate-900\">\n {getPoiPrimaryName(selectedPoi, locale)}\n </div>\n {selectedPoi.terminalName && selectedPoi.portName && (\n <div className=\"text-xs text-slate-500 mt-0.5\">{selectedPoi.portName}</div>\n )}\n {(selectedPoi.city || selectedPoi.country) && (\n <div className=\"text-xs text-slate-500 mt-0.5\">\n {[selectedPoi.city, selectedPoi.country].filter(Boolean).join(', ')}\n </div>\n )}\n <div className=\"text-[11px] font-mono text-slate-400 mt-1\">\n {selectedPoi.locode || selectedPoi.code}\n </div>\n </div>\n </InfoWindowF>\n )}\n </GoogleMap>\n\n {/* Loading Indicator for Trace */}\n {(isTraceLoading || isDebouncing) && (\n <div className=\"absolute top-3 right-3 bg-card/95 backdrop-blur-sm rounded-lg shadow-sm px-2 py-1 border border-border\">\n <div className=\"flex items-center gap-1\">\n <div className=\"w-3 h-3 border-2 border-blue-400 border-t-transparent rounded-full animate-spin\" />\n <span className=\"text-xs text-muted-foreground\">\n {t('shipment_tracking.map.loadingTrace', 'Loading...')}\n </span>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n}\n\nexport default VesselTrackingMap\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }