Merge pull request #3613 from inaturalist/mob-1396-multiple-taps-of-submitting-id-suggestion-create-multiple

MOB-1396: disable suggest id buttons while pending
This commit is contained in:
Seth Peterson
2026-05-14 11:02:50 -05:00
committed by GitHub
6 changed files with 33 additions and 8 deletions

View File

@@ -233,7 +233,10 @@ const IdentificationSheets: React.FC<Props> = ( {
cancelable: true,
} ), [t] );
const { mutate: createIdentificationMutate } = useAuthenticatedMutation(
const {
mutate: createIdentificationMutate,
isPending: isCreateIdPending,
} = useAuthenticatedMutation(
( idParams, optsWithAuth ) => createIdentification( idParams, optsWithAuth ),
{
onSuccess: data => {
@@ -252,7 +255,8 @@ const IdentificationSheets: React.FC<Props> = ( {
showErrorAlert( error );
},
onSettled: () => {
// Clear params gotten via useRoute to prevent re-showing sheets
dispatch( { type: SUBMIT_IDENTIFICATION } );
closeAgreeWithIdSheet( );
navigation.setParams(
{ identAt: undefined, identTaxonId: undefined, identTaxonFromVision: undefined },
);
@@ -334,16 +338,13 @@ const IdentificationSheets: React.FC<Props> = ( {
loadActivityItem( );
createIdentificationMutate( { identification: agreeParams } );
closeAgreeWithIdSheet( );
}, [closeAgreeWithIdSheet, createIdentificationMutate, observation?.uuid, loadActivityItem] );
}, [createIdentificationMutate, observation?.uuid, loadActivityItem] );
const potentialDisagreeSheetDiscardChanges = useCallback( ( ) => {
dispatch( { type: HIDE_POTENTIAL_DISAGREEMENT_SHEET } );
}, [] );
const doSuggestId = useCallback( ( potentialDisagree?: boolean ) => {
dispatch( { type: SUBMIT_IDENTIFICATION } );
if ( !newIdentification?.taxon ) {
throw new Error( "Cannot create an identification without a taxon" );
}
@@ -422,6 +423,7 @@ const IdentificationSheets: React.FC<Props> = ( {
onAgree={onAgree}
editIdentBody={editIdentBody}
hidden={showIdentBodySheet}
loading={isCreateIdPending}
onPressClose={closeAgreeWithIdSheet}
identification={agreeIdentification}
/>
@@ -454,6 +456,7 @@ const IdentificationSheets: React.FC<Props> = ( {
<SuggestIDSheet
editIdentBody={editIdentBody}
hidden={showIdentBodySheet}
loading={isCreateIdPending}
onSuggestId={onSuggestId}
identification={newIdentification}
onPressClose={hideSuggestedIdSheet}
@@ -461,6 +464,7 @@ const IdentificationSheets: React.FC<Props> = ( {
)}
{showPotentialDisagreementSheet && newIdentification && (
<PotentialDisagreementSheet
loading={isCreateIdPending}
onPotentialDisagreePressed={onPotentialDisagreePressed}
onPressClose={potentialDisagreeSheetDiscardChanges}
newTaxon={newIdentification.taxon}

View File

@@ -20,6 +20,7 @@ type Props = {
taxon: { id: number },
vision?: boolean
},
loading?: boolean,
onAgree:Function,
onPressClose: Function,
}
@@ -39,6 +40,7 @@ const AgreeWithIDSheet = ( {
editIdentBody,
hidden,
identification,
loading,
onAgree,
onPressClose,
}: Props ): Node => (
@@ -74,6 +76,7 @@ const AgreeWithIDSheet = ( {
editIdentBody( );
}}
className="mx-2 flex-1"
disabled={loading}
testID="ObsDetail.AgreeId.EditCommentButton"
accessibilityHint={t( "Opens-edit-comment-form" )}
/>
@@ -85,6 +88,7 @@ const AgreeWithIDSheet = ( {
editIdentBody( );
}}
className="mx-2 flex-1"
disabled={loading}
testID="ObsDetail.AgreeId.commentButton"
accessibilityHint={t( "Opens-add-comment-form" )}
/>
@@ -94,6 +98,8 @@ const AgreeWithIDSheet = ( {
text={t( "AGREE" )}
onPress={( ) => onAgree( identification )}
className="mx-2 flex-1"
disabled={loading}
loading={loading}
testID="ObsDetail.AgreeId.cvSuggestionsButton"
accessibilityRole="link"
accessibilityHint={t( "Navigates-to-suggest-identification" )}

View File

@@ -12,6 +12,7 @@ import type { RealmTaxon } from "realmModels/types";
import { useCurrentUser, useTranslation } from "sharedHooks";
interface Props {
loading?: boolean;
onPressClose: () => void;
onPotentialDisagreePressed: ( _checkedValue: string ) => void;
newTaxon: RealmTaxon | ApiTaxon;
@@ -19,6 +20,7 @@ interface Props {
}
const PotentialDisagreementSheet = ( {
loading,
onPressClose,
onPotentialDisagreePressed,
newTaxon,
@@ -90,8 +92,8 @@ const PotentialDisagreementSheet = ( {
headerText={t( "POTENTIAL-DISAGREEMENT" )}
confirm={checkBoxValue => {
onPotentialDisagreePressed( checkBoxValue );
onPressClose( );
}}
loading={loading}
confirmText={t( "SUBMIT-ID-SUGGESTION" )}
onPressClose={onPressClose}
radioValues={radioValues}

View File

@@ -15,6 +15,7 @@ interface Props {
body?: string;
taxon: { id: number };
};
loading?: boolean;
onSuggestId: ( ) => void;
editIdentBody: () => void;
onPressClose?: () => void;
@@ -23,6 +24,7 @@ interface Props {
const SuggestIDSheet = ( {
hidden,
identification,
loading,
onSuggestId,
editIdentBody,
onPressClose,
@@ -66,6 +68,7 @@ const SuggestIDSheet = ( {
editIdentBody( );
}}
className="mx-2 flex-1"
disabled={loading}
testID="SuggestID.EditCommentButton"
/>
)
@@ -76,6 +79,7 @@ const SuggestIDSheet = ( {
editIdentBody( );
}}
className="mx-2 flex-1"
disabled={loading}
testID="SuggestID.commentButton"
accessibilityHint={t( "Opens-add-comment-form" )}
/>
@@ -86,6 +90,8 @@ const SuggestIDSheet = ( {
onSuggestId( );
}}
className="mx-2 flex-1"
disabled={loading}
loading={loading}
testID="SuggestIDSheet.cvSuggestionsButton"
accessibilityRole="link"
accessibilityHint={t( "Adds-ID" )}

View File

@@ -14,6 +14,7 @@ interface Props {
confirmText?: string;
headerText: string;
insideModal?: boolean;
loading?: boolean;
onPressClose?: ( ) => void;
radioValues: Record<string, {
value: string;
@@ -34,6 +35,7 @@ const RadioButtonSheet = ( {
confirmText,
headerText,
insideModal,
loading,
onPressClose,
radioValues,
selectedValue = "none",
@@ -81,7 +83,8 @@ const RadioButtonSheet = ( {
onPress={( ) => {
confirm( checkedValue );
}}
disabled={!isDirty}
disabled={!isDirty || loading}
loading={loading}
text={radioValues[checkedValue]?.buttonText ?? confirmLabel}
accessibilityLabel={radioValues[checkedValue]?.buttonText ?? confirmLabel}
/>

View File

@@ -47,7 +47,11 @@ describe( "IdentificationSheets", () => {
if ( options && options.onSuccess ) {
options.onSuccess( { id: 1 } );
}
if ( options && options.onSettled ) {
options.onSettled( );
}
},
isPending: false,
} ) );
} );