@collabdt/core 0.3.1 → 0.3.3
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.
- package/dist/core/components/authentication/ForgotPassword.d.ts.map +1 -1
- package/dist/core/components/authentication/ForgotPassword.js +0 -1
- package/dist/core/components/authentication/ForgotPassword.js.map +1 -1
- package/dist/core/components/ui/Comments/CollapsibleCommentItem.d.ts +12 -2
- package/dist/core/components/ui/Comments/CollapsibleCommentItem.d.ts.map +1 -1
- package/dist/core/components/ui/Comments/CollapsibleCommentItem.js +137 -139
- package/dist/core/components/ui/Comments/CollapsibleCommentItem.js.map +1 -1
- package/dist/core/components/ui/Comments/Comment.d.ts +18 -1
- package/dist/core/components/ui/Comments/Comment.d.ts.map +1 -1
- package/dist/core/components/ui/Comments/Comment.js +94 -23
- package/dist/core/components/ui/Comments/Comment.js.map +1 -1
- package/dist/core/components/ui/Comments/CommentActionButtons.d.ts +38 -0
- package/dist/core/components/ui/Comments/CommentActionButtons.d.ts.map +1 -0
- package/dist/core/components/ui/Comments/CommentActionButtons.js +134 -0
- package/dist/core/components/ui/Comments/CommentActionButtons.js.map +1 -0
- package/dist/core/components/ui/Comments/CommentInput.d.ts.map +1 -1
- package/dist/core/components/ui/Comments/CommentInput.js +5 -2
- package/dist/core/components/ui/Comments/CommentInput.js.map +1 -1
- package/dist/core/components/ui/Comments/CommentsSection.d.ts.map +1 -1
- package/dist/core/components/ui/Comments/CommentsSection.js +86 -42
- package/dist/core/components/ui/Comments/CommentsSection.js.map +1 -1
- package/dist/core/components/ui/Comments/commentUtils.d.ts.map +1 -1
- package/dist/core/components/ui/Comments/commentUtils.js +2 -1
- package/dist/core/components/ui/Comments/commentUtils.js.map +1 -1
- package/dist/core/components/ui/FilesManager/src/useFileUploadWithProgress.d.ts.map +1 -1
- package/dist/core/components/ui/FilesManager/src/useFileUploadWithProgress.js +0 -1
- package/dist/core/components/ui/FilesManager/src/useFileUploadWithProgress.js.map +1 -1
- package/dist/core/components/ui/InfoSidebar/Container.d.ts.map +1 -1
- package/dist/core/components/ui/InfoSidebar/Container.js +16 -12
- package/dist/core/components/ui/InfoSidebar/Container.js.map +1 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts +1 -2
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js +66 -94
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js.map +1 -1
- package/dist/core/components/ui/Sensors/Sensor.d.ts +16 -3
- package/dist/core/components/ui/Sensors/Sensor.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/Sensor.js +76 -37
- package/dist/core/components/ui/Sensors/Sensor.js.map +1 -1
- package/dist/core/components/ui/Sensors/SensorChart.d.ts +12 -2
- package/dist/core/components/ui/Sensors/SensorChart.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/SensorChart.js +49 -12
- package/dist/core/components/ui/Sensors/SensorChart.js.map +1 -1
- package/dist/core/components/ui/Sensors/SensorDetailDialog.d.ts +9 -0
- package/dist/core/components/ui/Sensors/SensorDetailDialog.d.ts.map +1 -0
- package/dist/core/components/ui/Sensors/SensorDetailDialog.js +128 -0
- package/dist/core/components/ui/Sensors/SensorDetailDialog.js.map +1 -0
- package/dist/core/components/ui/Sensors/SensorInput.d.ts +6 -1
- package/dist/core/components/ui/Sensors/SensorInput.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/SensorInput.js +94 -9
- package/dist/core/components/ui/Sensors/SensorInput.js.map +1 -1
- package/dist/core/components/ui/Sensors/SensorTagsSection.d.ts +3 -1
- package/dist/core/components/ui/Sensors/SensorTagsSection.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/SensorTagsSection.js +4 -1
- package/dist/core/components/ui/Sensors/SensorTagsSection.js.map +1 -1
- package/dist/core/components/ui/Sensors/SensorsSection.d.ts +1 -3
- package/dist/core/components/ui/Sensors/SensorsSection.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/SensorsSection.js +33 -10
- package/dist/core/components/ui/Sensors/SensorsSection.js.map +1 -1
- package/dist/core/components/ui/Sensors/TimeZoneSelect.d.ts +7 -0
- package/dist/core/components/ui/Sensors/TimeZoneSelect.d.ts.map +1 -0
- package/dist/core/components/ui/Sensors/TimeZoneSelect.js +56 -0
- package/dist/core/components/ui/Sensors/TimeZoneSelect.js.map +1 -0
- package/dist/core/components/ui/Sensors/sensorData.d.ts +42 -0
- package/dist/core/components/ui/Sensors/sensorData.d.ts.map +1 -0
- package/dist/core/components/ui/Sensors/sensorData.js +118 -0
- package/dist/core/components/ui/Sensors/sensorData.js.map +1 -0
- package/dist/core/components/ui/Sensors/sensorRange.d.ts +24 -0
- package/dist/core/components/ui/Sensors/sensorRange.d.ts.map +1 -0
- package/dist/core/components/ui/Sensors/sensorRange.js +34 -0
- package/dist/core/components/ui/Sensors/sensorRange.js.map +1 -0
- package/dist/core/components/ui/Sensors/useSensorSeries.d.ts +15 -0
- package/dist/core/components/ui/Sensors/useSensorSeries.d.ts.map +1 -0
- package/dist/core/components/ui/Sensors/useSensorSeries.js +63 -0
- package/dist/core/components/ui/Sensors/useSensorSeries.js.map +1 -0
- package/dist/core/components/ui/Sidebar.d.ts.map +1 -1
- package/dist/core/components/ui/Sidebar.js +27 -4
- package/dist/core/components/ui/Sidebar.js.map +1 -1
- package/dist/core/components/ui/ToolbarButton.d.ts.map +1 -1
- package/dist/core/components/ui/ToolbarButton.js +0 -1
- package/dist/core/components/ui/ToolbarButton.js.map +1 -1
- package/dist/core/components/viewers/Data/advancedFilter/FiltersDialog.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/advancedFilter/FiltersDialog.js +0 -2
- package/dist/core/components/viewers/Data/advancedFilter/FiltersDialog.js.map +1 -1
- package/dist/core/components/viewers/Data/details/EnergySourcesGrid.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/details/EnergySourcesGrid.js +0 -10
- package/dist/core/components/viewers/Data/details/EnergySourcesGrid.js.map +1 -1
- package/dist/core/components/viewers/Data/files/DatatableFileAdder.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/files/DatatableFileAdder.js +0 -1
- package/dist/core/components/viewers/Data/files/DatatableFileAdder.js.map +1 -1
- package/dist/core/components/viewers/Data/files/utils/fuzzySearch.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/files/utils/fuzzySearch.js +0 -1
- package/dist/core/components/viewers/Data/files/utils/fuzzySearch.js.map +1 -1
- package/dist/core/components/viewers/Data/userDetails/UserMoreOptions.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/userDetails/UserMoreOptions.js +0 -1
- package/dist/core/components/viewers/Data/userDetails/UserMoreOptions.js.map +1 -1
- package/dist/core/components/viewers/Data/utils/filterHelper.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/utils/filterHelper.js +0 -2
- package/dist/core/components/viewers/Data/utils/filterHelper.js.map +1 -1
- package/dist/core/components/viewers/Viewer.js +1 -1
- package/dist/core/components/viewers/Viewer.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/CommunicationTab/src/TopicsSection.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/CommunicationTab/src/TopicsSection.js +0 -3
- package/dist/core/components/viewers/bim/src/BimSidebar/src/CommunicationTab/src/TopicsSection.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js +1 -7
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.js +1 -9
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.d.ts +1 -3
- package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.js +2 -2
- package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/TabSelector.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/TabSelector.js +4 -3
- package/dist/core/components/viewers/bim/src/BimSidebar/src/TabSelector.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/index.js +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/index.js.map +1 -1
- package/dist/core/components/viewers/bim/src/ClippingPlane.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/ClippingPlane.js +0 -1
- package/dist/core/components/viewers/bim/src/ClippingPlane.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/index.d.ts +1 -2
- package/dist/core/components/viewers/bim/src/tools/AddToBim/index.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js +25 -2
- package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimComment.d.ts +16 -10
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimComment.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimComment.js +26 -6
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimComment.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimCommentCluster.d.ts +2 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimCommentCluster.d.ts.map +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimCommentCluster.js +5 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimCommentCluster.js.map +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.d.ts +8 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.js +15 -3
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/clusterMarkersByScreenSpace.d.ts +44 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/clusterMarkersByScreenSpace.d.ts.map +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/clusterMarkersByScreenSpace.js +77 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/clusterMarkersByScreenSpace.js.map +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentCameraUtils.d.ts +3 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentCameraUtils.d.ts.map +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentCameraUtils.js +5 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentCameraUtils.js.map +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentMarkerConfig.d.ts +33 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentMarkerConfig.d.ts.map +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentMarkerConfig.js +90 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentMarkerConfig.js.map +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/renderCSS2DMarkers.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/renderCSS2DMarkers.js +2 -2
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/renderCSS2DMarkers.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useCommentMarkers.d.ts +7 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useCommentMarkers.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useCommentMarkers.js +50 -73
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useCommentMarkers.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.d.ts +7 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.js +39 -11
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/ClippingTool/ClippingTool.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/ClippingTool/ClippingTool.js +1 -5
- package/dist/core/components/viewers/bim/src/tools/ClippingTool/ClippingTool.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/ExplodeByLevelTool.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/ExplodeByLevelTool.js +0 -1
- package/dist/core/components/viewers/bim/src/tools/ExplodeByLevelTool.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/measureBimTool.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/measureBimTool.js +1 -2
- package/dist/core/components/viewers/bim/src/tools/measureBimTool.js.map +1 -1
- package/dist/core/components/viewers/map/MapViewer.d.ts +1 -2
- package/dist/core/components/viewers/map/MapViewer.d.ts.map +1 -1
- package/dist/core/components/viewers/map/MapViewer.js +2 -2
- package/dist/core/components/viewers/map/MapViewer.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/arcGISDatasets.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/arcGISDatasets.js +11 -14
- package/dist/core/components/viewers/map/datasets/src/arcGISDatasets.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/ckanDatasets.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/ckanDatasets.js +2 -5
- package/dist/core/components/viewers/map/datasets/src/ckanDatasets.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/localDatasets.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/localDatasets.js +0 -3
- package/dist/core/components/viewers/map/datasets/src/localDatasets.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/opendatasoftDatasets.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/opendatasoftDatasets.js +0 -11
- package/dist/core/components/viewers/map/datasets/src/opendatasoftDatasets.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/DatabaseBuildingPopover/src/BuildingsTools.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/DatabaseBuildingPopover/src/BuildingsTools.js +0 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/DatabaseBuildingPopover/src/BuildingsTools.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.js +0 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/OpenDataFeaturePopover.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/OpenDataFeaturePopover.js +0 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/OpenDataFeaturePopover.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/index.d.ts +1 -2
- package/dist/core/components/viewers/map/src/MapLayers/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/index.js +2 -2
- package/dist/core/components/viewers/map/src/MapLayers/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/CommentLayer/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/CommentLayer/index.js +174 -53
- package/dist/core/components/viewers/map/src/MapLayers/src/CommentLayer/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/components/MapFileManager.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/components/MapFileManager.js +2 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/components/MapFileManager.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.d.ts +1 -3
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.js +74 -42
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/TabSelector.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/TabSelector.js +4 -3
- package/dist/core/components/viewers/map/src/MapSidebar/TabSelector.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/index.js +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.js +0 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.js +1 -5
- package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.d.ts +1 -3
- package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.js +2 -2
- package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/tools/AddTools/AddFile/utils/uploadToPresignedURLS.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/tools/AddTools/AddFile/utils/uploadToPresignedURLS.js +1 -3
- package/dist/core/components/viewers/map/src/tools/AddTools/AddFile/utils/uploadToPresignedURLS.js.map +1 -1
- package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.d.ts.map +1 -1
- package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.js +0 -1
- package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.js.map +1 -1
- package/dist/core/components/viewers/map/utils/flyToEach.d.ts.map +1 -1
- package/dist/core/components/viewers/map/utils/flyToEach.js +0 -1
- package/dist/core/components/viewers/map/utils/flyToEach.js.map +1 -1
- package/dist/core/components/viewers/map/utils/getOsmIdbyCoordinates.d.ts.map +1 -1
- package/dist/core/components/viewers/map/utils/getOsmIdbyCoordinates.js +0 -2
- package/dist/core/components/viewers/map/utils/getOsmIdbyCoordinates.js.map +1 -1
- package/dist/core/components/viewers/shared/markers/BimMarkerCluster.d.ts +19 -0
- package/dist/core/components/viewers/shared/markers/BimMarkerCluster.d.ts.map +1 -0
- package/dist/core/components/viewers/shared/markers/BimMarkerCluster.js +108 -0
- package/dist/core/components/viewers/shared/markers/BimMarkerCluster.js.map +1 -0
- package/dist/core/components/viewers/shared/markers/computeMarkerLookAt.d.ts +24 -0
- package/dist/core/components/viewers/shared/markers/computeMarkerLookAt.d.ts.map +1 -0
- package/dist/core/components/viewers/shared/markers/computeMarkerLookAt.js +27 -0
- package/dist/core/components/viewers/shared/markers/computeMarkerLookAt.js.map +1 -0
- package/dist/core/components/viewers/shared/markers/types.d.ts +66 -0
- package/dist/core/components/viewers/shared/markers/types.d.ts.map +1 -0
- package/dist/core/components/viewers/shared/markers/types.js +1 -0
- package/dist/core/components/viewers/shared/markers/types.js.map +1 -0
- package/dist/core/components/viewers/shared/markers/useMarkerLayerBim.d.ts +22 -0
- package/dist/core/components/viewers/shared/markers/useMarkerLayerBim.d.ts.map +1 -0
- package/dist/core/components/viewers/shared/markers/useMarkerLayerBim.js +233 -0
- package/dist/core/components/viewers/shared/markers/useMarkerLayerBim.js.map +1 -0
- package/dist/core/hooks/comments/comments.d.ts +11 -0
- package/dist/core/hooks/comments/comments.d.ts.map +1 -1
- package/dist/core/hooks/comments/comments.js +3 -1
- package/dist/core/hooks/comments/comments.js.map +1 -1
- package/dist/core/hooks/comments/createCommentHooks.d.ts +11 -0
- package/dist/core/hooks/comments/createCommentHooks.d.ts.map +1 -1
- package/dist/core/hooks/comments/createCommentHooks.js +30 -1
- package/dist/core/hooks/comments/createCommentHooks.js.map +1 -1
- package/dist/core/hooks/files/files.d.ts.map +1 -1
- package/dist/core/hooks/files/files.js +0 -1
- package/dist/core/hooks/files/files.js.map +1 -1
- package/dist/core/hooks/ui/useResizableSidebarWidth.d.ts +30 -0
- package/dist/core/hooks/ui/useResizableSidebarWidth.d.ts.map +1 -0
- package/dist/core/hooks/ui/useResizableSidebarWidth.js +75 -0
- package/dist/core/hooks/ui/useResizableSidebarWidth.js.map +1 -0
- package/dist/core/i18n/messages/en.json +10 -1
- package/dist/core/i18n/messages/es.json +11 -2
- package/dist/core/i18n/messages/fr.json +11 -2
- package/dist/core/store/AppConfig/context.d.ts.map +1 -1
- package/dist/core/store/AppConfig/context.js +4 -1
- package/dist/core/store/AppConfig/context.js.map +1 -1
- package/dist/core/store/AppConfig/reducer.d.ts +10 -0
- package/dist/core/store/AppConfig/reducer.d.ts.map +1 -1
- package/dist/core/store/AppConfig/reducer.js +10 -0
- package/dist/core/store/AppConfig/reducer.js.map +1 -1
- package/dist/core/store/Datasets/reducer.d.ts.map +1 -1
- package/dist/core/store/Datasets/reducer.js +0 -2
- package/dist/core/store/Datasets/reducer.js.map +1 -1
- package/dist/core/store/Files/reducer.js +0 -1
- package/dist/core/store/Files/reducer.js.map +1 -1
- package/dist/core/store/Menus/context.d.ts.map +1 -1
- package/dist/core/store/Menus/context.js +8 -2
- package/dist/core/store/Menus/context.js.map +1 -1
- package/dist/core/store/Menus/reducer.d.ts +65 -1
- package/dist/core/store/Menus/reducer.d.ts.map +1 -1
- package/dist/core/store/Menus/reducer.js +39 -3
- package/dist/core/store/Menus/reducer.js.map +1 -1
- package/dist/core/utils/markerUtils.d.ts +10 -0
- package/dist/core/utils/markerUtils.d.ts.map +1 -1
- package/dist/core/utils/markerUtils.js +9 -1
- package/dist/core/utils/markerUtils.js.map +1 -1
- package/dist/core/utils/memcache.d.ts.map +1 -1
- package/dist/core/utils/memcache.js +0 -7
- package/dist/core/utils/memcache.js.map +1 -1
- package/dist/core/utils/timeUtils.d.ts +24 -1
- package/dist/core/utils/timeUtils.d.ts.map +1 -1
- package/dist/core/utils/timeUtils.js +52 -3
- package/dist/core/utils/timeUtils.js.map +1 -1
- package/package.json +4 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../src/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// Dependencies\r\nimport * as LR from 'lucide-react'\r\nimport { useSession } from 'next-auth/react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as React from 'react'\r\nimport { toast } from 'sonner'\r\n\r\nimport { useCreateBuilding, useBuildings, useBuilding } from '../../../../../../hooks/buildings/buildings'\r\nimport { usePermissions } from '../../../../../../store'\r\n\r\n// Shadcn Components\r\nimport { MapContext } from '../../../../../../store'\r\nimport { useMenusContext } from '../../../../../../store'\r\nimport { Button, Label } from '../../../../../ui/'\r\nimport { LoadingSpinner } from '../../../../../ui/LoadingSpinner'\r\nimport { PopoverContent } from '../../../../../ui/Popover'\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from '../../../../../ui/Select'\r\n\r\n// Icons\r\n\r\n// Types / Utilities\r\nimport { getDetailedAddress } from '../../../utils/geocoder'\r\nimport { MarkerManager } from '../../../utils/MarkerManager'\r\n\r\nimport type { Building } from '../../../../../../types/dbTypes'\r\nimport type { MapGeoJSONFeature } from 'maplibre-gl'\r\n\r\n\r\n\r\n// Hooks\r\n\r\ninterface NonDatabaseBuildingPopoverProps {\r\n feature: MapGeoJSONFeature\r\n isOpen: boolean\r\n onCloseAction: () => void\r\n}\r\n\r\nexport default function NonDatabaseBuildingPopover({\r\n feature,\r\n onCloseAction,\r\n}: NonDatabaseBuildingPopoverProps) {\r\n // Translation\r\n const t = useTranslations('NonDatabaseBuildingPopover')\r\n // Permissions\r\n const { ability } = usePermissions()\r\n\r\n const { data: session } = useSession()\r\n const user = session?.user\r\n\r\n const { state: mapState } = React.useContext(MapContext)\r\n const { currentLocation, map, organizationCountry } = mapState.map\r\n\r\n const { setSelectedItem } = useMenusContext()\r\n\r\n // Use the create building hook\r\n const { createBuilding, isMutating, createError, createdData } = useCreateBuilding()\r\n\r\n // Get all buildings for searching\r\n const { buildings } = useBuildings()\r\n\r\n const featureProps = feature?.properties || {}\r\n const featureid = feature?.id\r\n const [name, setName] = React.useState('')\r\n const [address, setAddress] = React.useState('')\r\n const [matchingBuildings, setMatchingBuildings] = React.useState<Building[]>([])\r\n const [selectedMatchingBuildingId, setSelectedMatchingBuildingId] = React.useState<string>('')\r\n const [showExistingBuildings, setShowExistingBuildings] = React.useState(false)\r\n const [isAttaching, setIsAttaching] = React.useState(false)\r\n\r\n const { updateBuilding, isMutating: isUpdating } = useBuilding(selectedMatchingBuildingId ? Number(selectedMatchingBuildingId) : null)\r\n\r\n const normalizeAddress = React.useCallback((value: string) => {\r\n return value\r\n .toLowerCase()\r\n .replace(/\\./g, '')\r\n .replace(/,/g, ' ')\r\n .replace(/\\bdr\\b/g, 'drive')\r\n .replace(/\\brd\\b/g, 'road')\r\n .replace(/\\bst\\b/g, 'street')\r\n .replace(/\\bave\\b/g, 'avenue')\r\n .replace(/\\s+/g, ' ')\r\n .trim()\r\n }, [])\r\n\r\n const clearExistingBuildingMatches = React.useCallback(() => {\r\n setMatchingBuildings([])\r\n setSelectedMatchingBuildingId('')\r\n setShowExistingBuildings(false)\r\n\r\n if (didSetSelectedItemRef.current && setSelectedItem) {\r\n setSelectedItem(null)\r\n didSetSelectedItemRef.current = false\r\n }\r\n }, [setSelectedItem])\r\n\r\n // Track if we set the selected item in this component\r\n const didSetSelectedItemRef = React.useRef(false)\r\n\r\n // Cleanup on unmount\r\n React.useEffect(() => {\r\n return () => {\r\n // Clear selected item if we set it\r\n if (didSetSelectedItemRef.current && setSelectedItem) {\r\n setSelectedItem(null)\r\n didSetSelectedItemRef.current = false\r\n }\r\n }\r\n }, [setSelectedItem])\r\n\r\n // Get address and search for matching buildings\r\n React.useEffect(() => {\r\n const getAddress = async (longitude: number, latitude: number) => {\r\n try {\r\n // Reverse geocode through the shared provider (Geocode Earth / self-hosted\r\n // Pelias, falling back to public OSM) so this stays in sync with the geocoder.\r\n const result = await getDetailedAddress([longitude, latitude], organizationCountry)\r\n const geocodedAddress = result?.properties?.name as string | undefined\r\n\r\n if (!geocodedAddress) {\r\n clearExistingBuildingMatches()\r\n return\r\n }\r\n\r\n setAddress(geocodedAddress)\r\n\r\n // Search for existing buildings with this address\r\n if (buildings && buildings.length > 0) {\r\n const normalizedGeocodedAddress = normalizeAddress(geocodedAddress)\r\n\r\n const matches = buildings.filter((building) => {\r\n if (!building.buildingAddress) return false\r\n\r\n const normalizedBuildingAddress = normalizeAddress(building.buildingAddress)\r\n return (\r\n normalizedBuildingAddress === normalizedGeocodedAddress ||\r\n normalizedBuildingAddress.includes(normalizedGeocodedAddress) ||\r\n normalizedGeocodedAddress.includes(normalizedBuildingAddress)\r\n )\r\n })\r\n\r\n if (matches.length > 0) {\r\n setMatchingBuildings(matches)\r\n setSelectedMatchingBuildingId(matches[0].id.toString())\r\n setShowExistingBuildings(true)\r\n\r\n // Set the first match as the selected item for the update hook\r\n if (setSelectedItem) {\r\n setSelectedItem(matches[0])\r\n didSetSelectedItemRef.current = true\r\n }\r\n } else {\r\n clearExistingBuildingMatches()\r\n }\r\n } else {\r\n clearExistingBuildingMatches()\r\n }\r\n }\r\n catch (error) {\r\n console.error('Error fetching municipality and countrySubdivision:', error)\r\n }\r\n }\r\n\r\n if (feature.properties?.coordinates) {\r\n const longitude = feature.properties.coordinates[0]\r\n const latitude = feature.properties.coordinates[1]\r\n getAddress(longitude, latitude)\r\n }\r\n }, [feature, buildings, setSelectedItem, normalizeAddress, clearExistingBuildingMatches])\r\n\r\n React.useEffect(() => {\r\n if (!setSelectedItem || !selectedMatchingBuildingId) return\r\n\r\n const selectedBuilding = matchingBuildings.find(\r\n building => building.id.toString() === selectedMatchingBuildingId,\r\n )\r\n\r\n if (!selectedBuilding) return\r\n\r\n setSelectedItem(selectedBuilding)\r\n didSetSelectedItemRef.current = true\r\n }, [matchingBuildings, selectedMatchingBuildingId, setSelectedItem])\r\n\r\n // Fallbacks from feature or map state\r\n const buildingCountrySubdivision = featureProps.de_ao_prov || currentLocation.countrySubdivision || null\r\n const buildingMunicipality = featureProps.de_ao_city || currentLocation.municipality || null\r\n const buildingPostalCode = featureProps.de_ao_post || currentLocation.postalCode || null\r\n const site = currentLocation.site || null\r\n const buildingOsmId = featureid.toString()\r\n\r\n // Create MarkerManager instance\r\n const markerManagerRef = React.useRef<MarkerManager | null>(null)\r\n\r\n // Initialize MarkerManager\r\n React.useEffect(() => {\r\n if (!markerManagerRef.current) {\r\n markerManagerRef.current = new MarkerManager()\r\n }\r\n\r\n // Cleanup on unmount\r\n return () => {\r\n if (markerManagerRef.current) {\r\n markerManagerRef.current.destroy()\r\n markerManagerRef.current = null\r\n }\r\n }\r\n }, [])\r\n\r\n // Get coordinates data from feature\r\n const [coordinates, setCoordinates] = React.useState(featureProps.coordinates || null)\r\n\r\n // Listen for marker coordinate changes\r\n React.useEffect(() => {\r\n if (!markerManagerRef.current) return\r\n\r\n const cleanup = markerManagerRef.current.onMoved((event) => {\r\n const newCoordinates = event.detail.coordinates\r\n if (newCoordinates) {\r\n setCoordinates(newCoordinates)\r\n }\r\n })\r\n\r\n return cleanup\r\n }, [])\r\n\r\n const handleBuildingNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {\r\n setName(event.target.value)\r\n }\r\n\r\n const handleAddressChange = (event: React.ChangeEvent<HTMLInputElement>) => {\r\n setAddress(event.target.value)\r\n }\r\n\r\n const selectedMatchingBuilding = matchingBuildings.find(\r\n building => building.id.toString() === selectedMatchingBuildingId,\r\n )\r\n\r\n const handleAttachExistingBuilding = async (building: Building) => {\r\n setIsAttaching(true)\r\n\r\n try {\r\n // Add OSM ID to existing building\r\n const result = await updateBuilding({\r\n buildingOsmId,\r\n // Set default storey number of 2 if building doesn't have one\r\n ...(building.buildingStoreyNum == null && { buildingStoreyNum: 2 })\r\n })\r\n\r\n toast.success(t('toastAttachSuccess'))\r\n\r\n // Clear the selected item after successful update\r\n if (setSelectedItem) {\r\n setSelectedItem(null)\r\n didSetSelectedItemRef.current = false\r\n }\r\n\r\n // Close the popover\r\n onCloseAction()\r\n\r\n } catch (error) {\r\n console.error('Error attaching building:', error)\r\n\r\n if (error?.status !== 401) {\r\n toast.error(t('toastAttachError'))\r\n }\r\n } finally {\r\n setIsAttaching(false)\r\n }\r\n }\r\n\r\n const handleCreateNewBuilding = async (event: React.FormEvent) => {\r\n event.preventDefault()\r\n\r\n // Get final values (prioritize user input, then existing data)\r\n const buildingName = name.trim() || featureProps._name || ''\r\n const finalAddress = address.trim() || address || ''\r\n\r\n if (!user?.organizationId) {\r\n toast.error(t('userNotFound'))\r\n return\r\n }\r\n\r\n // Use updated coordinates from marker if available\r\n const buildingCoordinates = coordinates || [featureProps.longitude, featureProps.latitude]\r\n\r\n const newBuilding: Partial<Building> = {\r\n buildingName,\r\n buildingAddress: finalAddress,\r\n buildingType: ['Other'],\r\n buildingOsmId,\r\n buildingLatitude: buildingCoordinates ? buildingCoordinates[1] : null,\r\n buildingLongitude: buildingCoordinates ? buildingCoordinates[0] : null,\r\n buildingCountrySubdivision,\r\n buildingMunicipality,\r\n buildingPostalCode,\r\n }\r\n\r\n try {\r\n const result = await createBuilding({\r\n buildingData: newBuilding,\r\n organizationId: user.organizationId.toString(),\r\n })\r\n\r\n // Remove marker after creating building\r\n if (markerManagerRef.current) {\r\n markerManagerRef.current.remove()\r\n }\r\n\r\n toast.success(t('toastSuccess'))\r\n\r\n // Close the popover on success\r\n onCloseAction()\r\n }\r\n catch (error) {\r\n console.error('Error creating building:', error)\r\n toast.error(t('toastError'))\r\n }\r\n }\r\n\r\n const handleLocationEdit = () => {\r\n // Create marker at current coordinates with editing enabled\r\n if (markerManagerRef.current && coordinates && map) {\r\n console.log('Creating editable marker at coordinates:', coordinates)\r\n markerManagerRef.current.create(coordinates as [number, number], map, {\r\n editing: true\r\n })\r\n }\r\n else {\r\n console.warn('Cannot create marker: missing coordinates or map instance')\r\n }\r\n }\r\n\r\n return (\r\n <PopoverContent className=\"w-64 -m-1\" side=\"top\">\r\n <form onSubmit={handleCreateNewBuilding}>\r\n {/* Header row: close button, no overlap with content below */}\r\n <div className=\"flex items-center justify-end mb-1\">\r\n <Button\r\n type=\"button\"\r\n onClick={onCloseAction}\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"shrink-0 p-0 m-0 text-muted-foreground hover:text-foreground\"\r\n aria-label={t('closeAriaLabel')}\r\n >\r\n <LR.X className=\"w-4 h-4\" />\r\n </Button>\r\n </div>\r\n\r\n <div className=\"grid gap-4\">\r\n {/* Show existing building if match found */}\r\n {showExistingBuildings && matchingBuildings.length > 0 && (\r\n <div className=\"space-y-1\">\r\n <div className=\"text-xs text-muted-foreground\">\r\n {t('existingBuildingFound')}\r\n </div>\r\n <div className=\"flex flex-col justify-between gap-2 p-2 bg-muted/50 border rounded-lg\">\r\n <div className=\"grid gap-1\">\r\n <Label htmlFor=\"existing-building-select\" className=\"text-xs text-muted-foreground\">\r\n {t('selectExistingBuildingLabel')}\r\n </Label>\r\n <Select\r\n value={selectedMatchingBuildingId}\r\n onValueChange={setSelectedMatchingBuildingId}\r\n >\r\n <SelectTrigger id=\"existing-building-select\" className=\"h-9 w-full\">\r\n <SelectValue placeholder={t('selectExistingBuildingPlaceholder')} />\r\n </SelectTrigger>\r\n <SelectContent>\r\n {matchingBuildings.map((building) => (\r\n <SelectItem key={building.id} value={building.id.toString()}>\r\n {building.buildingName || building.buildingAddress || `${t('na')} (${building.id})`}\r\n </SelectItem>\r\n ))}\r\n </SelectContent>\r\n </Select>\r\n </div>\r\n <Button\r\n variant=\"outline\"\r\n size=\"sm\"\r\n className='w-full'\r\n onClick={() => selectedMatchingBuilding && handleAttachExistingBuilding(selectedMatchingBuilding)}\r\n disabled={isAttaching || isUpdating || !selectedMatchingBuilding}\r\n >\r\n {(isAttaching || isUpdating) ? (\r\n <>\r\n <LoadingSpinner />\r\n <span>{t('attaching')}</span>\r\n </>\r\n ) : (\r\n <>\r\n <LR.Link />\r\n {t('attachBuilding')}\r\n </>\r\n )}\r\n </Button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n <div className=\"space-y-4\">\r\n <div className=\"grid gap-2\">\r\n <Label htmlFor=\"building-name\" className=\"text-xs text-muted-foreground\">\r\n {t('nameLabel')}\r\n </Label>\r\n <input\r\n id=\"building-name\"\r\n value={name}\r\n onChange={handleBuildingNameChange}\r\n placeholder={name || t('namePlaceholder')}\r\n className={`font-medium leading-none bg-transparent border-b border-gray-300 focus:outline-none focus:border-primary px-1 py-1 ${name ? 'placeholder:text-foreground' : 'placeholder:text-muted-foreground'}`}\r\n aria-label={t('nameInputAriaLabel')}\r\n required\r\n disabled={!ability.can('create', 'Building')}\r\n />\r\n </div>\r\n\r\n <div className=\"grid gap-2\">\r\n <Label htmlFor=\"building-address\" className=\"text-xs text-muted-foreground\">\r\n {t('addressLabel')}\r\n </Label>\r\n <input\r\n id=\"building-address\"\r\n value={address}\r\n onChange={handleAddressChange}\r\n placeholder={address || t('addressPlaceholder')}\r\n className={`font-medium leading-none bg-transparent focus:outline-none focus:border-primary px-1 py-1 ${address ? 'placeholder:text-foreground' : 'placeholder:text-muted-foreground'}`}\r\n aria-label={t('addressAriaLabel')}\r\n required\r\n disabled={!ability.can('create', 'Building')}\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div className=\"flex items-center gap-3 justify-center mt-4\">\r\n <Button\r\n type=\"button\"\r\n variant=\"outline\"\r\n aria-label=\"Edit Location\"\r\n title=\"Edit Location\"\r\n onClick={handleLocationEdit}\r\n disabled={!ability.can('update', 'Building')}\r\n >\r\n <LR.LocationEdit className=\"w-4 h-4\" />\r\n </Button>\r\n\r\n <Button\r\n type=\"submit\"\r\n variant=\"outline\"\r\n aria-label={t('addBuilding')}\r\n title={t('addBuilding')}\r\n disabled={isMutating || !ability.can('create', 'Building')}\r\n >\r\n {isMutating\r\n ? (\r\n <>``\r\n <LoadingSpinner />\r\n <span className=\"text-sm\">{t('creating')}</span>\r\n </>\r\n )\r\n : (\r\n <>\r\n <LR.Building2 className=\"w-4 h-4\" />\r\n <span className=\"text-sm\">{t('addBuilding')}</span>\r\n </>\r\n )}\r\n </Button>\r\n </div>\r\n </form>\r\n </PopoverContent>\r\n )\r\n}"],"mappings":"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","names":["_a"]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../src/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// Dependencies\r\nimport * as LR from 'lucide-react'\r\nimport { useSession } from 'next-auth/react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as React from 'react'\r\nimport { toast } from 'sonner'\r\n\r\nimport { useCreateBuilding, useBuildings, useBuilding } from '../../../../../../hooks/buildings/buildings'\r\nimport { usePermissions } from '../../../../../../store'\r\n\r\n// Shadcn Components\r\nimport { MapContext } from '../../../../../../store'\r\nimport { useMenusContext } from '../../../../../../store'\r\nimport { Button, Label } from '../../../../../ui/'\r\nimport { LoadingSpinner } from '../../../../../ui/LoadingSpinner'\r\nimport { PopoverContent } from '../../../../../ui/Popover'\r\nimport {\r\n Select,\r\n SelectContent,\r\n SelectItem,\r\n SelectTrigger,\r\n SelectValue,\r\n} from '../../../../../ui/Select'\r\n\r\n// Icons\r\n\r\n// Types / Utilities\r\nimport { getDetailedAddress } from '../../../utils/geocoder'\r\nimport { MarkerManager } from '../../../utils/MarkerManager'\r\n\r\nimport type { Building } from '../../../../../../types/dbTypes'\r\nimport type { MapGeoJSONFeature } from 'maplibre-gl'\r\n\r\n\r\n\r\n// Hooks\r\n\r\ninterface NonDatabaseBuildingPopoverProps {\r\n feature: MapGeoJSONFeature\r\n isOpen: boolean\r\n onCloseAction: () => void\r\n}\r\n\r\nexport default function NonDatabaseBuildingPopover({\r\n feature,\r\n onCloseAction,\r\n}: NonDatabaseBuildingPopoverProps) {\r\n // Translation\r\n const t = useTranslations('NonDatabaseBuildingPopover')\r\n // Permissions\r\n const { ability } = usePermissions()\r\n\r\n const { data: session } = useSession()\r\n const user = session?.user\r\n\r\n const { state: mapState } = React.useContext(MapContext)\r\n const { currentLocation, map, organizationCountry } = mapState.map\r\n\r\n const { setSelectedItem } = useMenusContext()\r\n\r\n // Use the create building hook\r\n const { createBuilding, isMutating, createError, createdData } = useCreateBuilding()\r\n\r\n // Get all buildings for searching\r\n const { buildings } = useBuildings()\r\n\r\n const featureProps = feature?.properties || {}\r\n const featureid = feature?.id\r\n const [name, setName] = React.useState('')\r\n const [address, setAddress] = React.useState('')\r\n const [matchingBuildings, setMatchingBuildings] = React.useState<Building[]>([])\r\n const [selectedMatchingBuildingId, setSelectedMatchingBuildingId] = React.useState<string>('')\r\n const [showExistingBuildings, setShowExistingBuildings] = React.useState(false)\r\n const [isAttaching, setIsAttaching] = React.useState(false)\r\n\r\n const { updateBuilding, isMutating: isUpdating } = useBuilding(selectedMatchingBuildingId ? Number(selectedMatchingBuildingId) : null)\r\n\r\n const normalizeAddress = React.useCallback((value: string) => {\r\n return value\r\n .toLowerCase()\r\n .replace(/\\./g, '')\r\n .replace(/,/g, ' ')\r\n .replace(/\\bdr\\b/g, 'drive')\r\n .replace(/\\brd\\b/g, 'road')\r\n .replace(/\\bst\\b/g, 'street')\r\n .replace(/\\bave\\b/g, 'avenue')\r\n .replace(/\\s+/g, ' ')\r\n .trim()\r\n }, [])\r\n\r\n const clearExistingBuildingMatches = React.useCallback(() => {\r\n setMatchingBuildings([])\r\n setSelectedMatchingBuildingId('')\r\n setShowExistingBuildings(false)\r\n\r\n if (didSetSelectedItemRef.current && setSelectedItem) {\r\n setSelectedItem(null)\r\n didSetSelectedItemRef.current = false\r\n }\r\n }, [setSelectedItem])\r\n\r\n // Track if we set the selected item in this component\r\n const didSetSelectedItemRef = React.useRef(false)\r\n\r\n // Cleanup on unmount\r\n React.useEffect(() => {\r\n return () => {\r\n // Clear selected item if we set it\r\n if (didSetSelectedItemRef.current && setSelectedItem) {\r\n setSelectedItem(null)\r\n didSetSelectedItemRef.current = false\r\n }\r\n }\r\n }, [setSelectedItem])\r\n\r\n // Get address and search for matching buildings\r\n React.useEffect(() => {\r\n const getAddress = async (longitude: number, latitude: number) => {\r\n try {\r\n // Reverse geocode through the shared provider (Geocode Earth / self-hosted\r\n // Pelias, falling back to public OSM) so this stays in sync with the geocoder.\r\n const result = await getDetailedAddress([longitude, latitude], organizationCountry)\r\n const geocodedAddress = result?.properties?.name as string | undefined\r\n\r\n if (!geocodedAddress) {\r\n clearExistingBuildingMatches()\r\n return\r\n }\r\n\r\n setAddress(geocodedAddress)\r\n\r\n // Search for existing buildings with this address\r\n if (buildings && buildings.length > 0) {\r\n const normalizedGeocodedAddress = normalizeAddress(geocodedAddress)\r\n\r\n const matches = buildings.filter((building) => {\r\n if (!building.buildingAddress) return false\r\n\r\n const normalizedBuildingAddress = normalizeAddress(building.buildingAddress)\r\n return (\r\n normalizedBuildingAddress === normalizedGeocodedAddress ||\r\n normalizedBuildingAddress.includes(normalizedGeocodedAddress) ||\r\n normalizedGeocodedAddress.includes(normalizedBuildingAddress)\r\n )\r\n })\r\n\r\n if (matches.length > 0) {\r\n setMatchingBuildings(matches)\r\n setSelectedMatchingBuildingId(matches[0].id.toString())\r\n setShowExistingBuildings(true)\r\n\r\n // Set the first match as the selected item for the update hook\r\n if (setSelectedItem) {\r\n setSelectedItem(matches[0])\r\n didSetSelectedItemRef.current = true\r\n }\r\n } else {\r\n clearExistingBuildingMatches()\r\n }\r\n } else {\r\n clearExistingBuildingMatches()\r\n }\r\n }\r\n catch (error) {\r\n console.error('Error fetching municipality and countrySubdivision:', error)\r\n }\r\n }\r\n\r\n if (feature.properties?.coordinates) {\r\n const longitude = feature.properties.coordinates[0]\r\n const latitude = feature.properties.coordinates[1]\r\n getAddress(longitude, latitude)\r\n }\r\n }, [feature, buildings, setSelectedItem, normalizeAddress, clearExistingBuildingMatches])\r\n\r\n React.useEffect(() => {\r\n if (!setSelectedItem || !selectedMatchingBuildingId) return\r\n\r\n const selectedBuilding = matchingBuildings.find(\r\n building => building.id.toString() === selectedMatchingBuildingId,\r\n )\r\n\r\n if (!selectedBuilding) return\r\n\r\n setSelectedItem(selectedBuilding)\r\n didSetSelectedItemRef.current = true\r\n }, [matchingBuildings, selectedMatchingBuildingId, setSelectedItem])\r\n\r\n // Fallbacks from feature or map state\r\n const buildingCountrySubdivision = featureProps.de_ao_prov || currentLocation.countrySubdivision || null\r\n const buildingMunicipality = featureProps.de_ao_city || currentLocation.municipality || null\r\n const buildingPostalCode = featureProps.de_ao_post || currentLocation.postalCode || null\r\n const site = currentLocation.site || null\r\n const buildingOsmId = featureid.toString()\r\n\r\n // Create MarkerManager instance\r\n const markerManagerRef = React.useRef<MarkerManager | null>(null)\r\n\r\n // Initialize MarkerManager\r\n React.useEffect(() => {\r\n if (!markerManagerRef.current) {\r\n markerManagerRef.current = new MarkerManager()\r\n }\r\n\r\n // Cleanup on unmount\r\n return () => {\r\n if (markerManagerRef.current) {\r\n markerManagerRef.current.destroy()\r\n markerManagerRef.current = null\r\n }\r\n }\r\n }, [])\r\n\r\n // Get coordinates data from feature\r\n const [coordinates, setCoordinates] = React.useState(featureProps.coordinates || null)\r\n\r\n // Listen for marker coordinate changes\r\n React.useEffect(() => {\r\n if (!markerManagerRef.current) return\r\n\r\n const cleanup = markerManagerRef.current.onMoved((event) => {\r\n const newCoordinates = event.detail.coordinates\r\n if (newCoordinates) {\r\n setCoordinates(newCoordinates)\r\n }\r\n })\r\n\r\n return cleanup\r\n }, [])\r\n\r\n const handleBuildingNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {\r\n setName(event.target.value)\r\n }\r\n\r\n const handleAddressChange = (event: React.ChangeEvent<HTMLInputElement>) => {\r\n setAddress(event.target.value)\r\n }\r\n\r\n const selectedMatchingBuilding = matchingBuildings.find(\r\n building => building.id.toString() === selectedMatchingBuildingId,\r\n )\r\n\r\n const handleAttachExistingBuilding = async (building: Building) => {\r\n setIsAttaching(true)\r\n\r\n try {\r\n // Add OSM ID to existing building\r\n const result = await updateBuilding({\r\n buildingOsmId,\r\n // Set default storey number of 2 if building doesn't have one\r\n ...(building.buildingStoreyNum == null && { buildingStoreyNum: 2 })\r\n })\r\n\r\n toast.success(t('toastAttachSuccess'))\r\n\r\n // Clear the selected item after successful update\r\n if (setSelectedItem) {\r\n setSelectedItem(null)\r\n didSetSelectedItemRef.current = false\r\n }\r\n\r\n // Close the popover\r\n onCloseAction()\r\n\r\n } catch (error) {\r\n console.error('Error attaching building:', error)\r\n\r\n if (error?.status !== 401) {\r\n toast.error(t('toastAttachError'))\r\n }\r\n } finally {\r\n setIsAttaching(false)\r\n }\r\n }\r\n\r\n const handleCreateNewBuilding = async (event: React.FormEvent) => {\r\n event.preventDefault()\r\n\r\n // Get final values (prioritize user input, then existing data)\r\n const buildingName = name.trim() || featureProps._name || ''\r\n const finalAddress = address.trim() || address || ''\r\n\r\n if (!user?.organizationId) {\r\n toast.error(t('userNotFound'))\r\n return\r\n }\r\n\r\n // Use updated coordinates from marker if available\r\n const buildingCoordinates = coordinates || [featureProps.longitude, featureProps.latitude]\r\n\r\n const newBuilding: Partial<Building> = {\r\n buildingName,\r\n buildingAddress: finalAddress,\r\n buildingType: ['Other'],\r\n buildingOsmId,\r\n buildingLatitude: buildingCoordinates ? buildingCoordinates[1] : null,\r\n buildingLongitude: buildingCoordinates ? buildingCoordinates[0] : null,\r\n buildingCountrySubdivision,\r\n buildingMunicipality,\r\n buildingPostalCode,\r\n }\r\n\r\n try {\r\n const result = await createBuilding({\r\n buildingData: newBuilding,\r\n organizationId: user.organizationId.toString(),\r\n })\r\n\r\n // Remove marker after creating building\r\n if (markerManagerRef.current) {\r\n markerManagerRef.current.remove()\r\n }\r\n\r\n toast.success(t('toastSuccess'))\r\n\r\n // Close the popover on success\r\n onCloseAction()\r\n }\r\n catch (error) {\r\n console.error('Error creating building:', error)\r\n toast.error(t('toastError'))\r\n }\r\n }\r\n\r\n const handleLocationEdit = () => {\r\n // Create marker at current coordinates with editing enabled\r\n if (markerManagerRef.current && coordinates && map) {\r\n markerManagerRef.current.create(coordinates as [number, number], map, {\r\n editing: true\r\n })\r\n }\r\n else {\r\n console.warn('Cannot create marker: missing coordinates or map instance')\r\n }\r\n }\r\n\r\n return (\r\n <PopoverContent className=\"w-64 -m-1\" side=\"top\">\r\n <form onSubmit={handleCreateNewBuilding}>\r\n {/* Header row: close button, no overlap with content below */}\r\n <div className=\"flex items-center justify-end mb-1\">\r\n <Button\r\n type=\"button\"\r\n onClick={onCloseAction}\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"shrink-0 p-0 m-0 text-muted-foreground hover:text-foreground\"\r\n aria-label={t('closeAriaLabel')}\r\n >\r\n <LR.X className=\"w-4 h-4\" />\r\n </Button>\r\n </div>\r\n\r\n <div className=\"grid gap-4\">\r\n {/* Show existing building if match found */}\r\n {showExistingBuildings && matchingBuildings.length > 0 && (\r\n <div className=\"space-y-1\">\r\n <div className=\"text-xs text-muted-foreground\">\r\n {t('existingBuildingFound')}\r\n </div>\r\n <div className=\"flex flex-col justify-between gap-2 p-2 bg-muted/50 border rounded-lg\">\r\n <div className=\"grid gap-1\">\r\n <Label htmlFor=\"existing-building-select\" className=\"text-xs text-muted-foreground\">\r\n {t('selectExistingBuildingLabel')}\r\n </Label>\r\n <Select\r\n value={selectedMatchingBuildingId}\r\n onValueChange={setSelectedMatchingBuildingId}\r\n >\r\n <SelectTrigger id=\"existing-building-select\" className=\"h-9 w-full\">\r\n <SelectValue placeholder={t('selectExistingBuildingPlaceholder')} />\r\n </SelectTrigger>\r\n <SelectContent>\r\n {matchingBuildings.map((building) => (\r\n <SelectItem key={building.id} value={building.id.toString()}>\r\n {building.buildingName || building.buildingAddress || `${t('na')} (${building.id})`}\r\n </SelectItem>\r\n ))}\r\n </SelectContent>\r\n </Select>\r\n </div>\r\n <Button\r\n variant=\"outline\"\r\n size=\"sm\"\r\n className='w-full'\r\n onClick={() => selectedMatchingBuilding && handleAttachExistingBuilding(selectedMatchingBuilding)}\r\n disabled={isAttaching || isUpdating || !selectedMatchingBuilding}\r\n >\r\n {(isAttaching || isUpdating) ? (\r\n <>\r\n <LoadingSpinner />\r\n <span>{t('attaching')}</span>\r\n </>\r\n ) : (\r\n <>\r\n <LR.Link />\r\n {t('attachBuilding')}\r\n </>\r\n )}\r\n </Button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n <div className=\"space-y-4\">\r\n <div className=\"grid gap-2\">\r\n <Label htmlFor=\"building-name\" className=\"text-xs text-muted-foreground\">\r\n {t('nameLabel')}\r\n </Label>\r\n <input\r\n id=\"building-name\"\r\n value={name}\r\n onChange={handleBuildingNameChange}\r\n placeholder={name || t('namePlaceholder')}\r\n className={`font-medium leading-none bg-transparent border-b border-gray-300 focus:outline-none focus:border-primary px-1 py-1 ${name ? 'placeholder:text-foreground' : 'placeholder:text-muted-foreground'}`}\r\n aria-label={t('nameInputAriaLabel')}\r\n required\r\n disabled={!ability.can('create', 'Building')}\r\n />\r\n </div>\r\n\r\n <div className=\"grid gap-2\">\r\n <Label htmlFor=\"building-address\" className=\"text-xs text-muted-foreground\">\r\n {t('addressLabel')}\r\n </Label>\r\n <input\r\n id=\"building-address\"\r\n value={address}\r\n onChange={handleAddressChange}\r\n placeholder={address || t('addressPlaceholder')}\r\n className={`font-medium leading-none bg-transparent focus:outline-none focus:border-primary px-1 py-1 ${address ? 'placeholder:text-foreground' : 'placeholder:text-muted-foreground'}`}\r\n aria-label={t('addressAriaLabel')}\r\n required\r\n disabled={!ability.can('create', 'Building')}\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div className=\"flex items-center gap-3 justify-center mt-4\">\r\n <Button\r\n type=\"button\"\r\n variant=\"outline\"\r\n aria-label=\"Edit Location\"\r\n title=\"Edit Location\"\r\n onClick={handleLocationEdit}\r\n disabled={!ability.can('update', 'Building')}\r\n >\r\n <LR.LocationEdit className=\"w-4 h-4\" />\r\n </Button>\r\n\r\n <Button\r\n type=\"submit\"\r\n variant=\"outline\"\r\n aria-label={t('addBuilding')}\r\n title={t('addBuilding')}\r\n disabled={isMutating || !ability.can('create', 'Building')}\r\n >\r\n {isMutating\r\n ? (\r\n <>``\r\n <LoadingSpinner />\r\n <span className=\"text-sm\">{t('creating')}</span>\r\n </>\r\n )\r\n : (\r\n <>\r\n <LR.Building2 className=\"w-4 h-4\" />\r\n <span className=\"text-sm\">{t('addBuilding')}</span>\r\n </>\r\n )}\r\n </Button>\r\n </div>\r\n </form>\r\n </PopoverContent>\r\n )\r\n}"],"mappings":"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","names":["_a"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OpenDataFeaturePopover.d.ts","sourceRoot":"","sources":["../../../../../../../../src/core/components/viewers/map/src/MapFeaturePopoverMenu/src/OpenDataFeaturePopover.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAqB9B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEpD,UAAU,2BAA2B;IACnC,OAAO,EAAE,iBAAiB,CAAA;IAC1B,MAAM,EAAE,OAAO,CAAA;IACf,aAAa,EAAE,MAAM,IAAI,CAAA;CAC1B;AAED,MAAM,CAAC,OAAO,UAAU,sBAAsB,CAAC,EAC7C,OAAO,EACP,MAAM,EACN,aAAa,GACd,EAAE,2BAA2B,
|
|
1
|
+
{"version":3,"file":"OpenDataFeaturePopover.d.ts","sourceRoot":"","sources":["../../../../../../../../src/core/components/viewers/map/src/MapFeaturePopoverMenu/src/OpenDataFeaturePopover.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAqB9B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAEpD,UAAU,2BAA2B;IACnC,OAAO,EAAE,iBAAiB,CAAA;IAC1B,MAAM,EAAE,OAAO,CAAA;IACf,aAAa,EAAE,MAAM,IAAI,CAAA;CAC1B;AAED,MAAM,CAAC,OAAO,UAAU,sBAAsB,CAAC,EAC7C,OAAO,EACP,MAAM,EACN,aAAa,GACd,EAAE,2BAA2B,qBAmL7B"}
|
package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/OpenDataFeaturePopover.js
CHANGED
|
@@ -82,7 +82,6 @@ function OpenDataFeaturePopover({
|
|
|
82
82
|
const isUrl = (value) => {
|
|
83
83
|
return value.startsWith("http://") || value.startsWith("https://");
|
|
84
84
|
};
|
|
85
|
-
console.log("Feature Properties:", featureProps);
|
|
86
85
|
const datasetName = featureProps.datasetName ? featureProps.datasetName.replaceAll("_", " ") : t("unknownDataset");
|
|
87
86
|
const dataset = addedDatasets.find((d) => d.name === featureProps.datasetName);
|
|
88
87
|
const datasetColor = dataset ? dataset.layerColor.color : stringToColour(datasetName);
|
package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/OpenDataFeaturePopover.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../src/core/components/viewers/map/src/MapFeaturePopoverMenu/src/OpenDataFeaturePopover.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// Dependencies\r\nimport * as LR from 'lucide-react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as React from 'react'\r\n\r\n// Shadcn Components\r\nimport { DatasetsContext } from '../../../../../../store/Datasets/context'\r\nimport { Button } from '../../../../../ui/Button'\r\nimport ColorCircle from '../../../../../ui/ColorCircle'\r\nimport { PopoverContent } from '../../../../../ui/Popover'\r\nimport {\r\n Table,\r\n TableBody,\r\n TableCell,\r\n TableHead,\r\n TableHeader,\r\n TableRow,\r\n} from '../../../../../ui/Table'\r\n\r\n// Icons\r\n\r\n// Types / Utilities\r\nimport { stringToColour } from '../../../utils/stringToColour'\r\n\r\nimport type { MapGeoJSONFeature } from 'maplibre-gl'\r\n\r\ninterface OpenDataFeaturePopoverProps {\r\n feature: MapGeoJSONFeature\r\n isOpen: boolean\r\n onCloseAction: () => void\r\n}\r\n\r\nexport default function OpenDataFeaturePopover({\r\n feature,\r\n isOpen,\r\n onCloseAction,\r\n}: OpenDataFeaturePopoverProps) {\r\n // Translation\r\n const t = useTranslations('OpenDataFeaturePopover')\r\n\r\n const {state: datasetsState} = React.useContext(DatasetsContext)\r\n const {addedDatasets} = datasetsState.datasets\r\n\r\n const featureProps = feature?.properties || {}\r\n // Filter out properties that are null, undefined, empty strings, or coordinate-related\r\n const validProperties = Object.entries(featureProps)\r\n .filter(([key, value]) => {\r\n // Check for null, undefined, or empty string values\r\n const lowValue = String(value).toLowerCase()\r\n if (\r\n value === null\r\n || value === undefined\r\n || value === ''\r\n || lowValue === 'null'\r\n || lowValue === 'undefined'\r\n || lowValue === 'none'\r\n ) {\r\n return false\r\n }\r\n\r\n // Filter out coordinate-related properties\r\n const lowerKey = key.toLowerCase()\r\n const excludingKeys = [\r\n 'globalid',\r\n 'latitude',\r\n 'lat',\r\n 'longitude',\r\n 'lng',\r\n 'lon',\r\n 'coordinates',\r\n 'coordina',\r\n 'x',\r\n 'y',\r\n 'z',\r\n 'geometry',\r\n 'cluster',\r\n 'cluster_id',\r\n 'point_count_abbreviated',\r\n 'datasetName',\r\n 'datasetColor',\r\n ]\r\n return !excludingKeys.includes(lowerKey)\r\n })\r\n .sort(([keyA], [keyB]) => {\r\n const aHasName = keyA.toLowerCase().includes('name')\r\n const bHasName = keyB.toLowerCase().includes('name')\r\n if (aHasName && !bHasName) return -1\r\n if (!aHasName && bHasName) return 1\r\n return 0\r\n })\r\n\r\n // Function to format property names (convert snake_case to readable format)\r\n const formatPropertyName = (key: string): string => {\r\n return key\r\n .replaceAll('_', ' ')\r\n .replaceAll(/\\b\\w/g, l => l.toUpperCase())\r\n }\r\n\r\n // Function to format property values\r\n const formatPropertyValue = (value: any, key?: string): string => {\r\n if (typeof value === 'boolean') {\r\n return value ? 'Yes' : 'No'\r\n }\r\n if (typeof value === 'number') {\r\n // Don't add commas for year-like fields\r\n if (key && key.toLowerCase().includes('year')) {\r\n return value.toString()\r\n }\r\n return value.toLocaleString()\r\n }\r\n if (typeof value === 'string') {\r\n // Handle URLs\r\n if (value.startsWith('http://') || value.startsWith('https://')) {\r\n return value\r\n }\r\n return value\r\n }\r\n return String(value)\r\n }\r\n\r\n // Function to check if value is a URL\r\n const isUrl = (value: string): boolean => {\r\n return value.startsWith('http://') || value.startsWith('https://')\r\n }\r\n\r\n console.log('Feature Properties:', featureProps)\r\n\r\n const datasetName = (featureProps.datasetName ? featureProps.datasetName.replaceAll('_', ' ') : t('unknownDataset'))\r\n const dataset = addedDatasets.find(d => d.name === featureProps.datasetName)\r\n const datasetColor = dataset ? dataset.layerColor.color : stringToColour(datasetName)\r\n\r\n return (\r\n <PopoverContent className=\"w-80 -m-1\" side=\"top\">\r\n <div className=\"grid gap-4\">\r\n <Button\r\n onClick={onCloseAction}\r\n variant=\"ghost\"\r\n className=\"absolute top-1 right-2 p-1 text-muted-foreground hover:text-foreground\"\r\n aria-label=\"Close\"\r\n >\r\n <LR.X className=\"w-4 h-4\" />\r\n </Button>\r\n <div className=\"space-y-2\">\r\n <div className=\"flex items-center gap-2\">\r\n <LR.Database className=\"w-4 h-4\" />\r\n <h4 className=\"font-medium leading-none\">{t('propertiesHeader')}</h4>\r\n </div>\r\n {/* Circle with the dataset color */}\r\n <div className=\"flex items-center gap-2 pl-[2px]\">\r\n <ColorCircle color={datasetColor} size={14} />\r\n <p className=\"text-xs text-muted-foreground\">\r\n {datasetName}\r\n </p>\r\n </div>\r\n </div>\r\n\r\n {validProperties.length > 0\r\n ? (\r\n <div className=\"max-h-64 overflow-auto\">\r\n <Table>\r\n <TableHeader>\r\n <TableRow>\r\n <TableHead className=\"w-1/3 text-xs\">{t('propertyTableHead')}</TableHead>\r\n <TableHead className=\"text-xs\">{t('valueTableHead')}</TableHead>\r\n </TableRow>\r\n </TableHeader>\r\n <TableBody>\r\n {validProperties.map(([key, value]) => (\r\n <TableRow key={key}>\r\n <TableCell className=\"font-medium text-xs py-2\">\r\n {formatPropertyName(key)}\r\n </TableCell>\r\n <TableCell className=\"text-xs py-2\">\r\n {isUrl(String(value))\r\n ? (\r\n <a\r\n href={String(value)}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"text-blue-600 hover:text-blue-800 underline break-all\"\r\n >\r\n {formatPropertyValue(value, key)}\r\n </a>\r\n )\r\n : (\r\n <span className=\"break-words\">\r\n {formatPropertyValue(value, key)}\r\n </span>\r\n )}\r\n </TableCell>\r\n </TableRow>\r\n ))}\r\n </TableBody>\r\n </Table>\r\n </div>\r\n )\r\n : (\r\n <div className=\"text-center py-4\">\r\n <LR.FileX className=\"w-8 h-8 text-muted-foreground mx-auto mb-2\" />\r\n <p className=\"text-sm text-muted-foreground\">\r\n {t('noPropertyAvail')}\r\n </p>\r\n </div>\r\n )}\r\n\r\n {validProperties.length > 10 && (\r\n <div className=\"text-xs text-muted-foreground text-center\">\r\n {t('showing')}\r\n {' '}\r\n {validProperties.length}\r\n {' '}\r\n {t('properties')}\r\n </div>\r\n )}\r\n </div>\r\n </PopoverContent>\r\n )\r\n}\r\n"],"mappings":";AAiJU,cAGA,YAHA;AA3IV,YAAY,QAAQ;AACpB,SAAS,uBAAuB;AAChC,YAAY,WAAW;AAGvB,SAAS,uBAAuB;AAChC,SAAS,cAAc;AACvB,OAAO,iBAAiB;AACxB,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAKP,SAAS,sBAAsB;AAUhB,SAAR,uBAAwC;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AACF,GAAgC;AAE9B,QAAM,IAAI,gBAAgB,wBAAwB;AAElD,QAAM,EAAC,OAAO,cAAa,IAAI,MAAM,WAAW,eAAe;AAC/D,QAAM,EAAC,cAAa,IAAI,cAAc;AAEtC,QAAM,gBAAe,mCAAS,eAAc,CAAC;AAE7C,QAAM,kBAAkB,OAAO,QAAQ,YAAY,EAChD,OAAO,CAAC,CAAC,KAAK,KAAK,MAAM;AAExB,UAAM,WAAW,OAAO,KAAK,EAAE,YAAY;AAC3C,QACE,UAAU,QACP,UAAU,UACV,UAAU,MACV,aAAa,UACb,aAAa,eACb,aAAa,QAChB;AACA,aAAO;AAAA,IACT;AAGA,UAAM,WAAW,IAAI,YAAY;AACjC,UAAM,gBAAgB;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,WAAO,CAAC,cAAc,SAAS,QAAQ;AAAA,EACzC,CAAC,EACA,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,MAAM;AACxB,UAAM,WAAW,KAAK,YAAY,EAAE,SAAS,MAAM;AACnD,UAAM,WAAW,KAAK,YAAY,EAAE,SAAS,MAAM;AACnD,QAAI,YAAY,CAAC,SAAU,QAAO;AAClC,QAAI,CAAC,YAAY,SAAU,QAAO;AAClC,WAAO;AAAA,EACT,CAAC;AAGH,QAAM,qBAAqB,CAAC,QAAwB;AAClD,WAAO,IACJ,WAAW,KAAK,GAAG,EACnB,WAAW,SAAS,OAAK,EAAE,YAAY,CAAC;AAAA,EAC7C;AAGA,QAAM,sBAAsB,CAAC,OAAY,QAAyB;AAChE,QAAI,OAAO,UAAU,WAAW;AAC9B,aAAO,QAAQ,QAAQ;AAAA,IACzB;AACA,QAAI,OAAO,UAAU,UAAU;AAE7B,UAAI,OAAO,IAAI,YAAY,EAAE,SAAS,MAAM,GAAG;AAC7C,eAAO,MAAM,SAAS;AAAA,MACxB;AACA,aAAO,MAAM,eAAe;AAAA,IAC9B;AACA,QAAI,OAAO,UAAU,UAAU;AAE7B,UAAI,MAAM,WAAW,SAAS,KAAK,MAAM,WAAW,UAAU,GAAG;AAC/D,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AACA,WAAO,OAAO,KAAK;AAAA,EACrB;AAGA,QAAM,QAAQ,CAAC,UAA2B;AACxC,WAAO,MAAM,WAAW,SAAS,KAAK,MAAM,WAAW,UAAU;AAAA,EACnE;AAEA,UAAQ,IAAI,uBAAuB,YAAY;AAE/C,QAAM,cAAe,aAAa,cAAc,aAAa,YAAY,WAAW,KAAK,GAAG,IAAI,EAAE,gBAAgB;AAClH,QAAM,UAAU,cAAc,KAAK,OAAK,EAAE,SAAS,aAAa,WAAW;AAC3E,QAAM,eAAe,UAAU,QAAQ,WAAW,QAAQ,eAAe,WAAW;AAEpF,SACE,oBAAC,kBAAe,WAAU,aAAY,MAAK,OACzC,+BAAC,SAAI,WAAU,cACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,SAAQ;AAAA,QACR,WAAU;AAAA,QACV,cAAW;AAAA,QAEX,8BAAC,GAAG,GAAH,EAAK,WAAU,WAAU;AAAA;AAAA,IAC5B;AAAA,IACA,qBAAC,SAAI,WAAU,aACb;AAAA,2BAAC,SAAI,WAAU,2BACb;AAAA,4BAAC,GAAG,UAAH,EAAY,WAAU,WAAU;AAAA,QACjC,oBAAC,QAAG,WAAU,4BAA4B,YAAE,kBAAkB,GAAE;AAAA,SAClE;AAAA,MAEA,qBAAC,SAAI,WAAU,oCACb;AAAA,4BAAC,eAAY,OAAO,cAAc,MAAM,IAAI;AAAA,QAC5C,oBAAC,OAAE,WAAU,iCACV,uBACH;AAAA,SACF;AAAA,OACF;AAAA,IAEC,gBAAgB,SAAS,IAEpB,oBAAC,SAAI,WAAU,0BACb,+BAAC,SACC;AAAA,0BAAC,eACC,+BAAC,YACC;AAAA,4BAAC,aAAU,WAAU,iBAAiB,YAAE,mBAAmB,GAAE;AAAA,QAC7D,oBAAC,aAAU,WAAU,WAAW,YAAE,gBAAgB,GAAE;AAAA,SACtD,GACF;AAAA,MACA,oBAAC,aACE,0BAAgB,IAAI,CAAC,CAAC,KAAK,KAAK,MAC/B,qBAAC,YACC;AAAA,4BAAC,aAAU,WAAU,4BAClB,6BAAmB,GAAG,GACzB;AAAA,QACA,oBAAC,aAAU,WAAU,gBAClB,gBAAM,OAAO,KAAK,CAAC,IAEd;AAAA,UAAC;AAAA;AAAA,YACC,MAAM,OAAO,KAAK;AAAA,YAClB,QAAO;AAAA,YACP,KAAI;AAAA,YACJ,WAAU;AAAA,YAET,8BAAoB,OAAO,GAAG;AAAA;AAAA,QACjC,IAGA,oBAAC,UAAK,WAAU,eACb,8BAAoB,OAAO,GAAG,GACjC,GAER;AAAA,WArBa,GAsBf,CACD,GACH;AAAA,OACF,GACF,IAGA,qBAAC,SAAI,WAAU,oBACb;AAAA,0BAAC,GAAG,OAAH,EAAS,WAAU,8CAA6C;AAAA,MACjE,oBAAC,OAAE,WAAU,iCACV,YAAE,iBAAiB,GACtB;AAAA,OACF;AAAA,IAGL,gBAAgB,SAAS,MACxB,qBAAC,SAAI,WAAU,6CACZ;AAAA,QAAE,SAAS;AAAA,MACX;AAAA,MACA,gBAAgB;AAAA,MAChB;AAAA,MACA,EAAE,YAAY;AAAA,OACjB;AAAA,KAEJ,GACF;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../src/core/components/viewers/map/src/MapFeaturePopoverMenu/src/OpenDataFeaturePopover.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// Dependencies\r\nimport * as LR from 'lucide-react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as React from 'react'\r\n\r\n// Shadcn Components\r\nimport { DatasetsContext } from '../../../../../../store/Datasets/context'\r\nimport { Button } from '../../../../../ui/Button'\r\nimport ColorCircle from '../../../../../ui/ColorCircle'\r\nimport { PopoverContent } from '../../../../../ui/Popover'\r\nimport {\r\n Table,\r\n TableBody,\r\n TableCell,\r\n TableHead,\r\n TableHeader,\r\n TableRow,\r\n} from '../../../../../ui/Table'\r\n\r\n// Icons\r\n\r\n// Types / Utilities\r\nimport { stringToColour } from '../../../utils/stringToColour'\r\n\r\nimport type { MapGeoJSONFeature } from 'maplibre-gl'\r\n\r\ninterface OpenDataFeaturePopoverProps {\r\n feature: MapGeoJSONFeature\r\n isOpen: boolean\r\n onCloseAction: () => void\r\n}\r\n\r\nexport default function OpenDataFeaturePopover({\r\n feature,\r\n isOpen,\r\n onCloseAction,\r\n}: OpenDataFeaturePopoverProps) {\r\n // Translation\r\n const t = useTranslations('OpenDataFeaturePopover')\r\n\r\n const {state: datasetsState} = React.useContext(DatasetsContext)\r\n const {addedDatasets} = datasetsState.datasets\r\n\r\n const featureProps = feature?.properties || {}\r\n // Filter out properties that are null, undefined, empty strings, or coordinate-related\r\n const validProperties = Object.entries(featureProps)\r\n .filter(([key, value]) => {\r\n // Check for null, undefined, or empty string values\r\n const lowValue = String(value).toLowerCase()\r\n if (\r\n value === null\r\n || value === undefined\r\n || value === ''\r\n || lowValue === 'null'\r\n || lowValue === 'undefined'\r\n || lowValue === 'none'\r\n ) {\r\n return false\r\n }\r\n\r\n // Filter out coordinate-related properties\r\n const lowerKey = key.toLowerCase()\r\n const excludingKeys = [\r\n 'globalid',\r\n 'latitude',\r\n 'lat',\r\n 'longitude',\r\n 'lng',\r\n 'lon',\r\n 'coordinates',\r\n 'coordina',\r\n 'x',\r\n 'y',\r\n 'z',\r\n 'geometry',\r\n 'cluster',\r\n 'cluster_id',\r\n 'point_count_abbreviated',\r\n 'datasetName',\r\n 'datasetColor',\r\n ]\r\n return !excludingKeys.includes(lowerKey)\r\n })\r\n .sort(([keyA], [keyB]) => {\r\n const aHasName = keyA.toLowerCase().includes('name')\r\n const bHasName = keyB.toLowerCase().includes('name')\r\n if (aHasName && !bHasName) return -1\r\n if (!aHasName && bHasName) return 1\r\n return 0\r\n })\r\n\r\n // Function to format property names (convert snake_case to readable format)\r\n const formatPropertyName = (key: string): string => {\r\n return key\r\n .replaceAll('_', ' ')\r\n .replaceAll(/\\b\\w/g, l => l.toUpperCase())\r\n }\r\n\r\n // Function to format property values\r\n const formatPropertyValue = (value: any, key?: string): string => {\r\n if (typeof value === 'boolean') {\r\n return value ? 'Yes' : 'No'\r\n }\r\n if (typeof value === 'number') {\r\n // Don't add commas for year-like fields\r\n if (key && key.toLowerCase().includes('year')) {\r\n return value.toString()\r\n }\r\n return value.toLocaleString()\r\n }\r\n if (typeof value === 'string') {\r\n // Handle URLs\r\n if (value.startsWith('http://') || value.startsWith('https://')) {\r\n return value\r\n }\r\n return value\r\n }\r\n return String(value)\r\n }\r\n\r\n // Function to check if value is a URL\r\n const isUrl = (value: string): boolean => {\r\n return value.startsWith('http://') || value.startsWith('https://')\r\n }\r\n\r\n const datasetName = (featureProps.datasetName ? featureProps.datasetName.replaceAll('_', ' ') : t('unknownDataset'))\r\n const dataset = addedDatasets.find(d => d.name === featureProps.datasetName)\r\n const datasetColor = dataset ? dataset.layerColor.color : stringToColour(datasetName)\r\n\r\n return (\r\n <PopoverContent className=\"w-80 -m-1\" side=\"top\">\r\n <div className=\"grid gap-4\">\r\n <Button\r\n onClick={onCloseAction}\r\n variant=\"ghost\"\r\n className=\"absolute top-1 right-2 p-1 text-muted-foreground hover:text-foreground\"\r\n aria-label=\"Close\"\r\n >\r\n <LR.X className=\"w-4 h-4\" />\r\n </Button>\r\n <div className=\"space-y-2\">\r\n <div className=\"flex items-center gap-2\">\r\n <LR.Database className=\"w-4 h-4\" />\r\n <h4 className=\"font-medium leading-none\">{t('propertiesHeader')}</h4>\r\n </div>\r\n {/* Circle with the dataset color */}\r\n <div className=\"flex items-center gap-2 pl-[2px]\">\r\n <ColorCircle color={datasetColor} size={14} />\r\n <p className=\"text-xs text-muted-foreground\">\r\n {datasetName}\r\n </p>\r\n </div>\r\n </div>\r\n\r\n {validProperties.length > 0\r\n ? (\r\n <div className=\"max-h-64 overflow-auto\">\r\n <Table>\r\n <TableHeader>\r\n <TableRow>\r\n <TableHead className=\"w-1/3 text-xs\">{t('propertyTableHead')}</TableHead>\r\n <TableHead className=\"text-xs\">{t('valueTableHead')}</TableHead>\r\n </TableRow>\r\n </TableHeader>\r\n <TableBody>\r\n {validProperties.map(([key, value]) => (\r\n <TableRow key={key}>\r\n <TableCell className=\"font-medium text-xs py-2\">\r\n {formatPropertyName(key)}\r\n </TableCell>\r\n <TableCell className=\"text-xs py-2\">\r\n {isUrl(String(value))\r\n ? (\r\n <a\r\n href={String(value)}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n className=\"text-blue-600 hover:text-blue-800 underline break-all\"\r\n >\r\n {formatPropertyValue(value, key)}\r\n </a>\r\n )\r\n : (\r\n <span className=\"break-words\">\r\n {formatPropertyValue(value, key)}\r\n </span>\r\n )}\r\n </TableCell>\r\n </TableRow>\r\n ))}\r\n </TableBody>\r\n </Table>\r\n </div>\r\n )\r\n : (\r\n <div className=\"text-center py-4\">\r\n <LR.FileX className=\"w-8 h-8 text-muted-foreground mx-auto mb-2\" />\r\n <p className=\"text-sm text-muted-foreground\">\r\n {t('noPropertyAvail')}\r\n </p>\r\n </div>\r\n )}\r\n\r\n {validProperties.length > 10 && (\r\n <div className=\"text-xs text-muted-foreground text-center\">\r\n {t('showing')}\r\n {' '}\r\n {validProperties.length}\r\n {' '}\r\n {t('properties')}\r\n </div>\r\n )}\r\n </div>\r\n </PopoverContent>\r\n )\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { Organization } from '../../../../../types/dbTypes';
|
|
3
|
-
export declare const MapLayers: ({
|
|
4
|
-
minioBaseUrl?: string;
|
|
3
|
+
export declare const MapLayers: ({ organization, maptilerKey }: {
|
|
5
4
|
organization?: Organization;
|
|
6
5
|
maptilerKey?: string;
|
|
7
6
|
}) => React.JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/map/src/MapLayers/index.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAa9B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAahE,eAAO,MAAM,SAAS,GAAI
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/map/src/MapLayers/index.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAa9B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAahE,eAAO,MAAM,SAAS,GAAI,+BAA+B;IAAE,YAAY,CAAC,EAAE,YAAY,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,sBAa7G,CAAA"}
|
|
@@ -18,14 +18,14 @@ function BimLayerGate() {
|
|
|
18
18
|
if (bimState.bim.bimModelsAddedToMap.length === 0) return null;
|
|
19
19
|
return /* @__PURE__ */ jsx(LazyBimLayer, {});
|
|
20
20
|
}
|
|
21
|
-
const MapLayers = ({
|
|
21
|
+
const MapLayers = ({ organization, maptilerKey }) => {
|
|
22
22
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
23
23
|
/* @__PURE__ */ jsx(SiteLayer, {}),
|
|
24
24
|
/* @__PURE__ */ jsx(CountryLayer, { organization, maptilerKey }),
|
|
25
25
|
/* @__PURE__ */ jsx(OpenDataLayers, {}),
|
|
26
26
|
/* @__PURE__ */ jsx(BuildingLayer, {}),
|
|
27
27
|
/* @__PURE__ */ jsx(CommentLayer, {}),
|
|
28
|
-
/* @__PURE__ */ jsx(SensorLayers, {
|
|
28
|
+
/* @__PURE__ */ jsx(SensorLayers, {}),
|
|
29
29
|
/* @__PURE__ */ jsx(FileLayers, {}),
|
|
30
30
|
/* @__PURE__ */ jsx(BimLayerGate, {})
|
|
31
31
|
] });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../src/core/components/viewers/map/src/MapLayers/index.tsx"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n'use client'\r\n\r\nimport dynamic from 'next/dynamic'\r\nimport * as React from 'react'\r\n\r\nimport { useBimContext } from '../../../../../store'\r\n\r\nimport { BuildingLayer } from './src/BuildingLayers'\r\nimport { CommentLayer } from './src/CommentLayer'\r\nimport { CountryLayer } from './src/CountryLayer'\r\nimport { FileLayers } from './src/FileLayer'\r\nimport { OpenDataLayers } from './src/OpenDataLayer/src'\r\nimport { SensorLayers } from './src/SensorsLayer'\r\nimport { SiteLayer } from './src/SiteLayer/SiteLayer'\r\n\r\n\r\nimport type { Organization } from '../../../../../types/dbTypes'\r\n\r\nconst LazyBimLayer = dynamic(\r\n () => import('./src/BimLayer').then(m => ({ default: m.BimLayer })),\r\n { ssr: false },\r\n)\r\n\r\nfunction BimLayerGate() {\r\n const { state: bimState } = useBimContext()\r\n if (bimState.bim.bimModelsAddedToMap.length === 0) return null\r\n return <LazyBimLayer />\r\n}\r\n\r\nexport const MapLayers = ({
|
|
1
|
+
{"version":3,"sources":["../../../../../../../src/core/components/viewers/map/src/MapLayers/index.tsx"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n'use client'\r\n\r\nimport dynamic from 'next/dynamic'\r\nimport * as React from 'react'\r\n\r\nimport { useBimContext } from '../../../../../store'\r\n\r\nimport { BuildingLayer } from './src/BuildingLayers'\r\nimport { CommentLayer } from './src/CommentLayer'\r\nimport { CountryLayer } from './src/CountryLayer'\r\nimport { FileLayers } from './src/FileLayer'\r\nimport { OpenDataLayers } from './src/OpenDataLayer/src'\r\nimport { SensorLayers } from './src/SensorsLayer'\r\nimport { SiteLayer } from './src/SiteLayer/SiteLayer'\r\n\r\n\r\nimport type { Organization } from '../../../../../types/dbTypes'\r\n\r\nconst LazyBimLayer = dynamic(\r\n () => import('./src/BimLayer').then(m => ({ default: m.BimLayer })),\r\n { ssr: false },\r\n)\r\n\r\nfunction BimLayerGate() {\r\n const { state: bimState } = useBimContext()\r\n if (bimState.bim.bimModelsAddedToMap.length === 0) return null\r\n return <LazyBimLayer />\r\n}\r\n\r\nexport const MapLayers = ({ organization, maptilerKey }: { organization?: Organization; maptilerKey?: string }) => {\r\n return (\r\n <>\r\n <SiteLayer />\r\n <CountryLayer organization={organization} maptilerKey={maptilerKey} />\r\n <OpenDataLayers />\r\n <BuildingLayer />\r\n <CommentLayer />\r\n <SensorLayers />\r\n <FileLayers />\r\n <BimLayerGate />\r\n </>\r\n )\r\n}\r\n"],"mappings":";AA6BS,SAKL,UALK,KAKL,YALK;AAxBT,OAAO,aAAa;AAGpB,SAAS,qBAAqB;AAE9B,SAAS,qBAAqB;AAC9B,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAC3B,SAAS,sBAAsB;AAC/B,SAAS,oBAAoB;AAC7B,SAAS,iBAAiB;AAK1B,MAAM,eAAe;AAAA,EACnB,MAAM,OAAO,gBAAgB,EAAE,KAAK,QAAM,EAAE,SAAS,EAAE,SAAS,EAAE;AAAA,EAClE,EAAE,KAAK,MAAM;AACf;AAEA,SAAS,eAAe;AACtB,QAAM,EAAE,OAAO,SAAS,IAAI,cAAc;AAC1C,MAAI,SAAS,IAAI,oBAAoB,WAAW,EAAG,QAAO;AAC1D,SAAO,oBAAC,gBAAa;AACvB;AAEO,MAAM,YAAY,CAAC,EAAE,cAAc,YAAY,MAA6D;AACjH,SACE,iCACE;AAAA,wBAAC,aAAU;AAAA,IACX,oBAAC,gBAAa,cAA4B,aAA0B;AAAA,IACpE,oBAAC,kBAAe;AAAA,IAChB,oBAAC,iBAAc;AAAA,IACf,oBAAC,gBAAa;AAAA,IACd,oBAAC,gBAAa;AAAA,IACd,oBAAC,cAAW;AAAA,IACZ,oBAAC,gBAAa;AAAA,KAChB;AAEJ;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/components/viewers/map/src/MapLayers/src/CommentLayer/index.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/components/viewers/map/src/MapLayers/src/CommentLayer/index.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAqE9B,eAAO,MAAM,YAAY,yBA6YxB,CAAA"}
|
|
@@ -24,39 +24,45 @@ import { useTranslations } from "next-intl";
|
|
|
24
24
|
import * as React from "react";
|
|
25
25
|
import { Source, Layer, Popup, Marker } from "react-map-gl/maplibre";
|
|
26
26
|
import { toast } from "sonner";
|
|
27
|
-
import {
|
|
27
|
+
import { useComments, useDeleteComments } from "../../../../../../../hooks/comments/comments";
|
|
28
28
|
import { useUser, useUsers } from "../../../../../../../hooks/users/users";
|
|
29
29
|
import { MapContext, MenusContext } from "../../../../../../../store";
|
|
30
30
|
import { ViewerNames } from "../../../../../../../types/dbTypes";
|
|
31
|
+
import { commentRingShadow } from "../../../../../../../utils/markerUtils";
|
|
31
32
|
import { Avatar } from "../../../../../../ui/Avatar";
|
|
32
33
|
import Comment from "../../../../../../ui/Comments/Comment";
|
|
33
34
|
import { UserAvatar } from "../../../../../../ui/UserAvatar";
|
|
34
35
|
import { extractCoordinatesFromFeature } from "../../../../utils/extractCoordinates";
|
|
35
36
|
import { MapLayerClickPriority } from "../../../../utils/MapEventManager/MapClickManager";
|
|
36
37
|
import { createClusterLayer, createClusterCountLayer, createUnclusteredPointLayer } from "../mapLayersUtils";
|
|
37
|
-
const CommentAvatarMarker = ({ feature, isHighlighted, onMouseEnter, onMouseLeave }) => {
|
|
38
|
+
const CommentAvatarMarker = ({ feature, isHighlighted, isFocused, onMouseEnter, onMouseLeave, onClick, onDoubleClick, center, offset }) => {
|
|
38
39
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
39
40
|
const authorId = (_a = feature.properties) == null ? void 0 : _a.authorId;
|
|
40
41
|
const { user: author } = useUser(authorId != null ? String(authorId) : "");
|
|
41
42
|
const userName = (_b = feature.properties) == null ? void 0 : _b.authorName;
|
|
42
43
|
const userImageFileId = (_c = feature.properties) == null ? void 0 : _c.imageFileId;
|
|
43
44
|
const resolvedImageFileId = (_e = (_d = author == null ? void 0 : author.imageFileId) != null ? _d : userImageFileId) != null ? _e : null;
|
|
44
|
-
const coords = extractCoordinatesFromFeature(feature);
|
|
45
|
+
const coords = center ? { lng: center[0], lat: center[1] } : extractCoordinatesFromFeature(feature);
|
|
45
46
|
if (!coords) return null;
|
|
46
|
-
|
|
47
|
+
const scale = isFocused ? 1.25 : isHighlighted ? 1.2 : 1;
|
|
48
|
+
return /* @__PURE__ */ jsx(Marker, { longitude: coords.lng, latitude: coords.lat, anchor: "center", offset, children: /* @__PURE__ */ jsx(
|
|
47
49
|
"div",
|
|
48
50
|
{
|
|
51
|
+
title: onDoubleClick ? "Double click to zoom" : void 0,
|
|
49
52
|
style: {
|
|
50
53
|
width: "36px",
|
|
51
54
|
height: "36px",
|
|
52
55
|
borderRadius: "50%",
|
|
53
|
-
boxShadow:
|
|
56
|
+
boxShadow: commentRingShadow({ highlight: isHighlighted, focused: isFocused }),
|
|
54
57
|
transition: "all 0.2s ease-in-out",
|
|
55
|
-
transform:
|
|
56
|
-
overflow: "hidden"
|
|
58
|
+
transform: `scale(${scale})`,
|
|
59
|
+
overflow: "hidden",
|
|
60
|
+
cursor: onClick || onDoubleClick ? "pointer" : void 0
|
|
57
61
|
},
|
|
58
62
|
onMouseEnter,
|
|
59
63
|
onMouseLeave,
|
|
64
|
+
onClick,
|
|
65
|
+
onDoubleClick,
|
|
60
66
|
children: /* @__PURE__ */ jsx(Avatar, { className: "h-full w-full", children: /* @__PURE__ */ jsx(
|
|
61
67
|
UserAvatar,
|
|
62
68
|
{
|
|
@@ -69,7 +75,7 @@ const CommentAvatarMarker = ({ feature, isHighlighted, onMouseEnter, onMouseLeav
|
|
|
69
75
|
) }, String((_g = (_f = feature.properties) == null ? void 0 : _f.id) != null ? _g : `${coords.lng},${coords.lat}`));
|
|
70
76
|
};
|
|
71
77
|
const CommentLayer = () => {
|
|
72
|
-
var _a
|
|
78
|
+
var _a;
|
|
73
79
|
const [hoveredCommentId, setHoveredCommentId] = React.useState(null);
|
|
74
80
|
const clusterLayer = createClusterLayer("comments");
|
|
75
81
|
const clusterCountLayer = createClusterCountLayer("comments");
|
|
@@ -82,22 +88,87 @@ const CommentLayer = () => {
|
|
|
82
88
|
const user = (_a = useSession().data) == null ? void 0 : _a.user;
|
|
83
89
|
const [popupInfo, setPopUpInfo] = React.useState(null);
|
|
84
90
|
const { user: popupAuthor } = useUser((popupInfo == null ? void 0 : popupInfo.authorId) != null ? String(popupInfo.authorId) : "");
|
|
85
|
-
const {
|
|
86
|
-
const { state: menusState } = React.useContext(MenusContext);
|
|
87
|
-
const { commentsVisibleInViewer, currentCommentId } = menusState.menus;
|
|
91
|
+
const { deleteComments } = useDeleteComments();
|
|
92
|
+
const { state: menusState, dispatch: menusDispatch, setIsSidebarOpen } = React.useContext(MenusContext);
|
|
93
|
+
const { commentsVisibleInViewer, currentCommentId, focusedCommentId, focusRequestId } = menusState.menus;
|
|
94
|
+
const focusComment = React.useCallback((commentId) => {
|
|
95
|
+
if (commentId == null) return;
|
|
96
|
+
menusDispatch({ type: "SET_CURRENT_COMMENT_ID", payload: { commentId } });
|
|
97
|
+
menusDispatch({ type: "SET_FOCUSED_COMMENT_ID", payload: { commentId } });
|
|
98
|
+
}, [menusDispatch]);
|
|
99
|
+
const requestSidebarAction = React.useCallback((commentId, action) => {
|
|
100
|
+
if (commentId == null) return;
|
|
101
|
+
setIsSidebarOpen(true);
|
|
102
|
+
menusDispatch({ type: "SET_SIDEBAR_SELECTED_TAB", payload: { selectedTab: "communication" } });
|
|
103
|
+
menusDispatch({ type: "SET_CURRENT_COMMENT_ID", payload: { commentId } });
|
|
104
|
+
menusDispatch({ type: "REQUEST_COMMENT_ACTION", payload: { commentId, action } });
|
|
105
|
+
}, [menusDispatch, setIsSidebarOpen]);
|
|
106
|
+
const [spider, setSpider] = React.useState(null);
|
|
107
|
+
const spiderCloseTimer = React.useRef(null);
|
|
108
|
+
const cancelSpiderClose = React.useCallback(() => {
|
|
109
|
+
if (spiderCloseTimer.current) {
|
|
110
|
+
clearTimeout(spiderCloseTimer.current);
|
|
111
|
+
spiderCloseTimer.current = null;
|
|
112
|
+
}
|
|
113
|
+
}, []);
|
|
114
|
+
const scheduleSpiderClose = React.useCallback(() => {
|
|
115
|
+
cancelSpiderClose();
|
|
116
|
+
spiderCloseTimer.current = setTimeout(() => setSpider(null), 150);
|
|
117
|
+
}, [cancelSpiderClose]);
|
|
118
|
+
const openPopupFromFeature = React.useCallback((feature) => {
|
|
119
|
+
var _a2, _b;
|
|
120
|
+
if (!feature || feature.properties.point_count) return;
|
|
121
|
+
if (feature.geometry.type !== "Point") return;
|
|
122
|
+
const [longitude, latitude] = feature.geometry.coordinates;
|
|
123
|
+
const p = feature.properties;
|
|
124
|
+
setPopUpInfo({
|
|
125
|
+
id: Number(p.id),
|
|
126
|
+
authorId: Number(p.authorId),
|
|
127
|
+
organizationId: (_a2 = feature.properties) == null ? void 0 : _a2.organizationId,
|
|
128
|
+
visible: (_b = feature.properties) == null ? void 0 : _b.visible,
|
|
129
|
+
longitude,
|
|
130
|
+
latitude,
|
|
131
|
+
text: p.text,
|
|
132
|
+
createdAt: p.createdAt,
|
|
133
|
+
authorName: p.authorName,
|
|
134
|
+
imageFileId: p.imageFileId,
|
|
135
|
+
viewer: ViewerNames.map
|
|
136
|
+
});
|
|
137
|
+
}, []);
|
|
88
138
|
const eligibleComments = comments.filter((comment) => comment.viewer === ViewerNames.map).map((comment) => {
|
|
89
|
-
var _a2,
|
|
139
|
+
var _a2, _b;
|
|
90
140
|
const user2 = users.find((u) => u.id === comment.authorId);
|
|
91
141
|
return __spreadProps(__spreadValues({}, comment), {
|
|
92
142
|
authorName: (_a2 = user2 == null ? void 0 : user2.name) != null ? _a2 : "Unknown User",
|
|
93
|
-
imageFileId: (
|
|
143
|
+
imageFileId: (_b = user2 == null ? void 0 : user2.imageFileId) != null ? _b : null
|
|
94
144
|
});
|
|
95
145
|
});
|
|
146
|
+
const eligibleCommentsRef = React.useRef(eligibleComments);
|
|
147
|
+
eligibleCommentsRef.current = eligibleComments;
|
|
96
148
|
React.useEffect(() => {
|
|
97
149
|
if (popupInfo && !comments.find((c) => c.id === popupInfo.id)) {
|
|
98
150
|
setPopUpInfo(null);
|
|
99
151
|
}
|
|
100
152
|
}, [comments, popupInfo]);
|
|
153
|
+
React.useEffect(() => {
|
|
154
|
+
if (focusedCommentId == null || !map) return;
|
|
155
|
+
const target = eligibleCommentsRef.current.find((c) => c.id === focusedCommentId);
|
|
156
|
+
if (!target || target.longitude == null || target.latitude == null) return;
|
|
157
|
+
map.flyTo({ center: [target.longitude, target.latitude], zoom: Math.max(map.getZoom(), 17), duration: 800 });
|
|
158
|
+
setPopUpInfo({
|
|
159
|
+
id: target.id,
|
|
160
|
+
authorId: target.authorId,
|
|
161
|
+
organizationId: target.organizationId,
|
|
162
|
+
visible: target.visible,
|
|
163
|
+
longitude: target.longitude,
|
|
164
|
+
latitude: target.latitude,
|
|
165
|
+
text: target.text,
|
|
166
|
+
createdAt: target.createdAt,
|
|
167
|
+
authorName: target.authorName,
|
|
168
|
+
imageFileId: target.imageFileId,
|
|
169
|
+
viewer: ViewerNames.map
|
|
170
|
+
});
|
|
171
|
+
}, [focusRequestId, map]);
|
|
101
172
|
const geojsonCommentData = React.useMemo(() => {
|
|
102
173
|
const convertDataToGeojson = (commentData) => {
|
|
103
174
|
const commentFeatures = commentData.map((comment) => {
|
|
@@ -134,26 +205,7 @@ const CommentLayer = () => {
|
|
|
134
205
|
React.useEffect(() => {
|
|
135
206
|
if (!map) return;
|
|
136
207
|
const showCommentPopUp = (e, features) => {
|
|
137
|
-
|
|
138
|
-
const feature = features == null ? void 0 : features[0];
|
|
139
|
-
if (!feature || feature.properties.point_count) return;
|
|
140
|
-
if (feature.geometry.type != "Point") return;
|
|
141
|
-
const [longitude, latitude] = feature.geometry.coordinates;
|
|
142
|
-
const featureProperties = feature.properties;
|
|
143
|
-
const { id, authorId, text, createdAt, authorName, imageFileId } = featureProperties;
|
|
144
|
-
setPopUpInfo({
|
|
145
|
-
id: Number(id),
|
|
146
|
-
authorId: Number(authorId),
|
|
147
|
-
organizationId: (_a2 = feature.properties) == null ? void 0 : _a2.organizationId,
|
|
148
|
-
visible: (_b2 = feature.properties) == null ? void 0 : _b2.visible,
|
|
149
|
-
longitude,
|
|
150
|
-
latitude,
|
|
151
|
-
text,
|
|
152
|
-
createdAt,
|
|
153
|
-
authorName,
|
|
154
|
-
imageFileId,
|
|
155
|
-
viewer: ViewerNames.map
|
|
156
|
-
});
|
|
208
|
+
openPopupFromFeature(features == null ? void 0 : features[0]);
|
|
157
209
|
};
|
|
158
210
|
const mouseEnterChangeCursor = () => {
|
|
159
211
|
map.getCanvas().style.cursor = "pointer";
|
|
@@ -169,12 +221,25 @@ const CommentLayer = () => {
|
|
|
169
221
|
map.off("mouseenter", "comments-unclustered-points", mouseEnterChangeCursor);
|
|
170
222
|
map.off("mouseleave", "comments-unclustered-points", mouseLeaveChangeCursor);
|
|
171
223
|
};
|
|
172
|
-
}, [map, mapClickManager]);
|
|
224
|
+
}, [map, mapClickManager, openPopupFromFeature]);
|
|
173
225
|
const handleRemoveComment = () => {
|
|
226
|
+
if ((popupInfo == null ? void 0 : popupInfo.id) == null) return;
|
|
174
227
|
toast.success(t("commentDeleted"));
|
|
175
|
-
|
|
228
|
+
const id = popupInfo.id;
|
|
229
|
+
const replyIds = comments.filter((c) => c.replyToId === id).map((c) => c.id);
|
|
230
|
+
void deleteComments({ ids: [id, ...replyIds] });
|
|
176
231
|
setPopUpInfo(null);
|
|
177
232
|
};
|
|
233
|
+
React.useEffect(() => {
|
|
234
|
+
if (!map) return;
|
|
235
|
+
const close = () => setSpider(null);
|
|
236
|
+
map.on("movestart", close);
|
|
237
|
+
map.on("zoomstart", close);
|
|
238
|
+
return () => {
|
|
239
|
+
map.off("movestart", close);
|
|
240
|
+
map.off("zoomstart", close);
|
|
241
|
+
};
|
|
242
|
+
}, [map]);
|
|
178
243
|
React.useEffect(() => {
|
|
179
244
|
if (!map) return;
|
|
180
245
|
const zoomInToDecluster = (e) => {
|
|
@@ -185,34 +250,45 @@ const CommentLayer = () => {
|
|
|
185
250
|
if (!("coordinates" in feature.geometry)) return;
|
|
186
251
|
const [lng, lat] = feature.geometry.coordinates;
|
|
187
252
|
const source = map.getSource("comments");
|
|
188
|
-
console.log(source);
|
|
189
|
-
console.log(clusterId);
|
|
190
253
|
source.getClusterExpansionZoom(clusterId).then(
|
|
191
254
|
(zoom) => {
|
|
192
|
-
console.log("easing to");
|
|
193
255
|
map.easeTo({ center: [lng, lat], zoom });
|
|
194
256
|
}
|
|
195
257
|
).catch((error) => {
|
|
196
258
|
console.error(error);
|
|
197
259
|
});
|
|
198
260
|
};
|
|
199
|
-
const
|
|
261
|
+
const expandClusterOnHover = (e) => {
|
|
262
|
+
var _a2;
|
|
200
263
|
map.getCanvas().style.cursor = "pointer";
|
|
264
|
+
const feature = (_a2 = e.features) == null ? void 0 : _a2[0];
|
|
265
|
+
if (!feature || !feature.properties.cluster_id) return;
|
|
266
|
+
if (!("coordinates" in feature.geometry)) return;
|
|
267
|
+
const center = feature.geometry.coordinates;
|
|
268
|
+
const clusterId = feature.properties.cluster_id;
|
|
269
|
+
const source = map.getSource("comments");
|
|
270
|
+
source.getClusterLeaves(clusterId, Infinity, 0).then((leaves) => {
|
|
271
|
+
cancelSpiderClose();
|
|
272
|
+
setSpider({ center, features: leaves });
|
|
273
|
+
}).catch((error) => {
|
|
274
|
+
console.error(error);
|
|
275
|
+
});
|
|
201
276
|
};
|
|
202
|
-
const
|
|
277
|
+
const mouseLeaveCluster = () => {
|
|
203
278
|
map.getCanvas().style.cursor = "";
|
|
279
|
+
scheduleSpiderClose();
|
|
204
280
|
};
|
|
205
281
|
map.on("click", "comments-clusters", zoomInToDecluster);
|
|
206
|
-
map.on("mouseenter", "comments-clusters",
|
|
207
|
-
map.on("mouseleave", "comments-clusters",
|
|
282
|
+
map.on("mouseenter", "comments-clusters", expandClusterOnHover);
|
|
283
|
+
map.on("mouseleave", "comments-clusters", mouseLeaveCluster);
|
|
208
284
|
return () => {
|
|
209
285
|
map.off("click", "comments-clusters", zoomInToDecluster);
|
|
210
|
-
map.off("mouseenter", "comments-clusters",
|
|
211
|
-
map.off("mouseleave", "comments-clusters",
|
|
286
|
+
map.off("mouseenter", "comments-clusters", expandClusterOnHover);
|
|
287
|
+
map.off("mouseleave", "comments-clusters", mouseLeaveCluster);
|
|
212
288
|
};
|
|
213
|
-
}, [map]);
|
|
289
|
+
}, [map, cancelSpiderClose, scheduleSpiderClose]);
|
|
214
290
|
const renderPopup = () => {
|
|
215
|
-
var _a2,
|
|
291
|
+
var _a2, _b, _c, _d;
|
|
216
292
|
if (!popupInfo) return null;
|
|
217
293
|
return /* @__PURE__ */ jsxs(
|
|
218
294
|
Popup,
|
|
@@ -230,11 +306,16 @@ const CommentLayer = () => {
|
|
|
230
306
|
Comment,
|
|
231
307
|
{
|
|
232
308
|
userName: popupInfo.authorName || "",
|
|
233
|
-
userImage: (
|
|
309
|
+
userImage: (_b = (_a2 = popupAuthor == null ? void 0 : popupAuthor.imageFileId) != null ? _a2 : popupInfo.imageFileId) != null ? _b : null,
|
|
234
310
|
userImageFileId: (_d = (_c = popupAuthor == null ? void 0 : popupAuthor.imageFileId) != null ? _c : popupInfo.imageFileId) != null ? _d : null,
|
|
235
311
|
text: popupInfo.text,
|
|
236
312
|
createdAt: popupInfo.createdAt,
|
|
237
|
-
|
|
313
|
+
showActions: true,
|
|
314
|
+
canEdit: user.id === String(popupInfo.authorId),
|
|
315
|
+
canDelete: user.id === String(popupInfo.authorId),
|
|
316
|
+
onEdit: user.id === String(popupInfo.authorId) ? () => requestSidebarAction(popupInfo.id, "edit") : void 0,
|
|
317
|
+
onReply: () => requestSidebarAction(popupInfo.id, "reply"),
|
|
318
|
+
onRemove: user.id === String(popupInfo.authorId) ? handleRemoveComment : void 0,
|
|
238
319
|
onClose: () => setPopUpInfo(null)
|
|
239
320
|
}
|
|
240
321
|
),
|
|
@@ -259,8 +340,8 @@ const CommentLayer = () => {
|
|
|
259
340
|
const allFeatures = map.querySourceFeatures("comments");
|
|
260
341
|
const unclusteredOnly = allFeatures.filter(
|
|
261
342
|
(f) => {
|
|
262
|
-
var _a2,
|
|
263
|
-
return !((_a2 = f.properties) == null ? void 0 : _a2.cluster) && !((
|
|
343
|
+
var _a2, _b;
|
|
344
|
+
return !((_a2 = f.properties) == null ? void 0 : _a2.cluster) && !((_b = f.properties) == null ? void 0 : _b.point_count);
|
|
264
345
|
}
|
|
265
346
|
);
|
|
266
347
|
const uniqueFeatures = /* @__PURE__ */ new Map();
|
|
@@ -298,20 +379,60 @@ const CommentLayer = () => {
|
|
|
298
379
|
var _a2;
|
|
299
380
|
return ((_a2 = feature.properties) == null ? void 0 : _a2.id) !== (popupInfo == null ? void 0 : popupInfo.id);
|
|
300
381
|
}).map((feature) => {
|
|
301
|
-
var _a2,
|
|
382
|
+
var _a2, _b, _c, _d;
|
|
302
383
|
return /* @__PURE__ */ jsx(
|
|
303
384
|
CommentAvatarMarker,
|
|
304
385
|
{
|
|
305
386
|
feature,
|
|
306
|
-
isHighlighted: currentCommentId === ((
|
|
387
|
+
isHighlighted: currentCommentId === ((_b = feature.properties) == null ? void 0 : _b.id) || hoveredCommentId === ((_c = feature.properties) == null ? void 0 : _c.id),
|
|
388
|
+
isFocused: focusedCommentId === ((_d = feature.properties) == null ? void 0 : _d.id),
|
|
307
389
|
onMouseEnter: () => {
|
|
308
390
|
var _a3;
|
|
309
391
|
return setHoveredCommentId((_a3 = feature.properties) == null ? void 0 : _a3.id);
|
|
310
392
|
},
|
|
311
|
-
onMouseLeave: () => setHoveredCommentId(null)
|
|
393
|
+
onMouseLeave: () => setHoveredCommentId(null),
|
|
394
|
+
onDoubleClick: () => {
|
|
395
|
+
var _a3;
|
|
396
|
+
return focusComment((_a3 = feature.properties) == null ? void 0 : _a3.id);
|
|
397
|
+
}
|
|
312
398
|
},
|
|
313
399
|
String((_a2 = feature.properties) == null ? void 0 : _a2.id)
|
|
314
400
|
);
|
|
401
|
+
}),
|
|
402
|
+
spider && spider.features.map((feature, i) => {
|
|
403
|
+
var _a2;
|
|
404
|
+
const n = spider.features.length;
|
|
405
|
+
const angle = 2 * Math.PI * i / n - Math.PI / 2;
|
|
406
|
+
const radius = Math.min(60, 24 + n * 4);
|
|
407
|
+
const offset = [Math.cos(angle) * radius, Math.sin(angle) * radius];
|
|
408
|
+
const id = (_a2 = feature.properties) == null ? void 0 : _a2.id;
|
|
409
|
+
return /* @__PURE__ */ jsx(
|
|
410
|
+
CommentAvatarMarker,
|
|
411
|
+
{
|
|
412
|
+
feature,
|
|
413
|
+
center: spider.center,
|
|
414
|
+
offset,
|
|
415
|
+
isHighlighted: currentCommentId === id || hoveredCommentId === id,
|
|
416
|
+
isFocused: focusedCommentId === id,
|
|
417
|
+
onMouseEnter: () => {
|
|
418
|
+
cancelSpiderClose();
|
|
419
|
+
setHoveredCommentId(id);
|
|
420
|
+
},
|
|
421
|
+
onMouseLeave: () => {
|
|
422
|
+
scheduleSpiderClose();
|
|
423
|
+
setHoveredCommentId(null);
|
|
424
|
+
},
|
|
425
|
+
onClick: () => {
|
|
426
|
+
openPopupFromFeature(feature);
|
|
427
|
+
setSpider(null);
|
|
428
|
+
},
|
|
429
|
+
onDoubleClick: () => {
|
|
430
|
+
focusComment(id);
|
|
431
|
+
setSpider(null);
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
`spider-${String(id)}`
|
|
435
|
+
);
|
|
315
436
|
})
|
|
316
437
|
]
|
|
317
438
|
}
|