Skip to content

Commit

Permalink
Merge pull request #505 from mlibrary/LIBSEARCH-1008-update-everythin…
Browse files Browse the repository at this point in the history
…g-results-bento-box-displays-with-new-language

[LIBSEARCH-1008] Update Everything results bento box displays with new language
  • Loading branch information
erinesullivan authored Nov 20, 2024
2 parents b5e5e97 + 0ed7b39 commit 5f7bc14
Show file tree
Hide file tree
Showing 11 changed files with 184 additions and 313 deletions.
2 changes: 0 additions & 2 deletions src/modules/pride/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
getDatastoreByUid,
getDatastoreSlugByUid,
getDatastoreUidBySlug,
getMultiSearchRecords,
getStateFromURL,
isValidURLSearchQuery,
prideParseField,
Expand All @@ -16,7 +15,6 @@ export {
getDatastoreByUid,
getDatastoreSlugByUid,
getDatastoreUidBySlug,
getMultiSearchRecords,
getStateFromURL,
initializePride,
isValidURLSearchQuery,
Expand Down
31 changes: 0 additions & 31 deletions src/modules/pride/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,36 +22,6 @@ const getDatastoreUidBySlug = (slugParam) => {
return uidDs?.uid;
};

const getMultiSearchRecords = (activeDatastore, allRecords) => {
const configDs = getDatastoreByUid(activeDatastore);

if (!configDs) {
return null;
}

const { datastores } = configDs;

// Pick records corresponding to configDs.datastores using Object.keys
const multiSearchRecords = datastores.reduce((selectedRecords, datastore) => {
if (allRecords[datastore]) {
selectedRecords[datastore] = allRecords[datastore];
}
return selectedRecords;
}, {});

const bentoBoxes = datastores.reduce(
(memo, datastore) => {
const { name, slug, uid } = getDatastoreByUid(datastore);
const records = (multiSearchRecords[datastore] && Object.values(multiSearchRecords[datastore]).splice(0, 3)) || [];
memo.push({ name, records, slug, uid });

return memo;
}, []
);

return bentoBoxes;
};

const getDatastoreSlugByUid = (uid) => {
const datastore = getDatastoreByUid(uid);

Expand Down Expand Up @@ -195,7 +165,6 @@ export {
getDatastoreByUid,
getDatastoreSlugByUid,
getDatastoreUidBySlug,
getMultiSearchRecords,
getStateFromURL,
isValidURLSearchQuery,
prideParseField,
Expand Down
193 changes: 73 additions & 120 deletions src/modules/records/components/BentoboxList/index.js
Original file line number Diff line number Diff line change
@@ -1,152 +1,105 @@
import './styles.css';
import { Anchor, Icon } from '../../../reusable';
import { getMultiSearchRecords } from '../../../pride';
import { getMultiSearchRecords } from '../../utilities';
import ILLRequestMessage from '../ILLRequestMessage';
import KeywordSwitch from '../KeywordSwitch';
import PropTypes from 'prop-types';
import React from 'react';
import RecordPreview from '../RecordPreview';
import RecordPreviewPlaceholder from '../RecordPreviewPlaceholder';
import { Specialists } from '../../../specialists';
import { useLocation } from 'react-router-dom';
import { useSelector } from 'react-redux';

const BentoboxResultsNum = ({ totalResults }) => {
// Results have loaded
if (typeof totalResults === 'number') {
return <span className='bentobox-results-info'>{totalResults.toLocaleString()} {`Result${totalResults === 1 ? '' : 's'}`}</span>;
}

// Loading results
return <span className='bentobox-results-info'>Loading...</span>;
};

BentoboxResultsNum.propTypes = {
totalResults: PropTypes.number
};

const BentoResults = ({ bentobox, search, searchQuery }) => {
// No results
if (search.data[bentobox.uid]?.totalAvailable === 0) {
return (
<>
{bentobox.uid === 'primo' && <KeywordSwitch datastore={bentobox} query={search.query} />}
<div className='bentobox-no-results'>
<p className='no-margin'><span className='strong'>No results</span> match your search.</p>
{['databases', 'onlinejournals'].includes(bentobox.uid) && (
<p className='u-margin-bottom-none'>Try our <Anchor to={`/${bentobox.slug}/browse`}>Browse {bentobox.name} page</Anchor> to view all titles alphabetically or by academic discipline.</p>
)}
{bentobox.uid === 'mirlyn' && (
<p className='u-margin-bottom-none'><ILLRequestMessage /></p>
)}
</div>
</>
);
}

// Loading results
if (bentobox.records.length === 0) {
return (
<div className='results-list results-list-border'>
{[...Array(3)].map((elementInArray, index) => {
return <RecordPreviewPlaceholder key={index} />;
})}
</div>
);
}

// Results
return (
<div className='results-list results-list-border'>
{bentobox.records.map((record, index) => {
if (index === 0) {
return (
<div key={`${index}keyword-switch`}>
<KeywordSwitch datastore={bentobox} query={search.query} />
<RecordPreview
key={index}
datastoreUid={bentobox.uid}
record={record}
searchQuery={searchQuery}
/>
</div>
);
}
return (
<RecordPreview
key={index}
datastoreUid={bentobox.uid}
record={record}
searchQuery={searchQuery}
/>
);
})}
</div>
);
};

BentoResults.propTypes = {
bentobox: PropTypes.object,
search: PropTypes.object,
searchQuery: PropTypes.string
};

const BentoFooter = ({ bentobox, search, searchQuery }) => {
// Loading or no results
if (search.data[bentobox.uid]?.totalAvailable === 0 || bentobox.records.length === 0) {
return null;
}

return (
<Anchor
className='bentobox-footer-container'
to={`/${bentobox.slug}${searchQuery}`}
>
<span>{`View all ${bentobox.name} results`}</span><Icon icon='arrow_forward' size='1.5rem' />
</Anchor>
);
};

BentoFooter.propTypes = {
bentobox: PropTypes.object,
search: PropTypes.object,
searchQuery: PropTypes.string
const descriptions = {
databases: 'Online resources of all types — text, images, audio, video, data, etc. — some open access, many restricted to U-M.',
mirlyn: 'Everything in our physical collection as well as ebooks, audio, video, and online journals.',
onlinejournals: 'Scholarly journals, newspapers, trade and popular magazines, annual publications, and more.',
primo: 'Articles from scholarly journals, magazines, and newspapers; ebooks and chapters; proceedings; reports; and more — all online.',
website: 'U-M Library created research guides, specialty sites, blogs, and online exhibits.'
};

const BentoboxList = () => {
const { records } = useSelector((state) => {
return state.records;
});
const { active: datastoreUid } = useSelector((state) => {
const { active } = useSelector((state) => {
return state.datastores;
});
const search = useSelector((state) => {
const { data, query } = useSelector((state) => {
return state.search;
});
const location = useLocation();
const searchQuery = location.search;

return (
<article className='bentobox-list' id='search-results'>
{getMultiSearchRecords(datastoreUid, records).map((bentobox, index) => {
if (!bentobox.records) {
<article className='bentobox-list'>
{getMultiSearchRecords(active, records).map((datastore, index) => {
const { name, records: datastoreRecords, slug, uid } = datastore;

if (!datastoreRecords) {
return null;
}

const totalResults = data[uid]?.totalAvailable;
const hasRecords = datastoreRecords.length > 0;

return (
<React.Fragment key={bentobox.uid}>
<React.Fragment key={uid}>
{index === 2 && <Specialists show={2} />}
<section className={`bentobox bentobox-${bentobox.uid}`}>
<div className='container__rounded'>
<Anchor
className='bentobox-heading-container'
to={`/${bentobox.slug}${searchQuery}`}
>
<h2 className='bentobox-heading'>{bentobox.name}</h2>
<BentoboxResultsNum totalResults={search.data[bentobox.uid].totalAvailable} />
</Anchor>
<BentoResults {...{ bentobox, datastoreUid, search, searchQuery }} />
<BentoFooter {...{ bentobox, search, searchQuery }} />
</div>
<section className={`container__rounded bentobox bentobox-${uid}`}>
<Anchor className='flex padding-x__m padding-y__xs bentobox-heading' to={`/${slug}${searchQuery}`}>
<h2 className='h4 margin__none'>{name}</h2>
<small>
{typeof totalResults === 'number'
? `${totalResults.toLocaleString()} Result${totalResults === 1 ? '' : 's'}`
: 'Loading...'}
</small>
</Anchor>
{descriptions[uid] && (
<div className='record-preview bentobox-description'>
<span>{descriptions[uid]}</span>
</div>
)}
{hasRecords && <KeywordSwitch {...{ datastore, query }} />}
{totalResults === 0
? (
<div className='record-preview bentobox-no-results'>
<p>
<span className='strong'>No results</span> match your search.
</p>
{['databases', 'onlinejournals'].includes(uid) && (
<p>
Try our <Anchor to={`/${slug}/browse`}>Browse {name} page</Anchor> to view all titles alphabetically or by academic discipline.
</p>
)}
{uid === 'mirlyn' && (
<p>
<ILLRequestMessage />
</p>
)}
</div>
)
: (
<>
<div className='results-list'>
{hasRecords
? datastoreRecords.map((record, place) => {
return (
<RecordPreview key={`${uid}-${place}`} {...{ datastoreUid: uid, record, searchQuery }} />
);
})
: Array.from({ length: 3 }).map((elementInArray, place) => {
return <RecordPreviewPlaceholder key={place} />;
})}
</div>
{hasRecords && (
<Anchor className='flex padding-x__m padding-y__s underline__hover bentobox-footer' to={`/${slug}${searchQuery}`}>
<span>{`View all ${name} results`}</span>
<Icon icon='arrow_forward' size='1.5rem' />
</Anchor>
)}
</>
)}
</section>
</React.Fragment>
);
Expand Down
54 changes: 54 additions & 0 deletions src/modules/records/components/BentoboxList/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
.bentobox-list {
align-items: start;
display: grid;
gap: 1.5rem;
justify-content: center;
width: 100%;
}

@media (min-width: 600px) {
.bentobox-list {
grid-template-columns: repeat(auto-fit, minmax(0, 20rem));
}
}

.bentobox {
overflow: hidden;
}

.bentobox-heading,
.bentobox-footer {
align-items: center;
justify-content: space-between;
min-height: 2.5rem;
}

.bentobox-heading {
background: var(--search-color-blue-400);
}

.bentobox-heading * {
color: white;
font-weight: 600;
}

.bentobox-heading:hover *:not(small) {
text-decoration: underline;
}

.bentobox-description {
background: var(--search-color-blue-200);
border: 0;
}

.bentobox-footer {
background: var(--search-color-grey-100);
}

.bentobox-no-results > *:first-child {
margin-top: 0;
}

.bentobox-no-results > *:last-child {
margin-bottom: 0;
}
6 changes: 1 addition & 5 deletions src/modules/records/components/ILLRequestMessage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ import { Anchor } from '../../../reusable';
import React from 'react';

const ILLRequestMessage = () => {
return (
<>
Place an <Anchor href='https://ill.lib.umich.edu/' utmSource='library-search-no-items'>Interlibrary Loan request</Anchor> if you need something we don&apos;t have. We&apos;ll get it from another institution.
</>
);
return <>Place an <Anchor href='https://ill.lib.umich.edu/' utmSource='library-search-no-items'>Interlibrary Loan request</Anchor> if you need something we don&apos;t have. We&apos;ll get it from another institution.</>;
};

export default ILLRequestMessage;
2 changes: 1 addition & 1 deletion src/modules/records/components/RecordList/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const RecordList = () => {
: (
<>
<GoToList {...{ datastore, list }} />
<div className='results-list results-list-border search-results'>
<div className='results-list search-results'>
{loadingRecords
? [...Array(count)].map((elementInArray, index) => {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import React from 'react';

const RecordPreviewPlaceholder = () => {
return (
<li className='record-preview record-preview-placeholder'>
<div className='placeholder placeholder-title' />
<article className='record-preview'>
<div className='placeholder placeholder-title margin-top__xs' />
<div className='placeholder placeholder-line placeholder-line-alt' />
<div className='placeholder placeholder-line record-placeholder-last' />
</li>
<div className='placeholder placeholder-line margin-bottom__xs' />
</article>
);
};

Expand Down
Loading

0 comments on commit 5f7bc14

Please sign in to comment.