diff --git a/App.tsx b/App.tsx index 8955ba7f..b8e152d3 100644 --- a/App.tsx +++ b/App.tsx @@ -424,11 +424,15 @@ const BaseApp: React.FunctionComponent<{ filter: (url: string) => url.includes('/observations/'), // Only handle observation links config: { screens: { - Observations: { + MainStack: { path: 'observations/#/view/observations', screens: { - observationsList: '', - observation: ':id', + bottomTabs: { + screens: { + Observations: '', + }, + }, + observationModal: ':id', }, }, }, diff --git a/components/observations/ObservationDetailView.tsx b/components/observations/ObservationDetailView.tsx index 05de6649..4ae96bb6 100644 --- a/components/observations/ObservationDetailView.tsx +++ b/components/observations/ObservationDetailView.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useMemo} from 'react'; -import {Image, ScrollView, StyleSheet} from 'react-native'; +import {Image, ScrollView} from 'react-native'; import Ionicons from '@expo/vector-icons/Ionicons'; import {useFocusEffect, useNavigation} from '@react-navigation/native'; @@ -46,7 +46,6 @@ import { FormatSnowAvailableForTransport, FormatWindLoading, InstabilityDistribution, - MapLayerFeature, Observation, Position, SnowAvailableForTransport, @@ -56,6 +55,7 @@ import { } from 'types/nationalAvalancheCenter'; import {observationDateToLocalShortDateString, utcDateToLocalShortDateString} from 'utils/date'; +// TODO: Remove NWACObs issue:1152 export const NWACObservationDetailView: React.FunctionComponent<{ id: string; }> = ({id}) => { @@ -66,13 +66,11 @@ export const NWACObservationDetailView: React.FunctionComponent<{ const capabilitiesResult = useAvalancheCenterCapabilities(); const capabilities = capabilitiesResult.data; - const mapFeatures = useMemo(() => mapFeaturesForCenter(mapLayer, observation?.center_id.toUpperCase() as AvalancheCenterID), [mapLayer, observation]); - if (incompleteQueryState(observationResult, mapResult, capabilitiesResult) || !observation || !mapLayer || !capabilities) { return ; } - return ; + return ; }; export const ObservationDetailView: React.FunctionComponent<{ @@ -86,12 +84,23 @@ export const ObservationDetailView: React.FunctionComponent<{ const capabilities = capabilitiesResult.data; const mapFeatures = useMemo(() => mapFeaturesForCenter(mapLayer, observation?.center_id.toUpperCase() as AvalancheCenterID), [mapLayer, observation?.center_id]); + const navigation = useNavigation(); + const zone_name = useMemo( + () => observation?.location_point?.lat && observation?.location_point?.lng && matchesZone(mapFeatures ?? [], observation.location_point?.lat, observation.location_point?.lng), + [observation, mapFeatures], + ); + + React.useEffect(() => { + if (zone_name) { + navigation.setOptions({title: `${zone_name} Observation`}); + } + }, [navigation, zone_name]); if (incompleteQueryState(observationResult, mapResult, capabilitiesResult) || !observation || !mapLayer || !capabilities || !capabilities) { return ; } - return ; + return ; }; const dataTableFlex = [1, 1]; @@ -177,18 +186,10 @@ export const withUnits = (value: string | number | null | undefined, units: stri export const ObservationCard: React.FunctionComponent<{ observation: Observation; - mapLayerFeatures: MapLayerFeature[]; capabilities: AllAvalancheCenterCapabilities; -}> = ({observation, mapLayerFeatures, capabilities}) => { - const navigation = useNavigation(); +}> = ({observation, capabilities}) => { const {avalanches_observed, avalanches_triggered, avalanches_caught} = observation.instability; - const zone_name = - observation.location_point?.lat && observation.location_point?.lng && matchesZone(mapLayerFeatures, observation.location_point?.lat, observation.location_point?.lng); - React.useEffect(() => { - if (zone_name) { - navigation.setOptions({title: `${zone_name} Observation`}); - } - }, [navigation, zone_name]); + const postHog = usePostHog(); const recordAnalytics = useCallback(() => { @@ -208,7 +209,7 @@ export const ObservationCard: React.FunctionComponent<{ const initialCameraBounds: CameraBounds = {ne: nePosition, sw: swPosition}; return ( - + diff --git a/components/observations/ObservationDetailViewModal.tsx b/components/observations/ObservationDetailViewModal.tsx new file mode 100644 index 00000000..ba3f8547 --- /dev/null +++ b/components/observations/ObservationDetailViewModal.tsx @@ -0,0 +1,76 @@ +import Ionicons from '@expo/vector-icons/Ionicons'; +import {useNavigation} from '@react-navigation/native'; +import {AvalancheCenterLogo} from 'components/AvalancheCenterLogo'; +import {incompleteQueryState, QueryState} from 'components/content/QueryState'; +import {HStack, View} from 'components/core'; +import {ObservationCard} from 'components/observations/ObservationDetailView'; +import {matchesZone} from 'components/observations/ObservationsFilterForm'; +import {Title3Black} from 'components/text'; +import {useAllMapLayers} from 'hooks/useAllMapLayers'; +import {useAvalancheCenterCapabilities} from 'hooks/useAvalancheCenterCapabilities'; +import {useNACObservation} from 'hooks/useNACObservation'; +import React, {useCallback, useMemo} from 'react'; +import {MainStackNavigationProps} from 'routes'; +import {colorLookup} from 'theme'; +import {AvalancheCenterID, mapFeaturesForCenter} from 'types/nationalAvalancheCenter'; + +export const ObservationDetailModalView: React.FunctionComponent<{ + id: string; +}> = ({id}) => { + const observationResult = useNACObservation(id); + const observation = observationResult.data; + const mapResult = useAllMapLayers(); + const mapLayer = mapResult.data; + const capabilitiesResult = useAvalancheCenterCapabilities(); + const capabilities = capabilitiesResult.data; + + const mapFeatures = useMemo(() => mapFeaturesForCenter(mapLayer, observation?.center_id.toUpperCase() as AvalancheCenterID), [mapLayer, observation?.center_id]); + const navigation = useNavigation(); + const zone_name = useMemo( + () => observation?.location_point?.lat && observation?.location_point?.lng && matchesZone(mapFeatures ?? [], observation.location_point?.lat, observation.location_point?.lng), + [observation, mapFeatures], + ); + + const closeModal = useCallback(() => navigation.goBack(), [navigation]); + + if (incompleteQueryState(observationResult, mapResult, capabilitiesResult) || !observation || !mapLayer || !capabilities || !capabilities) { + return ; + } + + return ( + + + + + ); +}; + +interface ObsDetailModalHeaderProps { + title: string; + centerId: AvalancheCenterID; + onClosePressed: () => void; +} + +const ObsDetailModalHeader: React.FunctionComponent = ({title, centerId, onClosePressed}) => { + return ( + + + + + + {title} + + + + + + ); +}; diff --git a/components/screens/navigation/MainStack.tsx b/components/screens/navigation/MainStack.tsx index a33e94fc..ea7923ed 100644 --- a/components/screens/navigation/MainStack.tsx +++ b/components/screens/navigation/MainStack.tsx @@ -5,6 +5,7 @@ import {NavigationHeader} from 'components/content/NavigationHeader'; import {View} from 'components/core'; import {FeatureFlagsDebuggerScreen} from 'components/FeatureFlagsDebugger'; import {NWACObservationDetailView, ObservationDetailView} from 'components/observations/ObservationDetailView'; +import {ObservationDetailModalView} from 'components/observations/ObservationDetailViewModal'; import {ObservationForm} from 'components/observations/ObservationForm'; import {ObservationsPortal} from 'components/observations/ObservationsPortal'; import {ForecastScreen} from 'components/screens/ForecastScreen'; @@ -78,6 +79,16 @@ export const MainStackNavigator: React.FunctionComponent<{ title: 'Observation', }} /> + + + { return ; }; -export const ObservationDetailScreen = ({route}: NativeStackScreenProps) => { +const ObservationDetailScreen = ({route}: NativeStackScreenProps) => { const {id} = route.params; return ( @@ -158,7 +169,17 @@ export const ObservationDetailScreen = ({route}: NativeStackScreenProps) => { +const ObservationDetailModal = ({route}: NativeStackScreenProps) => { + const {id} = route.params; + + return ( + + + + ); +}; + +const NWACObservationDetailScreen = ({route}: NativeStackScreenProps) => { const {id} = route.params; return ( @@ -169,7 +190,7 @@ export const NWACObservationDetailScreen = ({route}: NativeStackScreenProps
) => { +const WeatherStationsDetailScreen = ({route}: NativeStackScreenProps) => { const {preferences} = usePreferences(); const center_id = preferences.center; return ( @@ -182,7 +203,7 @@ export const WeatherStationsDetailScreen = ({route}: NativeStackScreenProps
) => { +const WeatherStationDetailScreen = ({route}: NativeStackScreenProps) => { const {preferences} = usePreferences(); const center_id = preferences.center; return ( diff --git a/routes.ts b/routes.ts index 006d5bdb..b0776daf 100644 --- a/routes.ts +++ b/routes.ts @@ -29,6 +29,9 @@ export type MainStackParamList = { observation: { id: string; }; + observationModal: { + id: string; + }; nwacObservation: { id: string; };