Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DO-NOT-MERGE: mapLayer: use the day query for previous layers #707

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/AvalancheForecastZoneMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export interface MapProps {

export const AvalancheForecastZoneMap: React.FunctionComponent<MapProps> = ({center, requestedTime}: MapProps) => {
const {logger} = React.useContext<LoggerProps>(LoggerContext);
const mapLayerResult = useMapLayer(center);
const mapLayerResult = useMapLayer(center, requestedTime);
const mapLayer = mapLayerResult.data;
const metadataResult = useAvalancheCenterMetadata(center);
const metadata = metadataResult.data;
Expand Down
2 changes: 1 addition & 1 deletion components/forecast/WeatherTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ export const NWACWeatherTab: React.FC<WeatherTabProps> = ({zone, center_id, requ
const metadata = avalancheCenterMetadataResult.data;
const nwacForecastResult = useNWACWeatherForecast(center_id, zone.id, requestedTime);
const nwacForecast = nwacForecastResult.data;
const mapLayerResult = useMapLayer(center_id);
const mapLayerResult = useMapLayer(center_id, requestedTime);
const mapLayer = mapLayerResult.data;
const weatherStationsResult = useWeatherStationsMetadata(center_id, metadata?.widget_config.stations?.token);
const weatherStations = weatherStationsResult.data;
Expand Down
6 changes: 4 additions & 2 deletions components/form/LocationField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,27 @@ import MapView, {LatLng, MapMarker, Region} from 'react-native-maps';
import {SafeAreaProvider, SafeAreaView} from 'react-native-safe-area-context';
import {colorLookup} from 'theme';
import {AvalancheCenterID} from 'types/nationalAvalancheCenter';
import {RequestedTime} from 'utils/date';

interface LocationFieldProps {
name: KeysMatching<ObservationFormData, LocationPoint>;
label: string;
center: AvalancheCenterID;
disabled?: boolean;
requestedTime: RequestedTime;
}

const latLngToLocationPoint = (latLng: LatLng) => ({lat: latLng.latitude, lng: latLng.longitude});
const locationPointToLatLng = (locationPoint: LocationPoint) => ({latitude: locationPoint.lat, longitude: locationPoint.lng});

export const LocationField = React.forwardRef<RNView, LocationFieldProps>(({name, label, center, disabled}, ref) => {
export const LocationField = React.forwardRef<RNView, LocationFieldProps>(({name, label, center, disabled, requestedTime}, ref) => {
const {
field,
fieldState: {error},
} = useController<ObservationFormData>({name: name});
const [modalVisible, setModalVisible] = useState(false);

const mapLayerResult = useMapLayer(center);
const mapLayerResult = useMapLayer(center, requestedTime);
const mapLayer = mapLayerResult.data;
const [initialRegion, setInitialRegion] = useState<Region>(defaultMapRegionForZones([]));
const [mapReady, setMapReady] = useState<boolean>(false);
Expand Down
9 changes: 6 additions & 3 deletions components/observations/ObservationDetailView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ import {
SnowAvailableForTransport,
WindLoading,
} from 'types/nationalAvalancheCenter';
import {pacificDateToLocalShortDateString, utcDateToLocalShortDateString, utcDateToLocalTimeString} from 'utils/date';
import {pacificDateToLocalShortDateString, parseRequestedTimeString, utcDateToLocalShortDateString, utcDateToLocalTimeString} from 'utils/date';

export const NWACObservationDetailView: React.FunctionComponent<{
id: string;
}> = ({id}) => {
const observationResult = useNWACObservation(parseInt(id));
const observation = observationResult.data;
const mapResult = useMapLayer(observation?.center_id);
const mapResult = useMapLayer(observation?.center_id, observation?.created_at ? parseRequestedTimeString(observation?.created_at) : undefined);
const mapLayer = mapResult.data;

if (incompleteQueryState(observationResult, mapResult) || !observation || !mapLayer) {
Expand All @@ -72,7 +72,10 @@ export const ObservationDetailView: React.FunctionComponent<{
}> = ({id}) => {
const observationResult = useNACObservation(id);
const observation = observationResult.data;
const mapResult = useMapLayer(observation?.center_id?.toUpperCase() as AvalancheCenterID);
const mapResult = useMapLayer(
observation?.center_id?.toUpperCase() as AvalancheCenterID,
observation?.created_at ? parseRequestedTimeString(observation?.created_at) : undefined,
);
const mapLayer = mapResult.data;

if (incompleteQueryState(observationResult, mapResult) || !observation || !mapLayer) {
Expand Down
8 changes: 4 additions & 4 deletions components/observations/ObservationsListView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import {
import {ObservationsStackNavigationProps} from 'routes';
import {colorLookup} from 'theme';
import {AvalancheCenterID, DangerLevel, MediaType, ObservationFragment, PartnerType} from 'types/nationalAvalancheCenter';
import {RequestedTime, pacificDateToLocalDateString, requestedTimeToUTCDate} from 'utils/date';
import {RequestedTime, formatRequestedTime, pacificDateToLocalDateString, requestedTimeToUTCDate} from 'utils/date';

interface ObservationsListViewItem {
id: ObservationFragment['id'];
Expand Down Expand Up @@ -70,7 +70,7 @@ export const ObservationsListView: React.FunctionComponent<ObservationsListViewP
const originalFilterConfig: ObservationFilterConfig = useMemo(() => createDefaultFilterConfig(requestedTime, additionalFilters), [requestedTime, additionalFilters]);
const [filterConfig, setFilterConfig] = useState<ObservationFilterConfig>(originalFilterConfig);
const [filterModalVisible, {set: setFilterModalVisible, on: showFilterModal}] = useToggle(false);
const mapResult = useMapLayer(center_id);
const mapResult = useMapLayer(center_id, requestedTime);
const mapLayer = mapResult.data;

const postHog = usePostHog();
Expand Down Expand Up @@ -220,8 +220,8 @@ export const ObservationsListView: React.FunctionComponent<ObservationsListViewP
);

const submit = useCallback(() => {
navigation.navigate('observationSubmit', {center_id});
}, [navigation, center_id]);
navigation.navigate('observationSubmit', {center_id: center_id, requestedTime: formatRequestedTime(requestedTime)});
}, [navigation, center_id, requestedTime]);

const [showSubmitButtonText, setShowSubmitButtonText] = useState(true);
const onScroll = useCallback(
Expand Down
5 changes: 4 additions & 1 deletion components/observations/ObservationsPortal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ export const ObservationsPortal: React.FC<{
() => navigation.navigate('observationsList', {center_id, requestedTime: formatRequestedTime(requestedTime)}),
[center_id, navigation, requestedTime],
);
const onSubmit = useCallback(() => navigation.navigate('observationSubmit', {center_id}), [center_id, navigation]);
const onSubmit = useCallback(
() => navigation.navigate('observationSubmit', {center_id: center_id, requestedTime: formatRequestedTime(requestedTime)}),
[center_id, navigation, requestedTime],
);
const postHog = usePostHog();

const recordAnalytics = useCallback(() => {
Expand Down
14 changes: 11 additions & 3 deletions components/observations/SimpleForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import Toast from 'react-native-toast-message';
import {ObservationsStackNavigationProps} from 'routes';
import {colorLookup} from 'theme';
import {AvalancheCenterID, ImageMediaItem, InstabilityDistribution, MediaType, userFacingCenterId} from 'types/nationalAvalancheCenter';
import {startOfSeasonLocalDate} from 'utils/date';
import {RequestedTime, startOfSeasonLocalDate} from 'utils/date';

const ImageListOverlay: React.FC<{index: number; onPress: (index: number) => void}> = ({index, onPress}) => {
const onPressHandler = useCallback(() => {
Expand All @@ -58,8 +58,9 @@ const ImageListOverlay: React.FC<{index: number; onPress: (index: number) => voi

export const SimpleForm: React.FC<{
center_id: AvalancheCenterID;
requestedTime: RequestedTime;
onClose?: () => void;
}> = ({center_id, onClose}) => {
}> = ({center_id, requestedTime, onClose}) => {
const metadataResult = useAvalancheCenterMetadata(center_id);
const metadata = metadataResult.data;
const navigation = useNavigation<ObservationsStackNavigationProps>();
Expand Down Expand Up @@ -458,7 +459,14 @@ export const SimpleForm: React.FC<{
}}
disabled={disableFormControls}
/>
<LocationField name="location_point" label="Latitude/Longitude" center={center_id} ref={getFieldRef('location_point')} disabled={disableFormControls} />
<LocationField
name="location_point"
label="Latitude/Longitude"
center={center_id}
ref={getFieldRef('location_point')}
disabled={disableFormControls}
requestedTime={requestedTime}
/>
</VStack>
</Card>
<Card borderRadius={0} borderColor="white" header={<Title3Semibold>Signs of instability</Title3Semibold>}>
Expand Down
4 changes: 2 additions & 2 deletions components/screens/ObservationsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ const ObservationsPortalScreen = ({route}: NativeStackScreenProps<ObservationsSt
};

const ObservationSubmitScreen = ({route}: NativeStackScreenProps<ObservationsStackParamList, 'observationSubmit'>) => {
const {center_id} = route.params;
return <SimpleForm center_id={center_id} />;
const {center_id, requestedTime} = route.params;
return <SimpleForm center_id={center_id} requestedTime={parseRequestedTimeString(requestedTime)} />;
};

const ObservationsListScreen = ({route}: NativeStackScreenProps<ObservationsStackParamList, 'observationsList'>) => {
Expand Down
4 changes: 2 additions & 2 deletions components/weather_data/NWACWeatherStationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {logger} from 'logger';
import {WeatherStackNavigationProps} from 'routes';
import {colorLookup} from 'theme';
import {MapLayer, MapLayerFeature, WeatherStationCollection, WeatherStationProperties, WeatherStationSource} from 'types/nationalAvalancheCenter';
import {RequestedTimeString} from 'utils/date';
import {parseRequestedTimeString, RequestedTimeString} from 'utils/date';

const stationGroupMapping = {
// Snoqualmie Pass
Expand Down Expand Up @@ -115,7 +115,7 @@ export const NWACStationsByZone = (mapLayer: MapLayer | undefined, stations: Wea

export const NWACStationList: React.FunctionComponent<{token: string; requestedTime: RequestedTimeString}> = ({token, requestedTime}) => {
const navigation = useNavigation<WeatherStackNavigationProps>();
const mapLayerResult = useMapLayer('NWAC');
const mapLayerResult = useMapLayer('NWAC', parseRequestedTimeString(requestedTime));
const mapLayer = mapLayerResult.data;
const weatherStationsResult = useWeatherStationsMetadata('NWAC', token);
const weatherStations = weatherStationsResult.data;
Expand Down
4 changes: 2 additions & 2 deletions components/weather_data/WeatherStationPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {usePostHog} from 'posthog-react-native';
import React, {useCallback} from 'react';
import {AvalancheCenterID} from 'types/nationalAvalancheCenter';
import {NotFoundError} from 'types/requests';
import {RequestedTimeString} from 'utils/date';
import {parseRequestedTimeString, RequestedTimeString} from 'utils/date';

interface Props {
center_id: AvalancheCenterID;
Expand Down Expand Up @@ -51,7 +51,7 @@ export const WeatherStations: React.FunctionComponent<{
requestedTime: RequestedTimeString;
}> = ({center_id, token, requestedTime}) => {
const [list, {toggle: toggleList}] = useToggle(false);
const mapLayerResult = useMapLayer(center_id);
const mapLayerResult = useMapLayer(center_id, parseRequestedTimeString(requestedTime));
const mapLayer = mapLayerResult.data;
const weatherStationsResult = useWeatherStationsMetadata(center_id, token);
const weatherStations = weatherStationsResult.data;
Expand Down
45 changes: 33 additions & 12 deletions hooks/useMapLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,39 @@ import {formatDistanceToNowStrict} from 'date-fns';
import {safeFetch} from 'hooks/fetch';
import {LoggerContext, LoggerProps} from 'loggerContext';
import {AvalancheCenterID, MapLayer, mapLayerSchema} from 'types/nationalAvalancheCenter';
import {apiDateString, RequestedTime, requestedTimeToUTCDate} from 'utils/date';
import {ZodError} from 'zod';

export const useMapLayer = (center_id: AvalancheCenterID | undefined): UseQueryResult<MapLayer, AxiosError | ZodError> => {
export const useMapLayer = (center_id: AvalancheCenterID | undefined, requestedTime: RequestedTime | undefined): UseQueryResult<MapLayer, AxiosError | ZodError> => {
const {nationalAvalancheCenterHost} = React.useContext<ClientProps>(ClientContext);
const {logger} = React.useContext<LoggerProps>(LoggerContext);
const key = center_id && queryKey(nationalAvalancheCenterHost, center_id);
const key = center_id && requestedTime && queryKey(nationalAvalancheCenterHost, center_id, requestedTime);
const [thisLogger] = useState(logger.child({query: key}));
useEffect(() => {
thisLogger.debug('initiating query');
}, [thisLogger]);

return useQuery<MapLayer, AxiosError | ZodError>({
queryKey: key,
queryFn: async (): Promise<MapLayer> => (center_id ? fetchMapLayer(nationalAvalancheCenterHost, center_id, thisLogger) : new Promise(() => null)),
enabled: !!center_id,
queryFn: async (): Promise<MapLayer> =>
center_id && requestedTime ? fetchMapLayer(nationalAvalancheCenterHost, center_id, requestedTime, thisLogger) : new Promise(() => null),
enabled: !!center_id && !!requestedTime,
cacheTime: Infinity, // hold on to this cached data forever
});
};

function queryKey(nationalAvalancheCenterHost: string, center_id: string) {
return ['map-layer', {host: nationalAvalancheCenterHost, center: center_id}];
function queryKey(nationalAvalancheCenterHost: string, center_id: string, requestedTime: RequestedTime) {
return [`map-layer`, {host: nationalAvalancheCenterHost, center: center_id, requestedTime: requestedTime}];
}

export const prefetchMapLayer = async (queryClient: QueryClient, nationalAvalancheCenterHost: string, center_id: AvalancheCenterID, logger: Logger) => {
const key = queryKey(nationalAvalancheCenterHost, center_id);
export const prefetchMapLayer = async (
queryClient: QueryClient,
nationalAvalancheCenterHost: string,
center_id: AvalancheCenterID,
requestedTime: RequestedTime,
logger: Logger,
) => {
const key = queryKey(nationalAvalancheCenterHost, center_id, requestedTime);
const thisLogger = logger.child({query: key});
thisLogger.debug('initiating query');

Expand All @@ -44,7 +52,7 @@ export const prefetchMapLayer = async (queryClient: QueryClient, nationalAvalanc
queryFn: async (): Promise<MapLayer> => {
const start = new Date();
thisLogger.trace(`prefetching`);
const result = await fetchMapLayer(nationalAvalancheCenterHost, center_id, thisLogger);
const result = await fetchMapLayer(nationalAvalancheCenterHost, center_id, requestedTime, thisLogger);
thisLogger.trace({duration: formatDistanceToNowStrict(start)}, `finished prefetching`);
return result;
},
Expand All @@ -53,11 +61,24 @@ export const prefetchMapLayer = async (queryClient: QueryClient, nationalAvalanc
});
};

const fetchMapLayer = async (nationalAvalancheCenterHost: string, center_id: AvalancheCenterID, logger: Logger): Promise<MapLayer> => {
const fetchMapLayer = async (nationalAvalancheCenterHost: string, center_id: AvalancheCenterID, requestedTime: RequestedTime, logger: Logger): Promise<MapLayer> => {
const url = `${nationalAvalancheCenterHost}/v2/public/products/map-layer/${center_id}`;
const params =
requestedTime === 'latest'
? {}
: {
day: apiDateString(requestedTimeToUTCDate(requestedTime)),
};
const what = 'avalanche avalanche center map layer';
const thisLogger = logger.child({url: url, what: what});
const data = await safeFetch(() => axios.get<AxiosResponse<unknown>>(url), thisLogger, what);
const thisLogger = logger.child({url: url, params: params, what: what});
const data = await safeFetch(
() =>
axios.get<AxiosResponse<unknown>>(url, {
params: params,
}),
thisLogger,
what,
);

const parseResult = mapLayerSchema.safeParse(data);
if (!parseResult.success) {
Expand Down
11 changes: 7 additions & 4 deletions network/prefetchAllActiveForecasts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import TimeseriesQuery from 'hooks/useWeatherStationTimeseries';
import {
AllAvalancheCenterCapabilities,
AvalancheCenter,
AvalancheCenterCapabilities,
AvalancheCenterID,
AvalancheForecastZoneStatus,
ForecastResult,
Expand Down Expand Up @@ -58,11 +59,13 @@ export const prefetchAllActiveForecasts = async (
void preloadAvalancheCenterLogo(queryClient, logger, id);
});

const centerCapabilities: AvalancheCenterCapabilities | undefined = capabilities?.centers.find(center => (center.id as AvalancheCenterID) === center_id);

await AvalancheCenterMetadataQuery.prefetch(queryClient, nationalAvalancheCenterHost, center_id, logger);
const metadata = queryClient.getQueryData<AvalancheCenter>(AvalancheCenterMetadataQuery.queryKey(nationalAvalancheCenterHost, center_id));

if (metadata?.widget_config?.danger_map) {
void AvalancheCenterMapLayerQuery.prefetch(queryClient, nationalAvalancheCenterHost, center_id, logger);
void AvalancheCenterMapLayerQuery.prefetch(queryClient, nationalAvalancheCenterHost, center_id, requestedTime, logger);
}

const endDate: Date = currentDateTime;
Expand All @@ -71,12 +74,12 @@ export const prefetchAllActiveForecasts = async (
// This call will prefetch the 50 most recent
void NWACObservationsQuery.prefetch(queryClient, nwacHost, center_id, endDate, logger);
}
if (metadata?.widget_config?.danger_map) {
if (centerCapabilities?.platforms.obs) {
// NAC fetches in 2 week chunks working backwards from endDate
void NACObservationsQuery.prefetch(queryClient, nationalAvalancheCenterHost, center_id, endDate, logger);
}

if (metadata?.widget_config?.stations?.token) {
if (centerCapabilities?.platforms.stations && metadata?.widget_config?.stations?.token) {
await WeatherStationsQuery.prefetch(queryClient, snowboundHost, center_id, metadata?.widget_config?.stations?.token, logger);
const weatherStations = queryClient.getQueryData<WeatherStationCollection>(WeatherStationsQuery.queryKey(snowboundHost, center_id));
const stationIds: Record<string, WeatherStationSource> = weatherStations
Expand All @@ -85,7 +88,7 @@ export const prefetchAllActiveForecasts = async (
void TimeseriesQuery.prefetch(queryClient, snowboundHost, metadata?.widget_config?.stations?.token, logger, stationIds, requestedTime, {days: 1});
}

if (metadata?.widget_config?.forecast) {
if (centerCapabilities?.platforms.forecasts && metadata?.widget_config?.forecast) {
metadata?.zones
.filter(zone => zone.status === AvalancheForecastZoneStatus.Active)
.forEach(zone => {
Expand Down
1 change: 1 addition & 0 deletions routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export type ObservationsStackParamList = {
};
observationSubmit: {
center_id: AvalancheCenterID;
requestedTime: RequestedTimeString;
};
observationsList: {
center_id: AvalancheCenterID;
Expand Down
Loading