From 1dd8130cadda00f901b16136c125492056fbcb0a Mon Sep 17 00:00:00 2001
From: ErikSin <67773827+ErikSin@users.noreply.github.com>
Date: Wed, 1 May 2024 14:26:42 -0700
Subject: [PATCH] feat: update header with new UI (#312)
* chore: update header to include modal
* chore: translations
* chore: missing dependencies
* chore: update save icon
* chore: delete old save icon
* chore: update use of save icon
* chore: destructure foruseEffect dependecy
---
messages/en.json | 16 +-
src/frontend/images/CheckMark.svg | 4 +
.../screens/ObservationEdit/SaveButton.tsx | 4 +-
.../screens/ObservationEdit/index.tsx | 6 +-
src/frontend/screens/PresetChooser.tsx | 2 +-
.../ProjectSettings/DeviceName/EditScreen.tsx | 37 ++---
.../CustomHeaderLeftClose.tsx | 153 +++++++++++-------
.../sharedComponents/icons/SaveIcon.tsx | 36 -----
src/frontend/sharedComponents/icons/index.tsx | 1 -
9 files changed, 127 insertions(+), 132 deletions(-)
create mode 100644 src/frontend/images/CheckMark.svg
delete mode 100644 src/frontend/sharedComponents/icons/SaveIcon.tsx
diff --git a/messages/en.json b/messages/en.json
index 8c74013b0..29b3c3229 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -3,17 +3,23 @@
"description": "Button on dialog to keep editing (cancelling close action)",
"message": "Continue editing"
},
- "AppContainer.EditHeader.discardChangesContent": {
- "description": "Button on dialog to cancel observation edits",
+ "AppContainer.EditHeader.discardChangesButton": {
+ "description": "Title of dialog that shows when cancelling observation edits",
"message": "Discard changes"
},
+ "AppContainer.EditHeader.discardChangesDescription": {
+ "message": "Your changes will not be saved. This cannot be undone."
+ },
"AppContainer.EditHeader.discardChangesTitle": {
"description": "Title of dialog that shows when cancelling observation edits",
"message": "Discard changes?"
},
- "AppContainer.EditHeader.discardContent": {
- "description": "Button on dialog to cancel a new observation",
- "message": "Discard without saving"
+ "AppContainer.EditHeader.discardObservationButton": {
+ "description": "Title of dialog that shows when cancelling observation edits",
+ "message": "Discard Observation"
+ },
+ "AppContainer.EditHeader.discardObservationDescription": {
+ "message": "Your Observation will not be saved. This cannot be undone."
},
"AppContainer.EditHeader.discardTitle": {
"description": "Title of dialog that shows when cancelling a new observation",
diff --git a/src/frontend/images/CheckMark.svg b/src/frontend/images/CheckMark.svg
new file mode 100644
index 000000000..1074ee1b0
--- /dev/null
+++ b/src/frontend/images/CheckMark.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/frontend/screens/ObservationEdit/SaveButton.tsx b/src/frontend/screens/ObservationEdit/SaveButton.tsx
index a9440a01b..4df3f4dc0 100644
--- a/src/frontend/screens/ObservationEdit/SaveButton.tsx
+++ b/src/frontend/screens/ObservationEdit/SaveButton.tsx
@@ -4,7 +4,6 @@ import debug from 'debug';
import {defineMessages, useIntl} from 'react-intl';
import {IconButton} from '../../sharedComponents/IconButton';
-import {SaveIcon} from '../../sharedComponents/icons/SaveIcon';
import {useNavigationFromRoot} from '../../hooks/useNavigationWithTypes';
import {usePersistedDraftObservation} from '../../hooks/persistedState/usePersistedDraftObservation';
import {useCreateObservation} from '../../hooks/server/observations';
@@ -14,6 +13,7 @@ import {useCreateBlobMutation} from '../../hooks/server/media';
import {DraftPhoto, Photo} from '../../contexts/PhotoPromiseContext/types';
import {useDraftObservation} from '../../hooks/useDraftObservation';
import {useCurrentTrackStore} from '../../hooks/tracks/useCurrentTrackStore';
+import SaveCheck from '../../images/CheckMark.svg';
const m = defineMessages({
noGpsTitle: {
@@ -242,7 +242,7 @@ export const SaveButton = ({
) : (
-
+
);
};
diff --git a/src/frontend/screens/ObservationEdit/index.tsx b/src/frontend/screens/ObservationEdit/index.tsx
index 6b6ee09ce..d9de9240a 100644
--- a/src/frontend/screens/ObservationEdit/index.tsx
+++ b/src/frontend/screens/ObservationEdit/index.tsx
@@ -56,9 +56,9 @@ export const ObservationEdit: NativeNavigationComponent<'ObservationEdit'> & {
navigation.navigate('AddPhoto');
}, [navigation]);
- const handleDetailsPress = React.useCallback(() => {
- navigation.navigate('ObservationDetails', {question: 1});
- }, [navigation]);
+ // const handleDetailsPress = React.useCallback(() => {
+ // navigation.navigate('ObservationDetails', {question: 1});
+ // }, [navigation]);
const bottomSheetItems = [
{
diff --git a/src/frontend/screens/PresetChooser.tsx b/src/frontend/screens/PresetChooser.tsx
index 4b65f427f..f4f553b1b 100644
--- a/src/frontend/screens/PresetChooser.tsx
+++ b/src/frontend/screens/PresetChooser.tsx
@@ -51,7 +51,7 @@ export const PresetChooser: NativeNavigationComponent<'PresetChooser'> = ({
),
});
- }, [prevRouteNameInStack, CustomHeaderLeft, CustomHeaderLeftClose]);
+ }, [prevRouteNameInStack, navigation]);
const presetsList = !presets
? null
diff --git a/src/frontend/screens/Settings/ProjectSettings/DeviceName/EditScreen.tsx b/src/frontend/screens/Settings/ProjectSettings/DeviceName/EditScreen.tsx
index d3b92fc95..0ea5c7d8e 100644
--- a/src/frontend/screens/Settings/ProjectSettings/DeviceName/EditScreen.tsx
+++ b/src/frontend/screens/Settings/ProjectSettings/DeviceName/EditScreen.tsx
@@ -13,7 +13,7 @@ import {
import {BLACK} from '../../../../lib/styles';
import {HookFormTextInput} from '../../../../sharedComponents/HookFormTextInput';
import {IconButton} from '../../../../sharedComponents/IconButton';
-import {SaveIcon} from '../../../../sharedComponents/icons';
+import SaveIcon from '../../../../images/CheckMark.svg';
import {useBottomSheetModal} from '../../../../sharedComponents/BottomSheetModal';
import {ErrorModal} from '../../../../sharedComponents/ErrorModal';
import {FieldRow} from './FieldRow';
@@ -72,14 +72,16 @@ export const EditScreen = ({
deviceName: string;
}>({defaultValues: {deviceName}});
- const editDeviceInfoMutation = useEditDeviceInfo();
+ const {isPending, mutate} = useEditDeviceInfo();
const {isDirty: nameHasChanges} = control.getFieldState(
'deviceName',
formState,
);
- const errorModal = useBottomSheetModal({openOnMount: false});
+ const {openSheet, sheetRef, closeSheet, isOpen} = useBottomSheetModal({
+ openOnMount: false,
+ });
React.useEffect(
function showDiscardChangesAlert() {
@@ -117,7 +119,7 @@ export const EditScreen = ({
return (
{}
: handleSubmit(async value => {
if (!nameHasChanges) {
@@ -125,33 +127,22 @@ export const EditScreen = ({
return;
}
- editDeviceInfoMutation.mutate(value.deviceName, {
+ mutate(value.deviceName, {
onSuccess: () =>
navigation.navigate('DeviceNameDisplay'),
onError: () => {
- errorModal.openSheet();
+ openSheet();
},
});
})
}>
- {editDeviceInfoMutation.isPending ? (
-
- ) : (
-
- )}
+ {isPending ? : }
);
},
});
},
- [
- handleSubmit,
- navigation,
- editDeviceInfoMutation.mutate,
- editDeviceInfoMutation.isPending,
- nameHasChanges,
- errorModal.openSheet,
- ],
+ [handleSubmit, navigation, isPending, mutate, nameHasChanges, openSheet],
);
return (
@@ -168,15 +159,11 @@ export const EditScreen = ({
style={{flex: 1, color: BLACK, fontSize: 16}}
showCharacterCount
autoFocus
- editable={!editDeviceInfoMutation.isPending}
+ editable={isPending}
/>
-
+
>
);
};
diff --git a/src/frontend/sharedComponents/CustomHeaderLeftClose.tsx b/src/frontend/sharedComponents/CustomHeaderLeftClose.tsx
index 53fce6bba..0551caef9 100644
--- a/src/frontend/sharedComponents/CustomHeaderLeftClose.tsx
+++ b/src/frontend/sharedComponents/CustomHeaderLeftClose.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import {HeaderBackButton} from '@react-navigation/elements';
import {HeaderBackButtonProps} from '@react-navigation/native-stack/lib/typescript/src/types';
-import {Alert, BackHandler} from 'react-native';
+import {BackHandler} from 'react-native';
import isEqual from 'lodash.isequal';
import {CloseIcon} from './icons';
@@ -18,6 +18,14 @@ import {
useFocusEffect,
useNavigation,
} from '@react-navigation/native';
+import {
+ BottomSheetContent,
+ BottomSheetModal,
+ useBottomSheetModal,
+} from './BottomSheetModal';
+
+import ErrorIcon from '../images/Error.svg';
+import DiscardIcon from '../images/delete.svg';
const m = defineMessages({
discardTitle: {
@@ -25,26 +33,35 @@ const m = defineMessages({
defaultMessage: 'Discard observation?',
description: 'Title of dialog that shows when cancelling a new observation',
},
- discardConfirm: {
- id: 'AppContainer.EditHeader.discardContent',
- defaultMessage: 'Discard without saving',
- description: 'Button on dialog to cancel a new observation',
+ discardObservationDescription: {
+ id: 'AppContainer.EditHeader.discardObservationDescription',
+ defaultMessage:
+ 'Your Observation will not be saved. This cannot be undone. ',
},
discardChangesTitle: {
id: 'AppContainer.EditHeader.discardChangesTitle',
defaultMessage: 'Discard changes?',
description: 'Title of dialog that shows when cancelling observation edits',
},
- discardChangesConfirm: {
- id: 'AppContainer.EditHeader.discardChangesContent',
- defaultMessage: 'Discard changes',
- description: 'Button on dialog to cancel observation edits',
+ discardChangesDescription: {
+ id: 'AppContainer.EditHeader.discardChangesDescription',
+ defaultMessage: 'Your changes will not be saved. This cannot be undone. ',
},
discardCancel: {
id: 'AppContainer.EditHeader.discardCancel',
defaultMessage: 'Continue editing',
description: 'Button on dialog to keep editing (cancelling close action)',
},
+ discardObservationButton: {
+ id: 'AppContainer.EditHeader.discardObservationButton',
+ defaultMessage: 'Discard Observation',
+ description: 'Title of dialog that shows when cancelling observation edits',
+ },
+ discardChangesButton: {
+ id: 'AppContainer.EditHeader.discardChangesButton',
+ defaultMessage: 'Discard changes',
+ description: 'Title of dialog that shows when cancelling observation edits',
+ },
});
// We use a slightly larger back icon, to improve accessibility
@@ -68,51 +85,80 @@ export const CustomHeaderLeftClose = ({
headerBackButtonProps,
observationId,
}: CustomHeaderLeftCloseProps) => {
- if (observationId) {
- return (
-
+ const {isOpen, sheetRef, closeSheet, openSheet} = useBottomSheetModal({
+ openOnMount: false,
+ });
+ const {formatMessage} = useIntl();
+ const {clearDraft} = useDraftObservation();
+ const navigation = useNavigationFromRoot();
+
+ const handleDiscard = React.useCallback(() => {
+ clearDraft();
+ navigation.dispatch(
+ CommonActions.reset({index: 0, routes: [{name: 'Home'}]}),
);
- }
+ }, [clearDraft, navigation]);
return (
-
+ <>
+ {observationId ? (
+
+ ) : (
+
+ )}
+
+ ,
+ },
+ {
+ onPress: closeSheet,
+ text: formatMessage(m.discardCancel),
+ variation: 'outlined',
+ },
+ ]}
+ icon={}
+ />
+
+ >
);
};
const HeaderBackNewObservation = ({
tintColor,
headerBackButtonProps,
-}: SharedBackButtonProps) => {
- const navigation = useNavigationFromRoot();
- const {formatMessage: t} = useIntl();
- const {clearDraft} = useDraftObservation();
-
- const onGoBack = React.useCallback(() => {
- Alert.alert(t(m.discardTitle), undefined, [
- {
- text: t(m.discardConfirm),
- onPress: () => {
- clearDraft();
- navigation.dispatch(
- CommonActions.reset({index: 0, routes: [{name: 'Home'}]}),
- );
- },
- },
- {text: t(m.discardCancel), onPress: () => {}},
- ]);
- }, [navigation, clearDraft, t]);
-
+ openBottomSheet,
+}: SharedBackButtonProps & {openBottomSheet: () => void}) => {
useFocusEffect(
React.useCallback(() => {
const onBackPress = () => {
- onGoBack();
+ openBottomSheet();
return true;
};
@@ -122,32 +168,30 @@ const HeaderBackNewObservation = ({
);
return () => subscription.remove();
- }, [onGoBack]),
+ }, [openBottomSheet]),
);
return (
);
};
type HeaderBackEditObservationProps = {
observationId: string;
+ openBottomSheet: () => void;
} & SharedBackButtonProps;
const HeaderBackEditObservation = ({
headerBackButtonProps,
tintColor,
-
+ openBottomSheet,
observationId,
}: HeaderBackEditObservationProps) => {
const navigation = useNavigationFromRoot();
- const {formatMessage: t} = useIntl();
-
- const {clearDraft} = useDraftObservation();
const {observation} = useObservationWithPreset(observationId);
const photos = usePersistedDraftObservation(store => store.photos);
const draftObservation = usePersistedDraftObservation(store => store.value);
@@ -165,20 +209,11 @@ const HeaderBackEditObservation = ({
e.preventDefault();
- Alert.alert(t(m.discardChangesTitle), undefined, [
- {
- text: t(m.discardChangesConfirm),
- onPress: () => {
- clearDraft();
- navigation.dispatch(e.data.action);
- },
- },
- {text: t(m.discardCancel), onPress: () => {}},
- ]);
+ openBottomSheet();
});
return () => unsubscribe();
- }, [observation, photos, draftObservation, navigation, clearDraft]);
+ }, [observation, photos, draftObservation, openBottomSheet, navigation]);
return (
(
-
-
-
-
-
-);
-
-const styles = StyleSheet.create({
- outerCircle: {
- width: 30,
- height: 30,
- backgroundColor: DARK_MANGO,
- borderRadius: 50,
- justifyContent: 'center',
- alignItems: 'center',
- },
- innerCircle: {
- backgroundColor: MANGO,
- height: 25,
- width: 25,
- borderRadius: 50,
- justifyContent: 'center',
- alignItems: 'center',
- },
-});
diff --git a/src/frontend/sharedComponents/icons/index.tsx b/src/frontend/sharedComponents/icons/index.tsx
index 636955b85..eadbba958 100644
--- a/src/frontend/sharedComponents/icons/index.tsx
+++ b/src/frontend/sharedComponents/icons/index.tsx
@@ -21,7 +21,6 @@ type ImageIconProps = {
export {GpsIcon} from './GpsIcon';
// export { CategoryIcon, CategoryCircleIcon } from "./CategoryIcon";
-export {SaveIcon} from './SaveIcon';
export {SyncIconCircle} from './SyncIconCircle';
export const AlertIcon = ({size = 30, color = RED, style}: FontIconProps) => (