Skip to content

Commit

Permalink
Es/saved observations (#200)
Browse files Browse the repository at this point in the history
* conditional default screen based on presence of observation

* clear observation on save

* chore: created function to detect which route the user is navigated to on initial load

* chore: back button on presets screen prompts user

* chore:change name of hasName to hasDeviceName

* chore: reset nav state from observation close

* chore: semantic changes
  • Loading branch information
ErikSin authored Apr 1, 2024
1 parent 6bb0e11 commit cc845c9
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 19 deletions.
5 changes: 4 additions & 1 deletion src/frontend/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
LocalDiscoveryProvider,
createLocalDiscoveryController,
} from './contexts/LocalDiscoveryContext';
import {Loading} from './sharedComponents/Loading';

const queryClient = new QueryClient();
const messagePort = new MessagePortLike();
Expand Down Expand Up @@ -56,7 +57,9 @@ const App = () => {
<ActiveProjectProvider>
<PhotoPromiseProvider>
<SecurityProvider>
<AppNavigator permissionAsked={permissionsAsked} />
<React.Suspense fallback={<Loading />}>
<AppNavigator permissionAsked={permissionsAsked} />
</React.Suspense>
</SecurityProvider>
</PhotoPromiseProvider>
</ActiveProjectProvider>
Expand Down
64 changes: 53 additions & 11 deletions src/frontend/Navigation/AppNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,17 @@ import {useIntl} from 'react-intl';
import BootSplash from 'react-native-bootsplash';
import {useDeviceInfo} from '../hooks/server/deviceInfo';
import {Loading} from '../sharedComponents/Loading';
import {createDeviceNamingScreens} from './ScreenGroups/DeviceNamingScreens';
import {
DeviceNamingSceens,
createDeviceNamingScreens,
} from './ScreenGroups/DeviceNamingScreens';
import {usePrefetchLastKnownLocation} from '../hooks/useLastSavedLocation';
import {usePersistedDraftObservation} from '../hooks/persistedState/usePersistedDraftObservation';
import {ClientGeneratedObservation} from '../sharedTypes';
import {Observation, Preset} from '@mapeo/schema';
import {matchPreset} from '../lib/utils';
import {AppList} from './ScreenGroups/AppScreens';
import {usePresetsQuery} from '../hooks/server/presets';

// import {devExperiments} from '../lib/DevExperiments';

Expand All @@ -34,7 +43,10 @@ import {usePrefetchLastKnownLocation} from '../hooks/useLastSavedLocation';

export const AppNavigator = ({permissionAsked}: {permissionAsked: boolean}) => {
const {formatMessage} = useIntl();

const existingObservation = usePersistedDraftObservation(
store => store.value,
);
const {data: presets} = usePresetsQuery();
const deviceInfo = useDeviceInfo();
usePrefetchLastKnownLocation();

Expand All @@ -48,14 +60,44 @@ export const AppNavigator = ({permissionAsked}: {permissionAsked: boolean}) => {
}

return (
<React.Suspense fallback={<Loading />}>
<RootStack.Navigator
initialRouteName="IntroToCoMapeo"
screenOptions={NavigatorScreenOptions}>
{deviceInfo.data && deviceInfo.data.name
? createDefaultScreenGroup(formatMessage)
: createDeviceNamingScreens(formatMessage)}
</RootStack.Navigator>
</React.Suspense>
<RootStack.Navigator
initialRouteName={getInitialRouteName({
hasDeviceName: !!deviceInfo.data?.name,
existingObservation,
presets,
})}
screenOptions={NavigatorScreenOptions}>
{deviceInfo.data?.name
? createDefaultScreenGroup(formatMessage)
: createDeviceNamingScreens(formatMessage)}
</RootStack.Navigator>
);
};

function getInitialRouteName(
initialInfo:
| {hasDeviceName: false}
| {
hasDeviceName: true;
existingObservation: null | ClientGeneratedObservation | Observation;
presets: Preset[];
},
): keyof AppList | keyof DeviceNamingSceens {
// if user has not set a name, navigate to intro screen where they will be prompted to set a name
if (!initialInfo.hasDeviceName) {
return 'IntroToCoMapeo';
}

// if no exisiting observation, navigate to home
if (!initialInfo.existingObservation) {
return 'Home';
}

// if existing observation and no preset match, user has started creating an observation but had not chosen a preset, so navigate to preset chooser
if (!matchPreset(initialInfo.existingObservation.tags, initialInfo.presets)) {
return 'PresetChooser';
}

// if existing observation and preset match, navigate to observation edit
return 'ObservationEdit';
}
17 changes: 14 additions & 3 deletions src/frontend/screens/ObservationEdit/SaveButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {useEditObservation} from '../../hooks/server/observations';
import {UIActivityIndicator} from 'react-native-indicators';
import {useCreateBlobMutation} from '../../hooks/server/media';
import {DraftPhoto, Photo} from '../../contexts/PhotoPromiseContext/types';
import {useDraftObservation} from '../../hooks/useDraftObservation';

const m = defineMessages({
noGpsTitle: {
Expand Down Expand Up @@ -66,6 +67,7 @@ export const SaveButton = ({
}) => {
const value = usePersistedDraftObservation(store => store.value);
const photos = usePersistedDraftObservation(store => store.photos);
const {clearDraft} = useDraftObservation();
const {formatMessage: t} = useIntl();
const navigation = useNavigationFromRoot();
const createObservationMutation = useCreateObservation();
Expand All @@ -85,6 +87,7 @@ export const SaveButton = ({
if (openErrorModal) openErrorModal();
},
onSuccess: () => {
clearDraft();
navigation.navigate('Home', {screen: 'Map'});
},
},
Expand Down Expand Up @@ -125,6 +128,7 @@ export const SaveButton = ({
if (openErrorModal) openErrorModal();
},
onSuccess: () => {
clearDraft();
navigation.navigate('Home', {screen: 'Map'});
},
},
Expand All @@ -140,9 +144,16 @@ export const SaveButton = ({
if (!observationId) throw new Error('Need an observation Id to edit');
if (!('versionId' in value))
throw new Error('Cannot update a unsaved observation (must create one)');
// @ts-expect-error
editObservationMutation.mutate({id: observationId, value});
navigation.pop();
editObservationMutation.mutate(
// @ts-expect-error
{id: observationId, value},
{
onSuccess: () => {
clearDraft();
navigation.pop();
},
},
);
}

const confirmationOptions: AlertButton[] = [
Expand Down
6 changes: 3 additions & 3 deletions src/frontend/screens/PresetChooser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ export const PresetChooser: NativeNavigationComponent<'PresetChooser'> = ({
React.useLayoutEffect(() => {
navigation.setOptions({
headerLeft: props =>
prevRouteNameInStack === 'Home' ? (
<CustomHeaderLeftClose headerBackButtonProps={props} />
) : (
prevRouteNameInStack === 'ObservationEdit' ? (
<CustomHeaderLeft headerBackButtonProps={props} />
) : (
<CustomHeaderLeftClose headerBackButtonProps={props} />
),
});
}, [prevRouteNameInStack, CustomHeaderLeft, CustomHeaderLeftClose]);
Expand Down
4 changes: 3 additions & 1 deletion src/frontend/sharedComponents/CustomHeaderLeftClose.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ const HeaderBackNewObservation = ({
text: t(m.discardConfirm),
onPress: () => {
clearDraft();
navigation.dispatch(CommonActions.navigate('Home', {screen: 'map'}));
navigation.dispatch(
CommonActions.reset({index: 0, routes: [{name: 'Home'}]}),
);
},
},
{text: t(m.discardCancel), onPress: () => {}},
Expand Down

0 comments on commit cc845c9

Please sign in to comment.