diff --git a/frontend/src/components/projectDetail/index.js b/frontend/src/components/projectDetail/index.js index 47068b8c3f..71f43535a5 100644 --- a/frontend/src/components/projectDetail/index.js +++ b/frontend/src/components/projectDetail/index.js @@ -23,7 +23,8 @@ import { ProjectInfoPanel } from './infoPanel'; import { OSMChaButton } from './osmchaButton'; import { LiveViewButton } from './liveViewButton'; import { useSetProjectPageTitleTag } from '../../hooks/UseMetaTags'; -import { useProjectContributionsQuery, useProjectTimelineQuery, useAvailableCountriesQuery } from '../../api/projects'; +import useHasLiveMonitoringFeature from '../../hooks/UseHasLiveMonitoringFeature'; +import { useProjectContributionsQuery, useProjectTimelineQuery } from '../../api/projects'; import { Alert } from '../alert'; import './styles.scss'; @@ -145,6 +146,8 @@ export const ProjectDetail = (props) => { props.project.projectId, ); + const hasLiveMonitoringFeature = useHasLiveMonitoringFeature(); + const htmlDescription = props.project.projectInfo && htmlFromMarkdown(props.project.projectInfo.description); const h2Classes = 'pl4 f3 f2-ns fw5 mt2 mb3 mb4-ns ttu barlow-condensed blue-dark'; @@ -154,16 +157,6 @@ export const ProjectDetail = (props) => { ); - const { data } = useAvailableCountriesQuery(); - - // check if the project has live monitoring feature enabled - // based on the country list provided by available.json - const hasLiveMonitoringFeature = !data - ? false - : props.project.countryTag.some((country) => - data.countries.some((item) => country.toLowerCase() === item.toLowerCase()), - ); - return (
@@ -358,11 +351,8 @@ export const ProjectDetail = (props) => { className="bg-white blue-dark ba b--grey-light pa3" /> - {/* - show live view button only for published projects & - when the project has live monitoring feature - */} - {props.project.status === 'PUBLISHED' && hasLiveMonitoringFeature && ( + {/* show live view button only when the project has live monitoring feature */} + {hasLiveMonitoringFeature && ( state.auth.userDetails); + const [hasLiveMonitoringFeature, setHasLiveMonitoringFeature] = useState(null); + + const { data: project } = useProjectQuery(projectId); + const { data: availableCountries } = useAvailableCountriesQuery(); + + useEffect(() => { + if (!availableCountries || !project || !userDetails) return; + + // set hasLiveMonitoringFeature to false if project is not published + // or expert mode is not enabled + if (project.data.status !== 'PUBLISHED' || !userDetails.isExpert) { + setHasLiveMonitoringFeature(false); + return; + } + + // check if the project has live monitoring feature enabled + // based on the country list provided by available.json + const isLiveMonitoringAvailableInCountry = project.data.countryTag.some((country) => + availableCountries.countries.some((item) => country.toLowerCase() === item.toLowerCase()), + ); + + setHasLiveMonitoringFeature(isLiveMonitoringAvailableInCountry); + }, [availableCountries, project, userDetails]); + + return hasLiveMonitoringFeature; +} diff --git a/frontend/src/views/projectLiveMonitoring.js b/frontend/src/views/projectLiveMonitoring.js index 188ef00a4e..4a1647391d 100644 --- a/frontend/src/views/projectLiveMonitoring.js +++ b/frontend/src/views/projectLiveMonitoring.js @@ -1,6 +1,8 @@ import React, { useState, useRef, useEffect } from 'react'; import ReactPlaceholder from 'react-placeholder'; import Select from 'react-select'; +import { useNavigate, useParams, Link } from 'react-router-dom'; +import { useDispatch } from 'react-redux'; import centroid from '@turf/centroid'; import { UnderpassFeatureList, @@ -9,95 +11,34 @@ import { UnderpassFeatureStats, UnderpassValidationStats, } from '@hotosm/underpass-ui'; -import { Link } from 'react-router-dom'; -import { useDispatch } from 'react-redux'; import { ProjectVisibilityBox } from '../components/projectDetail/visibilityBox'; import { ProjectStatusBox } from '../components/projectDetail/statusBox'; import { useSetTitleTag } from '../hooks/UseMetaTags'; -import { useParams } from 'react-router-dom'; import { useFetch } from '../hooks/UseFetch'; +import useHasLiveMonitoringFeature from '../hooks/UseHasLiveMonitoringFeature'; +import { + underpassConfig, + availableImageryOptions, + statusList, + mappingTypesTags, + mappingTypesFeatureTypes, +} from '../config/underpass'; import './projectLiveMonitoring.css'; -import { MAPBOX_TOKEN, UNDERPASS_URL } from '../config'; - -const availableImageryOptions = [ - { label: 'OSM', value: 'osm' }, - { label: 'Bing', value: 'Bing' }, - { label: 'Mapbox Satellite', value: 'Mapbox' }, - { label: 'ESRI World Imagery', value: 'EsriWorldImagery' }, -]; const availableImageryValues = availableImageryOptions.map((item) => item.value); -const config = { - API_URL: UNDERPASS_URL, - MAPBOX_TOKEN: MAPBOX_TOKEN, - // set default sources of Tasking Manager - sources: { - osm: { - type: 'raster', - tiles: ['https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'], - tileSize: 256, - attribution: '© OpenStreetMap Contributors', - maxzoom: 19, - }, - Bing: { - type: 'raster', - tiles: ['https://ecn.t3.tiles.virtualearth.net/tiles/a{quadkey}.jpeg?g=1'], - tileSize: 256, - attribution: '© OpenStreetMap Contributors', - maxzoom: 18, - }, - Mapbox: { - type: 'raster', - tiles: [ - `https://api.mapbox.com/styles/v1/mapbox/satellite-v9/tiles/{z}/{x}/{y}?access_token=${MAPBOX_TOKEN}`, - ], - tileSize: 512, - attribution: '© OpenStreetMap Contributors © Mapbox', - maxzoom: 19, - }, - EsriWorldImagery: { - type: 'raster', - tiles: [ - 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', - ], - tileSize: 256, - attribution: '© OpenStreetMap Contributors © ESRI', - maxzoom: 18, - }, - }, -}; - -const statusList = { - ALL: '', - UNSQUARED: 'badgeom', - OVERLAPPING: 'overlapping', - BADVALUE: 'badvalue', -}; - -const mappingTypesTags = { - ROADS: 'highway', - BUILDINGS: 'building', - WATERWAYS: 'waterway', -}; - -const mappingTypesFeatureTypes = { - ROADS: 'line', - BUILDINGS: 'polygon', - WATERWAYS: 'line', -}; - export function ProjectLiveMonitoring() { const { id } = useParams(); const dispatch = useDispatch(); + const navigate = useNavigate(); const [coords, setCoords] = useState([0, 0]); const [activeFeature, setActiveFeature] = useState(null); const [tags, setTags] = useState('building'); const [featureType, setFeatureType] = useState('polygon'); const [mapSource, setMapSource] = useState('osm'); const [imageryOptions, setImageryOptions] = useState(availableImageryOptions); - const [mapConfig, setMapConfig] = useState(config); + const [mapConfig, setMapConfig] = useState(underpassConfig); const [realtimeList, setRealtimeList] = useState(false); const [realtimeMap, setRealtimeMap] = useState(false); const [listAll, setListAll] = useState(false); @@ -113,6 +54,15 @@ export function ProjectLiveMonitoring() { const [areaOfInterest, setAreaOfInterest] = useState(null); const [project, setProject] = useState(null); + const hasLiveMonitoringFeature = useHasLiveMonitoringFeature(); + + // navigate to homepage when a project without live monitoring feature + // is accessed directly from the route + useEffect(() => { + if (hasLiveMonitoringFeature === null || hasLiveMonitoringFeature) return; + navigate('/'); + }, [navigate, hasLiveMonitoringFeature]); + useEffect(() => { if (!Object.keys(data).length) return; setProject(data); @@ -322,14 +272,14 @@ export function ProjectLiveMonitoring() { tags={tags} hashtag={'hotosm-project-' + id} featureType={featureType} - apiUrl={config.API_URL} + apiUrl={underpassConfig.API_URL} area={areaOfInterest} /> @@ -382,7 +332,7 @@ export function ProjectLiveMonitoring() { setActiveFeature({ properties: { tags, status }, ...feature }); }} realtime={realtimeList} - config={config} + config={underpassConfig} status={listAll ? '' : status} orderBy="created_at" onFetchFirstTime={(mostRecentFeature) => {