Skip to content

Commit

Permalink
Merge pull request #896 from City-of-Helsinki/UHF-9108
Browse files Browse the repository at this point in the history
UHF-9108 Common components for React search header and empty text
  • Loading branch information
teroelonen authored Jan 30, 2024
2 parents 1728bc4 + 391c573 commit d538697
Show file tree
Hide file tree
Showing 26 changed files with 277 additions and 311 deletions.
4 changes: 2 additions & 2 deletions dist/css/styles.min.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/js/district-and-project-search.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/js/health-station-search.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/js/job-search.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/js/linkedevents.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/js/maternity-and-child-health-clinic-search.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/js/school-search.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion hdbt.libraries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ event-list:
- core/drupal

school-search:
version: 1.2
version: 1.3
js:
dist/js/school-search.min.js: {
preprocess: false
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useAtomValue, useSetAtom } from 'jotai';
import useSWR from 'swr';
import { SyntheticEvent, createRef } from 'react';

import Result from '../types/Result';
import Pagination from '@/react/common/Pagination';
import useScrollToResults from '@/react/common/hooks/useScrollToResults';
import LoadingOverlay from '@/react/common/LoadingOverlay';
Expand All @@ -13,7 +14,8 @@ import useQueryString from '../hooks/useQueryString';
import Global from '../enum/Global';
import Settings from '../enum/Settings';
import type URLParams from '../types/URLParams';
import Result from '../types/Result';
import ResultsHeader from '@/react/common/ResultsHeader';
import ResultsEmpty from '@/react/common/ResultsEmpty';

