Skip to content

Commit

Permalink
fix: fill ObsEdit BottomBar with Save button when logged out (#2597)
Browse files Browse the repository at this point in the history
* chore: TypeScript and style fixes
* fix: fill ObsEdit BottomBar with Save button when logged out
  • Loading branch information
kueda authored Jan 8, 2025
1 parent feec556 commit 7ec14e9
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 65 deletions.
2 changes: 1 addition & 1 deletion ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1526,7 +1526,7 @@ SPEC CHECKSUMS:
MMKV: f7d1d5945c8765f97f39c3d121f353d46735d801
MMKVCore: c04b296010fcb1d1638f2c69405096aac12f6390
Mute: 20135a96076f140cc82bfc8b810e2d6150d8ec7e
RCT-Folly: cd21f1661364f975ae76b3308167ad66b09f53f5
RCT-Folly: 7169b2b1c44399c76a47b5deaaba715eeeb476c0
RCTRequired: 77f73950d15b8c1a2b48ba5b79020c3003d1c9b5
RCTTypeSafety: ede1e2576424d89471ef553b2aed09fbbcc038e3
React: 2ddb437e599df2f1bffa9b248de2de4cfa0227f0
Expand Down
26 changes: 16 additions & 10 deletions src/components/ObsEdit/BottomButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
ButtonBar
} from "components/SharedComponents";
import { View } from "components/styledComponents";
import type { Node } from "react";
import React from "react";
import { useTranslation } from "sharedHooks";
import { getShadow } from "styles/global";
Expand All @@ -14,8 +13,13 @@ const DROP_SHADOW = getShadow( {
shadowOpacity: 0.2
} );

export const UPLOAD = "upload";
export const SAVE = "save";

export type ButtonType = typeof SAVE | typeof UPLOAD | null;

