@collabdt/core 0.0.41 → 0.0.43

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 (265) hide show
  1. package/README.md +1 -1
  2. package/dist/core/components/Toolbar.d.ts.map +1 -1
  3. package/dist/core/components/Toolbar.js.map +1 -1
  4. package/dist/core/components/ToolbarBody.js.map +1 -1
  5. package/dist/core/components/TopNavigationBar.js.map +1 -1
  6. package/dist/core/components/authentication/ForgotPassword.js.map +1 -1
  7. package/dist/core/components/authentication/Signin.js.map +1 -1
  8. package/dist/core/components/authentication/Signup.js.map +1 -1
  9. package/dist/core/components/settings/src/OrganizationSkeleton.js.map +1 -1
  10. package/dist/core/components/settings/src/SettingsSkeleton.js.map +1 -1
  11. package/dist/core/components/ui/Comments/CollapsibleCommentItem.d.ts.map +1 -1
  12. package/dist/core/components/ui/Comments/CollapsibleCommentItem.js.map +1 -1
  13. package/dist/core/components/ui/Comments/CommentsSection.d.ts.map +1 -1
  14. package/dist/core/components/ui/Comments/CommentsSection.js.map +1 -1
  15. package/dist/core/components/ui/DataTable.d.ts.map +1 -1
  16. package/dist/core/components/ui/DataTable.js +7 -0
  17. package/dist/core/components/ui/DataTable.js.map +1 -1
  18. package/dist/core/components/ui/FilesManager/src/FileItemComponent.d.ts.map +1 -1
  19. package/dist/core/components/ui/FilesManager/src/FileItemComponent.js.map +1 -1
  20. package/dist/core/components/ui/FilesManager/src/FileMarker.d.ts +5 -2
  21. package/dist/core/components/ui/FilesManager/src/FileMarker.d.ts.map +1 -1
  22. package/dist/core/components/ui/FilesManager/src/FileMarker.js +84 -21
  23. package/dist/core/components/ui/FilesManager/src/FileMarker.js.map +1 -1
  24. package/dist/core/components/ui/FilesManager/src/convertIfcToFragmentsFile.d.ts.map +1 -1
  25. package/dist/core/components/ui/FilesManager/src/convertIfcToFragmentsFile.js.map +1 -1
  26. package/dist/core/components/ui/FilesManager/src/useFileUploadHandler.d.ts.map +1 -1
  27. package/dist/core/components/ui/FilesManager/src/useFileUploadHandler.js.map +1 -1
  28. package/dist/core/components/ui/Icons/IfcIcon.d.ts.map +1 -1
  29. package/dist/core/components/ui/Icons/IfcIcon.js.map +1 -1
  30. package/dist/core/components/ui/InfoSidebar/index.d.ts.map +1 -1
  31. package/dist/core/components/ui/InfoSidebar/index.js.map +1 -1
  32. package/dist/core/components/ui/Navbar.d.ts.map +1 -1
  33. package/dist/core/components/ui/Navbar.js.map +1 -1
  34. package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts.map +1 -1
  35. package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js.map +1 -1
  36. package/dist/core/components/ui/Sensors/SensorTagsSection.d.ts.map +1 -1
  37. package/dist/core/components/ui/Sensors/SensorTagsSection.js.map +1 -1
  38. package/dist/core/components/ui/Sensors/SensorsSection.d.ts.map +1 -1
  39. package/dist/core/components/ui/Sensors/SensorsSection.js.map +1 -1
  40. package/dist/core/components/ui/ShareFeature/ShareToolSubmenu.d.ts.map +1 -1
  41. package/dist/core/components/ui/ShareFeature/ShareToolSubmenu.js.map +1 -1
  42. package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.js +2 -2
  43. package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.js.map +1 -1
  44. package/dist/core/components/viewers/Data/siteDetails/AssociatedBuildings.js +2 -2
  45. package/dist/core/components/viewers/Data/siteDetails/AssociatedBuildings.js.map +1 -1
  46. package/dist/core/components/viewers/Viewer.d.ts.map +1 -1
  47. package/dist/core/components/viewers/Viewer.js +5 -1
  48. package/dist/core/components/viewers/Viewer.js.map +1 -1
  49. package/dist/core/components/viewers/bim/BimToolbar.d.ts.map +1 -1
  50. package/dist/core/components/viewers/bim/BimToolbar.js.map +1 -1
  51. package/dist/core/components/viewers/bim/BimViewer.d.ts.map +1 -1
  52. package/dist/core/components/viewers/bim/BimViewer.js +14 -5
  53. package/dist/core/components/viewers/bim/BimViewer.js.map +1 -1
  54. package/dist/core/components/viewers/bim/src/BimLoadingState/index.d.ts.map +1 -1
  55. package/dist/core/components/viewers/bim/src/BimLoadingState/index.js +6 -0
  56. package/dist/core/components/viewers/bim/src/BimLoadingState/index.js.map +1 -1
  57. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
  58. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js +168 -39
  59. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js.map +1 -1
  60. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.d.ts.map +1 -1
  61. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.js.map +1 -1
  62. package/dist/core/components/viewers/bim/src/BimSidebar/src/LayersTab/src/FloorplanSection.d.ts.map +1 -1
  63. package/dist/core/components/viewers/bim/src/BimSidebar/src/LayersTab/src/FloorplanSection.js +1 -1
  64. package/dist/core/components/viewers/bim/src/BimSidebar/src/LayersTab/src/FloorplanSection.js.map +1 -1
  65. package/dist/core/components/viewers/bim/src/DXFLoader/index.d.ts +14 -37
  66. package/dist/core/components/viewers/bim/src/DXFLoader/index.d.ts.map +1 -1
  67. package/dist/core/components/viewers/bim/src/DXFLoader/index.js +31 -318
  68. package/dist/core/components/viewers/bim/src/DXFLoader/index.js.map +1 -1
  69. package/dist/core/components/viewers/bim/src/FloorplanTool/index.d.ts +66 -7
  70. package/dist/core/components/viewers/bim/src/FloorplanTool/index.d.ts.map +1 -1
  71. package/dist/core/components/viewers/bim/src/FloorplanTool/index.js +253 -21
  72. package/dist/core/components/viewers/bim/src/FloorplanTool/index.js.map +1 -1
  73. package/dist/core/components/viewers/bim/src/ModelManager/index.d.ts.map +1 -1
  74. package/dist/core/components/viewers/bim/src/ModelManager/index.js +9 -0
  75. package/dist/core/components/viewers/bim/src/ModelManager/index.js.map +1 -1
  76. package/dist/core/components/viewers/bim/src/SimpleBimViewer.d.ts.map +1 -1
  77. package/dist/core/components/viewers/bim/src/SimpleBimViewer.js.map +1 -1
  78. package/dist/core/components/viewers/bim/src/lib/TrueNorthPopover.d.ts +3 -2
  79. package/dist/core/components/viewers/bim/src/lib/TrueNorthPopover.d.ts.map +1 -1
  80. package/dist/core/components/viewers/bim/src/lib/TrueNorthPopover.js.map +1 -1
  81. package/dist/core/components/viewers/bim/src/lib/useFriendlyIfcClassName.d.ts.map +1 -1
  82. package/dist/core/components/viewers/bim/src/lib/useFriendlyIfcClassName.js +3 -4
  83. package/dist/core/components/viewers/bim/src/lib/useFriendlyIfcClassName.js.map +1 -1
  84. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.d.ts.map +1 -1
  85. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js +40 -18
  86. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js.map +1 -1
  87. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/AddDxf.d.ts +2 -5
  88. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/AddDxf.d.ts.map +1 -1
  89. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/AddDxf.js +45 -59
  90. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/AddDxf.js.map +1 -1
  91. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.js +1 -0
  92. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.js.map +1 -1
  93. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileHandler.d.ts +10 -1
  94. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileHandler.d.ts.map +1 -1
  95. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileHandler.js +25 -73
  96. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileHandler.js.map +1 -1
  97. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileMarkerUtils.d.ts +7 -3
  98. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileMarkerUtils.d.ts.map +1 -1
  99. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileMarkerUtils.js +42 -78
  100. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileMarkerUtils.js.map +1 -1
  101. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/Position3DCard.d.ts.map +1 -1
  102. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/Position3DCard.js +52 -75
  103. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/Position3DCard.js.map +1 -1
  104. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useFilePlacement.d.ts +15 -3
  105. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useFilePlacement.d.ts.map +1 -1
  106. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useFilePlacement.js +165 -105
  107. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useFilePlacement.js.map +1 -1
  108. package/dist/core/components/viewers/index.d.ts.map +1 -1
  109. package/dist/core/components/viewers/index.js.map +1 -1
  110. package/dist/core/components/viewers/map/MapViewer.d.ts.map +1 -1
  111. package/dist/core/components/viewers/map/MapViewer.js +1 -0
  112. package/dist/core/components/viewers/map/MapViewer.js.map +1 -1
  113. package/dist/core/components/viewers/map/datasets/DatasetManager/index.d.ts.map +1 -1
  114. package/dist/core/components/viewers/map/datasets/DatasetManager/index.js +4 -3
  115. package/dist/core/components/viewers/map/datasets/DatasetManager/index.js.map +1 -1
  116. package/dist/core/components/viewers/map/datasets/RowActions.d.ts.map +1 -1
  117. package/dist/core/components/viewers/map/datasets/RowActions.js +148 -0
  118. package/dist/core/components/viewers/map/datasets/RowActions.js.map +1 -1
  119. package/dist/core/components/viewers/map/datasets/index.d.ts.map +1 -1
  120. package/dist/core/components/viewers/map/datasets/index.js +32 -15
  121. package/dist/core/components/viewers/map/datasets/index.js.map +1 -1
  122. package/dist/core/components/viewers/map/datasets/src/builtinLiveDatasets.d.ts +4 -0
  123. package/dist/core/components/viewers/map/datasets/src/builtinLiveDatasets.d.ts.map +1 -0
  124. package/dist/core/components/viewers/map/datasets/src/builtinLiveDatasets.js +43 -0
  125. package/dist/core/components/viewers/map/datasets/src/builtinLiveDatasets.js.map +1 -0
  126. package/dist/core/components/viewers/map/datasets/src/localDatasets.d.ts.map +1 -1
  127. package/dist/core/components/viewers/map/datasets/src/localDatasets.js +39 -3
  128. package/dist/core/components/viewers/map/datasets/src/localDatasets.js.map +1 -1
  129. package/dist/core/components/viewers/map/datasets/src/minioDatasets.d.ts +1 -1
  130. package/dist/core/components/viewers/map/datasets/src/minioDatasets.d.ts.map +1 -1
  131. package/dist/core/components/viewers/map/datasets/src/minioDatasets.js +2 -1
  132. package/dist/core/components/viewers/map/datasets/src/minioDatasets.js.map +1 -1
  133. package/dist/core/components/viewers/map/datasets/src/publishedTiles.d.ts +47 -0
  134. package/dist/core/components/viewers/map/datasets/src/publishedTiles.d.ts.map +1 -0
  135. package/dist/core/components/viewers/map/datasets/src/publishedTiles.js +114 -0
  136. package/dist/core/components/viewers/map/datasets/src/publishedTiles.js.map +1 -0
  137. package/dist/core/components/viewers/map/datasets/src/wmsTime.d.ts +49 -0
  138. package/dist/core/components/viewers/map/datasets/src/wmsTime.d.ts.map +1 -0
  139. package/dist/core/components/viewers/map/datasets/src/wmsTime.js +100 -0
  140. package/dist/core/components/viewers/map/datasets/src/wmsTime.js.map +1 -0
  141. package/dist/core/components/viewers/map/src/Geocoder.d.ts.map +1 -1
  142. package/dist/core/components/viewers/map/src/Geocoder.js +9 -9
  143. package/dist/core/components/viewers/map/src/Geocoder.js.map +1 -1
  144. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.d.ts.map +1 -1
  145. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.js +25 -43
  146. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.js.map +1 -1
  147. package/dist/core/components/viewers/map/src/MapLayers/index.d.ts.map +1 -1
  148. package/dist/core/components/viewers/map/src/MapLayers/index.js.map +1 -1
  149. package/dist/core/components/viewers/map/src/MapLayers/src/BimLayer/index.d.ts.map +1 -1
  150. package/dist/core/components/viewers/map/src/MapLayers/src/BimLayer/index.js +19 -2
  151. package/dist/core/components/viewers/map/src/MapLayers/src/BimLayer/index.js.map +1 -1
  152. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/countryLayerUtils.d.ts +9 -0
  153. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/countryLayerUtils.d.ts.map +1 -0
  154. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/countryLayerUtils.js +28 -0
  155. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/countryLayerUtils.js.map +1 -0
  156. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.d.ts.map +1 -1
  157. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.js +1 -16
  158. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.js.map +1 -1
  159. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/FileModelLayer/FileModelLayer.d.ts.map +1 -1
  160. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/FileModelLayer/FileModelLayer.js.map +1 -1
  161. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.d.ts.map +1 -1
  162. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.js +31 -2
  163. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.js.map +1 -1
  164. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.d.ts +21 -0
  165. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.d.ts.map +1 -0
  166. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.js +111 -0
  167. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.js.map +1 -0
  168. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/index.d.ts.map +1 -1
  169. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/index.js +77 -2
  170. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/index.js.map +1 -1
  171. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
  172. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.js.map +1 -1
  173. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.d.ts.map +1 -1
  174. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.js.map +1 -1
  175. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.d.ts.map +1 -1
  176. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.js +10 -3
  177. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.js.map +1 -1
  178. package/dist/core/components/viewers/map/utils/geocoder.d.ts +6 -2
  179. package/dist/core/components/viewers/map/utils/geocoder.d.ts.map +1 -1
  180. package/dist/core/components/viewers/map/utils/geocoder.js +10 -62
  181. package/dist/core/components/viewers/map/utils/geocoder.js.map +1 -1
  182. package/dist/core/components/viewers/map/utils/geocoding/adapters.d.ts +5 -0
  183. package/dist/core/components/viewers/map/utils/geocoding/adapters.d.ts.map +1 -0
  184. package/dist/core/components/viewers/map/utils/geocoding/adapters.js +192 -0
  185. package/dist/core/components/viewers/map/utils/geocoding/adapters.js.map +1 -0
  186. package/dist/core/components/viewers/map/utils/geocoding/config.d.ts +6 -0
  187. package/dist/core/components/viewers/map/utils/geocoding/config.d.ts.map +1 -0
  188. package/dist/core/components/viewers/map/utils/geocoding/config.js +14 -0
  189. package/dist/core/components/viewers/map/utils/geocoding/config.js.map +1 -0
  190. package/dist/core/components/viewers/map/utils/geocoding/index.d.ts +8 -0
  191. package/dist/core/components/viewers/map/utils/geocoding/index.d.ts.map +1 -0
  192. package/dist/core/components/viewers/map/utils/geocoding/index.js +44 -0
  193. package/dist/core/components/viewers/map/utils/geocoding/index.js.map +1 -0
  194. package/dist/core/components/viewers/map/utils/geocoding/osm.d.ts +6 -0
  195. package/dist/core/components/viewers/map/utils/geocoding/osm.d.ts.map +1 -0
  196. package/dist/core/components/viewers/map/utils/geocoding/osm.js +39 -0
  197. package/dist/core/components/viewers/map/utils/geocoding/osm.js.map +1 -0
  198. package/dist/core/components/viewers/map/utils/geocoding/pelias.d.ts +8 -0
  199. package/dist/core/components/viewers/map/utils/geocoding/pelias.d.ts.map +1 -0
  200. package/dist/core/components/viewers/map/utils/geocoding/pelias.js +35 -0
  201. package/dist/core/components/viewers/map/utils/geocoding/pelias.js.map +1 -0
  202. package/dist/core/components/viewers/pointcloud/PointCloudToolbar.d.ts.map +1 -1
  203. package/dist/core/components/viewers/pointcloud/PointCloudToolbar.js.map +1 -1
  204. package/dist/core/components/viewers/pointcloud/PointCloudViewer.js +1 -3
  205. package/dist/core/components/viewers/pointcloud/PointCloudViewer.js.map +1 -1
  206. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.d.ts.map +1 -1
  207. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js +2 -3
  208. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js.map +1 -1
  209. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
  210. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/FilesSection.js +8 -2
  211. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/FilesSection.js.map +1 -1
  212. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.d.ts.map +1 -1
  213. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.js.map +1 -1
  214. package/dist/core/components/viewers/pointcloud/src/tools/PerformanceSettingsTools/NodeSizeSelectionTool.js +9 -9
  215. package/dist/core/components/viewers/pointcloud/src/tools/PerformanceSettingsTools/NodeSizeSelectionTool.js.map +1 -1
  216. package/dist/core/hooks/provider.js.map +1 -1
  217. package/dist/core/plugins/host/provider.d.ts.map +1 -1
  218. package/dist/core/plugins/host/provider.js.map +1 -1
  219. package/dist/core/store/AppConfig/context.d.ts.map +1 -1
  220. package/dist/core/store/AppConfig/context.js.map +1 -1
  221. package/dist/core/store/BIM/context.d.ts.map +1 -1
  222. package/dist/core/store/BIM/context.js.map +1 -1
  223. package/dist/core/store/BIM/reducer.d.ts +0 -1
  224. package/dist/core/store/BIM/reducer.d.ts.map +1 -1
  225. package/dist/core/store/BIM/reducer.js +0 -4
  226. package/dist/core/store/BIM/reducer.js.map +1 -1
  227. package/dist/core/store/Buildings/context.d.ts.map +1 -1
  228. package/dist/core/store/Buildings/context.js.map +1 -1
  229. package/dist/core/store/Content/context.d.ts.map +1 -1
  230. package/dist/core/store/Content/context.js.map +1 -1
  231. package/dist/core/store/Datasets/context.d.ts.map +1 -1
  232. package/dist/core/store/Datasets/context.js +2 -1
  233. package/dist/core/store/Datasets/context.js.map +1 -1
  234. package/dist/core/store/Datasets/reducer.d.ts +2 -0
  235. package/dist/core/store/Datasets/reducer.d.ts.map +1 -1
  236. package/dist/core/store/Datasets/reducer.js +9 -4
  237. package/dist/core/store/Datasets/reducer.js.map +1 -1
  238. package/dist/core/store/Files/context.d.ts.map +1 -1
  239. package/dist/core/store/Files/context.js.map +1 -1
  240. package/dist/core/store/Map/context.d.ts.map +1 -1
  241. package/dist/core/store/Map/context.js.map +1 -1
  242. package/dist/core/store/Menus/context.d.ts.map +1 -1
  243. package/dist/core/store/Menus/context.js.map +1 -1
  244. package/dist/core/store/Permissions/context.d.ts.map +1 -1
  245. package/dist/core/store/Permissions/context.js.map +1 -1
  246. package/dist/core/store/PointCloud/context.d.ts.map +1 -1
  247. package/dist/core/store/PointCloud/context.js.map +1 -1
  248. package/dist/core/store/Tools/context.d.ts.map +1 -1
  249. package/dist/core/store/Tools/context.js.map +1 -1
  250. package/dist/core/types/datasetTypes.d.ts +8 -1
  251. package/dist/core/types/datasetTypes.d.ts.map +1 -1
  252. package/dist/core/types/dbTypes.d.ts +13 -13
  253. package/dist/core/types/dbTypes.d.ts.map +1 -1
  254. package/dist/core/types/dbTypes.js +13 -13
  255. package/dist/core/types/dbTypes.js.map +1 -1
  256. package/dist/core/types/index.d.ts +1 -1
  257. package/dist/core/types/index.d.ts.map +1 -1
  258. package/dist/core/types/index.js.map +1 -1
  259. package/dist/core/utils/imageUtils.js +1 -1
  260. package/dist/core/utils/imageUtils.js.map +1 -1
  261. package/package.json +2 -1
  262. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudViewer-old.d.ts +0 -3
  263. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudViewer-old.d.ts.map +0 -1
  264. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudViewer-old.js +0 -173
  265. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudViewer-old.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/index.tsx"],"sourcesContent":["\"use client\";\r\n\r\nimport * as React from \"react\";\r\nimport { Source, Layer, Popup } from \"react-map-gl/maplibre\";\r\nimport type { MapMouseEvent } from \"maplibre-gl\";\r\n\r\nimport { MapContext } from \"../../../../../../../../store/Map/context\";\r\nimport type { Building } from '../../../../../../../../types/dbTypes';\r\nimport { DatasetsContext } from '../../../../../../../../store';\r\nimport { MapLayerClickPriority } from \"../../../../../utils/MapEventManager/MapClickManager\";\r\nimport MapFeaturePopoverMenu from \"../../../../MapFeaturePopoverMenu\";\r\nimport { fitGeoJsonBounds } from \"../../../../../utils/fitGeojsonBounds\";\r\n\r\ninterface BuildingDataset {\r\n \"type\": \"buildings\";\r\n \"data\": Building[];\r\n \"name\": string;\r\n \"visible\"?: boolean;\r\n}\r\n\r\nconst isBuildingDataset = (dataset: any): dataset is BuildingDataset => {\r\n return dataset.type === \"buildings\" && \"data\" in dataset;\r\n};\r\n\r\nconst parseNumericValue = (value: unknown): number | null => {\r\n if (typeof value === 'number' && Number.isFinite(value)) return value;\r\n if (typeof value !== 'string') return null;\r\n const cleaned = value.replace(/[$%\\s]/g, '').replace(/,/g, '');\r\n const parsed = Number.parseFloat(cleaned);\r\n return Number.isFinite(parsed) ? parsed : null;\r\n};\r\n\r\nconst computeMinMax = (\r\n features: import('geojson').Feature[],\r\n fieldName: string,\r\n): { min: number; max: number } | null => {\r\n let min = Number.POSITIVE_INFINITY;\r\n let max = Number.NEGATIVE_INFINITY;\r\n let found = false;\r\n for (const feature of features) {\r\n const properties = (feature.properties || {}) as Record<string, unknown>;\r\n const value = parseNumericValue(properties[fieldName]);\r\n if (value === null) continue;\r\n found = true;\r\n if (value < min) min = value;\r\n if (value > max) max = value;\r\n }\r\n if (!found) return null;\r\n return { min, max: max === min ? min + 1 : max };\r\n};\r\n\r\n// ─── Per-dataset GeoJSON layer ────────────────────────────────────────\r\n// Each dataset manages its own fetch lifecycle. This means:\r\n// • datasets render PROGRESSIVELY as each one loads (no blocking)\r\n// • unmounting a dataset cancels only ITS fetch\r\n// • re-renders of one dataset never cancel fetches for another\r\n\r\ninterface GeoJsonDatasetLayerProps {\r\n dataset: any;\r\n index: number;\r\n onLayerReady: (datasetName: string, layerIds: string[]) => void;\r\n onLayerRemoved: (datasetName: string) => void;\r\n}\r\n\r\nconst GeoJsonDatasetLayer = React.memo(({ dataset, index, onLayerReady, onLayerRemoved }: GeoJsonDatasetLayerProps) => {\r\n const { state: mapState } = React.useContext(MapContext);\r\n const { map } = mapState.map;\r\n\r\n const [featureCollection, setFeatureCollection] = React.useState<import('geojson').FeatureCollection | null>(null);\r\n const fitBoundsAppliedRef = React.useRef(false);\r\n\r\n // Fetch features once when the component mounts (or dataset identity changes)\r\n React.useEffect(() => {\r\n if (!map) return;\r\n let cancelled = false;\r\n\r\n const load = async () => {\r\n try {\r\n const fetched = await dataset.getFeatures();\r\n if (cancelled) return;\r\n\r\n const fc: import('geojson').FeatureCollection =\r\n fetched?.type === 'FeatureCollection'\r\n ? fetched\r\n : { type: 'FeatureCollection', features: [] };\r\n\r\n setFeatureCollection(fc);\r\n } catch (error) {\r\n console.error(`OpenDataLayers: Error fetching features for \"${dataset.name}\":`, error);\r\n }\r\n };\r\n\r\n load();\r\n return () => { cancelled = true; };\r\n }, [map, dataset.name]);\r\n\r\n // Build the layer JSX from the loaded feature collection\r\n const layerContent = React.useMemo(() => {\r\n if (!featureCollection || featureCollection.features.length === 0) return null;\r\n\r\n const geometryType = featureCollection.features[0]?.geometry?.type;\r\n if (!geometryType) return null;\r\n\r\n // ── colour resolution ──\r\n let layerColor: any = dataset.layerColor?.color || '#0d9488';\r\n let numericFieldName: string | undefined;\r\n\r\n if (dataset.selectedFieldName) {\r\n const selectedField = dataset.fields?.find((field: any) => field.name === dataset.selectedFieldName);\r\n if (selectedField?.layerColor) {\r\n if (selectedField.colorType === 'single') {\r\n layerColor = selectedField.layerColor.color;\r\n }\r\n if (selectedField.colorType === 'minMax') {\r\n try {\r\n const fieldName = dataset.selectedFieldName;\r\n numericFieldName = `__numeric_${fieldName}`;\r\n const range = computeMinMax(featureCollection.features, fieldName);\r\n if (range) {\r\n const minColor = selectedField.layerColor.minColor || dataset.layerColor?.minColor || dataset.layerColor?.color || '#0d9488';\r\n const maxColor = selectedField.layerColor.maxColor || dataset.layerColor?.maxColor || dataset.layerColor?.color || '#0d9488';\r\n layerColor = [\r\n 'interpolate', ['linear'],\r\n ['to-number', ['get', numericFieldName], range.min],\r\n range.min, minColor,\r\n range.max, maxColor,\r\n ];\r\n }\r\n } catch (error) {\r\n console.warn('Failed to build interpolate for field', dataset.selectedFieldName, error);\r\n }\r\n }\r\n if (selectedField.colorType === 'boolean') {\r\n const minColor = selectedField.layerColor.minColor || dataset.layerColor?.minColor || dataset.layerColor?.color || '#0d9488';\r\n const maxColor = selectedField.layerColor.maxColor || dataset.layerColor?.maxColor || dataset.layerColor?.color || '#0d9488';\r\n const fieldName = dataset.selectedFieldName;\r\n layerColor = [\r\n 'case',\r\n ['any',\r\n ['==', ['get', fieldName], true],\r\n ['==', ['get', fieldName], 1],\r\n ['==', ['downcase', ['to-string', ['get', fieldName]]], 'true'],\r\n ['==', ['downcase', ['to-string', ['get', fieldName]]], 'yes'],\r\n ],\r\n maxColor,\r\n minColor,\r\n ];\r\n }\r\n }\r\n }\r\n\r\n // ── inject datasetName + numeric shadow field into each feature ──\r\n const enrichedFC: import('geojson').FeatureCollection = {\r\n ...featureCollection,\r\n features: featureCollection.features.map((feature) => {\r\n let numericVal: number | undefined;\r\n if (numericFieldName && dataset.selectedFieldName) {\r\n const v = parseNumericValue((feature.properties || {})[dataset.selectedFieldName]);\r\n if (v !== null) numericVal = v;\r\n }\r\n return {\r\n ...feature,\r\n properties: {\r\n ...feature.properties,\r\n datasetName: dataset.name,\r\n layer_color: layerColor,\r\n ...(numericFieldName && numericVal !== undefined ? { [numericFieldName]: numericVal } : {}),\r\n },\r\n };\r\n }),\r\n };\r\n\r\n // ── build layer props per geometry type ──\r\n const registeredIds: string[] = [];\r\n\r\n if (geometryType === 'Point' || geometryType === 'MultiPoint') {\r\n const paint = {\r\n 'circle-radius': 6,\r\n 'circle-color': layerColor,\r\n 'circle-opacity': 0.8,\r\n 'circle-stroke-width': 2,\r\n 'circle-stroke-color': '#ffffff',\r\n };\r\n registeredIds.push(`${dataset.name}-unclustered-point`);\r\n\r\n return {\r\n registeredIds,\r\n jsx: (\r\n <Source\r\n id={`${dataset.name}-source`}\r\n key={`${index}-${dataset.name}-source`}\r\n type=\"geojson\"\r\n data={enrichedFC}\r\n cluster={true}\r\n clusterMaxZoom={11}\r\n clusterRadius={50}\r\n >\r\n <Layer\r\n id={`${dataset.name}-clusters`}\r\n filter={['has', 'point_count']}\r\n type=\"circle\"\r\n paint={{\r\n 'circle-color': dataset.layerColor?.color || '#0d9488',\r\n 'circle-radius': ['step', ['get', 'point_count'], 20, 100, 30, 750, 40],\r\n 'circle-opacity': 0.9,\r\n }}\r\n />\r\n <Layer\r\n id={`${dataset.name}-cluster-count`}\r\n filter={['has', 'point_count']}\r\n type=\"symbol\"\r\n layout={{\r\n 'text-field': '{point_count_abbreviated}',\r\n 'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],\r\n 'text-size': 12,\r\n }}\r\n paint={{ 'text-color': '#fff' }}\r\n />\r\n <Layer\r\n id={`${dataset.name}-unclustered-point`}\r\n filter={['!', ['has', 'point_count']]}\r\n type=\"circle\"\r\n paint={paint}\r\n />\r\n </Source>\r\n ),\r\n };\r\n }\r\n\r\n if (geometryType === 'LineString' || geometryType === 'MultiLineString') {\r\n const mainId = `${dataset.name}-line`;\r\n registeredIds.push(mainId);\r\n return {\r\n registeredIds,\r\n jsx: (\r\n <Source\r\n id={`${dataset.name}-source`}\r\n key={`${index}-${dataset.name}-source`}\r\n type=\"geojson\"\r\n data={enrichedFC}\r\n >\r\n <Layer\r\n id={mainId}\r\n type=\"line\"\r\n paint={{ 'line-color': layerColor, 'line-width': 3, 'line-opacity': 1 }}\r\n />\r\n </Source>\r\n ),\r\n };\r\n }\r\n\r\n if (geometryType === 'Polygon' || geometryType === 'MultiPolygon') {\r\n const fillId = `${dataset.name}-fill`;\r\n const outlineId = `${dataset.name}-outline`;\r\n registeredIds.push(fillId, outlineId);\r\n return {\r\n registeredIds,\r\n jsx: (\r\n <Source\r\n id={`${dataset.name}-source`}\r\n key={`${index}-${dataset.name}-source`}\r\n type=\"geojson\"\r\n data={enrichedFC}\r\n >\r\n <Layer\r\n id={fillId}\r\n type=\"fill\"\r\n paint={{ 'fill-color': layerColor, 'fill-opacity': 0.5 }}\r\n />\r\n <Layer\r\n id={outlineId}\r\n type=\"line\"\r\n paint={{ 'line-color': '#ffffff', 'line-width': 2 }}\r\n />\r\n </Source>\r\n ),\r\n };\r\n }\r\n\r\n return null;\r\n }, [featureCollection, dataset.name, dataset.layerColor, dataset.selectedFieldName, dataset.fields, index]);\r\n\r\n // Register / unregister interactive layer IDs with the parent\r\n React.useEffect(() => {\r\n if (layerContent?.registeredIds) {\r\n onLayerReady(dataset.name, layerContent.registeredIds);\r\n }\r\n return () => { onLayerRemoved(dataset.name); };\r\n }, [layerContent?.registeredIds, dataset.name, onLayerReady, onLayerRemoved]);\r\n\r\n return layerContent?.jsx ?? null;\r\n});\r\nGeoJsonDatasetLayer.displayName = 'GeoJsonDatasetLayer';\r\n\r\n\r\n// ─── Per-dataset MVT layer ────────────────────────────────────────────\r\n\r\ninterface MVTDatasetLayerProps {\r\n dataset: any;\r\n index: number;\r\n onLayerReady: (datasetName: string, layerIds: string[]) => void;\r\n onLayerRemoved: (datasetName: string) => void;\r\n}\r\n\r\nconst MVTDatasetLayer = React.memo(({ dataset, index, onLayerReady, onLayerRemoved }: MVTDatasetLayerProps) => {\r\n const tileUrl = dataset.url || dataset.information;\r\n const sourceLayer = (dataset as any)?.serviceInfo?.sourceLayer || dataset.id || dataset.name.toLowerCase().replace(/\\s+/g, '_');\r\n const layerColor = dataset.layerColor?.color || '#0d9488';\r\n const isPointLayer = dataset.layerType === 'circle' || /point/i.test(sourceLayer);\r\n const isMartinBuilding = /buildings?/i.test((dataset as any)?.serviceInfo?.sourceLayer || dataset.id || dataset.name);\r\n const extraIsBuilding = (dataset.layerType === 'fill' || (isMartinBuilding && !dataset.layerType)) && !isPointLayer;\r\n\r\n const mainLayerId = isPointLayer\r\n ? `${dataset.name}-points`\r\n : extraIsBuilding\r\n ? `${dataset.name}-extrusion`\r\n : `${dataset.name}-fill`;\r\n const outlineLayerId = `${dataset.name}-outline`;\r\n\r\n // Register interactive layer IDs\r\n React.useEffect(() => {\r\n const ids = isPointLayer ? [mainLayerId] : [mainLayerId, outlineLayerId];\r\n onLayerReady(dataset.name, ids);\r\n return () => { onLayerRemoved(dataset.name); };\r\n }, [dataset.name, mainLayerId, outlineLayerId, isPointLayer, onLayerReady, onLayerRemoved]);\r\n\r\n if (!tileUrl) {\r\n console.error(`❌ OpenDataLayers: No tile URL found for MVT dataset \"${dataset.name}\"`);\r\n return null;\r\n }\r\n\r\n if (extraIsBuilding) {\r\n return (\r\n <Source id={`${dataset.name}-source`} key={`${index}-${dataset.name}-source`} type=\"vector\" tiles={[tileUrl]}>\r\n <Layer\r\n id={mainLayerId} type=\"fill-extrusion\" source-layer={sourceLayer}\r\n paint={{\r\n 'fill-extrusion-color': layerColor,\r\n 'fill-extrusion-height': ['coalesce', ['to-number', ['get', 'heightmax']], 0],\r\n 'fill-extrusion-opacity': 0.8,\r\n }}\r\n minzoom={15.5}\r\n />\r\n <Layer id={outlineLayerId} type=\"line\" source-layer={sourceLayer} paint={{ 'line-color': layerColor, 'line-width': 1, 'line-opacity': 0.8 }} />\r\n </Source>\r\n );\r\n }\r\n\r\n if (isPointLayer) {\r\n return (\r\n <Source id={`${dataset.name}-source`} key={`${index}-${dataset.name}-source`} type=\"vector\" tiles={[tileUrl]}>\r\n <Layer\r\n id={mainLayerId} type=\"circle\" source-layer={sourceLayer}\r\n paint={{ 'circle-radius': 6, 'circle-color': layerColor, 'circle-opacity': 0.8, 'circle-stroke-width': 2, 'circle-stroke-color': '#ffffff' }}\r\n />\r\n </Source>\r\n );\r\n }\r\n\r\n return (\r\n <Source id={`${dataset.name}-source`} key={`${index}-${dataset.name}-source`} type=\"vector\" tiles={[tileUrl]}>\r\n <Layer id={mainLayerId} type=\"fill\" source-layer={sourceLayer} paint={{ 'fill-color': layerColor, 'fill-opacity': 0.6 }} />\r\n <Layer id={outlineLayerId} type=\"line\" source-layer={sourceLayer} paint={{ 'line-color': layerColor, 'line-width': 1, 'line-opacity': 0.8 }} />\r\n </Source>\r\n );\r\n});\r\nMVTDatasetLayer.displayName = 'MVTDatasetLayer';\r\n\r\n\r\n// ─── Main orchestrator ────────────────────────────────────────────────\r\n\r\nexport const OpenDataLayers = () => {\r\n const { \"state\": mapState, \"dispatch\": mapDispatch } = React.useContext(MapContext);\r\n const { map, mapClickManager } = mapState.map;\r\n\r\n const { state: datasetState } = React.useContext(DatasetsContext);\r\n const { addedDatasets } = datasetState.datasets;\r\n\r\n const [clickedFeature, setClickedFeature] = React.useState<any>(null);\r\n const [addedFeaturesPopup, setAddedFeaturesPopup] = React.useState<Array<{\r\n id: string | number;\r\n popup: React.ReactElement;\r\n }>>([]);\r\n\r\n // Track interactive layer IDs per dataset for click handling\r\n const layerIdsMapRef = React.useRef<Record<string, string[]>>({});\r\n const [allLayerNames, setAllLayerNames] = React.useState<string[]>([]);\r\n\r\n const handleLayerReady = React.useCallback((datasetName: string, layerIds: string[]) => {\r\n layerIdsMapRef.current[datasetName] = layerIds;\r\n setAllLayerNames(Object.values(layerIdsMapRef.current).flat());\r\n }, []);\r\n\r\n const handleLayerRemoved = React.useCallback((datasetName: string) => {\r\n delete layerIdsMapRef.current[datasetName];\r\n setAllLayerNames(Object.values(layerIdsMapRef.current).flat());\r\n }, []);\r\n\r\n // ── Click handling ──\r\n React.useEffect(() => {\r\n if (!map || !mapClickManager || allLayerNames.length === 0) return;\r\n\r\n const handleMapClick = (e: MapMouseEvent) => {\r\n const clicked = map.queryRenderedFeatures(e.point, { layers: allLayerNames });\r\n const localClickedFeature = clicked?.[0];\r\n\r\n if (!localClickedFeature) {\r\n setClickedFeature(null);\r\n return;\r\n }\r\n\r\n const lng = e.lngLat.lng;\r\n const lat = e.lngLat.lat;\r\n const coordinates = [lng, lat];\r\n const properties = localClickedFeature.properties || {};\r\n const _name = Object.entries(properties).find(([key]) => key.toLowerCase().includes('name'))?.[1] || undefined;\r\n\r\n let datasetNameFromFeature = properties.datasetName;\r\n if (!datasetNameFromFeature && localClickedFeature.layer) {\r\n const layerId = localClickedFeature.layer.id;\r\n const suffixes = ['-unclustered-point', '-clusters', '-cluster-count', '-outline', '-fill', '-line', '-circle', '-extrusion', '-points'];\r\n let extractedName = layerId;\r\n for (const suffix of suffixes) {\r\n if (layerId.endsWith(suffix)) {\r\n extractedName = layerId.slice(0, -suffix.length);\r\n break;\r\n }\r\n }\r\n if (extractedName === layerId && layerId.includes('-')) {\r\n extractedName = layerId.slice(0, layerId.lastIndexOf('-'));\r\n }\r\n datasetNameFromFeature = extractedName;\r\n }\r\n\r\n const featureId = properties.globalid || properties.id || `temp-${Date.now()}`;\r\n localClickedFeature.id = featureId;\r\n localClickedFeature.properties = { ...properties, coordinates, _name, datasetName: datasetNameFromFeature };\r\n setClickedFeature(localClickedFeature);\r\n };\r\n\r\n for (const layerId of allLayerNames) {\r\n mapClickManager.register(layerId, MapLayerClickPriority.OpenDataLayerClickPriority, handleMapClick);\r\n }\r\n\r\n return () => {\r\n for (const layerId of allLayerNames) {\r\n mapClickManager.unregister(layerId);\r\n }\r\n };\r\n }, [map, mapClickManager, allLayerNames]);\r\n\r\n // ── Hover cursor handling ──\r\n React.useEffect(() => {\r\n if (!map) return;\r\n\r\n const canvas = map.getCanvas();\r\n\r\n const setDefaultCursor = () => {\r\n canvas.style.cursor = 'default';\r\n };\r\n\r\n if (allLayerNames.length === 0) {\r\n setDefaultCursor();\r\n return;\r\n }\r\n\r\n const handleMouseMove = (e: MapMouseEvent) => {\r\n const hoveredFeatures = map.queryRenderedFeatures(e.point, { layers: allLayerNames });\r\n canvas.style.cursor = hoveredFeatures.length > 0 ? 'pointer' : 'default';\r\n };\r\n\r\n const handleMouseLeave = () => {\r\n setDefaultCursor();\r\n };\r\n\r\n map.on('mousemove', handleMouseMove);\r\n map.on('mouseleave', handleMouseLeave);\r\n\r\n return () => {\r\n map.off('mousemove', handleMouseMove);\r\n map.off('mouseleave', handleMouseLeave);\r\n setDefaultCursor();\r\n };\r\n }, [map, allLayerNames]);\r\n\r\n // ── Popup ──\r\n React.useEffect(() => {\r\n if (!clickedFeature || !clickedFeature.properties?.coordinates) {\r\n setAddedFeaturesPopup([]);\r\n return;\r\n }\r\n const popup = (\r\n <Popup\r\n anchor=\"bottom\"\r\n closeButton={true}\r\n closeOnClick={false}\r\n closeOnMove={false}\r\n focusAfterOpen={true}\r\n key={clickedFeature.id}\r\n latitude={clickedFeature.properties.coordinates[1]}\r\n longitude={clickedFeature.properties.coordinates[0]}\r\n >\r\n <MapFeaturePopoverMenu\r\n feature={clickedFeature}\r\n onCloseAction={() => clearClickedFeature()}\r\n />\r\n </Popup>\r\n );\r\n setAddedFeaturesPopup([{ id: clickedFeature.id as string | number, popup }]);\r\n }, [clickedFeature]);\r\n\r\n function clearClickedFeature() {\r\n mapDispatch({ type: \"SET_CLICKED_FEATURE\", payload: { clickedFeature: null } });\r\n setClickedFeature(null);\r\n }\r\n\r\n // ── Sort datasets by display order ──\r\n const sortedDatasets = React.useMemo(() => {\r\n if (!addedDatasets?.length) return [];\r\n return [...addedDatasets].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\r\n }, [addedDatasets]);\r\n\r\n return (\r\n <>\r\n {sortedDatasets.map((dataset, index) => {\r\n if (dataset.visible === false) return null;\r\n if (isBuildingDataset(dataset)) return null;\r\n\r\n if (dataset.type === 'MVT' || dataset.datasetType === 'MVT') {\r\n return (\r\n <MVTDatasetLayer\r\n key={dataset.name}\r\n dataset={dataset}\r\n index={index}\r\n onLayerReady={handleLayerReady}\r\n onLayerRemoved={handleLayerRemoved}\r\n />\r\n );\r\n }\r\n\r\n return (\r\n <GeoJsonDatasetLayer\r\n key={dataset.name}\r\n dataset={dataset}\r\n index={index}\r\n onLayerReady={handleLayerReady}\r\n onLayerRemoved={handleLayerRemoved}\r\n />\r\n );\r\n })}\r\n\r\n {addedFeaturesPopup.map((popup) => (\r\n <React.Fragment key={popup.id}>{popup.popup}</React.Fragment>\r\n ))}\r\n </>\r\n );\r\n};\r\n"],"mappings":"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","names":["_a"]}