const ResultsContainer = (): JSX.Element => {
const { size } = Global;
Expand Down Expand Up @@ -56,21 +58,14 @@ const ResultsContainer = (): JSX.Element => {
return (
<ResultsError
error={error || initializationError}
className='district-project-search__results'
className='react-search__results'
ref={scrollTarget}
/>
);
}

if (!data?.hits?.hits.length) {
return (
<div className="district-project-search__results">
<div className='district-project-search__listing__no-results' ref={scrollTarget}>
<h2>{Drupal.t('Oh no! We did not find anything matching the search terms.', {}, { context: 'District and project search' })}</h2>
<p>{Drupal.t('Our website currently shows only some of the projects and residential areas of Helsinki. You can try again by removing some of the limiting search terms or by starting over.', {}, { context: 'District and project search' })}</p>
</div>
</div>
);
return <ResultsEmpty ref={scrollTarget} />;
}

const results = data.hits.hits;
Expand All @@ -84,29 +79,23 @@ const ResultsContainer = (): JSX.Element => {
};

return (
<div className="district-project-search__results">
<div className="district-project-search__results_heading">
<div className="district-project-search__count__container" ref={scrollTarget}>
<span className="district-project-search__count">
<span className="district-project-search__count-total">{total} </span>
<span className="district-project-search__count-label">{Drupal.t('search results', {}, { context: 'District and project search' })} </span>
</span>
</div>
<div className="district-project-search__sort__container">
<ResultsSort />
</div>
</div>
<div className="react-search__results">
<ResultsHeader
resultText={
<>
{ Drupal.formatPlural(total, '1 search result', '@count search results',{},{ context: 'District and project search' }) }
</>
}
actions={<ResultsSort />}
actionsClass="hdbt-search--react__results--sort"
ref={scrollTarget}
/>

<div className='district-project-search__container'>
{/* Safari requires role='list' for lists that have no bullet points */}
<div className='hdbt-search--react__results--container'>
{/* eslint-disable-next-line jsx-a11y/no-redundant-roles */}
<ul className='district-project-search__listing' role='list'>
{results.map((hit: Result) => (
<li>
<ResultCard key={hit._id} {...hit._source} />
</li>
<ResultCard key={hit._id} {...hit._source} />
))}
</ul>
<Pagination
currentPage={currentPage}
pages={5}
Expand Down
40 changes: 21 additions & 19 deletions src/js/react/apps/health-station-search/components/ResultsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import AppSettings from '../enum/AppSettings';
import { HealthStation } from '../types/HealthStation';
import ResultCard from './ResultCard';
import { paramsAtom } from '../store';
import ResultsHeader from '@/react/common/ResultsHeader';
import ResultsEmpty from '@/react/common/ResultsEmpty';

type ResultsListProps = {
data: any;
Expand Down Expand Up @@ -48,11 +50,7 @@ const ResultsList = ({ data, error, isLoading, isValidating, page, updatePage }:
}

if (!data?.hits?.hits.length) {
return (
<div ref={scrollTarget}>
{Drupal.t('No results were found for the criteria you entered. Try changing your search criteria.', {}, { context: 'React search: no search results' })}
</div>
);
return <ResultsEmpty ref={scrollTarget} />;
}

const results = data.hits.hits;
Expand All @@ -65,21 +63,25 @@ const ResultsList = ({ data, error, isLoading, isValidating, page, updatePage }:

return (
<div className='react-search__results'>
<div className='hdbt-search--react__result-top-area'>
{!Number.isNaN(total) &&
<h3 className='hdbt-search--react__results--title' ref={scrollTarget}>
{ Drupal.formatPlural(total, '1 health station', '@count health stations', {}, {context: 'Health station search: result count'}) }
</h3>
<ResultsHeader
resultText={
<>
{ Drupal.formatPlural(total, '1 health station', '@count health stations',{},{context: 'Health station search: result count'}) }
</>
}
<div className='hdbt-search--react__results--tablist' role='tablist'>
<button type='button' className='tablist-tab' role='tab' aria-selected={!useMap} aria-controls='hdbt-search--react__results--tabpanel' onClick={() => setUseMap(false)}>
{ Drupal.t('View as a list', {}, {context: 'React search: result display'}) }
</button>
<button type='button' className='tablist-tab' role='tab' aria-selected={useMap} aria-controls='hdbt-search--react__results--tabpanel' onClick={() => setUseMap(true)}>
{ Drupal.t('View in a map', {}, {context: 'React search: result display'}) }
</button>
</div>
</div>
actions={
<div className='hdbt-search--react__results--tablist' role='tablist'>
<button type='button' className='tablist-tab' role='tab' aria-selected={!useMap} aria-controls='hdbt-search--react__results--tabpanel' onClick={() => setUseMap(false)}>
{ Drupal.t('View as a list', {}, {context: 'React search: result display'}) }
</button>
<button type='button' className='tablist-tab' role='tab' aria-selected={useMap} aria-controls='hdbt-search--react__results--tabpanel' onClick={() => setUseMap(true)}>
{ Drupal.t('View in a map', {}, {context: 'React search: result display'}) }
</button>
</div>
}
actionsClass="hdbt-search--react__results--sort"
ref={scrollTarget}
/>
<div id='hdbt-search--react__results--tabpanel' role="tabpanel">
{
useMap ?
Expand Down
16 changes: 0 additions & 16 deletions src/js/react/apps/job-search/components/results/NoResults.tsx

This file was deleted.

28 changes: 0 additions & 28 deletions src/js/react/apps/job-search/components/results/ResultsCount.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import URLParams from '../types/URLParams';
import { configurationsAtom, pageAtom, setPageAtom, urlAtom } from '../store';
import usePromotedQuery from '../hooks/usePromotedQuery';
import useIndexQuery from '../hooks/useIndexQuery';
import NoResults from '../components/results/NoResults';
import IndexFields from '../enum/IndexFields';
import ResultsSort from '../components/results/ResultsSort';
import ResultsCount from '../components/results/ResultsCount';
import ResultsList from '../components/results/ResultsList';
import ResultsHeader from '@/react/common/ResultsHeader';
import ResultsEmpty from '@/react/common/ResultsEmpty';

const PromotedResultsContainer = () => {
const { size } = Global;
Expand Down Expand Up @@ -49,7 +49,7 @@ const PromotedResultsContainer = () => {
return (
<ResultsError
error={error || initializationError || data.error}
className='job-search__results'
className='react-search__results'
ref={scrollTarget}
/>
);
Expand All @@ -60,31 +60,39 @@ const PromotedResultsContainer = () => {
// Typecheck and combine totals from both queries
const promotedTotal = Number(promotedResponse.aggregations?.total_count?.value);
const baseTotal = Number(baseResponse.aggregations?.total_count?.value);
const total = (Number.isNaN(promotedTotal) ? 0 : promotedTotal) + (Number.isNaN(baseTotal) ? 0 : baseTotal);
const totalNumber = (Number.isNaN(promotedTotal) ? 0 : promotedTotal) + (Number.isNaN(baseTotal) ? 0 : baseTotal);
const total = totalNumber.toString();

if (total <= 0) {
return <NoResults ref={scrollTarget} />;
if (totalNumber <= 0) {
return <ResultsEmpty wrapperClass='hdbt-search--react__results--container' ref={scrollTarget} />;
}

const pages = Math.floor(total / size);
const addLastPage = total > size && total % size;
const pages = Math.floor(totalNumber / size);
const addLastPage = totalNumber > size && totalNumber % size;

// Typecheck and combine job totals (aggregated vacancies)
const promotedJobs = promotedResponse.aggregations?.[IndexFields.NUMBER_OF_JOBS]?.value;
const baseJobs = baseResponse.aggregations?.[IndexFields.NUMBER_OF_JOBS]?.value;
const jobs = (Number.isNaN(promotedJobs) ? 0 : promotedJobs) + (Number.isNaN(baseJobs) ? 0 : baseJobs);
const jobs: string = (Number.isNaN(promotedJobs) ? 0 : promotedJobs) + (Number.isNaN(baseJobs) ? 0 : baseJobs);
const results = [...promotedResponse.hits.hits, ...baseResponse.hits.hits];

return (
<>
<div className='job-search__results-stats'>
<ResultsCount
jobs={jobs}
total={total}
ref={scrollTarget}
/>
<ResultsSort />
</div>
<ResultsHeader
resultText={
<>
{ Drupal.formatPlural(jobs, '1 open position', '@count open positions',{},{ context: 'Job search results statline' }) }
</>
}
optionalResultsText={
<>
{ Drupal.formatPlural(total, '1 job listing', '@count job listings',{},{context: 'Job search results statline'}) }
</>
}
actions={<ResultsSort />}
actionsClass="hdbt-search--react__results--sort"
ref={scrollTarget}
/>
<ResultsList hits={results} />
<Pagination
currentPage={currentPage}
Expand Down
35 changes: 21 additions & 14 deletions src/js/react/apps/job-search/containers/SimpleResultsContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import URLParams from '../types/URLParams';
import { urlAtom , configurationsAtom, pageAtom, setPageAtom } from '../store';
import useQueryString from '../hooks/useQueryString';
import useIndexQuery from '../hooks/useIndexQuery';
import ResultsCount from '../components/results/ResultsCount';
import NoResults from '../components/results/NoResults';
import ResultsSort from '../components/results/ResultsSort';
import ResultsList from '../components/results/ResultsList';
import Global from '../enum/Global';
import IndexFields from '../enum/IndexFields';
import ResultsHeader from '@/react/common/ResultsHeader';
import ResultsEmpty from '@/react/common/ResultsEmpty';

const SimpleResultsContainer = () => {
const { size } = Global;
Expand Down Expand Up @@ -43,14 +43,14 @@ const SimpleResultsContainer = () => {
return (
<ResultsError
error={error || initializationError}
className='job-search__results'
className='react-search__results'
ref={scrollTarget}
/>
);
}

if (!data?.hits?.hits.length) {
return <NoResults ref={scrollTarget} />;
return <ResultsEmpty wrapperClass='hdbt-search--react__results--container' ref={scrollTarget} />;
}

const results = data.hits.hits;
Expand All @@ -59,18 +59,25 @@ const SimpleResultsContainer = () => {
const addLastPage = total > size && total % size;

// Total number of available jobs
const jobs: number = data?.aggregations?.[IndexFields.NUMBER_OF_JOBS]?.value;
const jobs = data?.aggregations?.[IndexFields.NUMBER_OF_JOBS]?.value;

return (
<>
<div className='job-search__results-stats'>
<ResultsCount
jobs={jobs}
total={total}
ref={scrollTarget}
/>
<ResultsSort />
</div>
<ResultsHeader
resultText={
<>
{ Drupal.formatPlural(jobs, '1 open position', '@count open positions',{},{ context: 'Job search results statline' }) }
</>
}
optionalResultsText={
<>
{ Drupal.formatPlural(total, '1 job listing', '@count job listings',{},{context: 'Job search results statline'}) }
</>
}
actions={<ResultsSort />}
actionsClass="hdbt-search--react__results--sort"
ref={scrollTarget}
/>
<ResultsList hits={results} />
<Pagination
currentPage={currentPage}
Expand All @@ -88,7 +95,7 @@ const SimpleResultsContainer = () => {
};

return (
<div className='job-search__results'>
<div className='react-search__results'>
<ResultWrapper loading={isLoading || isValidating}>
{getResults()}
</ResultWrapper>
Expand Down
Loading

0 comments on commit d538697

Please sign in to comment.