Hide "id with ai button" for no media or sound only (#2896)

* Add Boolean to control button being shown

Same Button component, only with changed indentation

* Apply margin between buttons to hide button instead

* Move left margin to container

Because ID button is now optional but container is not.

* Increase margin between buttons

Not part of the ticket, but it was not according to designs.

* Use existing state for the button

* Update integration test

* Update duplicate testID

* Add unit test for showing button behaviour based on photos
This commit is contained in:
Johannes Klein
2025-05-16 15:30:06 +02:00
committed by GitHub
parent ed3f0e982c
commit a20a22bad8
3 changed files with 57 additions and 31 deletions

View File

@@ -85,33 +85,37 @@ const IdentificationSection = ( {
<View key={resetScreen?.toString( )}>
<IconicTaxonChooser
before={(
<View className="flex-row">
<Button
level={identTaxon
? "neutral"
: "focus"}
onPress={navToSuggestions}
text={t( "ID-WITH-AI" )}
className={classnames( "rounded-full py-1 h-[36px] ml-6", {
"border border-darkGray border-[2px]": identTaxon
} )}
testID="ObsEdit.Suggestions"
icon={(
<INatIcon
name="sparkly-label"
size={24}
color={identTaxon
? colors.darkGray
: colors.white}
<View className="flex-row ml-6">
{hasPhotos
? (
<Button
level={identTaxon
? "neutral"
: "focus"}
onPress={navToSuggestions}
text={t( "ID-WITH-AI" )}
className={classnames( "rounded-full py-1 mr-4 h-[36px]", {
"border border-darkGray border-[2px]": identTaxon
} )}
testID="ObsEdit.IDWithAI"
icon={(
<INatIcon
name="sparkly-label"
size={24}
color={identTaxon
? colors.darkGray
: colors.white}
/>
)}
accessibilityLabel={t( "View-suggestions" )}
/>
)}
accessibilityLabel={t( "View-suggestions" )}
/>
)
: null}
<Button
level="neutral"
onPress={navToSuggestionsSearch}
text={t( "SEARCH" )}
className="rounded-full py-1 h-[36px] ml-2 border border-darkGray border-[2px]"
className="rounded-full py-1 h-[36px] border border-darkGray border-[2px]"
testID="ObsEdit.Suggestions"
icon={(
<INatIcon

View File

@@ -117,15 +117,20 @@ describe( "Suggestions", ( ) => {
// We need to navigate from MyObs to ObsEdit to Suggestions for all of these
// tests
async function navigateToSuggestionsViaObsEditForObservation( observation ) {
async function navigateToSuggestionsViaObsEditForObservation( observation, options ) {
const observationGridItem = await screen.findByTestId(
`MyObservations.obsGridItem.${observation.uuid}`
);
await actor.press( observationGridItem );
const addIdButton = observation.taxon
? await screen.findByLabelText( "Edit identification" )
: await screen.findByText( "ID WITH AI" );
await actor.press( addIdButton );
if ( options?.toTaxonSearch ) {
const taxonSearchButton = await screen.findByText( "SEARCH" );
await actor.press( taxonSearchButton );
} else {
const addIdButton = observation.taxon
? await screen.findByLabelText( "Edit identification" )
: await screen.findByText( "ID WITH AI" );
await actor.press( addIdButton );
}
}
async function navigateToSuggestionsViaCameraForObservation( ) {
@@ -304,12 +309,12 @@ describe( "Suggestions", ( ) => {
"should navigate back to ObsEdit with expected observation"
+ " when reached from ObsEdit via Suggestions and search result chosen",
async ( ) => {
const observations = [
factory( "LocalObservation", { geoprivacy: "obscured" } )
];
const observations = makeUnsyncedObservations();
useStore.setState( { observations } );
await renderAppWithObservations( observations, __filename );
await navigateToSuggestionsViaObsEditForObservation( observations[0] );
await navigateToSuggestionsViaObsEditForObservation( observations[0], {
toTaxonSearch: true
} );
const searchInput = await screen.findByLabelText( "Search for a taxon" );
const mockSearchResultTaxon = factory( "RemoteTaxon" );
inatjs.search.mockResolvedValue( makeResponse( [

View File

@@ -4,6 +4,13 @@ import React from "react";
import factory from "tests/factory";
import { renderComponent } from "tests/helpers/render";
const observationWithPhotos = factory( "RemoteObservation", {
observationPhotos: [{ id: 1 }]
} );
const observationWithoutPhotos = factory( "RemoteObservation", {
observationPhotos: []
} );
const firstObservation = factory( "RemoteObservation", {
taxon: {
name: "Fungi",
@@ -33,6 +40,16 @@ const renderIdentificationSection = ( obs, index = 0, resetState = false ) => re
);
describe( "IdentificationSection", () => {
it( "should show ID WITH AI button when observation has photos", ( ) => {
renderIdentificationSection( [observationWithPhotos] );
expect( screen.getByText( "ID WITH AI" ) ).toBeTruthy();
} );
it( "should not show ID WITH AI button when observation has no photos", ( ) => {
renderIdentificationSection( [observationWithoutPhotos] );
expect( screen.queryByText( "ID WITH AI" ) ).toBeNull();
} );
it( "should show correct iconic taxon selection when navigating multiple observations", ( ) => {
renderIdentificationSection( mockObservations );
const fungiIcon = screen.getByTestId( "IconicTaxonButton.fungi" );