Skip to content

Commit

Permalink
Update GenomeSelectorBySearchQuery (#1032)
Browse files Browse the repository at this point in the history
- Disabled search field in GenomeSelectorBySearchQuery if the search brought results
- Added content to show if there have been no search results
- Added styles and behaviour to disabled ShadedInput component
- Added a TextButton component, which uses native html button and thus is better for accessibility
   than spans or divs
  • Loading branch information
azangru authored Oct 3, 2023
1 parent 1f0c5a6 commit b749490
Show file tree
Hide file tree
Showing 14 changed files with 323 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import { useLazyGetSpeciesSearchResultsQuery } from 'src/content/app/new-species

import useSelectableGenomesTable from 'src/content/app/new-species-selector/components/selectable-genomes-table/useSelectableGenomesTable';

import SpeciesSearchField from 'src/content/app/new-species-selector/components/species-search-field/SpeciesSearchField';
import AddSpecies from 'src/content/app/new-species-selector/components/species-search-field/AddSpecies';
import SpeciesSearchField from '../species-search-field/SpeciesSearchField';
import SpeciesSearchResultsSummary from 'src/content/app/new-species-selector/components/species-search-results-summary/SpeciesSearchResultsSummary';
import SpeciesSearchResultsTable from 'src/content/app/new-species-selector/components/species-search-results-table/SpeciesSearchResultsTable';

Expand All @@ -31,19 +32,18 @@ import styles from './GenomeSelectorBySearchQuery.scss';
type Props = {
query: string;
onSpeciesAdd: (genomes: SpeciesSearchMatch[]) => void;
onClose: () => void;
};

const GenomeSelectorBySearchQuery = (props: Props) => {
const { query } = props;
const [hasQueryChangedSinceSubmission, setHasQueryChangedSinceSubmission] =
useState(false);
const { query, onClose } = props;
const [canSubmitSearch, setCanSubmitSearch] = useState(false);
const [searchTrigger, result] = useLazyGetSpeciesSearchResultsQuery();
const { currentData } = result;

const {
genomes,
stagedGenomes,
setStagedGenomes,
isTableExpanded,
onTableExpandToggle,
onGenomePreselectToggle
Expand All @@ -53,44 +53,52 @@ const GenomeSelectorBySearchQuery = (props: Props) => {
searchTrigger({ query });
}, []);

const onInput = () => {
setHasQueryChangedSinceSubmission(true);
setStagedGenomes([]); // remove all preselected species because user has changed value of the search field
};

const onSearchSubmit = () => {
searchTrigger({ query });
setHasQueryChangedSinceSubmission(false);
const onSearchInput = () => {
if (!canSubmitSearch) {
setCanSubmitSearch(true);
}
};

const onSpeciesAdd = () => {
props.onSpeciesAdd(stagedGenomes);
};

const speciesSearchFieldMode = stagedGenomes.length
? 'species-add'
: 'species-search';
const onSearchSubmit = () => {
searchTrigger({ query });
setCanSubmitSearch(false);
};

return (
<div className={styles.main}>
<SpeciesSearchField
onInput={onInput}
onSearchSubmit={onSearchSubmit}
mode={speciesSearchFieldMode}
onSpeciesAdd={onSpeciesAdd}
canSubmit={hasQueryChangedSinceSubmission}
/>
{currentData && !hasQueryChangedSinceSubmission && (
{currentData?.matches.length ? (
<AddSpecies
query={query}
canAdd={stagedGenomes.length > 0}
onAdd={onSpeciesAdd}
onCancel={onClose}
/>
) : (
<SpeciesSearchField
onInput={onSearchInput}
canSubmit={canSubmitSearch}
onSearchSubmit={onSearchSubmit}
/>
)}

{currentData && (
<>
<SpeciesSearchResultsSummary searchResult={currentData} />
<div className={styles.tableContainer}>
<SpeciesSearchResultsTable
results={genomes}
isExpanded={isTableExpanded}
onTableExpandToggle={onTableExpandToggle}
onSpeciesSelectToggle={onGenomePreselectToggle}
/>
</div>

{currentData.matches.length > 0 && (
<div className={styles.tableContainer}>
<SpeciesSearchResultsTable
results={genomes}
isExpanded={isTableExpanded}
onTableExpandToggle={onTableExpandToggle}
onSpeciesSelectToggle={onGenomePreselectToggle}
/>
</div>
)}
</>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import React from 'react';
import classNames from 'classnames';

import ShadedInput from 'src/shared/components/input/ShadedInput';
import { PrimaryButton } from 'src/shared/components/button/Button';
import TextButton from 'src/shared/components/text-button/TextButton';

import styles from './SpeciesSearchField.scss';

export type Props = {
query: string;
canAdd: boolean;
onAdd: () => void;
onCancel: () => void;
};

const AddSpecies = (props: Props) => {
const { query, canAdd, onAdd, onCancel } = props;

return (
<div className={styles.grid}>
<label>Find a species</label>
<ShadedInput
size="large"
className={styles.input}
value={query}
disabled={true}
/>
<div className={classNames(styles.controls, styles.addSpeciesControls)}>
<PrimaryButton disabled={!canAdd} onClick={onAdd}>
Add
</PrimaryButton>
<TextButton onClick={onCancel}>Cancel</TextButton>
</div>
</div>
);
};

export default AddSpecies;
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
@import 'src/styles/common';

.speciesSearchField {
.grid {
display: grid;
grid-template-areas:
'label .'
'input button';
grid-template-columns: 486px 64px;
'input controls';
grid-template-columns: 486px max-content;
row-gap: 10px;
column-gap: 45px;
}
Expand All @@ -19,11 +19,17 @@
grid-area: input;
}

.button {
grid-area: button;
.controls {
grid-area: controls;
align-self: center;
}

.submit {
--primary-button-color: #{$blue};
}

.addSpeciesControls {
display: flex;
align-items: center;
gap: 30px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import React, { type MouseEvent, FormEvent } from 'react';
import React, { FormEvent } from 'react';
import classNames from 'classnames';

import { useAppDispatch, useAppSelector } from 'src/store';
Expand All @@ -27,18 +27,15 @@ import { PrimaryButton } from 'src/shared/components/button/Button';

import styles from './SpeciesSearchField.scss';

type Mode = 'species-search' | 'species-add';

export type Props = {
onSearchSubmit: () => void;
mode?: Mode;
canSubmit?: boolean;
onSpeciesAdd?: () => void;
onInput?: ((event: FormEvent<HTMLInputElement>) => void) | (() => void);
};

const SpeciesSearchField = (props: Props) => {
const { mode = 'species-search', canSubmit = true } = props;
const { canSubmit = true } = props;
const dispatch = useAppDispatch();
const query = useAppSelector(getSpeciesSearchQuery);

Expand All @@ -53,13 +50,8 @@ const SpeciesSearchField = (props: Props) => {
props.onSearchSubmit();
};

const onAdd = (event: MouseEvent<HTMLButtonElement>) => {
event.preventDefault(); // to avoid triggering form submission
props.onSpeciesAdd?.();
};

return (
<form className={styles.speciesSearchField} onSubmit={onSubmit}>
<form className={styles.grid} onSubmit={onSubmit}>
<label>Find a species</label>
<ShadedInput
size="large"
Expand All @@ -71,18 +63,12 @@ const SpeciesSearchField = (props: Props) => {
help={helpText}
minLength={3}
/>
{mode === 'species-search' ? (
<PrimaryButton
disabled={!canSubmit || query.length < 3}
className={classNames(styles.button, styles.submit)}
>
Find
</PrimaryButton>
) : (
<PrimaryButton className={styles.button} onClick={onAdd}>
Add
</PrimaryButton>
)}
<PrimaryButton
disabled={!canSubmit || query.length < 3}
className={classNames(styles.controls, styles.submit)}
>
Find
</PrimaryButton>
</form>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,21 @@
.searchMatchesCount {
font-weight: $bold;
}

.noMatchesMessage {
color: $red;
margin-top: 40px;
margin-bottom: 30px;
}

.searchHelp p {
margin: 0;
}

.searchHelp ul {
padding-inline-start: 20px;
}

.searchHelp li {
list-style: disc;
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,57 @@ type Props = {
// TODO: add a filter component to this section

const SpeciesSearchResultsSummary = (props: Props) => {
const searchMatchesCount = props.searchResult?.meta.total_count;
const searchMatchesCount = props.searchResult?.meta.total_count ?? 0;

// TODO: style the contents differently if the results are from a popular species
return searchMatchesCount > 0 ? (
<SuccessfulSearchResults count={searchMatchesCount} />
) : (
<NoResults />
);
};

const SuccessfulSearchResults = (props: { count: number }) => {
const { count } = props;

return (
<section className={styles.container}>
{searchMatchesCount && searchMatchesCount > 1 && (
<span>
<span className={styles.searchMatchesCount}>{count}</span> results
</span>
</section>
);
};

const NoResults = () => {
return (
<section className={styles.container}>
<div>
<span>
<span className={styles.searchMatchesCount}>
{searchMatchesCount}
</span>{' '}
results
<span className={styles.searchMatchesCount}>0</span> results
</span>
)}
</div>
<div className={styles.noMatchesMessage}>
Sorry, we don’t recognise, or may not have data for this species
</div>
<SearchHelp />
</section>
);
};

const SearchHelp = () => {
return (
<div className={styles.searchHelp}>
<p>
In order to help you find what you’re really looking for, could we
suggest
</p>
<ul>
<li>only search for a species</li>
<li>use a full name where possible</li>
<li>try a different name or identifier</li>
</ul>
</div>
);
};

export default SpeciesSearchResultsSummary;
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ const SpeciesSelectorResultslView = () => {

return (
<ModalView onClose={onClose}>
<Content />
<Content onClose={onClose} />
</ModalView>
);
};

const Content = () => {
const Content = (props: { onClose: () => void }) => {
const modalView = useAppSelector(getSpeciesSelectorModalView);
const query = useAppSelector(getSpeciesSearchQuery);
const selectedPopularSpecies = useAppSelector(getSelectedPopularSpecies);
Expand All @@ -62,7 +62,11 @@ const Content = () => {
};

return modalView === 'species-search' ? (
<GenomeSelectorBySearchQuery query={query} onSpeciesAdd={onSpeciesAdd} />
<GenomeSelectorBySearchQuery
query={query}
onSpeciesAdd={onSpeciesAdd}
onClose={props.onClose}
/>
) : selectedPopularSpecies ? (
<GenomeSelectorBySpeciesTaxonomyId
speciesTaxonomyId={selectedPopularSpecies.species_taxonomy_id}
Expand Down
4 changes: 4 additions & 0 deletions src/shared/components/input/Input.scss
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@
}
}

.shadedInputDisabled {
background-color: $light-grey;
}

.flatInputWrapper {
background-color: var(--flat-input-background-colour, $white);
padding: 0 15px;
Expand Down
Loading

0 comments on commit b749490

Please sign in to comment.