From da507eae6bf5f64b6e0a458c90af37577236dd4f Mon Sep 17 00:00:00 2001 From: Doug Martin Date: Fri, 30 Aug 2024 10:30:00 -0400 Subject: [PATCH] feat: Display collections in search results [PT-188117039] Splits out collections from resources and displays them at the top of the page. --- .../src/library/components/collections.scss | 22 +++++++ .../src/library/components/collections.tsx | 60 +++++++++++++++++++ .../components/stem-finder-result.scss | 2 +- .../library/components/stem-finder-result.tsx | 14 +++-- .../src/library/components/stem-finder.tsx | 47 ++++++++++++--- 5 files changed, 131 insertions(+), 14 deletions(-) create mode 100644 rails/react-components/src/library/components/collections.scss create mode 100644 rails/react-components/src/library/components/collections.tsx diff --git a/rails/react-components/src/library/components/collections.scss b/rails/react-components/src/library/components/collections.scss new file mode 100644 index 000000000..ca788eee2 --- /dev/null +++ b/rails/react-components/src/library/components/collections.scss @@ -0,0 +1,22 @@ +@import '../../shared/styles/variables/_variables.scss'; + +.finderResultsCollections { + margin-bottom: 30px; + + .finderResultsCollectionsHeader { + margin-bottom: 10px; + + .finderResultsCollectionsCount { + display: flex; + justify-content: space-between; + } + } + + .findResultsCollectionsShowMore { + background: $col-orange; + color: $white; + padding: 5px 10px; + display: inline-block; + border-radius: 4px; + } +} diff --git a/rails/react-components/src/library/components/collections.tsx b/rails/react-components/src/library/components/collections.tsx new file mode 100644 index 000000000..30754449d --- /dev/null +++ b/rails/react-components/src/library/components/collections.tsx @@ -0,0 +1,60 @@ +import React from "react"; +import StemFinderResult from "./stem-finder-result"; +import pluralize from "../helpers/pluralize"; + +import css from "./collections.scss"; + +interface Props { + collections: any[] + numTotalCollections: number; +} + +interface State { + displayCount: number +} + +export default class Collections extends React.Component { + constructor (props: Props) { + super(props); + + this.state = { + displayCount: Math.min(2, props.numTotalCollections) + }; + } + + UNSAFE_componentWillReceiveProps (nextProps: any) { + this.setState((prev) => ({displayCount: Math.min(prev.displayCount, nextProps.numTotalCollections)})); + } + + handleShowMore = () => { + this.setState((prev) => ({displayCount: Math.min(prev.displayCount + 2, this.props.numTotalCollections)})); + }; + + render () { + const { displayCount } = this.state; + const { collections, numTotalCollections } = this.props; + const showingAll = displayCount >= numTotalCollections; + const collectionCount = showingAll ? numTotalCollections : displayCount + " of " + numTotalCollections; + + const displayCollections = collections.slice(0, displayCount); + + return ( +
+
+

Collections

+
+
+ Showing { collectionCount + " " + pluralize(collectionCount, "Collection", "Collections") } matching your search +
+
+
+
+ { displayCollections.map((collection: any, index: any) => { + return ; + }) } +
+ {!showingAll && } +
+ ); + } +} diff --git a/rails/react-components/src/library/components/stem-finder-result.scss b/rails/react-components/src/library/components/stem-finder-result.scss index 2bab96093..3ac152ec2 100644 --- a/rails/react-components/src/library/components/stem-finder-result.scss +++ b/rails/react-components/src/library/components/stem-finder-result.scss @@ -230,7 +230,7 @@ } } .previewLink { - width: 130px; + width: 140px; .previewLinkButton { background: #fff; diff --git a/rails/react-components/src/library/components/stem-finder-result.tsx b/rails/react-components/src/library/components/stem-finder-result.tsx index aa2d869fa..8143f5c22 100644 --- a/rails/react-components/src/library/components/stem-finder-result.tsx +++ b/rails/react-components/src/library/components/stem-finder-result.tsx @@ -357,7 +357,7 @@ const StemFinderResult = Component({ }, render () { - const { resource, index } = this.props; + const { resource, index, opacity } = this.props; const resourceTypeClass = resource.material_type.toLowerCase(); const finderResultClasses = this.state.isOpen ? `resourceItem ${css.finderResult} ${css.open} ${css[resourceTypeClass]}` : `resourceItem ${css.finderResult} ${css[resourceTypeClass]}`; const resourceName = resource.name; @@ -367,9 +367,14 @@ const StemFinderResult = Component({ const projectNameRegex = / |-|\./g; const projectClass = projectName ? projectName.replace(projectNameRegex, "").toLowerCase() : null; const transitionDelay = 100 * index; + const style: React.CSSProperties = { transitionDelay: transitionDelay + "ms" }; + + if (opacity !== undefined) { + style.opacity = opacity; + } return ( -
+
{resource.name}
@@ -389,10 +394,9 @@ const StemFinderResult = Component({
{ resource.material_type !== "Collection" ? { resource.links.preview.text } - : View Collection + : Go to Collection } - { resource.material_type !== "Collection" && -
+ {
{ projectName }
} diff --git a/rails/react-components/src/library/components/stem-finder.tsx b/rails/react-components/src/library/components/stem-finder.tsx index fa37e6300..aa7e3beb4 100644 --- a/rails/react-components/src/library/components/stem-finder.tsx +++ b/rails/react-components/src/library/components/stem-finder.tsx @@ -10,6 +10,7 @@ import filters from "../helpers/filters"; import portalObjectHelpers from "../helpers/portal-object-helpers"; import AutoSuggest from "./search/auto-suggest"; import FeaturedCollections from "./featured-collections/featured-collections"; +import Collections from "./collections"; import css from "./stem-finder.scss"; @@ -53,6 +54,7 @@ interface State { lastSearchResultCount: number, noResourcesFound: boolean, numTotalResources: number, + numTotalCollections: number; opacity: number, resources: any[], searching: boolean, @@ -139,6 +141,7 @@ class StemFinder extends React.Component { lastSearchResultCount: 0, noResourcesFound: false, numTotalResources: 0, + numTotalCollections: 0, opacity: 1, resources: [], searching: false, @@ -286,6 +289,7 @@ class StemFinder extends React.Component { let resources = incremental ? this.state.resources.slice(0) : []; const searchPage = incremental ? this.state.searchPage + 1 : 1; const keyword = jQuery.trim(this.state.searchInput); + const collections: any[] = incremental ? this.state.collections.slice(0) : []; /* eslint-enable react/no-access-state-in-setstate */ // short circuit further incremental searches when all data has been downloaded @@ -317,6 +321,7 @@ class StemFinder extends React.Component { dataType: "json" }).done((result1: any) => { let numTotalResources = 0; + let numTotalCollections = 0; const results = result1.results; const usersAuthoredResourcesCount = result1.filters.number_authored_resources; let lastSearchResultCount = 0; @@ -324,13 +329,22 @@ class StemFinder extends React.Component { results.forEach((result: any) => { result.materials.forEach((material: any) => { portalObjectHelpers.processResource(material); - resources.push(material); if (material.material_type === "Collection") { featuredCollections.push(material); + // only set collections on initial search + if (!incremental) { + collections.push(material); + } + } else { + resources.push(material); + lastSearchResultCount++; } - lastSearchResultCount++; }); - numTotalResources += result.pagination.total_items; + if (result.type === "collections") { + numTotalCollections = collections.length; + } else { + numTotalResources += result.pagination.total_items; + } }); if (featuredCollections.length > 1) { @@ -345,8 +359,10 @@ class StemFinder extends React.Component { this.setState({ firstSearch: false, featuredCollections, + collections, resources, numTotalResources, + numTotalCollections, searchPage, displayLimit, searching: false, @@ -739,6 +755,25 @@ class StemFinder extends React.Component { }, 500); } + renderCollections () { + const { collections, searchInput, numTotalCollections } = this.state; + const showCollections = (searchInput.trim().length > 0 || !this.noOptionsSelected()) && collections.length > 0; + + if (showCollections) { + return ; + } + + let featuredCollections = this.state.featuredCollections; + featuredCollections = featuredCollections.sort(() => Math.random() - Math.random()).slice(0, 3); + const showFeaturedCollections = !this.state.hideFeatured && this.state.initPage && this.noOptionsSelected() && featuredCollections.length > 0; + + if (showFeaturedCollections) { + return ; + } + + return null; + } + renderResults () { if (this.state.firstSearch) { return ( @@ -748,14 +783,10 @@ class StemFinder extends React.Component { ); } - let featuredCollections = this.state.featuredCollections; - featuredCollections = featuredCollections.sort(() => Math.random() - Math.random()).slice(0, 3); const resources = this.state.resources.slice(0, this.state.displayLimit); return ( <> - { (!this.state.hideFeatured && this.state.initPage && this.noOptionsSelected() && featuredCollections.length > 0) && - - } + { this.renderCollections() } { this.renderResultsHeader() }
{ resources.map((resource: any, index: any) => {