1
+ {"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/index.tsx"],"sourcesContent":["\"use client\";\r\n\r\nimport * as React from \"react\";\r\nimport { Source, Layer, Popup } from \"react-map-gl/maplibre\";\r\nimport type { MapMouseEvent } from \"maplibre-gl\";\r\n\r\nimport { MapContext } from \"../../../../../../../../store/Map/context\";\r\nimport type { Building } from '../../../../../../../../types/dbTypes';\r\nimport { DatasetsContext } from '../../../../../../../../store';\r\nimport { MapLayerClickPriority } from \"../../../../../utils/MapEventManager/MapClickManager\";\r\nimport MapFeaturePopoverMenu from \"../../../../MapFeaturePopoverMenu\";\r\nimport { fitGeoJsonBounds } from \"../../../../../utils/fitGeojsonBounds\";\r\nimport { createPortal } from \"react-dom\";\r\nimport { WmsTimeControl } from \"./WmsTimeControl\";\r\nimport { fetchWmsFrames, buildWmsTimeUrl, wmsLegendUrl } from \"../../../../../datasets/src/wmsTime\";\r\n\r\ninterface BuildingDataset {\r\n \"type\": \"buildings\";\r\n \"data\": Building[];\r\n \"name\": string;\r\n \"visible\"?: boolean;\r\n}\r\n\r\nconst isBuildingDataset = (dataset: any): dataset is BuildingDataset => {\r\n return dataset.type === \"buildings\" && \"data\" in dataset;\r\n};\r\n\r\nconst parseNumericValue = (value: unknown): number | null => {\r\n if (typeof value === 'number' && Number.isFinite(value)) return value;\r\n if (typeof value !== 'string') return null;\r\n const cleaned = value.replace(/[$%\\s]/g, '').replace(/,/g, '');\r\n const parsed = Number.parseFloat(cleaned);\r\n return Number.isFinite(parsed) ? parsed : null;\r\n};\r\n\r\nconst computeMinMax = (\r\n features: import('geojson').Feature[],\r\n fieldName: string,\r\n): { min: number; max: number } | null => {\r\n let min = Number.POSITIVE_INFINITY;\r\n let max = Number.NEGATIVE_INFINITY;\r\n let found = false;\r\n for (const feature of features) {\r\n const properties = (feature.properties || {}) as Record<string, unknown>;\r\n const value = parseNumericValue(properties[fieldName]);\r\n if (value === null) continue;\r\n found = true;\r\n if (value < min) min = value;\r\n if (value > max) max = value;\r\n }\r\n if (!found) return null;\r\n return { min, max: max === min ? min + 1 : max };\r\n};\r\n\r\n// ─── Per-dataset GeoJSON layer ────────────────────────────────────────\r\n// Each dataset manages its own fetch lifecycle. This means:\r\n// • datasets render PROGRESSIVELY as each one loads (no blocking)\r\n// • unmounting a dataset cancels only ITS fetch\r\n// • re-renders of one dataset never cancel fetches for another\r\n\r\ninterface GeoJsonDatasetLayerProps {\r\n dataset: any;\r\n index: number;\r\n onLayerReady: (datasetName: string, layerIds: string[]) => void;\r\n onLayerRemoved: (datasetName: string) => void;\r\n}\r\n\r\nconst GeoJsonDatasetLayer = React.memo(({ dataset, index, onLayerReady, onLayerRemoved }: GeoJsonDatasetLayerProps) => {\r\n const { state: mapState } = React.useContext(MapContext);\r\n const { map } = mapState.map;\r\n\r\n const [featureCollection, setFeatureCollection] = React.useState<import('geojson').FeatureCollection | null>(null);\r\n const fitBoundsAppliedRef = React.useRef(false);\r\n\r\n // Fetch features once when the component mounts (or dataset identity changes)\r\n React.useEffect(() => {\r\n if (!map) return;\r\n let cancelled = false;\r\n\r\n const load = async () => {\r\n try {\r\n const fetched = await dataset.getFeatures();\r\n if (cancelled) return;\r\n\r\n const fc: import('geojson').FeatureCollection =\r\n fetched?.type === 'FeatureCollection'\r\n ? fetched\r\n : { type: 'FeatureCollection', features: [] };\r\n\r\n setFeatureCollection(fc);\r\n } catch (error) {\r\n console.error(`OpenDataLayers: Error fetching features for \"${dataset.name}\":`, error);\r\n }\r\n };\r\n\r\n load();\r\n return () => { cancelled = true; };\r\n }, [map, dataset.name]);\r\n\r\n // Build the layer JSX from the loaded feature collection\r\n const layerContent = React.useMemo(() => {\r\n if (!featureCollection || featureCollection.features.length === 0) return null;\r\n\r\n const geometryType = featureCollection.features[0]?.geometry?.type;\r\n if (!geometryType) return null;\r\n\r\n // ── colour resolution ──\r\n let layerColor: any = dataset.layerColor?.color || '#0d9488';\r\n let numericFieldName: string | undefined;\r\n\r\n if (dataset.selectedFieldName) {\r\n const selectedField = dataset.fields?.find((field: any) => field.name === dataset.selectedFieldName);\r\n if (selectedField?.layerColor) {\r\n if (selectedField.colorType === 'single') {\r\n layerColor = selectedField.layerColor.color;\r\n }\r\n if (selectedField.colorType === 'minMax') {\r\n try {\r\n const fieldName = dataset.selectedFieldName;\r\n numericFieldName = `__numeric_${fieldName}`;\r\n const range = computeMinMax(featureCollection.features, fieldName);\r\n if (range) {\r\n const minColor = selectedField.layerColor.minColor || dataset.layerColor?.minColor || dataset.layerColor?.color || '#0d9488';\r\n const maxColor = selectedField.layerColor.maxColor || dataset.layerColor?.maxColor || dataset.layerColor?.color || '#0d9488';\r\n layerColor = [\r\n 'interpolate', ['linear'],\r\n ['to-number', ['get', numericFieldName], range.min],\r\n range.min, minColor,\r\n range.max, maxColor,\r\n ];\r\n }\r\n } catch (error) {\r\n console.warn('Failed to build interpolate for field', dataset.selectedFieldName, error);\r\n }\r\n }\r\n if (selectedField.colorType === 'boolean') {\r\n const minColor = selectedField.layerColor.minColor || dataset.layerColor?.minColor || dataset.layerColor?.color || '#0d9488';\r\n const maxColor = selectedField.layerColor.maxColor || dataset.layerColor?.maxColor || dataset.layerColor?.color || '#0d9488';\r\n const fieldName = dataset.selectedFieldName;\r\n layerColor = [\r\n 'case',\r\n ['any',\r\n ['==', ['get', fieldName], true],\r\n ['==', ['get', fieldName], 1],\r\n ['==', ['downcase', ['to-string', ['get', fieldName]]], 'true'],\r\n ['==', ['downcase', ['to-string', ['get', fieldName]]], 'yes'],\r\n ],\r\n maxColor,\r\n minColor,\r\n ];\r\n }\r\n }\r\n }\r\n\r\n // ── inject datasetName + numeric shadow field into each feature ──\r\n const enrichedFC: import('geojson').FeatureCollection = {\r\n ...featureCollection,\r\n features: featureCollection.features.map((feature) => {\r\n let numericVal: number | undefined;\r\n if (numericFieldName && dataset.selectedFieldName) {\r\n const v = parseNumericValue((feature.properties || {})[dataset.selectedFieldName]);\r\n if (v !== null) numericVal = v;\r\n }\r\n return {\r\n ...feature,\r\n properties: {\r\n ...feature.properties,\r\n datasetName: dataset.name,\r\n layer_color: layerColor,\r\n ...(numericFieldName && numericVal !== undefined ? { [numericFieldName]: numericVal } : {}),\r\n },\r\n };\r\n }),\r\n };\r\n\r\n // ── build layer props per geometry type ──\r\n const registeredIds: string[] = [];\r\n\r\n if (geometryType === 'Point' || geometryType === 'MultiPoint') {\r\n const paint = {\r\n 'circle-radius': 6,\r\n 'circle-color': layerColor,\r\n 'circle-opacity': 0.8,\r\n 'circle-stroke-width': 2,\r\n 'circle-stroke-color': '#ffffff',\r\n };\r\n registeredIds.push(`${dataset.name}-unclustered-point`);\r\n\r\n return {\r\n registeredIds,\r\n jsx: (\r\n <Source\r\n id={`${dataset.name}-source`}\r\n key={`${index}-${dataset.name}-source`}\r\n type=\"geojson\"\r\n data={enrichedFC}\r\n cluster={true}\r\n clusterMaxZoom={11}\r\n clusterRadius={50}\r\n >\r\n <Layer\r\n id={`${dataset.name}-clusters`}\r\n filter={['has', 'point_count']}\r\n type=\"circle\"\r\n paint={{\r\n 'circle-color': dataset.layerColor?.color || '#0d9488',\r\n 'circle-radius': ['step', ['get', 'point_count'], 20, 100, 30, 750, 40],\r\n 'circle-opacity': 0.9,\r\n }}\r\n />\r\n <Layer\r\n id={`${dataset.name}-cluster-count`}\r\n filter={['has', 'point_count']}\r\n type=\"symbol\"\r\n layout={{\r\n 'text-field': '{point_count_abbreviated}',\r\n 'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'],\r\n 'text-size': 12,\r\n }}\r\n paint={{ 'text-color': '#fff' }}\r\n />\r\n <Layer\r\n id={`${dataset.name}-unclustered-point`}\r\n filter={['!', ['has', 'point_count']]}\r\n type=\"circle\"\r\n paint={paint}\r\n />\r\n </Source>\r\n ),\r\n };\r\n }\r\n\r\n if (geometryType === 'LineString' || geometryType === 'MultiLineString') {\r\n const mainId = `${dataset.name}-line`;\r\n registeredIds.push(mainId);\r\n return {\r\n registeredIds,\r\n jsx: (\r\n <Source\r\n id={`${dataset.name}-source`}\r\n key={`${index}-${dataset.name}-source`}\r\n type=\"geojson\"\r\n data={enrichedFC}\r\n >\r\n <Layer\r\n id={mainId}\r\n type=\"line\"\r\n paint={{ 'line-color': layerColor, 'line-width': 3, 'line-opacity': 1 }}\r\n />\r\n </Source>\r\n ),\r\n };\r\n }\r\n\r\n if (geometryType === 'Polygon' || geometryType === 'MultiPolygon') {\r\n const fillId = `${dataset.name}-fill`;\r\n const outlineId = `${dataset.name}-outline`;\r\n registeredIds.push(fillId, outlineId);\r\n return {\r\n registeredIds,\r\n jsx: (\r\n <Source\r\n id={`${dataset.name}-source`}\r\n key={`${index}-${dataset.name}-source`}\r\n type=\"geojson\"\r\n data={enrichedFC}\r\n >\r\n <Layer\r\n id={fillId}\r\n type=\"fill\"\r\n paint={{ 'fill-color': layerColor, 'fill-opacity': 0.5 }}\r\n />\r\n <Layer\r\n id={outlineId}\r\n type=\"line\"\r\n paint={{ 'line-color': '#ffffff', 'line-width': 2 }}\r\n />\r\n </Source>\r\n ),\r\n };\r\n }\r\n\r\n return null;\r\n }, [featureCollection, dataset.name, dataset.layerColor, dataset.selectedFieldName, dataset.fields, index]);\r\n\r\n // Register / unregister interactive layer IDs with the parent\r\n React.useEffect(() => {\r\n if (layerContent?.registeredIds) {\r\n onLayerReady(dataset.name, layerContent.registeredIds);\r\n }\r\n return () => { onLayerRemoved(dataset.name); };\r\n }, [layerContent?.registeredIds, dataset.name, onLayerReady, onLayerRemoved]);\r\n\r\n return layerContent?.jsx ?? null;\r\n});\r\nGeoJsonDatasetLayer.displayName = 'GeoJsonDatasetLayer';\r\n\r\n\r\n// ─── Per-dataset MVT layer ────────────────────────────────────────────\r\n\r\ninterface MVTDatasetLayerProps {\r\n dataset: any;\r\n index: number;\r\n onLayerReady: (datasetName: string, layerIds: string[]) => void;\r\n onLayerRemoved: (datasetName: string) => void;\r\n}\r\n\r\nconst MVTDatasetLayer = React.memo(({ dataset, index, onLayerReady, onLayerRemoved }: MVTDatasetLayerProps) => {\r\n const tileUrl = dataset.url || dataset.information;\r\n const sourceLayer = (dataset as any)?.serviceInfo?.sourceLayer || dataset.id || dataset.name.toLowerCase().replace(/\\s+/g, '_');\r\n const layerColor = dataset.layerColor?.color || '#0d9488';\r\n const isPointLayer = dataset.layerType === 'circle' || /point/i.test(sourceLayer);\r\n const isMartinBuilding = /buildings?/i.test((dataset as any)?.serviceInfo?.sourceLayer || dataset.id || dataset.name);\r\n // Only extrude actual building layers. A polygon dataset resolves to layerType\r\n // 'fill', so keying extrusion off 'fill' alone routed every polygon (e.g. published\r\n // open-data boundaries) into the zero-height, minzoom-15.5 extrusion branch — leaving\r\n // only the outline visible. Non-building polygons fall through to the flat-fill branch.\r\n const extraIsBuilding = isMartinBuilding && !isPointLayer;\r\n\r\n const mainLayerId = isPointLayer\r\n ? `${dataset.name}-points`\r\n : extraIsBuilding\r\n ? `${dataset.name}-extrusion`\r\n : `${dataset.name}-fill`;\r\n const outlineLayerId = `${dataset.name}-outline`;\r\n\r\n // Register interactive layer IDs\r\n React.useEffect(() => {\r\n const ids = isPointLayer ? [mainLayerId] : [mainLayerId, outlineLayerId];\r\n onLayerReady(dataset.name, ids);\r\n return () => { onLayerRemoved(dataset.name); };\r\n }, [dataset.name, mainLayerId, outlineLayerId, isPointLayer, onLayerReady, onLayerRemoved]);\r\n\r\n if (!tileUrl) {\r\n console.error(`❌ OpenDataLayers: No tile URL found for MVT dataset \"${dataset.name}\"`);\r\n return null;\r\n }\r\n\r\n if (extraIsBuilding) {\r\n return (\r\n <Source id={`${dataset.name}-source`} key={`${index}-${dataset.name}-source`} type=\"vector\" tiles={[tileUrl]}>\r\n <Layer\r\n id={mainLayerId} type=\"fill-extrusion\" source-layer={sourceLayer}\r\n paint={{\r\n 'fill-extrusion-color': layerColor,\r\n 'fill-extrusion-height': ['coalesce', ['to-number', ['get', 'heightmax']], 0],\r\n 'fill-extrusion-opacity': 0.8,\r\n }}\r\n minzoom={15.5}\r\n />\r\n <Layer id={outlineLayerId} type=\"line\" source-layer={sourceLayer} paint={{ 'line-color': layerColor, 'line-width': 1, 'line-opacity': 0.8 }} />\r\n </Source>\r\n );\r\n }\r\n\r\n if (isPointLayer) {\r\n return (\r\n <Source id={`${dataset.name}-source`} key={`${index}-${dataset.name}-source`} type=\"vector\" tiles={[tileUrl]}>\r\n <Layer\r\n id={mainLayerId} type=\"circle\" source-layer={sourceLayer}\r\n paint={{ 'circle-radius': 6, 'circle-color': layerColor, 'circle-opacity': 0.8, 'circle-stroke-width': 2, 'circle-stroke-color': '#ffffff' }}\r\n />\r\n </Source>\r\n );\r\n }\r\n\r\n return (\r\n <Source id={`${dataset.name}-source`} key={`${index}-${dataset.name}-source`} type=\"vector\" tiles={[tileUrl]}>\r\n <Layer id={mainLayerId} type=\"fill\" source-layer={sourceLayer} paint={{ 'fill-color': layerColor, 'fill-opacity': 0.6 }} />\r\n {/* White outline (matches the original GeoJSON polygon style) so subdivision\r\n boundaries stay legible — a same-colour outline read as one solid blob. */}\r\n <Layer id={outlineLayerId} type=\"line\" source-layer={sourceLayer} paint={{ 'line-color': '#ffffff', 'line-width': 2 }} />\r\n </Source>\r\n );\r\n});\r\nMVTDatasetLayer.displayName = 'MVTDatasetLayer';\r\n\r\n\r\n// ─── Per-dataset WMS raster layer ─────────────────────────────────────\r\n// Live/federated WMS overlays (e.g. the GeoMet weather radar). The dataset's\r\n// `url` is a MapLibre raster tile template (GetMap with a literal\r\n// {bbox-epsg-3857}); MapLibre fetches tiles directly, so there's nothing to\r\n// parse and no features to query (raster → not interactive).\r\n\r\ninterface WMSDatasetLayerProps {\r\n dataset: any;\r\n index: number;\r\n onLayerReady: (datasetName: string, layerIds: string[]) => void;\r\n onLayerRemoved: (datasetName: string) => void;\r\n}\r\n\r\nconst WMSDatasetLayer = React.memo(({ dataset, index, onLayerReady, onLayerRemoved }: WMSDatasetLayerProps) => {\r\n const { state: mapState } = React.useContext(MapContext);\r\n const { map } = mapState.map;\r\n\r\n const tileUrl = dataset.url || dataset.information;\r\n const layerId = `${dataset.name}-wms`;\r\n const sourceId = `${dataset.name}-source`;\r\n\r\n const timeEnabled = !!dataset.timeEnabled && !!dataset.wms;\r\n const [frames, setFrames] = React.useState<string[]>([]);\r\n const [activeTime, setActiveTime] = React.useState<string | null>(null);\r\n // The bottom-left overlay stack's portal slot (MapViewer renders it). Resolved\r\n // in an effect so the node exists (post-commit) before we portal into it.\r\n const [controlSlot, setControlSlot] = React.useState<HTMLElement | null>(null);\r\n React.useEffect(() => {\r\n if (timeEnabled) setControlSlot(document.getElementById('wms-time-slot'));\r\n }, [timeEnabled]);\r\n\r\n // Register with no interactive layer ids — a raster has no queryable features.\r\n React.useEffect(() => {\r\n onLayerReady(dataset.name, []);\r\n return () => { onLayerRemoved(dataset.name); };\r\n }, [dataset.name, onLayerReady, onLayerRemoved]);\r\n\r\n // Load the WMS time extent once (time-enabled datasets only).\r\n React.useEffect(() => {\r\n if (!timeEnabled || !dataset.wms) return;\r\n let cancelled = false;\r\n fetchWmsFrames(dataset.wms.baseUrl, dataset.wms.layers)\r\n .then(f => { if (!cancelled) setFrames(f); })\r\n .catch(() => { /* fetchWmsFrames already swallows; keep static */ });\r\n return () => { cancelled = true; };\r\n }, [timeEnabled, dataset.wms?.baseUrl, dataset.wms?.layers]);\r\n\r\n // Imperatively swap the raster source's tiles per frame. The <Source tiles>\r\n // prop below never changes after mount, so there's no react-map-gl tug-of-war\r\n // and no flicker — this setTiles call is the single source of truth for TIME.\r\n React.useEffect(() => {\r\n if (!map || !activeTime || !dataset.wms) return;\r\n const src = map.getSource(sourceId) as { setTiles?: (t: string[]) => void } | undefined;\r\n if (src?.setTiles) {\r\n src.setTiles([buildWmsTimeUrl(dataset.wms.baseUrl, dataset.wms.layers, activeTime)]);\r\n }\r\n }, [map, activeTime, sourceId, dataset.wms?.baseUrl, dataset.wms?.layers]);\r\n\r\n if (!tileUrl) {\r\n console.error(`❌ OpenDataLayers: No tile URL found for WMS dataset \"${dataset.name}\"`);\r\n return null;\r\n }\r\n\r\n const showControl = timeEnabled && frames.length > 1 && map && controlSlot;\r\n\r\n return (\r\n <>\r\n <Source id={sourceId} key={`${index}-${dataset.name}-source`} type=\"raster\" tiles={[tileUrl]} tileSize={256}>\r\n <Layer id={layerId} type=\"raster\" paint={{ 'raster-opacity': 0.85 }} />\r\n </Source>\r\n {showControl && createPortal(\r\n <WmsTimeControl\r\n frames={frames}\r\n onTimeChange={setActiveTime}\r\n label={dataset.name}\r\n legendUrl={dataset.wms ? wmsLegendUrl(dataset.wms.baseUrl, dataset.wms.layers) : undefined}\r\n />,\r\n controlSlot,\r\n )}\r\n </>\r\n );\r\n});\r\nWMSDatasetLayer.displayName = 'WMSDatasetLayer';\r\n\r\n\r\n// ─── Main orchestrator ────────────────────────────────────────────────\r\n\r\nexport const OpenDataLayers = () => {\r\n const { \"state\": mapState, \"dispatch\": mapDispatch } = React.useContext(MapContext);\r\n const { map, mapClickManager } = mapState.map;\r\n\r\n const { state: datasetState } = React.useContext(DatasetsContext);\r\n const { addedDatasets } = datasetState.datasets;\r\n\r\n const [clickedFeature, setClickedFeature] = React.useState<any>(null);\r\n const [addedFeaturesPopup, setAddedFeaturesPopup] = React.useState<Array<{\r\n id: string | number;\r\n popup: React.ReactElement;\r\n }>>([]);\r\n\r\n // Track interactive layer IDs per dataset for click handling\r\n const layerIdsMapRef = React.useRef<Record<string, string[]>>({});\r\n const [allLayerNames, setAllLayerNames] = React.useState<string[]>([]);\r\n\r\n const handleLayerReady = React.useCallback((datasetName: string, layerIds: string[]) => {\r\n layerIdsMapRef.current[datasetName] = layerIds;\r\n setAllLayerNames(Object.values(layerIdsMapRef.current).flat());\r\n }, []);\r\n\r\n const handleLayerRemoved = React.useCallback((datasetName: string) => {\r\n delete layerIdsMapRef.current[datasetName];\r\n setAllLayerNames(Object.values(layerIdsMapRef.current).flat());\r\n }, []);\r\n\r\n // ── Click handling ──\r\n React.useEffect(() => {\r\n if (!map || !mapClickManager || allLayerNames.length === 0) return;\r\n\r\n const handleMapClick = (e: MapMouseEvent) => {\r\n const clicked = map.queryRenderedFeatures(e.point, { layers: allLayerNames });\r\n const localClickedFeature = clicked?.[0];\r\n\r\n if (!localClickedFeature) {\r\n setClickedFeature(null);\r\n return;\r\n }\r\n\r\n const lng = e.lngLat.lng;\r\n const lat = e.lngLat.lat;\r\n const coordinates = [lng, lat];\r\n const properties = localClickedFeature.properties || {};\r\n const _name = Object.entries(properties).find(([key]) => key.toLowerCase().includes('name'))?.[1] || undefined;\r\n\r\n let datasetNameFromFeature = properties.datasetName;\r\n if (!datasetNameFromFeature && localClickedFeature.layer) {\r\n const layerId = localClickedFeature.layer.id;\r\n const suffixes = ['-unclustered-point', '-clusters', '-cluster-count', '-outline', '-fill', '-line', '-circle', '-extrusion', '-points'];\r\n let extractedName = layerId;\r\n for (const suffix of suffixes) {\r\n if (layerId.endsWith(suffix)) {\r\n extractedName = layerId.slice(0, -suffix.length);\r\n break;\r\n }\r\n }\r\n if (extractedName === layerId && layerId.includes('-')) {\r\n extractedName = layerId.slice(0, layerId.lastIndexOf('-'));\r\n }\r\n datasetNameFromFeature = extractedName;\r\n }\r\n\r\n const featureId = properties.globalid || properties.id || `temp-${Date.now()}`;\r\n localClickedFeature.id = featureId;\r\n localClickedFeature.properties = { ...properties, coordinates, _name, datasetName: datasetNameFromFeature };\r\n setClickedFeature(localClickedFeature);\r\n };\r\n\r\n for (const layerId of allLayerNames) {\r\n mapClickManager.register(layerId, MapLayerClickPriority.OpenDataLayerClickPriority, handleMapClick);\r\n }\r\n\r\n return () => {\r\n for (const layerId of allLayerNames) {\r\n mapClickManager.unregister(layerId);\r\n }\r\n };\r\n }, [map, mapClickManager, allLayerNames]);\r\n\r\n // ── Hover cursor handling ──\r\n React.useEffect(() => {\r\n if (!map) return;\r\n\r\n const canvas = map.getCanvas();\r\n\r\n const setDefaultCursor = () => {\r\n canvas.style.cursor = 'default';\r\n };\r\n\r\n if (allLayerNames.length === 0) {\r\n setDefaultCursor();\r\n return;\r\n }\r\n\r\n const handleMouseMove = (e: MapMouseEvent) => {\r\n const hoveredFeatures = map.queryRenderedFeatures(e.point, { layers: allLayerNames });\r\n canvas.style.cursor = hoveredFeatures.length > 0 ? 'pointer' : 'default';\r\n };\r\n\r\n const handleMouseLeave = () => {\r\n setDefaultCursor();\r\n };\r\n\r\n map.on('mousemove', handleMouseMove);\r\n map.on('mouseleave', handleMouseLeave);\r\n\r\n return () => {\r\n map.off('mousemove', handleMouseMove);\r\n map.off('mouseleave', handleMouseLeave);\r\n setDefaultCursor();\r\n };\r\n }, [map, allLayerNames]);\r\n\r\n // ── Popup ──\r\n React.useEffect(() => {\r\n if (!clickedFeature || !clickedFeature.properties?.coordinates) {\r\n setAddedFeaturesPopup([]);\r\n return;\r\n }\r\n const popup = (\r\n <Popup\r\n anchor=\"bottom\"\r\n closeButton={true}\r\n closeOnClick={false}\r\n closeOnMove={false}\r\n focusAfterOpen={true}\r\n key={clickedFeature.id}\r\n latitude={clickedFeature.properties.coordinates[1]}\r\n longitude={clickedFeature.properties.coordinates[0]}\r\n >\r\n <MapFeaturePopoverMenu\r\n feature={clickedFeature}\r\n onCloseAction={() => clearClickedFeature()}\r\n />\r\n </Popup>\r\n );\r\n setAddedFeaturesPopup([{ id: clickedFeature.id as string | number, popup }]);\r\n }, [clickedFeature]);\r\n\r\n function clearClickedFeature() {\r\n mapDispatch({ type: \"SET_CLICKED_FEATURE\", payload: { clickedFeature: null } });\r\n setClickedFeature(null);\r\n }\r\n\r\n // ── Sort datasets by display order ──\r\n const sortedDatasets = React.useMemo(() => {\r\n if (!addedDatasets?.length) return [];\r\n return [...addedDatasets].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\r\n }, [addedDatasets]);\r\n\r\n return (\r\n <>\r\n {sortedDatasets.map((dataset, index) => {\r\n if (dataset.visible === false) return null;\r\n if (isBuildingDataset(dataset)) return null;\r\n\r\n if (dataset.type === 'WMS' || dataset.datasetType === 'WMS') {\r\n return (\r\n <WMSDatasetLayer\r\n key={dataset.name}\r\n dataset={dataset}\r\n index={index}\r\n onLayerReady={handleLayerReady}\r\n onLayerRemoved={handleLayerRemoved}\r\n />\r\n );\r\n }\r\n\r\n if (dataset.type === 'MVT' || dataset.datasetType === 'MVT') {\r\n return (\r\n <MVTDatasetLayer\r\n key={dataset.name}\r\n dataset={dataset}\r\n index={index}\r\n onLayerReady={handleLayerReady}\r\n onLayerRemoved={handleLayerRemoved}\r\n />\r\n );\r\n }\r\n\r\n return (\r\n <GeoJsonDatasetLayer\r\n key={dataset.name}\r\n dataset={dataset}\r\n index={index}\r\n onLayerReady={handleLayerReady}\r\n onLayerRemoved={handleLayerRemoved}\r\n />\r\n );\r\n })}\r\n\r\n {addedFeaturesPopup.map((popup) => (\r\n <React.Fragment key={popup.id}>{popup.popup}</React.Fragment>\r\n ))}\r\n </>\r\n );\r\n};\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA+LoB,SA6PZ,UApPgB,KATJ;AA7LpB,YAAY,WAAW;AACvB,SAAS,QAAQ,OAAO,aAAa;AAGrC,SAAS,kBAAkB;AAE3B,SAAS,uBAAuB;AAChC,SAAS,6BAA6B;AACtC,OAAO,2BAA2B;AAElC,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB;AAC/B,SAAS,gBAAgB,iBAAiB,oBAAoB;AAS9D,MAAM,oBAAoB,CAAC,YAA6C;AACpE,SAAO,QAAQ,SAAS,eAAe,UAAU;AACrD;AAEA,MAAM,oBAAoB,CAAC,UAAkC;AACzD,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,EAAG,QAAO;AAChE,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,UAAU,MAAM,QAAQ,WAAW,EAAE,EAAE,QAAQ,MAAM,EAAE;AAC7D,QAAM,SAAS,OAAO,WAAW,OAAO;AACxC,SAAO,OAAO,SAAS,MAAM,IAAI,SAAS;AAC9C;AAEA,MAAM,gBAAgB,CAClB,UACA,cACsC;AACtC,MAAI,MAAM,OAAO;AACjB,MAAI,MAAM,OAAO;AACjB,MAAI,QAAQ;AACZ,aAAW,WAAW,UAAU;AAC5B,UAAM,aAAc,QAAQ,cAAc,CAAC;AAC3C,UAAM,QAAQ,kBAAkB,WAAW,SAAS,CAAC;AACrD,QAAI,UAAU,KAAM;AACpB,YAAQ;AACR,QAAI,QAAQ,IAAK,OAAM;AACvB,QAAI,QAAQ,IAAK,OAAM;AAAA,EAC3B;AACA,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,EAAE,KAAK,KAAK,QAAQ,MAAM,MAAM,IAAI,IAAI;AACnD;AAeA,MAAM,sBAAsB,MAAM,KAAK,CAAC,EAAE,SAAS,OAAO,cAAc,eAAe,MAAgC;AAnEvH;AAoEI,QAAM,EAAE,OAAO,SAAS,IAAI,MAAM,WAAW,UAAU;AACvD,QAAM,EAAE,IAAI,IAAI,SAAS;AAEzB,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,MAAM,SAAqD,IAAI;AACjH,QAAM,sBAAsB,MAAM,OAAO,KAAK;AAG9C,QAAM,UAAU,MAAM;AAClB,QAAI,CAAC,IAAK;AACV,QAAI,YAAY;AAEhB,UAAM,OAAO,YAAY;AACrB,UAAI;AACA,cAAM,UAAU,MAAM,QAAQ,YAAY;AAC1C,YAAI,UAAW;AAEf,cAAM,MACF,mCAAS,UAAS,sBACZ,UACA,EAAE,MAAM,qBAAqB,UAAU,CAAC,EAAE;AAEpD,6BAAqB,EAAE;AAAA,MAC3B,SAAS,OAAO;AACZ,gBAAQ,MAAM,gDAAgD,QAAQ,IAAI,MAAM,KAAK;AAAA,MACzF;AAAA,IACJ;AAEA,SAAK;AACL,WAAO,MAAM;AAAE,kBAAY;AAAA,IAAM;AAAA,EACrC,GAAG,CAAC,KAAK,QAAQ,IAAI,CAAC;AAGtB,QAAM,eAAe,MAAM,QAAQ,MAAM;AApG7C,QAAAA,KAAA;AAqGQ,QAAI,CAAC,qBAAqB,kBAAkB,SAAS,WAAW,EAAG,QAAO;AAE1E,UAAM,gBAAe,MAAAA,MAAA,kBAAkB,SAAS,CAAC,MAA5B,gBAAAA,IAA+B,aAA/B,mBAAyC;AAC9D,QAAI,CAAC,aAAc,QAAO;AAG1B,QAAI,eAAkB,aAAQ,eAAR,mBAAoB,UAAS;AACnD,QAAI;AAEJ,QAAI,QAAQ,mBAAmB;AAC3B,YAAM,iBAAgB,aAAQ,WAAR,mBAAgB,KAAK,CAAC,UAAe,MAAM,SAAS,QAAQ;AAClF,UAAI,+CAAe,YAAY;AAC3B,YAAI,cAAc,cAAc,UAAU;AACtC,uBAAa,cAAc,WAAW;AAAA,QAC1C;AACA,YAAI,cAAc,cAAc,UAAU;AACtC,cAAI;AACA,kBAAM,YAAY,QAAQ;AAC1B,+BAAmB,aAAa,SAAS;AACzC,kBAAM,QAAQ,cAAc,kBAAkB,UAAU,SAAS;AACjE,gBAAI,OAAO;AACP,oBAAM,WAAW,cAAc,WAAW,cAAY,aAAQ,eAAR,mBAAoB,eAAY,aAAQ,eAAR,mBAAoB,UAAS;AACnH,oBAAM,WAAW,cAAc,WAAW,cAAY,aAAQ,eAAR,mBAAoB,eAAY,aAAQ,eAAR,mBAAoB,UAAS;AACnH,2BAAa;AAAA,gBACT;AAAA,gBAAe,CAAC,QAAQ;AAAA,gBACxB,CAAC,aAAa,CAAC,OAAO,gBAAgB,GAAG,MAAM,GAAG;AAAA,gBAClD,MAAM;AAAA,gBAAK;AAAA,gBACX,MAAM;AAAA,gBAAK;AAAA,cACf;AAAA,YACJ;AAAA,UACJ,SAAS,OAAO;AACZ,oBAAQ,KAAK,yCAAyC,QAAQ,mBAAmB,KAAK;AAAA,UAC1F;AAAA,QACJ;AACA,YAAI,cAAc,cAAc,WAAW;AACvC,gBAAM,WAAW,cAAc,WAAW,cAAY,aAAQ,eAAR,mBAAoB,eAAY,aAAQ,eAAR,mBAAoB,UAAS;AACnH,gBAAM,WAAW,cAAc,WAAW,cAAY,aAAQ,eAAR,mBAAoB,eAAY,aAAQ,eAAR,mBAAoB,UAAS;AACnH,gBAAM,YAAY,QAAQ;AAC1B,uBAAa;AAAA,YACT;AAAA,YACA;AAAA,cAAC;AAAA,cACG,CAAC,MAAM,CAAC,OAAO,SAAS,GAAG,IAAI;AAAA,cAC/B,CAAC,MAAM,CAAC,OAAO,SAAS,GAAG,CAAC;AAAA,cAC5B,CAAC,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,OAAO,SAAS,CAAC,CAAC,GAAG,MAAM;AAAA,cAC9D,CAAC,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,OAAO,SAAS,CAAC,CAAC,GAAG,KAAK;AAAA,YACjE;AAAA,YACA;AAAA,YACA;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAGA,UAAM,aAAkD,iCACjD,oBADiD;AAAA,MAEpD,UAAU,kBAAkB,SAAS,IAAI,CAAC,YAAY;AAClD,YAAI;AACJ,YAAI,oBAAoB,QAAQ,mBAAmB;AAC/C,gBAAM,IAAI,mBAAmB,QAAQ,cAAc,CAAC,GAAG,QAAQ,iBAAiB,CAAC;AACjF,cAAI,MAAM,KAAM,cAAa;AAAA,QACjC;AACA,eAAO,iCACA,UADA;AAAA,UAEH,YAAY,gDACL,QAAQ,aADH;AAAA,YAER,aAAa,QAAQ;AAAA,YACrB,aAAa;AAAA,cACT,oBAAoB,eAAe,SAAY,EAAE,CAAC,gBAAgB,GAAG,WAAW,IAAI,CAAC;AAAA,QAEjG;AAAA,MACJ,CAAC;AAAA,IACL;AAGA,UAAM,gBAA0B,CAAC;AAEjC,QAAI,iBAAiB,WAAW,iBAAiB,cAAc;AAC3D,YAAM,QAAQ;AAAA,QACV,iBAAiB;AAAA,QACjB,gBAAgB;AAAA,QAChB,kBAAkB;AAAA,QAClB,uBAAuB;AAAA,QACvB,uBAAuB;AAAA,MAC3B;AACA,oBAAc,KAAK,GAAG,QAAQ,IAAI,oBAAoB;AAEtD,aAAO;AAAA,QACH;AAAA,QACA,KACI;AAAA,UAAC;AAAA;AAAA,YACG,IAAI,GAAG,QAAQ,IAAI;AAAA,YAEnB,MAAK;AAAA,YACL,MAAM;AAAA,YACN,SAAS;AAAA,YACT,gBAAgB;AAAA,YAChB,eAAe;AAAA,YAEf;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACG,IAAI,GAAG,QAAQ,IAAI;AAAA,kBACnB,QAAQ,CAAC,OAAO,aAAa;AAAA,kBAC7B,MAAK;AAAA,kBACL,OAAO;AAAA,oBACH,kBAAgB,aAAQ,eAAR,mBAAoB,UAAS;AAAA,oBAC7C,iBAAiB,CAAC,QAAQ,CAAC,OAAO,aAAa,GAAG,IAAI,KAAK,IAAI,KAAK,EAAE;AAAA,oBACtE,kBAAkB;AAAA,kBACtB;AAAA;AAAA,cACJ;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACG,IAAI,GAAG,QAAQ,IAAI;AAAA,kBACnB,QAAQ,CAAC,OAAO,aAAa;AAAA,kBAC7B,MAAK;AAAA,kBACL,QAAQ;AAAA,oBACJ,cAAc;AAAA,oBACd,aAAa,CAAC,uBAAuB,uBAAuB;AAAA,oBAC5D,aAAa;AAAA,kBACjB;AAAA,kBACA,OAAO,EAAE,cAAc,OAAO;AAAA;AAAA,cAClC;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACG,IAAI,GAAG,QAAQ,IAAI;AAAA,kBACnB,QAAQ,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC;AAAA,kBACpC,MAAK;AAAA,kBACL;AAAA;AAAA,cACJ;AAAA;AAAA;AAAA,UAjCK,GAAG,KAAK,IAAI,QAAQ,IAAI;AAAA,QAkCjC;AAAA,MAER;AAAA,IACJ;AAEA,QAAI,iBAAiB,gBAAgB,iBAAiB,mBAAmB;AACrE,YAAM,SAAS,GAAG,QAAQ,IAAI;AAC9B,oBAAc,KAAK,MAAM;AACzB,aAAO;AAAA,QACH;AAAA,QACA,KACI;AAAA,UAAC;AAAA;AAAA,YACG,IAAI,GAAG,QAAQ,IAAI;AAAA,YAEnB,MAAK;AAAA,YACL,MAAM;AAAA,YAEN;AAAA,cAAC;AAAA;AAAA,gBACG,IAAI;AAAA,gBACJ,MAAK;AAAA,gBACL,OAAO,EAAE,cAAc,YAAY,cAAc,GAAG,gBAAgB,EAAE;AAAA;AAAA,YAC1E;AAAA;AAAA,UARK,GAAG,KAAK,IAAI,QAAQ,IAAI;AAAA,QASjC;AAAA,MAER;AAAA,IACJ;AAEA,QAAI,iBAAiB,aAAa,iBAAiB,gBAAgB;AAC/D,YAAM,SAAS,GAAG,QAAQ,IAAI;AAC9B,YAAM,YAAY,GAAG,QAAQ,IAAI;AACjC,oBAAc,KAAK,QAAQ,SAAS;AACpC,aAAO;AAAA,QACH;AAAA,QACA,KACI;AAAA,UAAC;AAAA;AAAA,YACG,IAAI,GAAG,QAAQ,IAAI;AAAA,YAEnB,MAAK;AAAA,YACL,MAAM;AAAA,YAEN;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACG,IAAI;AAAA,kBACJ,MAAK;AAAA,kBACL,OAAO,EAAE,cAAc,YAAY,gBAAgB,IAAI;AAAA;AAAA,cAC3D;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACG,IAAI;AAAA,kBACJ,MAAK;AAAA,kBACL,OAAO,EAAE,cAAc,WAAW,cAAc,EAAE;AAAA;AAAA,cACtD;AAAA;AAAA;AAAA,UAbK,GAAG,KAAK,IAAI,QAAQ,IAAI;AAAA,QAcjC;AAAA,MAER;AAAA,IACJ;AAEA,WAAO;AAAA,EACX,GAAG,CAAC,mBAAmB,QAAQ,MAAM,QAAQ,YAAY,QAAQ,mBAAmB,QAAQ,QAAQ,KAAK,CAAC;AAG1G,QAAM,UAAU,MAAM;AAClB,QAAI,6CAAc,eAAe;AAC7B,mBAAa,QAAQ,MAAM,aAAa,aAAa;AAAA,IACzD;AACA,WAAO,MAAM;AAAE,qBAAe,QAAQ,IAAI;AAAA,IAAG;AAAA,EACjD,GAAG,CAAC,6CAAc,eAAe,QAAQ,MAAM,cAAc,cAAc,CAAC;AAE5E,UAAO,kDAAc,QAAd,YAAqB;AAChC,CAAC;AACD,oBAAoB,cAAc;AAYlC,MAAM,kBAAkB,MAAM,KAAK,CAAC,EAAE,SAAS,OAAO,cAAc,eAAe,MAA4B;AAnT/G;AAoTI,QAAM,UAAU,QAAQ,OAAO,QAAQ;AACvC,QAAM,gBAAe,wCAAiB,gBAAjB,mBAA8B,gBAAe,QAAQ,MAAM,QAAQ,KAAK,YAAY,EAAE,QAAQ,QAAQ,GAAG;AAC9H,QAAM,eAAa,aAAQ,eAAR,mBAAoB,UAAS;AAChD,QAAM,eAAe,QAAQ,cAAc,YAAY,SAAS,KAAK,WAAW;AAChF,QAAM,mBAAmB,cAAc,OAAM,wCAAiB,gBAAjB,mBAA8B,gBAAe,QAAQ,MAAM,QAAQ,IAAI;AAKpH,QAAM,kBAAkB,oBAAoB,CAAC;AAE7C,QAAM,cAAc,eACd,GAAG,QAAQ,IAAI,YACf,kBACI,GAAG,QAAQ,IAAI,eACf,GAAG,QAAQ,IAAI;AACzB,QAAM,iBAAiB,GAAG,QAAQ,IAAI;AAGtC,QAAM,UAAU,MAAM;AAClB,UAAM,MAAM,eAAe,CAAC,WAAW,IAAI,CAAC,aAAa,cAAc;AACvE,iBAAa,QAAQ,MAAM,GAAG;AAC9B,WAAO,MAAM;AAAE,qBAAe,QAAQ,IAAI;AAAA,IAAG;AAAA,EACjD,GAAG,CAAC,QAAQ,MAAM,aAAa,gBAAgB,cAAc,cAAc,cAAc,CAAC;AAE1F,MAAI,CAAC,SAAS;AACV,YAAQ,MAAM,6DAAwD,QAAQ,IAAI,GAAG;AACrF,WAAO;AAAA,EACX;AAEA,MAAI,iBAAiB;AACjB,WACI,qBAAC,UAAO,IAAI,GAAG,QAAQ,IAAI,WAAmD,MAAK,UAAS,OAAO,CAAC,OAAO,GACvG;AAAA;AAAA,QAAC;AAAA;AAAA,UACG,IAAI;AAAA,UAAa,MAAK;AAAA,UAAiB,gBAAc;AAAA,UACrD,OAAO;AAAA,YACH,wBAAwB;AAAA,YACxB,yBAAyB,CAAC,YAAY,CAAC,aAAa,CAAC,OAAO,WAAW,CAAC,GAAG,CAAC;AAAA,YAC5E,0BAA0B;AAAA,UAC9B;AAAA,UACA,SAAS;AAAA;AAAA,MACb;AAAA,MACA,oBAAC,SAAM,IAAI,gBAAgB,MAAK,QAAO,gBAAc,aAAa,OAAO,EAAE,cAAc,YAAY,cAAc,GAAG,gBAAgB,IAAI,GAAG;AAAA,SAVtG,GAAG,KAAK,IAAI,QAAQ,IAAI,SAWnE;AAAA,EAER;AAEA,MAAI,cAAc;AACd,WACI,oBAAC,UAAO,IAAI,GAAG,QAAQ,IAAI,WAAmD,MAAK,UAAS,OAAO,CAAC,OAAO,GACvG;AAAA,MAAC;AAAA;AAAA,QACG,IAAI;AAAA,QAAa,MAAK;AAAA,QAAS,gBAAc;AAAA,QAC7C,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,YAAY,kBAAkB,KAAK,uBAAuB,GAAG,uBAAuB,UAAU;AAAA;AAAA,IAC/I,KAJuC,GAAG,KAAK,IAAI,QAAQ,IAAI,SAKnE;AAAA,EAER;AAEA,SACI,qBAAC,UAAO,IAAI,GAAG,QAAQ,IAAI,WAAmD,MAAK,UAAS,OAAO,CAAC,OAAO,GACvG;AAAA,wBAAC,SAAM,IAAI,aAAa,MAAK,QAAO,gBAAc,aAAa,OAAO,EAAE,cAAc,YAAY,gBAAgB,IAAI,GAAG;AAAA,IAGzH,oBAAC,SAAM,IAAI,gBAAgB,MAAK,QAAO,gBAAc,aAAa,OAAO,EAAE,cAAc,WAAW,cAAc,EAAE,GAAG;AAAA,OAJhF,GAAG,KAAK,IAAI,QAAQ,IAAI,SAKnE;AAER,CAAC;AACD,gBAAgB,cAAc;AAgB9B,MAAM,kBAAkB,MAAM,KAAK,CAAC,EAAE,SAAS,OAAO,cAAc,eAAe,MAA4B;AAvY/G;AAwYI,QAAM,EAAE,OAAO,SAAS,IAAI,MAAM,WAAW,UAAU;AACvD,QAAM,EAAE,IAAI,IAAI,SAAS;AAEzB,QAAM,UAAU,QAAQ,OAAO,QAAQ;AACvC,QAAM,UAAU,GAAG,QAAQ,IAAI;AAC/B,QAAM,WAAW,GAAG,QAAQ,IAAI;AAEhC,QAAM,cAAc,CAAC,CAAC,QAAQ,eAAe,CAAC,CAAC,QAAQ;AACvD,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAAmB,CAAC,CAAC;AACvD,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAwB,IAAI;AAGtE,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAA6B,IAAI;AAC7E,QAAM,UAAU,MAAM;AAClB,QAAI,YAAa,gBAAe,SAAS,eAAe,eAAe,CAAC;AAAA,EAC5E,GAAG,CAAC,WAAW,CAAC;AAGhB,QAAM,UAAU,MAAM;AAClB,iBAAa,QAAQ,MAAM,CAAC,CAAC;AAC7B,WAAO,MAAM;AAAE,qBAAe,QAAQ,IAAI;AAAA,IAAG;AAAA,EACjD,GAAG,CAAC,QAAQ,MAAM,cAAc,cAAc,CAAC;AAG/C,QAAM,UAAU,MAAM;AAClB,QAAI,CAAC,eAAe,CAAC,QAAQ,IAAK;AAClC,QAAI,YAAY;AAChB,mBAAe,QAAQ,IAAI,SAAS,QAAQ,IAAI,MAAM,EACjD,KAAK,OAAK;AAAE,UAAI,CAAC,UAAW,WAAU,CAAC;AAAA,IAAG,CAAC,EAC3C,MAAM,MAAM;AAAA,IAAqD,CAAC;AACvE,WAAO,MAAM;AAAE,kBAAY;AAAA,IAAM;AAAA,EACrC,GAAG,CAAC,cAAa,aAAQ,QAAR,mBAAa,UAAS,aAAQ,QAAR,mBAAa,MAAM,CAAC;AAK3D,QAAM,UAAU,MAAM;AAClB,QAAI,CAAC,OAAO,CAAC,cAAc,CAAC,QAAQ,IAAK;AACzC,UAAM,MAAM,IAAI,UAAU,QAAQ;AAClC,QAAI,2BAAK,UAAU;AACf,UAAI,SAAS,CAAC,gBAAgB,QAAQ,IAAI,SAAS,QAAQ,IAAI,QAAQ,UAAU,CAAC,CAAC;AAAA,IACvF;AAAA,EACJ,GAAG,CAAC,KAAK,YAAY,WAAU,aAAQ,QAAR,mBAAa,UAAS,aAAQ,QAAR,mBAAa,MAAM,CAAC;AAEzE,MAAI,CAAC,SAAS;AACV,YAAQ,MAAM,6DAAwD,QAAQ,IAAI,GAAG;AACrF,WAAO;AAAA,EACX;AAEA,QAAM,cAAc,eAAe,OAAO,SAAS,KAAK,OAAO;AAE/D,SACI,iCACI;AAAA,wBAAC,UAAO,IAAI,UAAkD,MAAK,UAAS,OAAO,CAAC,OAAO,GAAG,UAAU,KACpG,8BAAC,SAAM,IAAI,SAAS,MAAK,UAAS,OAAO,EAAE,kBAAkB,KAAK,GAAG,KAD9C,GAAG,KAAK,IAAI,QAAQ,IAAI,SAEnD;AAAA,IACC,eAAe;AAAA,MACZ;AAAA,QAAC;AAAA;AAAA,UACG;AAAA,UACA,cAAc;AAAA,UACd,OAAO,QAAQ;AAAA,UACf,WAAW,QAAQ,MAAM,aAAa,QAAQ,IAAI,SAAS,QAAQ,IAAI,MAAM,IAAI;AAAA;AAAA,MACrF;AAAA,MACA;AAAA,IACJ;AAAA,KACJ;AAER,CAAC;AACD,gBAAgB,cAAc;AAKvB,MAAM,iBAAiB,MAAM;AAChC,QAAM,EAAE,SAAS,UAAU,YAAY,YAAY,IAAI,MAAM,WAAW,UAAU;AAClF,QAAM,EAAE,KAAK,gBAAgB,IAAI,SAAS;AAE1C,QAAM,EAAE,OAAO,aAAa,IAAI,MAAM,WAAW,eAAe;AAChE,QAAM,EAAE,cAAc,IAAI,aAAa;AAEvC,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAc,IAAI;AACpE,QAAM,CAAC,oBAAoB,qBAAqB,IAAI,MAAM,SAGtD,CAAC,CAAC;AAGN,QAAM,iBAAiB,MAAM,OAAiC,CAAC,CAAC;AAChE,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAAmB,CAAC,CAAC;AAErE,QAAM,mBAAmB,MAAM,YAAY,CAAC,aAAqB,aAAuB;AACpF,mBAAe,QAAQ,WAAW,IAAI;AACtC,qBAAiB,OAAO,OAAO,eAAe,OAAO,EAAE,KAAK,CAAC;AAAA,EACjE,GAAG,CAAC,CAAC;AAEL,QAAM,qBAAqB,MAAM,YAAY,CAAC,gBAAwB;AAClE,WAAO,eAAe,QAAQ,WAAW;AACzC,qBAAiB,OAAO,OAAO,eAAe,OAAO,EAAE,KAAK,CAAC;AAAA,EACjE,GAAG,CAAC,CAAC;AAGL,QAAM,UAAU,MAAM;AAClB,QAAI,CAAC,OAAO,CAAC,mBAAmB,cAAc,WAAW,EAAG;AAE5D,UAAM,iBAAiB,CAAC,MAAqB;AAhfrD;AAifY,YAAM,UAAU,IAAI,sBAAsB,EAAE,OAAO,EAAE,QAAQ,cAAc,CAAC;AAC5E,YAAM,sBAAsB,mCAAU;AAEtC,UAAI,CAAC,qBAAqB;AACtB,0BAAkB,IAAI;AACtB;AAAA,MACJ;AAEA,YAAM,MAAM,EAAE,OAAO;AACrB,YAAM,MAAM,EAAE,OAAO;AACrB,YAAM,cAAc,CAAC,KAAK,GAAG;AAC7B,YAAM,aAAa,oBAAoB,cAAc,CAAC;AACtD,YAAM,UAAQ,YAAO,QAAQ,UAAU,EAAE,KAAK,CAAC,CAAC,GAAG,MAAM,IAAI,YAAY,EAAE,SAAS,MAAM,CAAC,MAA7E,mBAAiF,OAAM;AAErG,UAAI,yBAAyB,WAAW;AACxC,UAAI,CAAC,0BAA0B,oBAAoB,OAAO;AACtD,cAAM,UAAU,oBAAoB,MAAM;AAC1C,cAAM,WAAW,CAAC,sBAAsB,aAAa,kBAAkB,YAAY,SAAS,SAAS,WAAW,cAAc,SAAS;AACvI,YAAI,gBAAgB;AACpB,mBAAW,UAAU,UAAU;AAC3B,cAAI,QAAQ,SAAS,MAAM,GAAG;AAC1B,4BAAgB,QAAQ,MAAM,GAAG,CAAC,OAAO,MAAM;AAC/C;AAAA,UACJ;AAAA,QACJ;AACA,YAAI,kBAAkB,WAAW,QAAQ,SAAS,GAAG,GAAG;AACpD,0BAAgB,QAAQ,MAAM,GAAG,QAAQ,YAAY,GAAG,CAAC;AAAA,QAC7D;AACA,iCAAyB;AAAA,MAC7B;AAEA,YAAM,YAAY,WAAW,YAAY,WAAW,MAAM,QAAQ,KAAK,IAAI,CAAC;AAC5E,0BAAoB,KAAK;AACzB,0BAAoB,aAAa,iCAAK,aAAL,EAAiB,aAAa,OAAO,aAAa,uBAAuB;AAC1G,wBAAkB,mBAAmB;AAAA,IACzC;AAEA,eAAW,WAAW,eAAe;AACjC,sBAAgB,SAAS,SAAS,sBAAsB,4BAA4B,cAAc;AAAA,IACtG;AAEA,WAAO,MAAM;AACT,iBAAW,WAAW,eAAe;AACjC,wBAAgB,WAAW,OAAO;AAAA,MACtC;AAAA,IACJ;AAAA,EACJ,GAAG,CAAC,KAAK,iBAAiB,aAAa,CAAC;AAGxC,QAAM,UAAU,MAAM;AAClB,QAAI,CAAC,IAAK;AAEV,UAAM,SAAS,IAAI,UAAU;AAE7B,UAAM,mBAAmB,MAAM;AAC3B,aAAO,MAAM,SAAS;AAAA,IAC1B;AAEA,QAAI,cAAc,WAAW,GAAG;AAC5B,uBAAiB;AACjB;AAAA,IACJ;AAEA,UAAM,kBAAkB,CAAC,MAAqB;AAC1C,YAAM,kBAAkB,IAAI,sBAAsB,EAAE,OAAO,EAAE,QAAQ,cAAc,CAAC;AACpF,aAAO,MAAM,SAAS,gBAAgB,SAAS,IAAI,YAAY;AAAA,IACnE;AAEA,UAAM,mBAAmB,MAAM;AAC3B,uBAAiB;AAAA,IACrB;AAEA,QAAI,GAAG,aAAa,eAAe;AACnC,QAAI,GAAG,cAAc,gBAAgB;AAErC,WAAO,MAAM;AACT,UAAI,IAAI,aAAa,eAAe;AACpC,UAAI,IAAI,cAAc,gBAAgB;AACtC,uBAAiB;AAAA,IACrB;AAAA,EACJ,GAAG,CAAC,KAAK,aAAa,CAAC;AAGvB,QAAM,UAAU,MAAM;AApkB1B;AAqkBQ,QAAI,CAAC,kBAAkB,GAAC,oBAAe,eAAf,mBAA2B,cAAa;AAC5D,4BAAsB,CAAC,CAAC;AACxB;AAAA,IACJ;AACA,UAAM,QACF;AAAA,MAAC;AAAA;AAAA,QACG,QAAO;AAAA,QACP,aAAa;AAAA,QACb,cAAc;AAAA,QACd,aAAa;AAAA,QACb,gBAAgB;AAAA,QAEhB,UAAU,eAAe,WAAW,YAAY,CAAC;AAAA,QACjD,WAAW,eAAe,WAAW,YAAY,CAAC;AAAA,QAElD;AAAA,UAAC;AAAA;AAAA,YACG,SAAS;AAAA,YACT,eAAe,MAAM,oBAAoB;AAAA;AAAA,QAC7C;AAAA;AAAA,MAPK,eAAe;AAAA,IAQxB;AAEJ,0BAAsB,CAAC,EAAE,IAAI,eAAe,IAAuB,MAAM,CAAC,CAAC;AAAA,EAC/E,GAAG,CAAC,cAAc,CAAC;AAEnB,WAAS,sBAAsB;AAC3B,gBAAY,EAAE,MAAM,uBAAuB,SAAS,EAAE,gBAAgB,KAAK,EAAE,CAAC;AAC9E,sBAAkB,IAAI;AAAA,EAC1B;AAGA,QAAM,iBAAiB,MAAM,QAAQ,MAAM;AACvC,QAAI,EAAC,+CAAe,QAAQ,QAAO,CAAC;AACpC,WAAO,CAAC,GAAG,aAAa,EAAE,KAAK,CAAC,GAAG,MAAG;AArmB9C;AAqmBkD,sBAAE,UAAF,YAAW,OAAM,OAAE,UAAF,YAAW;AAAA,KAAE;AAAA,EAC5E,GAAG,CAAC,aAAa,CAAC;AAElB,SACI,iCACK;AAAA,mBAAe,IAAI,CAAC,SAAS,UAAU;AACpC,UAAI,QAAQ,YAAY,MAAO,QAAO;AACtC,UAAI,kBAAkB,OAAO,EAAG,QAAO;AAEvC,UAAI,QAAQ,SAAS,SAAS,QAAQ,gBAAgB,OAAO;AACzD,eACI;AAAA,UAAC;AAAA;AAAA,YAEG;AAAA,YACA;AAAA,YACA,cAAc;AAAA,YACd,gBAAgB;AAAA;AAAA,UAJX,QAAQ;AAAA,QAKjB;AAAA,MAER;AAEA,UAAI,QAAQ,SAAS,SAAS,QAAQ,gBAAgB,OAAO;AACzD,eACI;AAAA,UAAC;AAAA;AAAA,YAEG;AAAA,YACA;AAAA,YACA,cAAc;AAAA,YACd,gBAAgB;AAAA;AAAA,UAJX,QAAQ;AAAA,QAKjB;AAAA,MAER;AAEA,aACI;AAAA,QAAC;AAAA;AAAA,UAEG;AAAA,UACA;AAAA,UACA,cAAc;AAAA,UACd,gBAAgB;AAAA;AAAA,QAJX,QAAQ;AAAA,MAKjB;AAAA,IAER,CAAC;AAAA,IAEA,mBAAmB,IAAI,CAAC,UACrB,oBAAC,MAAM,UAAN,EAA+B,gBAAM,SAAjB,MAAM,EAAiB,CAC/C;AAAA,KACL;AAER;","names":["_a"]}
@@ -1 +1 @@
1
- {"version":3,"file":"FilesSection.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,OAAO,EAAE,MAAM,IAAI,KAAK,EAAE,MAAM,uCAAuC,CAAA;AAqBvE,UAAU,iBAAiB;IACzB,KAAK,EAAE,KAAK,EAAE,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAU,EAAE,EAAE,iBAAiB,qBA6IhF"}
1
+ {"version":3,"file":"FilesSection.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,OAAO,EAAE,MAAM,IAAI,KAAK,EAAE,MAAM,uCAAuC,CAAA;AAoBvE,UAAU,iBAAiB;IACzB,KAAK,EAAE,KAAK,EAAE,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAU,EAAE,EAAE,iBAAiB,qBA6IhF"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.tsx"],"sourcesContent":["'use client'\r\n\r\nimport * as React from 'react'\r\nimport * as LR from 'lucide-react'\r\nimport { BuildingsContext, FilesContext, MenusContext } from '../../../../../../../../store'\r\nimport { CollapsibleSection } from '../../../../../../../ui/CollapsibleSection'\r\nimport ConfirmDialog from '../../../../../../../ConfirmDialog'\r\nimport { useTranslations } from 'next-intl'\r\nimport { useFileDeleteHandler, FileItemComponent, useFileActions, useFileUploadWithProgress } from '../../../../../../../ui/FilesManager'\r\nimport { DbFile as IFile } from '../../../../../../../../types/dbTypes'\r\nimport { useDeleteFile } from '../../../../../../../../hooks/files/files'\r\nimport { mutate } from 'swr'\r\nimport { LoadingSpinner } from '../../../../../../../ui/LoadingSpinner'\r\n\r\n// Audit Phase 1.C (F-19): hoist out of the JSX so the array reference is\r\n// stable across renders. Inline `options={['view','move','info','delete']}`\r\n// gets a new array identity on every render, defeating React.memo on\r\n// FileItemComponent.\r\nconst FILE_OPTIONS: import('../../../../../../../../types/global').FileAction[] = ['view', 'move', 'info', 'delete']\r\n\r\nconst shouldExcludeByTag = (tag?: string | null): boolean => {\r\n if (!tag) return false\r\n return tag === 'user' || tag === 'bim-file' || tag === 'fragment-file' || tag === 'bimModel'\r\n}\r\n\r\nconst shouldExcludeByType = (type?: string | null): boolean => {\r\n if (!type) return false\r\n return type === 'bim-file'\r\n}\r\n\r\ninterface FilesSectionProps {\r\n files: IFile[]\r\n query?: string\r\n}\r\n\r\nexport function FilesSection({ files: _filesProp, query = '' }: FilesSectionProps) {\r\n const t = useTranslations('FileSelection')\r\n\r\n const { state: buildingsState } = React.useContext(BuildingsContext)\r\n const { state: fileState, dispatch: fileDispatch } = React.useContext(FilesContext)\r\n const files = fileState.files.files\r\n const { mapFileIds } = fileState.files\r\n const { building } = buildingsState.buildings\r\n const buildingId = building?.id || -1\r\n\r\n const { deleteFile: deleteFileApi } = useDeleteFile(buildingId)\r\n\r\n // Wrap so the store is updated immediately alongside the API call\r\n const deleteFile = React.useCallback(async (fileId: number) => {\r\n fileDispatch({ type: 'REMOVE_FILE', payload: { id: fileId } })\r\n await deleteFileApi(fileId)\r\n }, [deleteFileApi, fileDispatch])\r\n\r\n const { handleDeleteFile } = useFileDeleteHandler({\r\n deleteFile,\r\n onDeleteSuccess: () => {},\r\n })\r\n\r\n const { handleAddFile, uploadState } = useFileUploadWithProgress({\r\n acceptedFileTypes: '*',\r\n onUploadSuccess: () => {\r\n console.log('File uploaded successfully')\r\n mutate(`/api/files`)\r\n },\r\n onUploadError: (error) => console.error('Error uploading file:', error),\r\n })\r\n\r\n const nonBimFiles = React.useMemo(() => {\r\n return files\r\n .filter(file => file.extension !== 'ifc' && file.extension !== 'frag')\r\n .filter(file => !shouldExcludeByTag(file.tag))\r\n .filter(file => !shouldExcludeByType((file as any).type))\r\n .map(file => ({ ...file, isVisible: mapFileIds.includes(file.id) }))\r\n .sort((a, b) => {\r\n const aOnMap = mapFileIds.includes(a.id)\r\n const bOnMap = mapFileIds.includes(b.id)\r\n if (aOnMap !== bOnMap) return aOnMap ? -1 : 1\r\n return a.name.localeCompare(b.name)\r\n })\r\n }, [files, mapFileIds])\r\n\r\n const [localFiles, setLocalFiles] = React.useState(nonBimFiles)\r\n\r\n React.useEffect(() => {\r\n setLocalFiles(nonBimFiles)\r\n }, [nonBimFiles])\r\n\r\n const handleMoveFile = React.useCallback((file: IFile) => {\r\n fileDispatch({ type: 'EDIT_FILE', payload: { file } })\r\n }, [fileDispatch])\r\n\r\n // Audit Phase 1.C (F-19b): useCallback so the onView prop identity stays\r\n // stable across renders. Otherwise useFileActions' internal useCallback\r\n // dep on onView re-fires every render, producing a new handleAction\r\n // identity, which defeats React.memo on FileItemComponent.\r\n const handleViewFile = React.useCallback((file: IFile, newVisibility: boolean) => {\r\n fileDispatch({\r\n type: newVisibility ? 'ADD_TO_MAP' : 'REMOVE_FROM_MAP',\r\n payload: { id: file.id },\r\n })\r\n }, [fileDispatch])\r\n\r\n const { handleAction, deleteDialog } = useFileActions({\r\n files: localFiles,\r\n setFiles: setLocalFiles,\r\n buildingId,\r\n handleDeleteFile,\r\n onView: handleViewFile,\r\n onMove: handleMoveFile,\r\n })\r\n\r\n const areAllMapFilesHidden = React.useMemo(\r\n () => nonBimFiles.every(file => !mapFileIds.includes(file.id)),\r\n [nonBimFiles, mapFileIds]\r\n )\r\n\r\n const filteredFiles = React.useMemo(() => {\r\n if (!query.trim()) return nonBimFiles\r\n return nonBimFiles.filter(file =>\r\n file.name.toLowerCase().includes(query.toLowerCase())\r\n )\r\n }, [nonBimFiles, query])\r\n\r\n const handleSwitchVariant = () => ({\r\n checked: !areAllMapFilesHidden,\r\n onCheckedChange: (checked: boolean) => {\r\n if (checked) {\r\n fileDispatch({ type: 'ADD_ALL_TO_MAP', payload: { ids: nonBimFiles.map(f => f.id) } })\r\n }\r\n else {\r\n fileDispatch({ type: 'REMOVE_ALL_FROM_MAP' } as never)\r\n }\r\n },\r\n })\r\n\r\n return (\r\n <div className=\"h-full min-h-0\">\r\n <CollapsibleSection\r\n title={t('filesTitle')}\r\n icon={LR.FileText}\r\n className=\"h-full min-h-0 flex flex-col\"\r\n style={{ height: '100%', minHeight: 0 }}\r\n itemCount={filteredFiles.length}\r\n onAddItem={uploadState.uploading ? undefined : handleAddFile}\r\n addItemTitle={uploadState.uploading ? `${t('uploadingFile')} ${uploadState.progress}%` : t('addFileTitle')}\r\n switchVariant={handleSwitchVariant()}\r\n >\r\n <div className=\"flex-1 min-h-0 overflow-y-auto space-y-1\">\r\n {uploadState.uploading && (\r\n <div className=\"flex items-center gap-2 px-2 py-2 text-sm text-muted-foreground\">\r\n <LoadingSpinner className=\"h-4 w-4\" />\r\n <span>{t('uploadingFile')} {uploadState.progress}%</span>\r\n </div>\r\n )}\r\n {filteredFiles.map((item) => (\r\n <FileItemComponent\r\n key={item.id}\r\n file={item}\r\n onAction={handleAction}\r\n options={FILE_OPTIONS}\r\n translationKey=\"FileSelection\"\r\n confirmDelete={false}\r\n />\r\n ))}\r\n </div>\r\n </CollapsibleSection>\r\n\r\n <ConfirmDialog\r\n isOpen={deleteDialog.isOpen}\r\n isDeleting={deleteDialog.isDeleting}\r\n onOpenChange={deleteDialog.onOpenChange}\r\n handleConfirm={deleteDialog.onConfirm}\r\n itemName={deleteDialog.itemName}\r\n />\r\n </div>\r\n )\r\n}\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.tsx"],"sourcesContent":["'use client'\r\n\r\nimport * as React from 'react'\r\nimport * as LR from 'lucide-react'\r\nimport { BuildingsContext, FilesContext, MenusContext } from '../../../../../../../../store'\r\nimport { CollapsibleSection } from '../../../../../../../ui/CollapsibleSection'\r\nimport ConfirmDialog from '../../../../../../../ConfirmDialog'\r\nimport { useTranslations } from 'next-intl'\r\nimport { useFileDeleteHandler, FileItemComponent, useFileActions, useFileUploadWithProgress } from '../../../../../../../ui/FilesManager'\r\nimport { DbFile as IFile } from '../../../../../../../../types/dbTypes'\r\nimport { useDeleteFile } from '../../../../../../../../hooks/files/files'\r\nimport { mutate } from 'swr'\r\nimport { LoadingSpinner } from '../../../../../../../ui/LoadingSpinner'\r\n\r\n// Hoisted out of the JSX so the array reference is stable across renders.\r\n// Inline `options={['view','move','info','delete']}` gets a new array identity\r\n// on every render, defeating React.memo on FileItemComponent.\r\nconst FILE_OPTIONS: import('../../../../../../../../types/global').FileAction[] = ['view', 'move', 'info', 'delete']\r\n\r\nconst shouldExcludeByTag = (tag?: string | null): boolean => {\r\n if (!tag) return false\r\n return tag === 'user' || tag === 'bim-file' || tag === 'fragment-file' || tag === 'bimModel'\r\n}\r\n\r\nconst shouldExcludeByType = (type?: string | null): boolean => {\r\n if (!type) return false\r\n return type === 'bim-file'\r\n}\r\n\r\ninterface FilesSectionProps {\r\n files: IFile[]\r\n query?: string\r\n}\r\n\r\nexport function FilesSection({ files: _filesProp, query = '' }: FilesSectionProps) {\r\n const t = useTranslations('FileSelection')\r\n\r\n const { state: buildingsState } = React.useContext(BuildingsContext)\r\n const { state: fileState, dispatch: fileDispatch } = React.useContext(FilesContext)\r\n const files = fileState.files.files\r\n const { mapFileIds } = fileState.files\r\n const { building } = buildingsState.buildings\r\n const buildingId = building?.id || -1\r\n\r\n const { deleteFile: deleteFileApi } = useDeleteFile(buildingId)\r\n\r\n // Wrap so the store is updated immediately alongside the API call\r\n const deleteFile = React.useCallback(async (fileId: number) => {\r\n fileDispatch({ type: 'REMOVE_FILE', payload: { id: fileId } })\r\n await deleteFileApi(fileId)\r\n }, [deleteFileApi, fileDispatch])\r\n\r\n const { handleDeleteFile } = useFileDeleteHandler({\r\n deleteFile,\r\n onDeleteSuccess: () => {},\r\n })\r\n\r\n const { handleAddFile, uploadState } = useFileUploadWithProgress({\r\n acceptedFileTypes: '*',\r\n onUploadSuccess: () => {\r\n console.log('File uploaded successfully')\r\n mutate(`/api/files`)\r\n },\r\n onUploadError: (error) => console.error('Error uploading file:', error),\r\n })\r\n\r\n const nonBimFiles = React.useMemo(() => {\r\n return files\r\n .filter(file => file.extension !== 'ifc' && file.extension !== 'frag')\r\n .filter(file => !shouldExcludeByTag(file.tag))\r\n .filter(file => !shouldExcludeByType((file as any).type))\r\n .map(file => ({ ...file, isVisible: mapFileIds.includes(file.id) }))\r\n .sort((a, b) => {\r\n const aOnMap = mapFileIds.includes(a.id)\r\n const bOnMap = mapFileIds.includes(b.id)\r\n if (aOnMap !== bOnMap) return aOnMap ? -1 : 1\r\n return a.name.localeCompare(b.name)\r\n })\r\n }, [files, mapFileIds])\r\n\r\n const [localFiles, setLocalFiles] = React.useState(nonBimFiles)\r\n\r\n React.useEffect(() => {\r\n setLocalFiles(nonBimFiles)\r\n }, [nonBimFiles])\r\n\r\n const handleMoveFile = React.useCallback((file: IFile) => {\r\n fileDispatch({ type: 'EDIT_FILE', payload: { file } })\r\n }, [fileDispatch])\r\n\r\n // useCallback so the onView prop identity stays stable across renders.\r\n // Otherwise useFileActions' internal useCallback dep on onView re-fires every\r\n // render, producing a new handleAction identity, which defeats React.memo on\r\n // FileItemComponent.\r\n const handleViewFile = React.useCallback((file: IFile, newVisibility: boolean) => {\r\n fileDispatch({\r\n type: newVisibility ? 'ADD_TO_MAP' : 'REMOVE_FROM_MAP',\r\n payload: { id: file.id },\r\n })\r\n }, [fileDispatch])\r\n\r\n const { handleAction, deleteDialog } = useFileActions({\r\n files: localFiles,\r\n setFiles: setLocalFiles,\r\n buildingId,\r\n handleDeleteFile,\r\n onView: handleViewFile,\r\n onMove: handleMoveFile,\r\n })\r\n\r\n const areAllMapFilesHidden = React.useMemo(\r\n () => nonBimFiles.every(file => !mapFileIds.includes(file.id)),\r\n [nonBimFiles, mapFileIds]\r\n )\r\n\r\n const filteredFiles = React.useMemo(() => {\r\n if (!query.trim()) return nonBimFiles\r\n return nonBimFiles.filter(file =>\r\n file.name.toLowerCase().includes(query.toLowerCase())\r\n )\r\n }, [nonBimFiles, query])\r\n\r\n const handleSwitchVariant = () => ({\r\n checked: !areAllMapFilesHidden,\r\n onCheckedChange: (checked: boolean) => {\r\n if (checked) {\r\n fileDispatch({ type: 'ADD_ALL_TO_MAP', payload: { ids: nonBimFiles.map(f => f.id) } })\r\n }\r\n else {\r\n fileDispatch({ type: 'REMOVE_ALL_FROM_MAP' } as never)\r\n }\r\n },\r\n })\r\n\r\n return (\r\n <div className=\"h-full min-h-0\">\r\n <CollapsibleSection\r\n title={t('filesTitle')}\r\n icon={LR.FileText}\r\n className=\"h-full min-h-0 flex flex-col\"\r\n style={{ height: '100%', minHeight: 0 }}\r\n itemCount={filteredFiles.length}\r\n onAddItem={uploadState.uploading ? undefined : handleAddFile}\r\n addItemTitle={uploadState.uploading ? `${t('uploadingFile')} ${uploadState.progress}%` : t('addFileTitle')}\r\n switchVariant={handleSwitchVariant()}\r\n >\r\n <div className=\"flex-1 min-h-0 overflow-y-auto space-y-1\">\r\n {uploadState.uploading && (\r\n <div className=\"flex items-center gap-2 px-2 py-2 text-sm text-muted-foreground\">\r\n <LoadingSpinner className=\"h-4 w-4\" />\r\n <span>{t('uploadingFile')} {uploadState.progress}%</span>\r\n </div>\r\n )}\r\n {filteredFiles.map((item) => (\r\n <FileItemComponent\r\n key={item.id}\r\n file={item}\r\n onAction={handleAction}\r\n options={FILE_OPTIONS}\r\n translationKey=\"FileSelection\"\r\n confirmDelete={false}\r\n />\r\n ))}\r\n </div>\r\n </CollapsibleSection>\r\n\r\n <ConfirmDialog\r\n isOpen={deleteDialog.isOpen}\r\n isDeleting={deleteDialog.isDeleting}\r\n onOpenChange={deleteDialog.onOpenChange}\r\n handleConfirm={deleteDialog.onConfirm}\r\n itemName={deleteDialog.itemName}\r\n />\r\n </div>\r\n )\r\n}\r\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"ModelsSection.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B,OAAO,KAAK,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,uCAAuC,CAAA;AAW7E,UAAU,kBAAkB;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,KAAU,EAAE,EAAE,kBAAkB,qBAuLtE"}
1
+ {"version":3,"file":"ModelsSection.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B,OAAO,KAAK,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,uCAAuC,CAAA;AAS7E,UAAU,kBAAkB;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,KAAU,EAAE,EAAE,kBAAkB,qBAoLtE"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.tsx"],"sourcesContent":["'use client'\r\n\r\nimport * as React from 'react'\r\nimport { useTranslations } from 'next-intl'\r\nimport ConfirmDialog from '../../../../../../../ConfirmDialog'\r\nimport * as LR from 'lucide-react'\r\nimport { BimContext, BuildingsContext } from '../../../../../../../../store'\r\nimport { CollapsibleSection } from '../../../../../../../ui/CollapsibleSection'\r\nimport { useDeleteFile } from '../../../../../../../../hooks/files/files'\r\nimport { useFileDeleteHandler, FileItemComponent, useFileActions, useFileUploadWithProgress } from '../../../../../../../ui/FilesManager'\r\nimport type { DbFile as DbFile } from '../../../../../../../../types/dbTypes'\r\nimport { mutate } from 'swr'\r\nimport { LoadingSpinner } from '../../../../../../../ui/LoadingSpinner'\r\nimport { toggleBimToMap as dispatchToggleBimToMap } from '../../../../../utils/toggleBimToMap'\r\n\r\n// Audit Phase 1.C (F-19): hoist options arrays so React.memo on\r\n// FileItemComponent isn't defeated by per-render array identity churn.\r\ntype FileAction = import('../../../../../../../../types/global').FileAction\r\nconst OPTIONS_ON_MAP: FileAction[] = ['download', 'view', 'move', 'info', 'delete']\r\nconst OPTIONS_OFF_MAP: FileAction[] = ['download', 'view', 'info', 'delete']\r\n\r\ninterface ModelsSectionProps {\r\n files: DbFile[]\r\n query?: string\r\n}\r\n\r\nexport function ModelsSection({ files, query = '' }: ModelsSectionProps) {\r\n // Translation\r\n const t = useTranslations('FileItemComponent')\r\n\r\n // Get Map context for models added to map\r\n const { state: bimState, dispatch: bimDispatch } = React.useContext(BimContext)\r\n const { bimModelsAddedToMap } = bimState.bim\r\n\r\n const { state: buildingsState } = React.useContext(BuildingsContext)\r\n const { buildings, building: currentBuilding } = buildingsState.buildings\r\n\r\n const { deleteFile } = useDeleteFile()\r\n\r\n // Use the reusable delete handler\r\n const { handleDeleteFile } = useFileDeleteHandler({\r\n deleteFile,\r\n onDeleteSuccess: () => {\r\n console.log('Model file deleted successfully')\r\n },\r\n })\r\n\r\n // Use the new upload hook with progress\r\n const { handleAddFile, uploadState } = useFileUploadWithProgress({\r\n acceptedFileTypes: '.ifc,.frag',\r\n onUploadSuccess: () => {\r\n console.log('Model uploaded successfully')\r\n mutate(`/api/files`)\r\n },\r\n onUploadError: (error) => {\r\n console.error('Error uploading model:', error)\r\n }\r\n })\r\n\r\n // Filter and sort models: BIM files only, with models added to map at the top\r\n const sortedModels = React.useMemo(() => {\r\n const bimFiles = files.filter(file => file.extension === 'frag')\r\n \r\n return bimFiles\r\n .map(file => {\r\n const isAddedToMap = bimModelsAddedToMap.some(model => model.bimFile.id === file.id)\r\n // F-19: bake isVisible in here so the JSX below doesn't have to\r\n // spread `{...file, isVisible: ...}` (which would create a new\r\n // identity per render and defeat React.memo on FileItemComponent).\r\n return { ...file, isAddedToMap, isVisible: isAddedToMap }\r\n })\r\n .sort((a, b) => {\r\n // Models added to map come first\r\n if (a.isAddedToMap && !b.isAddedToMap) return -1\r\n if (!a.isAddedToMap && b.isAddedToMap) return 1\r\n return 0\r\n })\r\n }, [files, bimModelsAddedToMap])\r\n\r\n // Local state for file management\r\n const [loadedModels, setLoadedModels] = React.useState(sortedModels)\r\n\r\n // Keep local list in sync with sorted models\r\n React.useEffect(() => {\r\n setLoadedModels(sortedModels)\r\n }, [sortedModels])\r\n\r\n const handleToggleModelOnMap = React.useCallback((file: DbFile, isVisible: boolean) => {\r\n if (isVisible) {\r\n // Add model to map — reuse the same payload shape as the building popover\r\n const building = buildings.find(b => b.id === file.attachedFilesBuildingId) ?? currentBuilding ?? null\r\n dispatchToggleBimToMap(bimDispatch, file, building)\r\n } else {\r\n // Remove model from map\r\n bimDispatch({\r\n type: 'REMOVE_BIM_FROM_MAP',\r\n payload: { bimModelName: file.name },\r\n })\r\n }\r\n }, [bimDispatch, buildings])\r\n\r\n const handleMoveModel = React.useCallback((file: DbFile) => {\r\n const isOnMap = bimModelsAddedToMap.some(m => m.bimFile.id === file.id)\r\n if (!isOnMap) return\r\n bimDispatch({\r\n type: 'EDIT_BIM_MODEL_BY_NAME',\r\n payload: { editingBimModel: file.name },\r\n })\r\n }, [bimDispatch, bimModelsAddedToMap])\r\n\r\n const resolveBuildingForFile = React.useCallback(async (file: DbFile) => {\r\n const attachedBuildingId = file.attachedFilesBuildingId\r\n\r\n if (attachedBuildingId == null) {\r\n return currentBuilding ?? null\r\n }\r\n\r\n const cachedBuilding = buildings.find(building => building.id === attachedBuildingId) ?? null\r\n if (cachedBuilding?.buildingOsmId != null) {\r\n return cachedBuilding\r\n }\r\n\r\n try {\r\n const response = await fetch(`/api/buildings/${attachedBuildingId}`)\r\n if (!response.ok) {\r\n return cachedBuilding ?? currentBuilding ?? null\r\n }\r\n\r\n const data = await response.json() as { building?: typeof cachedBuilding }\r\n return data.building ?? cachedBuilding ?? currentBuilding ?? null\r\n }\r\n catch {\r\n return cachedBuilding ?? currentBuilding ?? null\r\n }\r\n }, [buildings, currentBuilding])\r\n\r\n const handleToggleModelOnMapAsync = React.useCallback(async (file: DbFile, isVisible: boolean) => {\r\n if (!isVisible) {\r\n bimDispatch({\r\n type: 'REMOVE_BIM_FROM_MAP',\r\n payload: { bimModelName: file.name },\r\n })\r\n return\r\n }\r\n\r\n const building = await resolveBuildingForFile(file)\r\n dispatchToggleBimToMap(bimDispatch, file, building)\r\n }, [bimDispatch, resolveBuildingForFile])\r\n\r\n // Use the common file actions hook\r\n const { handleAction, deleteDialog } = useFileActions({\r\n files: loadedModels,\r\n setFiles: setLoadedModels,\r\n buildingId: null,\r\n handleDeleteFile,\r\n onView: handleToggleModelOnMapAsync,\r\n onMove: handleMoveModel,\r\n })\r\n\r\n // Filter models based on search query — use sortedModels directly so the\r\n // sidebar always reflects the current BimContext state without waiting for\r\n // the loadedModels sync effect (which lags one render behind).\r\n const filteredModels = React.useMemo(() => {\r\n if (!query.trim()) return sortedModels\r\n return sortedModels.filter(file =>\r\n file.name.toLowerCase().includes(query.toLowerCase())\r\n )\r\n }, [sortedModels, query])\r\n\r\n return (\r\n <div className=\"h-full min-h-0\">\r\n <CollapsibleSection\r\n title={t('modelsTitles')}\r\n icon={LR.Box}\r\n className=\"h-full min-h-0 flex flex-col\"\r\n style={{ height: '100%', minHeight: 0 }}\r\n itemCount={filteredModels.length}\r\n onAddItem={uploadState.uploading ? undefined : handleAddFile}\r\n addItemTitle={uploadState.uploading ? `${t('uploadingFile')} ${uploadState.progress}%` : t('addBimTitle')}\r\n >\r\n <div className=\"flex-1 min-h-0 overflow-y-scroll space-y-1\">\r\n {uploadState.uploading && (\r\n <div className=\"flex items-center gap-2 px-2 py-2 text-sm text-muted-foreground\">\r\n <LoadingSpinner className=\"h-4 w-4\" />\r\n <span>{t('uploadingFile')} {uploadState.progress}%</span>\r\n </div>\r\n )}\r\n {filteredModels.map((file) => (\r\n <div key={file.id}>\r\n <FileItemComponent\r\n file={file}\r\n onAction={handleAction}\r\n options={file.isAddedToMap ? OPTIONS_ON_MAP : OPTIONS_OFF_MAP}\r\n confirmDelete={false}\r\n />\r\n </div>\r\n ))}\r\n </div>\r\n </CollapsibleSection>\r\n\r\n <ConfirmDialog\r\n isOpen={deleteDialog.isOpen}\r\n isDeleting={deleteDialog.isDeleting}\r\n onOpenChange={deleteDialog.onOpenChange}\r\n handleConfirm={deleteDialog.onConfirm}\r\n itemName={deleteDialog.itemName}\r\n />\r\n </div>\r\n )\r\n}\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.tsx"],"sourcesContent":["'use client'\r\n\r\nimport * as React from 'react'\r\nimport { useTranslations } from 'next-intl'\r\nimport ConfirmDialog from '../../../../../../../ConfirmDialog'\r\nimport * as LR from 'lucide-react'\r\nimport { BimContext, BuildingsContext } from '../../../../../../../../store'\r\nimport { CollapsibleSection } from '../../../../../../../ui/CollapsibleSection'\r\nimport { useDeleteFile } from '../../../../../../../../hooks/files/files'\r\nimport { useFileDeleteHandler, FileItemComponent, useFileActions, useFileUploadWithProgress } from '../../../../../../../ui/FilesManager'\r\nimport type { DbFile as DbFile } from '../../../../../../../../types/dbTypes'\r\nimport { mutate } from 'swr'\r\nimport { LoadingSpinner } from '../../../../../../../ui/LoadingSpinner'\r\nimport { toggleBimToMap as dispatchToggleBimToMap } from '../../../../../utils/toggleBimToMap'\r\n\r\ntype FileAction = import('../../../../../../../../types/global').FileAction\r\nconst OPTIONS_ON_MAP: FileAction[] = ['download', 'view', 'move', 'info', 'delete']\r\nconst OPTIONS_OFF_MAP: FileAction[] = ['download', 'view', 'info', 'delete']\r\n\r\ninterface ModelsSectionProps {\r\n files: DbFile[]\r\n query?: string\r\n}\r\n\r\nexport function ModelsSection({ files, query = '' }: ModelsSectionProps) {\r\n // Translation\r\n const t = useTranslations('FileItemComponent')\r\n\r\n // Get Map context for models added to map\r\n const { state: bimState, dispatch: bimDispatch } = React.useContext(BimContext)\r\n const { bimModelsAddedToMap } = bimState.bim\r\n\r\n const { state: buildingsState } = React.useContext(BuildingsContext)\r\n const { buildings, building: currentBuilding } = buildingsState.buildings\r\n\r\n const { deleteFile } = useDeleteFile()\r\n\r\n // Use the reusable delete handler\r\n const { handleDeleteFile } = useFileDeleteHandler({\r\n deleteFile,\r\n onDeleteSuccess: () => {\r\n console.log('Model file deleted successfully')\r\n },\r\n })\r\n\r\n // Use the new upload hook with progress\r\n const { handleAddFile, uploadState } = useFileUploadWithProgress({\r\n acceptedFileTypes: '.ifc,.frag',\r\n onUploadSuccess: () => {\r\n console.log('Model uploaded successfully')\r\n mutate(`/api/files`)\r\n },\r\n onUploadError: (error) => {\r\n console.error('Error uploading model:', error)\r\n }\r\n })\r\n\r\n // Filter and sort models: BIM files only, with models added to map at the top\r\n const sortedModels = React.useMemo(() => {\r\n const bimFiles = files.filter(file => file.extension === 'frag')\r\n \r\n return bimFiles\r\n .map(file => {\r\n const isAddedToMap = bimModelsAddedToMap.some(model => model.bimFile.id === file.id)\r\n return { ...file, isAddedToMap, isVisible: isAddedToMap }\r\n })\r\n .sort((a, b) => {\r\n // Models added to map come first\r\n if (a.isAddedToMap && !b.isAddedToMap) return -1\r\n if (!a.isAddedToMap && b.isAddedToMap) return 1\r\n return 0\r\n })\r\n }, [files, bimModelsAddedToMap])\r\n\r\n // Local state for file management\r\n const [loadedModels, setLoadedModels] = React.useState(sortedModels)\r\n\r\n // Keep local list in sync with sorted models\r\n React.useEffect(() => {\r\n setLoadedModels(sortedModels)\r\n }, [sortedModels])\r\n\r\n const handleToggleModelOnMap = React.useCallback((file: DbFile, isVisible: boolean) => {\r\n if (isVisible) {\r\n // Add model to map — reuse the same payload shape as the building popover\r\n const building = buildings.find(b => b.id === file.attachedFilesBuildingId) ?? currentBuilding ?? null\r\n dispatchToggleBimToMap(bimDispatch, file, building)\r\n } else {\r\n // Remove model from map\r\n bimDispatch({\r\n type: 'REMOVE_BIM_FROM_MAP',\r\n payload: { bimModelName: file.name },\r\n })\r\n }\r\n }, [bimDispatch, buildings])\r\n\r\n const handleMoveModel = React.useCallback((file: DbFile) => {\r\n const isOnMap = bimModelsAddedToMap.some(m => m.bimFile.id === file.id)\r\n if (!isOnMap) return\r\n bimDispatch({\r\n type: 'EDIT_BIM_MODEL_BY_NAME',\r\n payload: { editingBimModel: file.name },\r\n })\r\n }, [bimDispatch, bimModelsAddedToMap])\r\n\r\n const resolveBuildingForFile = React.useCallback(async (file: DbFile) => {\r\n const attachedBuildingId = file.attachedFilesBuildingId\r\n\r\n if (attachedBuildingId == null) {\r\n return currentBuilding ?? null\r\n }\r\n\r\n const cachedBuilding = buildings.find(building => building.id === attachedBuildingId) ?? null\r\n if (cachedBuilding?.buildingOsmId != null) {\r\n return cachedBuilding\r\n }\r\n\r\n try {\r\n const response = await fetch(`/api/buildings/${attachedBuildingId}`)\r\n if (!response.ok) {\r\n return cachedBuilding ?? currentBuilding ?? null\r\n }\r\n\r\n const data = await response.json() as { building?: typeof cachedBuilding }\r\n return data.building ?? cachedBuilding ?? currentBuilding ?? null\r\n }\r\n catch {\r\n return cachedBuilding ?? currentBuilding ?? null\r\n }\r\n }, [buildings, currentBuilding])\r\n\r\n const handleToggleModelOnMapAsync = React.useCallback(async (file: DbFile, isVisible: boolean) => {\r\n if (!isVisible) {\r\n bimDispatch({\r\n type: 'REMOVE_BIM_FROM_MAP',\r\n payload: { bimModelName: file.name },\r\n })\r\n return\r\n }\r\n\r\n const building = await resolveBuildingForFile(file)\r\n dispatchToggleBimToMap(bimDispatch, file, building)\r\n }, [bimDispatch, resolveBuildingForFile])\r\n\r\n // Use the common file actions hook\r\n const { handleAction, deleteDialog } = useFileActions({\r\n files: loadedModels,\r\n setFiles: setLoadedModels,\r\n buildingId: null,\r\n handleDeleteFile,\r\n onView: handleToggleModelOnMapAsync,\r\n onMove: handleMoveModel,\r\n })\r\n\r\n // Filter models based on search query — use sortedModels directly so the\r\n // sidebar always reflects the current BimContext state without waiting for\r\n // the loadedModels sync effect (which lags one render behind).\r\n const filteredModels = React.useMemo(() => {\r\n if (!query.trim()) return sortedModels\r\n return sortedModels.filter(file =>\r\n file.name.toLowerCase().includes(query.toLowerCase())\r\n )\r\n }, [sortedModels, query])\r\n\r\n return (\r\n <div className=\"h-full min-h-0\">\r\n <CollapsibleSection\r\n title={t('modelsTitles')}\r\n icon={LR.Box}\r\n className=\"h-full min-h-0 flex flex-col\"\r\n style={{ height: '100%', minHeight: 0 }}\r\n itemCount={filteredModels.length}\r\n onAddItem={uploadState.uploading ? undefined : handleAddFile}\r\n addItemTitle={uploadState.uploading ? `${t('uploadingFile')} ${uploadState.progress}%` : t('addBimTitle')}\r\n >\r\n <div className=\"flex-1 min-h-0 overflow-y-scroll space-y-1\">\r\n {uploadState.uploading && (\r\n <div className=\"flex items-center gap-2 px-2 py-2 text-sm text-muted-foreground\">\r\n <LoadingSpinner className=\"h-4 w-4\" />\r\n <span>{t('uploadingFile')} {uploadState.progress}%</span>\r\n </div>\r\n )}\r\n {filteredModels.map((file) => (\r\n <div key={file.id}>\r\n <FileItemComponent\r\n file={file}\r\n onAction={handleAction}\r\n options={file.isAddedToMap ? OPTIONS_ON_MAP : OPTIONS_OFF_MAP}\r\n confirmDelete={false}\r\n />\r\n </div>\r\n ))}\r\n </div>\r\n </CollapsibleSection>\r\n\r\n <ConfirmDialog\r\n isOpen={deleteDialog.isOpen}\r\n isDeleting={deleteDialog.isDeleting}\r\n onOpenChange={deleteDialog.onOpenChange}\r\n handleConfirm={deleteDialog.onConfirm}\r\n itemName={deleteDialog.itemName}\r\n />\r\n </div>\r\n )\r\n}\r\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"TerrainLevel.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,wBAAgB,YAAY,sBA6H3B"}
1
+ {"version":3,"file":"TerrainLevel.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAW9B,wBAAgB,YAAY,sBAqI3B"}
@@ -5,6 +5,7 @@ import { useTranslations } from "next-intl";
5
5
  import * as LR from "lucide-react";
6
6
  import { Tabs, TabsList, TabsTrigger } from "../../../../../../../ui/Tabs";
7
7
  import { AppConfigContext, MapContext } from "../../../../../../../../store";
8
+ const MAPTILER_KEY = process.env.NEXT_PUBLIC_MAPTILER_KEY;
8
9
  function TerrainLevel() {
9
10
  var _a;
10
11
  const tMap = useTranslations("MapCustomization");
@@ -18,17 +19,22 @@ function TerrainLevel() {
18
19
  mapDispatch({ type: "UPDATE_TERRAIN_LEVEL", payload: { terrainLevel: "medium" } });
19
20
  }
20
21
  }, [isCanadaOrg, terrainLevel, mapDispatch]);
22
+ React.useEffect(() => {
23
+ if (!MAPTILER_KEY && terrainLevel === "medium") {
24
+ mapDispatch({ type: "UPDATE_TERRAIN_LEVEL", payload: { terrainLevel: "disabled" } });
25
+ }
26
+ }, [terrainLevel, mapDispatch]);
21
27
  React.useEffect(() => {
22
28
  if (!map) return;
23
29
  const updateTerrain = () => {
24
30
  if (terrainLevel === "disabled") {
25
31
  map.setTerrain(null);
26
- } else if (terrainLevel === "medium") {
32
+ } else if (terrainLevel === "medium" && MAPTILER_KEY) {
27
33
  const terrainSourceExists = map.getSource("terrain-source");
28
34
  if (!terrainSourceExists) {
29
35
  map.addSource("terrain-source", {
30
36
  type: "raster-dem",
31
- url: "https://api.maptiler.com/tiles/terrain-rgb-v2/tiles.json?key=VwEIy1NDSOiSGeTOXMr1",
37
+ url: `https://api.maptiler.com/tiles/terrain-rgb-v2/tiles.json?key=${MAPTILER_KEY}`,
32
38
  tileSize: 256
33
39
  });
34
40
  }
@@ -85,6 +91,7 @@ function TerrainLevel() {
85
91
  }, [map, terrainLevel, isCanadaOrg]);
86
92
  const handleTerrainLevel = (value) => {
87
93
  if (!isCanadaOrg && value === "high") return;
94
+ if (!MAPTILER_KEY && value === "medium") return;
88
95
  mapDispatch({ type: "UPDATE_TERRAIN_LEVEL", payload: { terrainLevel: value } });
89
96
  };
90
97
  return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
@@ -94,7 +101,7 @@ function TerrainLevel() {
94
101
  /* @__PURE__ */ jsx(LR.ArrowDownToLine, { className: "w-4 h-4 mr-2" }),
95
102
  tMap("disabled")
96
103
  ] }),
97
- /* @__PURE__ */ jsxs(TabsTrigger, { value: "medium", children: [
104
+ /* @__PURE__ */ jsxs(TabsTrigger, { value: "medium", disabled: !MAPTILER_KEY, children: [
98
105
  /* @__PURE__ */ jsx(LR.Mountain, { className: "w-4 h-4 mr-2" }),
99
106
  tMap("medium")
100
107
  ] }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.tsx"],"sourcesContent":["'use client'\r\n\r\nimport * as React from 'react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as LR from 'lucide-react'\r\nimport { Tabs, TabsList, TabsTrigger } from '../../../../../../../ui/Tabs'\r\nimport { AppConfigContext, MapContext } from '../../../../../../../../store'\r\nimport { TerrainLevel as TerrainLevelType } from '../../../../../../../../types/map'\r\n\r\nexport function TerrainLevel() {\r\n const tMap = useTranslations('MapCustomization')\r\n const { state: appConfigState } = React.useContext(AppConfigContext)\r\n const { dispatch: mapDispatch, state: mapState } = React.useContext(MapContext)\r\n const { map, terrainLevel } = mapState.map\r\n const organizationCountry = (appConfigState.appConfig.organization?.country || '').toUpperCase()\r\n const isCanadaOrg = organizationCountry === 'CA'\r\n\r\n React.useEffect(() => {\r\n if (!isCanadaOrg && terrainLevel === 'high') {\r\n mapDispatch({ type: 'UPDATE_TERRAIN_LEVEL', payload: { terrainLevel: 'medium' } })\r\n }\r\n }, [isCanadaOrg, terrainLevel, mapDispatch])\r\n\r\n // Terrain control effect\r\n React.useEffect(() => {\r\n if (!map) return\r\n\r\n const updateTerrain = () => {\r\n if (terrainLevel === 'disabled') {\r\n // Disable terrain\r\n map.setTerrain(null)\r\n } else if (terrainLevel === 'medium') {\r\n // Check if terrain source already exists\r\n const terrainSourceExists = map.getSource('terrain-source')\r\n \r\n // Add terrain source if it doesn't exist\r\n if (!terrainSourceExists) {\r\n map.addSource('terrain-source', {\r\n type: 'raster-dem',\r\n url: 'https://api.maptiler.com/tiles/terrain-rgb-v2/tiles.json?key=VwEIy1NDSOiSGeTOXMr1',\r\n tileSize: 256,\r\n })\r\n }\r\n // Enable terrain with medium exaggeration\r\n map.setTerrain({\r\n source: 'terrain-source',\r\n exaggeration: 1,\r\n })\r\n } else if (terrainLevel === 'high' && isCanadaOrg) {\r\n // Check if NRCan terrain sources already exist\r\n const nrcanTerrainExists = map.getSource('hrdem-terrain')\r\n const nrcanHillshadeExists = map.getSource('hrdem-hillshade')\r\n \r\n // Add NRCan terrain source if it doesn't exist\r\n if (!nrcanTerrainExists) {\r\n map.addSource('hrdem-terrain', {\r\n type: 'raster-dem',\r\n tiles: [\r\n '/api/nrcan-hr-dem?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&FORMAT=image/png&TRANSPARENT=false&LAYERS=dtm&CRS=EPSG:3857&STYLES=&WIDTH=256&HEIGHT=256&BBOX={bbox-epsg-3857}'\r\n ],\r\n tileSize: 256,\r\n maxzoom: 15,\r\n attribution: 'Contains information licensed under the Open Government Licence – Canada',\r\n })\r\n }\r\n \r\n // Add NRCan hillshade source and layer if they don't exist\r\n if (!nrcanHillshadeExists) {\r\n map.addSource('hrdem-hillshade', {\r\n type: 'raster',\r\n tiles: [\r\n '/api/nrcan-hr-hillshade?request=GetCapabilities&service=WMS&version=1.3.0&layers=dsm-hillshade&legend_format=image&png&feature_info_type=text&xml'\r\n ],\r\n tileSize: 256,\r\n maxzoom: 15,\r\n attribution: 'Contains information licensed under the Open Government Licence – Canada',\r\n })\r\n \r\n // Add hillshade layer if it doesn't exist\r\n if (!map.getLayer('nrcan-hillshade')) {\r\n map.addLayer({\r\n id: 'nrcan-hillshade',\r\n type: 'raster',\r\n source: 'hrdem-hillshade',\r\n paint: {\r\n 'raster-opacity': 0.15,\r\n },\r\n })\r\n }\r\n }\r\n \r\n // Enable high-resolution terrain with lower exaggeration\r\n map.setTerrain({\r\n source: 'hrdem-terrain',\r\n exaggeration: 0.0002,\r\n })\r\n }\r\n }\r\n\r\n // Wait for map to be loaded before updating terrain\r\n if (map.loaded()) {\r\n updateTerrain()\r\n } else {\r\n map.once('load', updateTerrain)\r\n }\r\n }, [map, terrainLevel, isCanadaOrg])\r\n\r\n const handleTerrainLevel = (value: TerrainLevelType) => {\r\n if (!isCanadaOrg && value === 'high') return\r\n\r\n mapDispatch({ type: 'UPDATE_TERRAIN_LEVEL', payload: { terrainLevel: value } })\r\n }\r\n\r\n return (\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{tMap('terrain')}</label>\r\n <Tabs value={terrainLevel} onValueChange={handleTerrainLevel} variant=\"switch\">\r\n <TabsList className=\"grid w-full grid-cols-3\">\r\n <TabsTrigger value=\"disabled\">\r\n <LR.ArrowDownToLine className=\"w-4 h-4 mr-2\" />\r\n {tMap('disabled')}\r\n </TabsTrigger>\r\n <TabsTrigger value=\"medium\">\r\n <LR.Mountain className=\"w-4 h-4 mr-2\" />\r\n {tMap('medium')}\r\n </TabsTrigger>\r\n <TabsTrigger value=\"high\" disabled={!isCanadaOrg}>\r\n <LR.MountainSnow className=\"w-4 h-4 mr-2\" />\r\n {tMap('high')}\r\n </TabsTrigger>\r\n </TabsList>\r\n </Tabs>\r\n </div>\r\n )\r\n}\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.tsx"],"sourcesContent":["'use client'\r\n\r\nimport * as React from 'react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as LR from 'lucide-react'\r\nimport { Tabs, TabsList, TabsTrigger } from '../../../../../../../ui/Tabs'\r\nimport { AppConfigContext, MapContext } from '../../../../../../../../store'\r\nimport { TerrainLevel as TerrainLevelType } from '../../../../../../../../types/map'\r\n\r\n// Key is supplied by the consuming app via NEXT_PUBLIC_MAPTILER_KEY (Next inlines\r\n// it at build time). Kept out of source so @collabdt/core carries no secret.\r\nconst MAPTILER_KEY = process.env.NEXT_PUBLIC_MAPTILER_KEY\r\n\r\nexport function TerrainLevel() {\r\n const tMap = useTranslations('MapCustomization')\r\n const { state: appConfigState } = React.useContext(AppConfigContext)\r\n const { dispatch: mapDispatch, state: mapState } = React.useContext(MapContext)\r\n const { map, terrainLevel } = mapState.map\r\n const organizationCountry = (appConfigState.appConfig.organization?.country || '').toUpperCase()\r\n const isCanadaOrg = organizationCountry === 'CA'\r\n\r\n React.useEffect(() => {\r\n if (!isCanadaOrg && terrainLevel === 'high') {\r\n mapDispatch({ type: 'UPDATE_TERRAIN_LEVEL', payload: { terrainLevel: 'medium' } })\r\n }\r\n }, [isCanadaOrg, terrainLevel, mapDispatch])\r\n\r\n // Medium terrain relies on MapTiler; without a key, fall back to disabled.\r\n React.useEffect(() => {\r\n if (!MAPTILER_KEY && terrainLevel === 'medium') {\r\n mapDispatch({ type: 'UPDATE_TERRAIN_LEVEL', payload: { terrainLevel: 'disabled' } })\r\n }\r\n }, [terrainLevel, mapDispatch])\r\n\r\n // Terrain control effect\r\n React.useEffect(() => {\r\n if (!map) return\r\n\r\n const updateTerrain = () => {\r\n if (terrainLevel === 'disabled') {\r\n // Disable terrain\r\n map.setTerrain(null)\r\n } else if (terrainLevel === 'medium' && MAPTILER_KEY) {\r\n // Check if terrain source already exists\r\n const terrainSourceExists = map.getSource('terrain-source')\r\n\r\n // Add terrain source if it doesn't exist\r\n if (!terrainSourceExists) {\r\n map.addSource('terrain-source', {\r\n type: 'raster-dem',\r\n url: `https://api.maptiler.com/tiles/terrain-rgb-v2/tiles.json?key=${MAPTILER_KEY}`,\r\n tileSize: 256,\r\n })\r\n }\r\n // Enable terrain with medium exaggeration\r\n map.setTerrain({\r\n source: 'terrain-source',\r\n exaggeration: 1,\r\n })\r\n } else if (terrainLevel === 'high' && isCanadaOrg) {\r\n // Check if NRCan terrain sources already exist\r\n const nrcanTerrainExists = map.getSource('hrdem-terrain')\r\n const nrcanHillshadeExists = map.getSource('hrdem-hillshade')\r\n \r\n // Add NRCan terrain source if it doesn't exist\r\n if (!nrcanTerrainExists) {\r\n map.addSource('hrdem-terrain', {\r\n type: 'raster-dem',\r\n tiles: [\r\n '/api/nrcan-hr-dem?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&FORMAT=image/png&TRANSPARENT=false&LAYERS=dtm&CRS=EPSG:3857&STYLES=&WIDTH=256&HEIGHT=256&BBOX={bbox-epsg-3857}'\r\n ],\r\n tileSize: 256,\r\n maxzoom: 15,\r\n attribution: 'Contains information licensed under the Open Government Licence – Canada',\r\n })\r\n }\r\n \r\n // Add NRCan hillshade source and layer if they don't exist\r\n if (!nrcanHillshadeExists) {\r\n map.addSource('hrdem-hillshade', {\r\n type: 'raster',\r\n tiles: [\r\n '/api/nrcan-hr-hillshade?request=GetCapabilities&service=WMS&version=1.3.0&layers=dsm-hillshade&legend_format=image&png&feature_info_type=text&xml'\r\n ],\r\n tileSize: 256,\r\n maxzoom: 15,\r\n attribution: 'Contains information licensed under the Open Government Licence – Canada',\r\n })\r\n \r\n // Add hillshade layer if it doesn't exist\r\n if (!map.getLayer('nrcan-hillshade')) {\r\n map.addLayer({\r\n id: 'nrcan-hillshade',\r\n type: 'raster',\r\n source: 'hrdem-hillshade',\r\n paint: {\r\n 'raster-opacity': 0.15,\r\n },\r\n })\r\n }\r\n }\r\n \r\n // Enable high-resolution terrain with lower exaggeration\r\n map.setTerrain({\r\n source: 'hrdem-terrain',\r\n exaggeration: 0.0002,\r\n })\r\n }\r\n }\r\n\r\n // Wait for map to be loaded before updating terrain\r\n if (map.loaded()) {\r\n updateTerrain()\r\n } else {\r\n map.once('load', updateTerrain)\r\n }\r\n }, [map, terrainLevel, isCanadaOrg])\r\n\r\n const handleTerrainLevel = (value: TerrainLevelType) => {\r\n if (!isCanadaOrg && value === 'high') return\r\n if (!MAPTILER_KEY && value === 'medium') return\r\n\r\n mapDispatch({ type: 'UPDATE_TERRAIN_LEVEL', payload: { terrainLevel: value } })\r\n }\r\n\r\n return (\r\n <div className=\"space-y-2\">\r\n <label className=\"text-sm font-medium\">{tMap('terrain')}</label>\r\n <Tabs value={terrainLevel} onValueChange={handleTerrainLevel} variant=\"switch\">\r\n <TabsList className=\"grid w-full grid-cols-3\">\r\n <TabsTrigger value=\"disabled\">\r\n <LR.ArrowDownToLine className=\"w-4 h-4 mr-2\" />\r\n {tMap('disabled')}\r\n </TabsTrigger>\r\n <TabsTrigger value=\"medium\" disabled={!MAPTILER_KEY}>\r\n <LR.Mountain className=\"w-4 h-4 mr-2\" />\r\n {tMap('medium')}\r\n </TabsTrigger>\r\n <TabsTrigger value=\"high\" disabled={!isCanadaOrg}>\r\n <LR.MountainSnow className=\"w-4 h-4 mr-2\" />\r\n {tMap('high')}\r\n </TabsTrigger>\r\n </TabsList>\r\n </Tabs>\r\n </div>\r\n )\r\n}\r\n"],"mappings":"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","names":[]}
@@ -4,7 +4,9 @@ export declare const getMunicipalityAndProvince: (latitude: string, longitude: s
4
4
  municipality: any;
5
5
  countrySubdivision: any;
6
6
  }>;
7
- export declare const fetchSuggestions: (input: string, countryCode?: string) => Promise<any>;
7
+ export declare const fetchSuggestions: (input: string, countryCode?: string) => Promise<Feature<import("geojson").Geometry, {
8
+ [name: string]: any;
9
+ }>[]>;
8
10
  export declare const parseLocation: (feature: Feature) => {
9
11
  name: any;
10
12
  region: string;
@@ -44,7 +46,9 @@ export declare const handleLocationSelect: (feature: Feature, map: any, type: st
44
46
  confidence: any;
45
47
  match_type: any;
46
48
  };
47
- export declare const getDetailedAddress: (coordinates: [number, number], countryCode?: string) => Promise<any>;
49
+ export declare const getDetailedAddress: (coordinates: [number, number], countryCode?: string) => Promise<Feature<import("geojson").Geometry, {
50
+ [name: string]: any;
51
+ }>>;
48
52
  export declare const buildingToFeature: (building: any) => {
49
53
  properties: {
50
54
  name: any;
@@ -1 +1 @@
1
- {"version":3,"file":"geocoder.d.ts","sourceRoot":"","sources":["../../../../../../src/core/components/viewers/map/utils/geocoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAA6D,MAAM,SAAS,CAAA;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAgB/C,eAAO,MAAM,0BAA0B,GAAU,UAAU,MAAM,EAAE,WAAW,MAAM,EAAE,oBAAkB;;;EA0CvG,CAAA;AAGD,eAAO,MAAM,gBAAgB,GAAU,OAAO,MAAM,EAAE,oBAAkB,iBAiCvE,CAAA;AAGD,eAAO,MAAM,aAAa,GAAI,SAAS,OAAO;;;;CAoC7C,CAAA;AAGD,eAAO,MAAM,oBAAoB,GAAI,SAAS,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,MAAM,EAAE,UAAU;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqF7G,CAAA;AAGD,eAAO,MAAM,kBAAkB,GAAU,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,oBAAkB,iBAgCzF,CAAA;AAGD,eAAO,MAAM,iBAAiB,GAAI,aAAQ;;;;;;;;;;;;;;;CAgCzC,CAAA;AAGD,eAAO,MAAM,oBAAoB,GAAI,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,GAAG,EAAE,UAAU;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,kBAK5G,CAAA;AAGD,eAAO,MAAM,oBAAoB,QAAO,IAGvC,CAAA"}
1
+ {"version":3,"file":"geocoder.d.ts","sourceRoot":"","sources":["../../../../../../src/core/components/viewers/map/utils/geocoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAS,MAAM,SAAS,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAe/C,eAAO,MAAM,0BAA0B,GAAU,UAAU,MAAM,EAAE,WAAW,MAAM,EAAE,cAAc,MAAM;;;EAmBzG,CAAA;AAGD,eAAO,MAAM,gBAAgB,GAAU,OAAO,MAAM,EAAE,cAAc,MAAM;;KAYzE,CAAA;AAGD,eAAO,MAAM,aAAa,GAAI,SAAS,OAAO;;;;CAoC7C,CAAA;AAGD,eAAO,MAAM,oBAAoB,GAAI,SAAS,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,MAAM,EAAE,UAAU;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqF7G,CAAA;AAGD,eAAO,MAAM,kBAAkB,GAAU,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc,MAAM;;GAc3F,CAAA;AAGD,eAAO,MAAM,iBAAiB,GAAI,aAAQ;;;;;;;;;;;;;;;CAgCzC,CAAA;AAGD,eAAO,MAAM,oBAAoB,GAAI,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,GAAG,EAAE,UAAU;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,kBAK5G,CAAA;AAGD,eAAO,MAAM,oBAAoB,QAAO,IAGvC,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import { MarkerManager } from "./MarkerManager";
2
- const GEOCODE_EARTH_API_KEY = process.env.NEXT_PUBLIC_GEOCODE_EARTH_API_KEY;
2
+ import { autocompleteGeocode, reverseGeocode } from "./geocoding";
3
3
  let geocoderMarkerManager = null;
4
4
  const getGeocoderMarkerManager = () => {
5
5
  if (!geocoderMarkerManager) {
@@ -7,31 +7,11 @@ const getGeocoderMarkerManager = () => {
7
7
  }
8
8
  return geocoderMarkerManager;
9
9
  };
10
- const getMunicipalityAndProvince = async (latitude, longitude, countryCode = "CA") => {
11
- const params = new URLSearchParams({
12
- "api_key": GEOCODE_EARTH_API_KEY,
13
- "point.lat": latitude,
14
- "point.lon": longitude,
15
- "boundary.country": countryCode.toUpperCase(),
16
- "layers": "coarse",
17
- "size": "1"
18
- // Limit to 1 result
19
- });
20
- const reverseGeocoderUrl = `https://api.geocode.earth/v1/reverse?${params}`;
10
+ const getMunicipalityAndProvince = async (latitude, longitude, countryCode) => {
21
11
  try {
22
- const response = await fetch(reverseGeocoderUrl, {
23
- headers: {
24
- "User-Agent": "CDT/1.0 (cdt@email.com)"
25
- }
26
- });
27
- if (!response.ok) {
28
- throw new Error(`HTTP error! status: ${response.status}`);
29
- }
30
- const data = await response.json();
31
- console.log("Reverse geocoding response:", data);
32
- if (data.features && data.features.length > 0) {
33
- const feature = data.features[0];
34
- const properties = feature.properties;
12
+ const features = await reverseGeocode(latitude, longitude, countryCode, { size: 1, coarse: true });
13
+ if (features.length > 0) {
14
+ const properties = features[0].properties;
35
15
  const municipality = properties.locality || properties.neighbourhood || properties.county || "";
36
16
  const countrySubdivision = properties.region_a || properties.region || "";
37
17
  return { municipality, countrySubdivision };
@@ -42,29 +22,12 @@ const getMunicipalityAndProvince = async (latitude, longitude, countryCode = "CA
42
22
  return { municipality: "", countrySubdivision: "" };
43
23
  }
44
24
  };
45
- const fetchSuggestions = async (input, countryCode = "CA") => {
25
+ const fetchSuggestions = async (input, countryCode) => {
46
26
  if (!input || input.length < 3) {
47
27
  return [];
48
28
  }
49
29
  try {
50
- const params = new URLSearchParams({
51
- "api_key": GEOCODE_EARTH_API_KEY,
52
- "text": input,
53
- "boundary.country": countryCode.toUpperCase(),
54
- "size": "5"
55
- // Limit results
56
- });
57
- const request = `https://api.geocode.earth/v1/autocomplete?${params}`;
58
- const response = await fetch(request, {
59
- headers: {
60
- "User-Agent": "GIS-App/1.0"
61
- }
62
- });
63
- if (!response.ok) {
64
- throw new Error(`HTTP error! status: ${response.status}`);
65
- }
66
- const geojson = await response.json();
67
- return geojson.features && geojson.features.length > 0 ? geojson.features : [];
30
+ return await autocompleteGeocode(input, countryCode, 5);
68
31
  } catch (error) {
69
32
  console.error("Error fetching address suggestions:", error);
70
33
  return [];
@@ -173,26 +136,11 @@ const handleLocationSelect = (feature, map, type, options) => {
173
136
  }
174
137
  return addressData;
175
138
  };
176
- const getDetailedAddress = async (coordinates, countryCode = "CA") => {
139
+ const getDetailedAddress = async (coordinates, countryCode) => {
177
140
  const [longitude, latitude] = coordinates;
178
- const params = new URLSearchParams({
179
- "api_key": GEOCODE_EARTH_API_KEY,
180
- "point.lat": latitude.toString(),
181
- "point.lon": longitude.toString(),
182
- "boundary.country": countryCode.toUpperCase(),
183
- "size": "1"
184
- });
185
- const reverseGeocoderUrl = `https://api.geocode.earth/v1/reverse?${params}`;
186
141
  try {
187
- const response = await fetch(reverseGeocoderUrl);
188
- if (!response.ok) {
189
- throw new Error(`HTTP error! status: ${response.status}`);
190
- }
191
- const data = await response.json();
192
- if (data.features && data.features.length > 0) {
193
- return data.features[0];
194
- }
195
- return null;
142
+ const features = await reverseGeocode(latitude.toString(), longitude.toString(), countryCode, { size: 1, layers: "address" });
143
+ return features.length > 0 ? features[0] : null;
196
144
  } catch (error) {
197
145
  console.error("Error fetching detailed address:", error);
198
146
  return null;