type Props = {
buttonPressed: boolean,
buttonPressed: ButtonType,
canSaveOnly: boolean,
handlePress: Function,
loading: boolean,
Expand All @@ -34,16 +38,16 @@ const BottomButtons = ( {
showFocusedUploadButton,
showHalfOpacity,
wasSynced
}: Props ): Node => {
}: Props ) => {
const { t } = useTranslation( );

const isSaving = buttonPressed === "save" && loading;
const isSaving = buttonPressed === SAVE && loading;
const disabled = buttonPressed !== null;

const saveChangesButton = (
<Button
className="px-[25px]"
onPress={( ) => handlePress( "save" )}
onPress={( ) => handlePress( SAVE )}
testID="ObsEdit.saveChangesButton"
text={t( "SAVE-CHANGES" )}
level={showFocusedChangesButton
Expand All @@ -56,22 +60,21 @@ const BottomButtons = ( {

const saveButton = {
title: t( "SAVE" ),
onPress: ( ) => handlePress( "save" ),
onPress: ( ) => handlePress( SAVE ),
isPrimary: false,
testID: "ObsEdit.saveButton",
disabled,
level: "neutral",
loading: isSaving,
isPrimary: false,
className: "px-[25px]"
};

const uploadButton = {
title: t( "UPLOAD-NOW" ),
onPress: ( ) => handlePress( "upload" ),
onPress: ( ) => handlePress( UPLOAD ),
isPrimary: true,
testID: "ObsEdit.uploadButton",
loading: buttonPressed === "upload" && loading,
loading: buttonPressed === UPLOAD && loading,
level: showFocusedUploadButton
? "focus"
: "neutral",
Expand All @@ -84,7 +87,10 @@ const BottomButtons = ( {
const renderButtons = ( ) => {
if ( canSaveOnly ) {
return (
<ButtonBar buttonConfiguration={[saveButton]} />
<ButtonBar
buttonConfiguration={[{ ...saveButton, className: "grow" }]}
containerClass="p-[15px]"
/>
);
}
if ( wasSynced ) {
Expand Down
33 changes: 17 additions & 16 deletions src/components/ObsEdit/BottomButtonsContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@ import {
import { REQUIRED_LOCATION_ACCURACY } from "components/LocationPicker/CrosshairCircle";
import useUploadObservations from "components/MyObservations/hooks/useUploadObservations.ts";
import { RealmContext } from "providers/contexts.ts";
import type { Node } from "react";
import React, { useCallback, useState } from "react";
import type { RealmObservation } from "realmModels/types";
import saveObservation from "sharedHelpers/saveObservation.ts";
import {
useCurrentUser,
useExitObservationFlow
} from "sharedHooks";
import useStore from "stores/useStore";

import BottomButtons from "./BottomButtons";
import type { ButtonType } from "./BottomButtons";
import BottomButtons, { UPLOAD } from "./BottomButtons";
import ImpreciseLocationSheet from "./Sheets/ImpreciseLocationSheet";
import MissingEvidenceSheet from "./Sheets/MissingEvidenceSheet";

Expand All @@ -22,7 +23,7 @@ const { useRealm } = RealmContext;
type Props = {
passesEvidenceTest: boolean,
observations: Array<Object>,
currentObservation: Object,
currentObservation: RealmObservation,
currentObservationIndex: number,
setCurrentObservationIndex: Function,
transitionAnimation: Function
Expand All @@ -35,7 +36,7 @@ const BottomButtonsContainer = ( {
observations,
setCurrentObservationIndex,
transitionAnimation
}: Props ): Node => {
}: Props ) => {
const { isConnected } = useNetInfo( );
const currentUser = useCurrentUser( );
const cameraRollUris = useStore( state => state.cameraRollUris );
Expand All @@ -48,27 +49,27 @@ const BottomButtonsContainer = ( {
const incrementTotalSavedObservations = useStore(
state => state.incrementTotalSavedObservations
);
const isNewObs = !currentObservation?._created_at;
const hasPhotos = currentObservation?.observationPhotos?.length > 0;
const isNewObs = !currentObservation._created_at;
const hasPhotos = currentObservation.observationPhotos?.length > 0;
const hasImportedPhotos = hasPhotos && cameraRollUris.length === 0;

const realm = useRealm( );
const [showMissingEvidenceSheet, setShowMissingEvidenceSheet] = useState( false );
const [showImpreciseLocationSheet, setShowImpreciseLocationSheet] = useState( false );
const [allowUserToUpload, setAllowUserToUpload] = useState( false );
const [buttonPressed, setButtonPressed] = useState( null );
const [buttonPressed, setButtonPressed] = useState<ButtonType>( null );
const [loading, setLoading] = useState( false );
const exitObservationFlow = useExitObservationFlow( );

const hasIdentification = currentObservation?.taxon
&& currentObservation?.taxon.rank_level !== 100;
const hasIdentification = currentObservation.taxon
&& currentObservation.taxon.rank_level !== 100;

const passesTests = passesEvidenceTest && hasIdentification;

const canUpload = currentUser && isConnected;
const canUpload = !!( currentUser && isConnected );
const { startUploadsFromMultiObsEdit } = useUploadObservations( canUpload );

const setNextScreen = useCallback( async ( { type }: Object ) => {
const setNextScreen = useCallback( async ( type: ButtonType ) => {
const savedObservation = await saveObservation( currentObservation, cameraRollUris, realm );
if ( savedObservation && observations?.length > 1 ) {
transitionAnimation();
Expand All @@ -81,7 +82,7 @@ const BottomButtonsContainer = ( {
resetMyObsOffsetToRestore( );
setMyObsOffset( 0 );
}
if ( type === "upload" ) {
if ( type === UPLOAD ) {
const { uuid } = savedObservation;
addTotalToolbarIncrements( savedObservation );
addToUploadQueue( uuid );
Expand Down Expand Up @@ -154,11 +155,11 @@ const BottomButtonsContainer = ( {
passesEvidenceTest
] );

const handlePress = useCallback( type => {
const handlePress = useCallback( ( type: ButtonType ) => {
if ( showMissingEvidence( ) ) { return; }
setLoading( true );
setButtonPressed( type );
setNextScreen( { type } );
setNextScreen( type );
}, [setNextScreen, showMissingEvidence] );

return (
Expand All @@ -179,9 +180,9 @@ const BottomButtonsContainer = ( {
handlePress={handlePress}
loading={loading}
showFocusedChangesButton={unsavedChanges}
showFocusedUploadButton={passesTests}
showFocusedUploadButton={!!passesTests}
showHalfOpacity={!passesEvidenceTest}
wasSynced={currentObservation?._synced_at}
wasSynced={!!( currentObservation?._synced_at )}
/>
</>
);
Expand Down
18 changes: 10 additions & 8 deletions src/components/ObsEdit/ObsEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,16 @@ const ObsEdit = ( ): Node => {
</KeyboardAwareScrollView>
</ViewWrapper>
{savedOrUploadedMultiObsFlow && <MultipleObservationsUploadStatus />}
<BottomButtonsContainer
currentObservation={currentObservation}
currentObservationIndex={currentObservationIndex}
observations={observations}
passesEvidenceTest={passesEvidenceTest}
setCurrentObservationIndex={setCurrentObservationIndex}
transitionAnimation={fade}
/>
{currentObservation && (
<BottomButtonsContainer
currentObservation={currentObservation}
currentObservationIndex={currentObservationIndex}
observations={observations}
passesEvidenceTest={passesEvidenceTest}
setCurrentObservationIndex={setCurrentObservationIndex}
transitionAnimation={fade}
/>
)}
{renderLocationPermissionGate( {
// If the user does not give location permissions in any form,
// navigate to the location picker (if granted we just continue fetching the location)
Expand Down
17 changes: 11 additions & 6 deletions src/components/SharedComponents/ButtonBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@ const DROP_SHADOW = getShadow( {

interface ButtonConfiguration {
title: string,
onPress: Function,
isPrimary: boolean
onPress: ( ) => void,
isPrimary: boolean,
className?: string
}

interface Props extends PropsWithChildren {
containerClass?: string,
onLayout?: () => void,
sticky?: boolean,
buttonConfiguration: Array<ButtonConfiguration>
buttonConfiguration?: Array<ButtonConfiguration>
}

// Ensure this component is placed outside of scroll views
Expand Down Expand Up @@ -46,17 +47,21 @@ const ButtonBar = ( {
onLayout={onLayout}
style={DROP_SHADOW}
>
{buttonConfiguration
&& buttonConfiguration.map( button => {
{buttonConfiguration && buttonConfiguration.map( button => {
const {
title, onPress, isPrimary, ...props
} = button;
return (
<Button
key={`ButtonBar-Button-${title}`}
maxFontSizeMultiplier={1}
text={title}
onPress={onPress}
isPrimary={isPrimary}
level={
isPrimary
? "primary"
: "neutral"
}
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
/>
Expand Down
27 changes: 14 additions & 13 deletions src/realmModels/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ export interface RealmObservationSound extends RealmObject {
sound: RealmSound;
}

export interface RealmTaxon extends RealmObject {
id: number;
defaultPhoto?: RealmPhoto,
name?: string;
preferredCommonName?: string;
rank?: string;
rank_level?: number;
isIconic?: boolean;
iconic_taxon_name?: string;
ancestor_ids?: number[];
_synced_at?: Date;
}

export interface RealmObservation extends RealmObject {
_created_at?: Date;
_synced_at?: Date;
Expand All @@ -48,22 +61,10 @@ export interface RealmObservation extends RealmObject {
positional_accuracy: number | null;
species_guess: string | null;
taxon_id: number | null;
taxon?: RealmTaxon;
uuid: string;
}

export interface RealmTaxon extends RealmObject {
id: number;
defaultPhoto?: RealmPhoto,
name?: string;
preferredCommonName?: string;
rank?: string;
rank_level?: number;
isIconic?: boolean;
iconic_taxon_name?: string;
ancestor_ids?: number[];
_synced_at?: Date;
}

export interface RealmUser extends RealmObject {
iconUrl?: string;
id: number;
Expand Down
6 changes: 3 additions & 3 deletions src/sharedHelpers/parseExif.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ export const parseExif = async ( photoUri: ?string ): Promise<Object> => {
// TODO: Johannes: I think this interface should be
// exported from the react-native-exif-reader library
export interface ExifToWrite {
latitude?: number;
longitude?: number;
positional_accuracy?: number;
latitude?: number | null;
longitude?: number | null;
positional_accuracy?: number | null;
}

export const writeExifToFile = async ( photoUri: ?string, exif: ExifToWrite ): Promise<Object> => {
Expand Down
5 changes: 3 additions & 2 deletions src/sharedHelpers/saveObservation.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type Realm from "realm";
import Observation from "realmModels/Observation";
import type { RealmObservation } from "realmModels/types";
import { ExifToWrite, writeExifToFile } from "sharedHelpers/parseExif";

const writeExifToCameraRollPhotos = async (
observation: Observation,
observation: RealmObservation,
cameraRollUris: string[],
exif: ExifToWrite
) => {
Expand All @@ -17,7 +18,7 @@ const writeExifToCameraRollPhotos = async (
};

const saveObservation = async (
observation: Observation,
observation: RealmObservation,
cameraRollUris: string[],
realm: Realm
) => {
Expand Down
Loading

0 comments on commit 7ec14e9

Please sign in to comment.