diff --git a/website/modules/case-studies-page/index.js b/website/modules/case-studies-page/index.js index f0f0241e..29daa7f8 100644 --- a/website/modules/case-studies-page/index.js +++ b/website/modules/case-studies-page/index.js @@ -13,6 +13,7 @@ module.exports = { { name: 'industry' }, { name: 'stack' }, { name: 'caseStudyType' }, + { name: 'partner' }, ], pieces: 'case-studies', piecesFiltersUrl: '/case-studies', @@ -59,6 +60,7 @@ module.exports = { industry: {}, stack: {}, caseStudyType: {}, + partner: {}, }); } }, diff --git a/website/modules/case-studies-page/services/NavigationService.js b/website/modules/case-studies-page/services/NavigationService.js index d0871f37..28e2f26e 100644 --- a/website/modules/case-studies-page/services/NavigationService.js +++ b/website/modules/case-studies-page/services/NavigationService.js @@ -9,15 +9,22 @@ */ class NavigationService { /** - * Converts tag slugs to IDs + * Converts slugs to document IDs for a given piece module * @param {Object} apos - ApostropheCMS instance * @param {Object} req - Request object - * @param {Array} slugs - Array of tag slugs - * @returns {Promise} Promise resolving to array of tag IDs + * @param {Array|string} slugs - Array of slugs or single slug (Express may pass string for one query param) + * @param {string} moduleKey - Key of the piece module in apos.modules (e.g. 'cases-tags', 'business-partner') + * @returns {Promise} Promise resolving to array of document IDs */ - static async convertSlugsToIds(apos, req, slugs) { - const tagPromises = slugs.map(async (slug) => { - const results = await apos.modules['cases-tags'] + static async convertSlugsToIdsForModule(apos, req, slugs, moduleKey) { + let slugList = []; + if (Array.isArray(slugs)) { + slugList = slugs; + } else if (slugs) { + slugList = [slugs]; + } + const docPromises = slugList.map(async (slug) => { + const results = await apos.modules[moduleKey] .find(req, { slug }) .toArray(); if (results.length > 0) { @@ -25,8 +32,40 @@ class NavigationService { } return null; }); - const tags = await Promise.all(tagPromises); - return tags.filter((tag) => tag).map((tag) => tag.aposDocId); + const docs = await Promise.all(docPromises); + return docs.filter((doc) => doc).map((doc) => doc.aposDocId); + } + + /** + * Converts tag slugs to IDs (cases-tags module) + * @param {Object} apos - ApostropheCMS instance + * @param {Object} req - Request object + * @param {Array} slugs - Array of tag slugs + * @returns {Promise} Promise resolving to array of tag IDs + */ + static convertSlugsToIds(apos, req, slugs) { + return NavigationService.convertSlugsToIdsForModule( + apos, + req, + slugs, + 'cases-tags', + ); + } + + /** + * Converts business partner slugs to IDs + * @param {Object} apos - ApostropheCMS instance + * @param {Object} req - Request object + * @param {Array} slugs - Array of partner slugs + * @returns {Promise} Promise resolving to array of partner IDs + */ + static convertPartnerSlugsToIds(apos, req, slugs) { + return NavigationService.convertSlugsToIdsForModule( + apos, + req, + slugs, + 'business-partner', + ); } /** @@ -37,45 +76,45 @@ class NavigationService { * @returns {Promise} Promise resolving to modified query object */ static async applyFiltersToQuery(query, req, apos) { + const filterConfigs = [ + { + param: 'industry', + convert: NavigationService.convertSlugsToIds, + field: 'industryIds', + }, + { + param: 'stack', + convert: NavigationService.convertSlugsToIds, + field: 'stackIds', + }, + { + param: 'caseStudyType', + convert: NavigationService.convertSlugsToIds, + field: 'caseStudyTypeIds', + }, + { + param: 'partner', + convert: NavigationService.convertPartnerSlugsToIds, + field: 'partnerIds', + }, + ]; + const idArrays = await Promise.all( + filterConfigs.map((config) => { + if (req.query[config.param]?.length) { + return config.convert(apos, req, req.query[config.param]); + } + return Promise.resolve([]); + }), + ); let filteredQuery = query; - - if (req.query.industry && req.query.industry.length > 0) { - const industryIds = await NavigationService.convertSlugsToIds( - apos, - req, - req.query.industry, - ); - if (industryIds.length > 0) { + for (let index = 0; index < filterConfigs.length; index += 1) { + const ids = idArrays[index]; + if (ids.length > 0) { filteredQuery = filteredQuery.and({ - industryIds: { $in: industryIds }, + [filterConfigs[index].field]: { $in: ids }, }); } } - - if (req.query.stack && req.query.stack.length > 0) { - const stackIds = await NavigationService.convertSlugsToIds( - apos, - req, - req.query.stack, - ); - if (stackIds.length > 0) { - filteredQuery = filteredQuery.and({ stackIds: { $in: stackIds } }); - } - } - - if (req.query.caseStudyType && req.query.caseStudyType.length > 0) { - const caseStudyTypeIds = await NavigationService.convertSlugsToIds( - apos, - req, - req.query.caseStudyType, - ); - if (caseStudyTypeIds.length > 0) { - filteredQuery = filteredQuery.and({ - caseStudyTypeIds: { $in: caseStudyTypeIds }, - }); - } - } - return filteredQuery; } diff --git a/website/modules/case-studies-page/services/TagCountService.js b/website/modules/case-studies-page/services/TagCountService.js index 9494f3d4..0637f474 100644 --- a/website/modules/case-studies-page/services/TagCountService.js +++ b/website/modules/case-studies-page/services/TagCountService.js @@ -9,16 +9,16 @@ */ class TagCountService { /** - * Creates a mapping from tag IDs to tag slugs - * @param {Array} casesTags - Array of tag objects - * @returns {Object} Map of tag ID to slug + * Creates a mapping from document ID to slug for any array of docs with aposDocId and slug + * @param {Array} docs - Array of document objects with aposDocId and slug + * @returns {Object} Map of document ID to slug */ - static createTagMap(casesTags) { - const tagMap = {}; - casesTags.forEach((tag) => { - tagMap[tag.aposDocId] = tag.slug; + static createIdToSlugMap(docs) { + const map = {}; + docs.forEach((doc) => { + map[doc.aposDocId] = doc.slug; }); - return tagMap; + return map; } /** @@ -47,21 +47,25 @@ class TagCountService { * @param {Object} req - ApostropheCMS request object * @param {Object} aposModules - ApostropheCMS modules * @param {Object} options - Module options - * @returns {Promise} Promise resolving to [caseStudies, casesTags] arrays + * @returns {Promise} Promise resolving to [caseStudies, casesTags, businessPartners] arrays */ static async fetchCaseStudiesAndTags(req, aposModules, options) { - const caseStudies = await aposModules[options.pieces].find(req).toArray(); - const casesTags = await aposModules['cases-tags'].find(req).toArray(); - return [caseStudies, casesTags]; + const [caseStudies, casesTags, businessPartners] = await Promise.all([ + aposModules[options.pieces].find(req).toArray(), + aposModules['cases-tags'].find(req).toArray(), + aposModules['business-partner'].find(req).toArray(), + ]); + return [caseStudies, casesTags, businessPartners]; } /** * Processes case studies to count tags by type * @param {Array} caseStudies - Array of case study objects * @param {Object} tagMap - Map of tag ID to slug + * @param {Object} partnerMap - Map of partner ID to slug * @param {Object} tagCounts - Object to store all tag counts */ - static processCaseStudies(caseStudies, tagMap, tagCounts) { + static processCaseStudies(caseStudies, tagMap, partnerMap, tagCounts) { caseStudies.forEach((study) => { TagCountService.countTagsOfType( study.industryIds, @@ -76,6 +80,12 @@ class TagCountService { tagMap, tagCounts.caseStudyType, ); + + TagCountService.countTagsOfType( + study.partnerIds, + partnerMap, + tagCounts.partner, + ); }); } @@ -91,14 +101,21 @@ class TagCountService { industry: {}, stack: {}, caseStudyType: {}, + partner: {}, }; - const [caseStudies, casesTags] = + const [caseStudies, casesTags, businessPartners] = await TagCountService.fetchCaseStudiesAndTags(req, aposModules, options); - const tagMap = TagCountService.createTagMap(casesTags); + const tagMap = TagCountService.createIdToSlugMap(casesTags); + const partnerMap = TagCountService.createIdToSlugMap(businessPartners); - TagCountService.processCaseStudies(caseStudies, tagMap, tagCounts); + TagCountService.processCaseStudies( + caseStudies, + tagMap, + partnerMap, + tagCounts, + ); return tagCounts; } diff --git a/website/modules/case-studies-page/services/UrlService.js b/website/modules/case-studies-page/services/UrlService.js index 9c0b17c4..4376be3e 100644 --- a/website/modules/case-studies-page/services/UrlService.js +++ b/website/modules/case-studies-page/services/UrlService.js @@ -41,6 +41,14 @@ class UrlService { }); } + // Add partner parameters + if (query.partner) { + const partners = UrlService.ensureArray(query.partner); + partners.forEach((partner, index) => { + params.append(`partner[${index}]`, partner); + }); + } + // Add search parameter if (query.search) { params.append('search', query.search); diff --git a/website/modules/case-studies-page/views/index.html b/website/modules/case-studies-page/views/index.html index 5eb103bf..23738a1d 100644 --- a/website/modules/case-studies-page/views/index.html +++ b/website/modules/case-studies-page/views/index.html @@ -19,7 +19,7 @@
Filter Case Studies
{% set hasActiveFilters = data.query.industry or data.query.stack or - data.query.caseStudyType %} {% if hasActiveFilters %} + data.query.caseStudyType or data.query.partner %} {% if hasActiveFilters %}

{{ data.totalPieces }} Ite{% if data.totalPieces == 1 %}m{% else %}ms{% endif %} Found @@ -32,7 +32,7 @@

@@ -46,7 +46,7 @@