Skip to content

[602] feat: Add case study pagination and navigation#154

Merged
Anton-88 merged 17 commits into
mainfrom
602-pagination-prev-next-case-studies
Jun 11, 2025
Merged

[602] feat: Add case study pagination and navigation#154
Anton-88 merged 17 commits into
mainfrom
602-pagination-prev-next-case-studies

Conversation

@IhorMasechko

Copy link
Copy Markdown
Contributor
  • Extract tag counting logic into TagCountService
  • Add NavigationService for previous/next case study navigation
  • Implement previous/next buttons on case study detail pages
  • Add back to all projects link with preserved filter state
  • Preserve query parameters across navigation links
  • Add CSS styling for navigation controls

This feature enhances user experience by allowing seamless navigation between case studies while preserving filter context, making it easier for users to browse through projects without losing their current search or filter state.

- Extract tag counting logic into TagCountService
- Add NavigationService for previous/next case study navigation
- Implement previous/next buttons on case study detail pages
- Add back to all projects link with preserved filter state
- Preserve query parameters across navigation links
- Add CSS styling for navigation controls
@IhorMasechko IhorMasechko requested a review from killev as a code owner June 5, 2025 13:17
@coderabbitai

coderabbitai Bot commented Jun 5, 2025

Copy link
Copy Markdown
Contributor
📝 Walkthrough
## Walkthrough

This update modularizes tag counting and navigation logic for the case studies page by introducing `TagCountService` and `NavigationService` classes. It updates lifecycle methods to fetch navigation data before rendering, restructures template layouts to add navigation and query-preserving links, and introduces new SCSS styles for the case study navigation component.

## Changes

| Files/Groups                                                                                      | Change Summary                                                                                                                                                                                                                                               |
|-------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `website/modules/asset/ui/src/scss/_cases.scss`                                                 | Added new SCSS styles for a "Case Study Navigation" component, including container, item, and text styles with responsive and state-based modifiers.                                                                                                         |
| `website/modules/asset/ui/src/scss/_animation.scss`                                            | Removed the `@keyframes tagSlideIn` animation definition.                                                                                                                                                                                                    |
| `website/modules/case-studies-page/index.js`                                                    | Refactored to use new `TagCountService` and `NavigationService` for tag counting and navigation logic; added `beforeShow` lifecycle method to fetch navigation data; updated methods to delegate to services.                                                  |
| `website/modules/case-studies-page/services/NavigationService.js`                               | Introduced `NavigationService` class with static methods for retrieving, indexing, and navigating between case studies.                                                                                                                                       |
| `website/modules/case-studies-page/services/TagCountService.js`                                 | Introduced `TagCountService` class with static methods for tag mapping, counting, fetching, and processing related to case studies tags.                                                                                                                    |
| `website/modules/case-studies-page/services/UrlService.js`                                     | Introduced `UrlService` class to build URLs with query parameters and attach navigation and tag count data to requests.                                                                                                                                        |
| `website/modules/case-studies-page/views/index.html`                                            | Modified article card links to generate URLs dynamically via `UrlService` to preserve and append filter/search query parameters.                                                                                                                             |
| `website/modules/case-studies-page/views/show.html`                                             | Restructured template to add navigation (prev/next) and back links with query preservation, reorganized layout sections, and clarified image and testimonial rendering.                                                                                        |
| `website/modules/@apostrophecms/shared-constants/ui/src/index.js`                               | Changed unquoted keys in `STANDARD_FORM_FIELD_NAMES` object to quoted string keys; no functional changes.                                                                                                                                                      |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant Server
    participant TagCountService
    participant NavigationService
    participant Templates

    User->>Server: Request case study page (with filters/search)
    Server->>TagCountService: Fetch and process tag counts
    Server->>NavigationService: Fetch navigation data (prev/next)
    Server->>Templates: Render page with tag counts and navigation data
    Templates->>User: Display page with navigation, filters, and preserved queries

Possibly related PRs

Suggested reviewers

  • VitalyyP
  • Anton-88
  • killev

</details>

<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 70027726f7e3345347f75389ba8517b06e9c72f5 and 3e98932d7022a6ada62431b98ad8d8963460f1b9.

</details>

<details>
<summary>📒 Files selected for processing (4)</summary>

* `website/modules/@apostrophecms/shared-constants/ui/src/index.js` (1 hunks)
* `website/modules/asset/ui/src/scss/_animation.scss` (0 hunks)
* `website/modules/asset/ui/src/scss/_cases.scss` (1 hunks)
* `website/modules/case-studies-page/views/index.html` (1 hunks)

</details>

<details>
<summary>💤 Files with no reviewable changes (1)</summary>

* website/modules/asset/ui/src/scss/_animation.scss

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (1)</summary>

* website/modules/@apostrophecms/shared-constants/ui/src/index.js

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (2)</summary>

* website/modules/case-studies-page/views/index.html
* website/modules/asset/ui/src/scss/_cases.scss

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (4)</summary>

* GitHub Check: lint
* GitHub Check: e2e-tests
* GitHub Check: unit-tests
* GitHub Check: security-scan

</details>

</details>
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=speedandfunction/website&utm_content=154):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

@IhorMasechko IhorMasechko changed the title feat: Add case study pagination and navigation [602] feat: Add case study pagination and navigation Jun 5, 2025
@github-actions

github-actions Bot commented Jun 5, 2025

Copy link
Copy Markdown

🔍 Vulnerabilities of apostrophe-cms:test

📦 Image Reference apostrophe-cms:test
digestsha256:0ea6ccb10e17ee1b1701c4e1a2a4f9e96204d9c3658086474e0e0b873e377b2e
vulnerabilitiescritical: 0 high: 3 medium: 0 low: 0
platformlinux/amd64
size290 MB
packages976
📦 Base Image node:23-alpine
also known as
  • 23-alpine3.22
  • 23.11-alpine
  • 23.11-alpine3.22
  • 23.11.1-alpine
  • 23.11.1-alpine3.22
digestsha256:b9d38d589853406ff0d4364f21969840c3e0397087643aef8eede40edbb6c7cd
vulnerabilitiescritical: 0 high: 0 medium: 0 low: 1
critical: 0 high: 1 medium: 0 low: 0 async 1.5.2 (npm)

pkg:npm/async@1.5.2

high 7.8: CVE--2021--43138 OWASP Top Ten 2017 Category A9 - Using Components with Known Vulnerabilities

Affected range<2.6.4
Fixed version2.6.4, 3.2.2
CVSS Score7.8
CVSS VectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
EPSS Score1.061%
EPSS Percentile77th percentile
Description

A vulnerability exists in Async through 3.2.1 (fixed in 3.2.2), which could let a malicious user obtain privileges via the mapValues() method.

critical: 0 high: 1 medium: 0 low: 0 connect-multiparty 2.2.0 (npm)

pkg:npm/connect-multiparty@2.2.0

high 7.8: CVE--2022--29623 Unrestricted Upload of File with Dangerous Type

Affected range<=2.2.0
Fixed versionNot Fixed
CVSS Score7.8
CVSS VectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
EPSS Score0.334%
EPSS Percentile56th percentile
Description

An arbitrary file upload vulnerability in the file upload module of Express Connect-Multiparty 2.2.0 allows attackers to execute arbitrary code via a crafted PDF file. NOTE: the Supplier has not verified this vulnerability report.

critical: 0 high: 1 medium: 0 low: 0 async 0.9.2 (npm)

pkg:npm/async@0.9.2

high 7.8: CVE--2021--43138 OWASP Top Ten 2017 Category A9 - Using Components with Known Vulnerabilities

Affected range<2.6.4
Fixed version2.6.4, 3.2.2
CVSS Score7.8
CVSS VectorCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
EPSS Score1.061%
EPSS Percentile77th percentile
Description

A vulnerability exists in Async through 3.2.1 (fixed in 3.2.2), which could let a malicious user obtain privileges via the mapValues() method.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (4)
website/modules/case-studies-page/services/TagCountService.js (1)

10-79: Consider using plain functions instead of a static-only class.

Since this class contains only static methods, consider converting it to a collection of plain functions or a namespace object for better JavaScript practices.

-class TagCountService {
-  static createTagMap(casesTags) {
+const TagCountService = {
+  createTagMap(casesTags) {
     const tagMap = {};
     casesTags.forEach((tag) => {
       tagMap[tag.aposDocId] = tag.slug;
     });
     return tagMap;
-  }
+  },

-  static countTagsOfType(tagIds, tagMap, countsForType) {
+  countTagsOfType(tagIds, tagMap, countsForType) {
     // ... rest of the method
-  }
+  },
   // ... other methods
-}
+};

This would also eliminate the this vs class name confusion in static methods.

🧰 Tools
🪛 Biome (1.9.4)

[error] 66-66: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 68-68: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 70-70: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

website/modules/case-studies-page/services/NavigationService.js (1)

10-91: Consider using plain functions instead of a static-only class.

Since this class contains only static methods, consider converting it to a collection of plain functions or a namespace object for better JavaScript practices.

-class NavigationService {
-  static async getAllCaseStudies(req, apos, applyFilters = false, pageModule = null) {
+const NavigationService = {
+  async getAllCaseStudies(req, apos, applyFilters = false, pageModule = null) {
     // ... method implementation
-  }
+  },

-  static findCurrentIndex(allCaseStudies, currentPiece) {
+  findCurrentIndex(allCaseStudies, currentPiece) {
     // ... method implementation
-  }
+  },
   // ... other methods
-}
+};

This approach is more idiomatic in JavaScript and eliminates the this confusion in static methods.

🧰 Tools
🪛 Biome (1.9.4)

[error] 78-78: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 85-85: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 87-87: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

website/modules/case-studies-page/views/show.html (1)

47-47: Maintain consistent text for navigation items.

The disabled navigation text is inconsistent - "previous" vs "next project".

-      <span class="cs_nav-text cs_nav-text--disabled">previous</span>
+      <span class="cs_nav-text cs_nav-text--disabled">previous project</span>

Also applies to: 71-71

website/modules/case-studies-page/index.js (1)

40-44: Remove unnecessary reqCopy variable.

The reqCopy = req pattern is unnecessary since JavaScript objects are passed by reference. You're already modifying the original req object.

-        const reqCopy = req;
-        if (!reqCopy.data) {
-          reqCopy.data = {};
+        if (!req.data) {
+          req.data = {};
         }
-        reqCopy.data.tagCounts = tagCounts;
+        req.data.tagCounts = tagCounts;

Apply the same simplification to all four occurrences in this file.

Also applies to: 48-57, 64-70, 74-80

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5c399b1 and d87f936.

📒 Files selected for processing (6)
  • website/modules/asset/ui/src/scss/_cases.scss (1 hunks)
  • website/modules/case-studies-page/index.js (3 hunks)
  • website/modules/case-studies-page/services/NavigationService.js (1 hunks)
  • website/modules/case-studies-page/services/TagCountService.js (1 hunks)
  • website/modules/case-studies-page/views/index.html (1 hunks)
  • website/modules/case-studies-page/views/show.html (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
website/modules/case-studies-page/services/TagCountService.js

[error] 9-77: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)


[error] 66-66: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 68-68: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 70-70: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

website/modules/case-studies-page/services/NavigationService.js

[error] 9-89: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)


[error] 78-78: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 85-85: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 87-87: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: e2e-tests
  • GitHub Check: lint
  • GitHub Check: unit-tests
  • GitHub Check: security-scan
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (2)
website/modules/case-studies-page/views/show.html (1)

6-19:

Details

❓ Verification inconclusive

Use proper URL encoding to prevent injection vulnerabilities.

The current implementation manually encodes brackets but doesn't properly encode the parameter values. This could lead to URL injection vulnerabilities if the query parameters contain special characters.

Consider using a proper URL encoding utility or filter. Check if Nunjucks or ApostropheCMS provides URL building helpers:

If no built-in utility exists, ensure all parameter values are properly encoded:

-{% set queryParams = queryParams.concat(['industry%5B' + loop.index0 + '%5D=' + industry]) %}
+{% set queryParams = queryParams.concat(['industry%5B' + loop.index0 + '%5D=' + industry | urlencode]) %}

Also applies to: 30-41, 54-65


🏁 Script executed:

#!/bin/bash
# Search for URL encoding utilities in the codebase
rg -A 5 "urlencode|encodeURI|URLSearchParams" --type js --type html

# Check if ApostropheCMS provides URL building helpers
ast-grep --pattern 'apos.$_.$_url'

Length of output: 106


Ensure safe URL encoding for query parameters

The manual %5B/%5D encoding only handles brackets and doesn’t escape other special characters in the values, opening the door to injection issues. Please verify whether your Nunjucks/Apostrophe setup provides a filter like urlencode (or a URL‐building helper). If not, add one or sanitize every dynamic segment.

• File: website/modules/case-studies-page/views/show.html
– Affected blocks: lines 6–19 (also apply similar changes at lines 30–41 and 54–65)

Example replacement:

-{% set queryParams = queryParams.concat(['industry%5B' + loop.index0 + '%5D=' + industry]) %}
+{% set queryParams = queryParams.concat([
+  'industry[' ~ loop.index0 ~ ']=' ~ (industry | urlencode)
+]) %}

Repeat for stack, caseStudyType, and search, ensuring every value is passed through the encoder.

website/modules/case-studies-page/index.js (1)

2-3: Good refactoring to extract services!

The extraction of tag counting and navigation logic into dedicated services improves modularity and testability. This follows the single responsibility principle well.

Also applies to: 95-103, 108-117

Comment thread website/modules/case-studies-page/views/index.html Outdated
Comment thread website/modules/asset/ui/src/scss/_cases.scss
Comment thread website/modules/case-studies-page/services/TagCountService.js Outdated
Comment thread website/modules/case-studies-page/services/NavigationService.js Outdated
Comment thread website/modules/case-studies-page/views/show.html

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
website/modules/case-studies-page/services/NavigationService.js (3)

37-37: Replace this with class name in static methods (additional instances).

These lines have the same issue flagged in past reviews for lines 136-145. Using this in static context is confusing since it refers to the class constructor.

Apply this diff to fix the remaining instances:

-      const industryIds = await this.convertSlugsToIds(
+      const industryIds = await NavigationService.convertSlugsToIds(
        apos,
        req,
        req.query.industry,
      );

-      const stackIds = await this.convertSlugsToIds(apos, req, req.query.stack);
+      const stackIds = await NavigationService.convertSlugsToIds(apos, req, req.query.stack);

-      const caseStudyTypeIds = await this.convertSlugsToIds(
+      const caseStudyTypeIds = await NavigationService.convertSlugsToIds(
        apos,
        req,
        req.query.caseStudyType,
      );

Also applies to: 50-50, 57-57

🧰 Tools
🪛 Biome (1.9.4)

[error] 37-37: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


89-89: Replace this with class name in static method.

Same issue as flagged in past reviews - using this in static context is confusing.

-      query = await this.applyFiltersToQuery(query, req, apos);
+      query = await NavigationService.applyFiltersToQuery(query, req, apos);
🧰 Tools
🪛 Biome (1.9.4)

[error] 89-89: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


135-146: Past review comment still applies - replace this with class name.

The previous review comment about replacing this with NavigationService in static methods still needs to be addressed.

🧰 Tools
🪛 Biome (1.9.4)

[error] 136-136: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 143-143: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 145-145: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

🧹 Nitpick comments (1)
website/modules/case-studies-page/services/NavigationService.js (1)

10-147: Consider the trade-offs of static-only class vs. module functions.

While static analysis suggests using simple functions instead of a static-only class, the current approach provides good namespace organization and follows common service patterns. However, you could alternatively export individual functions from this module if you prefer a more functional approach.

The current class-based approach is acceptable for a service layer in an enterprise application context.

🧰 Tools
🪛 Biome (1.9.4)

[error] 9-147: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)


[error] 37-37: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 50-50: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 57-57: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 89-89: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 136-136: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 143-143: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 145-145: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d87f936 and cd929ff.

📒 Files selected for processing (2)
  • website/modules/case-studies-page/services/NavigationService.js (1 hunks)
  • website/modules/case-studies-page/views/show.html (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • website/modules/case-studies-page/views/show.html
🧰 Additional context used
🧬 Code Graph Analysis (1)
website/modules/case-studies-page/services/NavigationService.js (2)
website/modules/case-studies-page/index.js (1)
  • NavigationService (3-3)
scripts/merged-prs-last-24h.js (1)
  • req (109-167)
🪛 Biome (1.9.4)
website/modules/case-studies-page/services/NavigationService.js

[error] 9-147: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)


[error] 37-37: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 50-50: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 57-57: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 89-89: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 136-136: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 143-143: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 145-145: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: security-scan
  • GitHub Check: e2e-tests
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (actions)
🔇 Additional comments (5)
website/modules/case-studies-page/services/NavigationService.js (5)

1-10: Excellent documentation and clear service responsibilities.

The class documentation clearly defines the single responsibility and provides a comprehensive overview of the service's capabilities.


18-24: Well-implemented parallel tag lookup with proper error handling.

The method efficiently fetches tags in parallel and correctly filters out failed lookups before extracting document IDs.


80-93: Solid implementation of filtered case study fetching.

The conditional filter application and sorting logic is well-implemented for the ApostropheCMS environment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 89-89: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


101-104: Clean and appropriate index lookup implementation.

The method correctly finds the current case study index, and the eslint disable is justified for ApostropheCMS _id field access.


112-125: Excellent navigation calculation with proper boundary handling.

The method correctly handles edge cases for first and last items in the navigation sequence.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
website/modules/case-studies-page/services/NavigationService.js (1)

43-43: ⚠️ Potential issue

Replace this with class name in static methods.

The static analysis correctly identifies that using this in static context is confusing since it refers to the class constructor. This is the same issue flagged in previous reviews.

Apply this fix to improve clarity:

-      const industryIds = await this.convertSlugsToIds(
+      const industryIds = await NavigationService.convertSlugsToIds(
         apos,
         req,
         req.query.industry,
       );

-      const stackIds = await this.convertSlugsToIds(apos, req, req.query.stack);
+      const stackIds = await NavigationService.convertSlugsToIds(apos, req, req.query.stack);

-      const caseStudyTypeIds = await this.convertSlugsToIds(
+      const caseStudyTypeIds = await NavigationService.convertSlugsToIds(
         apos,
         req,
         req.query.caseStudyType,
       );

-      query = await this.applyFiltersToQuery(query, req, apos);
+      query = await NavigationService.applyFiltersToQuery(query, req, apos);

-    const allCaseStudies = await this.getAllCaseStudies(
+    const allCaseStudies = await NavigationService.getAllCaseStudies(
       req,
       apos,
       true,
       pageModule,
     );

-    const currentIndex = this.findCurrentIndex(allCaseStudies, currentPiece);
+    const currentIndex = NavigationService.findCurrentIndex(allCaseStudies, currentPiece);

-    return this.calculatePrevNext(allCaseStudies, currentIndex);
+    return NavigationService.calculatePrevNext(allCaseStudies, currentIndex);

Also applies to: 56-56, 63-63, 95-95, 142-142, 149-149, 151-151

🧰 Tools
🪛 Biome (1.9.4)

[error] 43-43: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

🧹 Nitpick comments (1)
website/modules/case-studies-page/services/NavigationService.js (1)

10-153: Consider refactoring to use simple functions instead of static-only class.

While the current implementation works, a class containing only static methods could be refactored to use simple exported functions, which might be more idiomatic and easier to test.

Example approach:

// Convert class to module with exported functions
const convertSlugsToIds = async (apos, req, slugs) => {
  // implementation
};

const applyFiltersToQuery = async (query, req, apos) => {
  // implementation  
};

// ... other functions

module.exports = {
  convertSlugsToIds,
  applyFiltersToQuery,
  getAllCaseStudies,
  findCurrentIndex,
  calculatePrevNext,
  getNavigationData
};
🧰 Tools
🪛 Biome (1.9.4)

[error] 9-153: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)


[error] 43-43: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 56-56: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 63-63: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 95-95: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 142-142: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 149-149: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 151-151: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cd929ff and 569e7ff.

📒 Files selected for processing (2)
  • website/modules/case-studies-page/index.js (3 hunks)
  • website/modules/case-studies-page/services/NavigationService.js (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
website/modules/case-studies-page/services/NavigationService.js

[error] 9-153: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)


[error] 43-43: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 56-56: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 63-63: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 95-95: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 142-142: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 149-149: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 151-151: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: lint
  • GitHub Check: unit-tests
  • GitHub Check: e2e-tests
  • GitHub Check: security-scan
🔇 Additional comments (6)
website/modules/case-studies-page/index.js (4)

2-3: LGTM! Good modularization.

The imports properly introduce the new service classes to handle tag counting and navigation logic, improving separation of concerns.


60-82: Well-structured lifecycle method with proper error handling.

The beforeShow method follows the same pattern as beforeIndex with consistent error handling and data structure initialization. The fallback values ensure the application remains functional even when navigation data cannot be retrieved.


95-103: Good refactoring to use TagCountService.

The method now properly delegates to the external service, improving code organization and reusability.


108-117: Clean navigation data method.

The method appropriately delegates to the NavigationService and provides all necessary parameters for navigation calculation.

website/modules/case-studies-page/services/NavigationService.js (2)

18-30: Solid slug-to-ID conversion logic.

The method properly handles asynchronous tag lookups, filters out null results, and extracts the correct document IDs. The use of Promise.all is appropriate for parallel processing.


118-131: Clean boundary handling for navigation calculation.

The method correctly handles edge cases for first and last items in the list, ensuring proper null values when no previous or next items exist.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
website/modules/case-studies-page/services/TagCountService.js (1)

66-76: Replace this with class name in static methods for clarity.

This issue was already identified in previous reviews and still needs to be addressed.

🧰 Tools
🪛 Biome (1.9.4)

[error] 66-66: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 68-68: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 70-70: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

website/modules/case-studies-page/services/NavigationService.js (1)

142-151: Replace this with class name in static methods for clarity.

This issue was already identified in previous reviews and still needs to be addressed.

🧰 Tools
🪛 Biome (1.9.4)

[error] 142-142: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 149-149: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 151-151: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

🧹 Nitpick comments (2)
website/modules/case-studies-page/services/TagCountService.js (1)

10-77: Consider using a module with exported functions instead of a static-only class.

While the current class structure works, you could simplify this to a module that exports individual functions, which might be more idiomatic for this use case.

-class TagCountService {
-  static createTagMap(casesTags) {
+function createTagMap(casesTags) {
    // ... implementation
-  }
+}

-  static countTagsOfType(tagIds, tagMap, countsForType) {
+function countTagsOfType(tagIds, tagMap, countsForType) {
    // ... implementation
-  }
+}

// ... other functions

-module.exports = TagCountService;
+module.exports = {
+  createTagMap,
+  countTagsOfType,
+  fetchCaseStudiesAndTags,
+  processCaseStudies
+};
🧰 Tools
🪛 Biome (1.9.4)

[error] 9-77: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)


[error] 66-66: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 68-68: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 70-70: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

website/modules/case-studies-page/services/NavigationService.js (1)

10-153: Consider using a module with exported functions instead of a static-only class.

Similar to TagCountService, you could simplify this to a module that exports individual functions for better consistency with functional programming patterns.

🧰 Tools
🪛 Biome (1.9.4)

[error] 9-153: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)


[error] 43-43: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 56-56: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 63-63: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 95-95: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 142-142: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 149-149: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 151-151: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 569e7ff and 2c1b273.

📒 Files selected for processing (3)
  • website/modules/case-studies-page/index.js (3 hunks)
  • website/modules/case-studies-page/services/NavigationService.js (1 hunks)
  • website/modules/case-studies-page/services/TagCountService.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • website/modules/case-studies-page/index.js
🧰 Additional context used
🪛 Biome (1.9.4)
website/modules/case-studies-page/services/NavigationService.js

[error] 9-153: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)


[error] 43-43: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 56-56: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 63-63: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 95-95: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 142-142: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 149-149: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 151-151: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

website/modules/case-studies-page/services/TagCountService.js

[error] 9-77: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)


[error] 66-66: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 68-68: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 70-70: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: e2e-tests
  • GitHub Check: lint
  • GitHub Check: security-scan
  • GitHub Check: unit-tests
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (6)
website/modules/case-studies-page/services/TagCountService.js (3)

16-22: LGTM! Clean mapping implementation.

The tag mapping logic is straightforward and correctly handles the transformation from tag objects to a lookup dictionary.


30-43: LGTM! Proper null safety and counting logic.

The method correctly handles edge cases with the optional chaining and length check, and the counting logic is sound.


52-56: LGTM! Straightforward data fetching.

The async data fetching logic is clean and returns the expected tuple of case studies and tags.

website/modules/case-studies-page/services/NavigationService.js (3)

18-30: LGTM! Efficient slug-to-ID conversion with proper null handling.

The use of Promise.all for concurrent tag lookups and filtering of null results is well implemented.


107-110: LGTM! Efficient index finding with clear underscore dangle comment.

The findIndex implementation is straightforward and the eslint disable comment appropriately documents the underscore-dangle exception.


118-131: LGTM! Correct navigation boundary logic.

The previous/next calculation properly handles edge cases for first and last items in the list.

Comment thread website/modules/case-studies-page/services/NavigationService.js Outdated
Comment thread website/modules/case-studies-page/services/NavigationService.js Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (5)
website/modules/case-studies-page/services/TagCountService.js (2)

66-76: Replace this with class name in static methods for clarity.

Using this in static context is confusing since it refers to the class constructor. Use the class name directly for better readability.

Apply this diff to fix the static method calls:

  static processCaseStudies(caseStudies, tagMap, tagCounts) {
    caseStudies.forEach((study) => {
-      this.countTagsOfType(study.industryIds, tagMap, tagCounts.industry);
+      TagCountService.countTagsOfType(study.industryIds, tagMap, tagCounts.industry);

-      this.countTagsOfType(study.stackIds, tagMap, tagCounts.stack);
+      TagCountService.countTagsOfType(study.stackIds, tagMap, tagCounts.stack);

-      this.countTagsOfType(
+      TagCountService.countTagsOfType(
        study.caseStudyTypeIds,
        tagMap,
        tagCounts.caseStudyType,
      );
    });
  }
🧰 Tools
🪛 Biome (1.9.4)

[error] 66-66: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 68-68: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 70-70: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


92-103: Replace this with class name in static methods for clarity.

The same issue occurs in the calculateTagCounts method where this is used to call other static methods.

Apply this diff:

    const [caseStudies, casesTags] = await this.fetchCaseStudiesAndTags(
      req,
      aposModules,
      options,
    );

-    const tagMap = this.createTagMap(casesTags);
+    const tagMap = TagCountService.createTagMap(casesTags);

-    this.processCaseStudies(caseStudies, tagMap, tagCounts);
+    TagCountService.processCaseStudies(caseStudies, tagMap, tagCounts);
🧰 Tools
🪛 Biome (1.9.4)

[error] 92-92: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 98-98: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 100-100: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

website/modules/case-studies-page/services/NavigationService.js (3)

43-47: Replace this with class name in static methods for clarity.

Using this in static context is confusing since it refers to the class constructor. Use the class name directly for better readability.

Apply this diff to fix the static method calls in applyFiltersToQuery:

    if (req.query.industry && req.query.industry.length > 0) {
-      const industryIds = await this.convertSlugsToIds(
+      const industryIds = await NavigationService.convertSlugsToIds(
        apos,
        req,
        req.query.industry,
      );
      // ... rest of method
    }

    if (req.query.stack && req.query.stack.length > 0) {
-      const stackIds = await this.convertSlugsToIds(apos, req, req.query.stack);
+      const stackIds = await NavigationService.convertSlugsToIds(apos, req, req.query.stack);
      // ... rest of method
    }

    if (req.query.caseStudyType && req.query.caseStudyType.length > 0) {
-      const caseStudyTypeIds = await this.convertSlugsToIds(
+      const caseStudyTypeIds = await NavigationService.convertSlugsToIds(
        apos,
        req,
        req.query.caseStudyType,
      );
      // ... rest of method
    }

Also applies to: 56-56, 63-67

🧰 Tools
🪛 Biome (1.9.4)

[error] 43-43: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


95-95: Replace this with class name in static methods for clarity.

Using this in static context is confusing since it refers to the class constructor. Use the class name directly for better readability.

Apply this diff:

-      query = await this.applyFiltersToQuery(query, req, apos);
+      query = await NavigationService.applyFiltersToQuery(query, req, apos);
🧰 Tools
🪛 Biome (1.9.4)

[error] 95-95: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


142-151: Replace this with class name in static methods for clarity.

Using this in static context is confusing since it refers to the class constructor. Use the class name directly for better readability.

Apply this diff to fix the static method calls in getNavigationData:

  static async getNavigationData(req, apos, pageModule, currentPiece) {
-    const allCaseStudies = await this.getAllCaseStudies(
+    const allCaseStudies = await NavigationService.getAllCaseStudies(
      req,
      apos,
      true,
      pageModule,
    );

-    const currentIndex = this.findCurrentIndex(allCaseStudies, currentPiece);
+    const currentIndex = NavigationService.findCurrentIndex(allCaseStudies, currentPiece);

-    return this.calculatePrevNext(allCaseStudies, currentIndex);
+    return NavigationService.calculatePrevNext(allCaseStudies, currentIndex);
  }
🧰 Tools
🪛 Biome (1.9.4)

[error] 142-142: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 149-149: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 151-151: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

🧹 Nitpick comments (1)
website/modules/case-studies-page/services/TagCountService.js (1)

10-104: Consider using individual functions instead of a static-only class.

While the current class structure provides good organization, consider whether individual exported functions might be more appropriate since this class contains only static members.

Alternative approach:

-class TagCountService {
-  static createTagMap(casesTags) {
+function createTagMap(casesTags) {
    // implementation
-  }
+}

-  static countTagsOfType(tagIds, tagMap, countsForType) {
+function countTagsOfType(tagIds, tagMap, countsForType) {
    // implementation
-  }
+}

// Export as an object
+module.exports = {
+  createTagMap,
+  countTagsOfType,
+  fetchCaseStudiesAndTags,
+  processCaseStudies,
+  calculateTagCounts,
+};
🧰 Tools
🪛 Biome (1.9.4)

[error] 9-104: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)


[error] 66-66: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 68-68: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 70-70: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 92-92: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 98-98: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 100-100: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2c1b273 and 407e2c0.

📒 Files selected for processing (5)
  • website/modules/case-studies-page/index.js (2 hunks)
  • website/modules/case-studies-page/services/NavigationService.js (1 hunks)
  • website/modules/case-studies-page/services/TagCountService.js (1 hunks)
  • website/modules/case-studies-page/services/UrlService.js (1 hunks)
  • website/modules/case-studies-page/views/index.html (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • website/modules/case-studies-page/views/index.html
🧰 Additional context used
🧬 Code Graph Analysis (1)
website/modules/case-studies-page/services/TagCountService.js (2)
website/modules/case-studies-page/index.js (1)
  • TagCountService (2-2)
scripts/merged-prs-last-24h.js (1)
  • req (109-167)
🪛 Biome (1.9.4)
website/modules/case-studies-page/services/TagCountService.js

[error] 9-104: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)


[error] 66-66: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 68-68: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 70-70: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 92-92: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 98-98: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 100-100: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

website/modules/case-studies-page/services/UrlService.js

[error] 9-98: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)


[error] 22-22: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 30-30: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 38-38: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 81-81: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

website/modules/case-studies-page/services/NavigationService.js

[error] 9-166: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)


[error] 43-43: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 56-56: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 63-63: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 95-95: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 142-142: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 149-149: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 151-151: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 164-164: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: lint
  • GitHub Check: e2e-tests
  • GitHub Check: unit-tests
  • GitHub Check: security-scan
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (6)
website/modules/case-studies-page/services/UrlService.js (1)

17-55: URL building logic looks solid.

The implementation correctly handles query parameters with proper encoding and supports both single values and arrays. The use of URLSearchParams ensures proper URL encoding.

🧰 Tools
🪛 Biome (1.9.4)

[error] 22-22: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 30-30: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)


[error] 38-38: Using this in a static context can be confusing.

this refers to the class.
Unsafe fix: Use the class name instead.

(lint/complexity/noThisInStatic)

website/modules/case-studies-page/index.js (3)

2-4: Good separation of concerns with new service imports.

The extraction of tag counting, navigation, and URL building logic into dedicated services improves code organization and maintainability.


48-64: Excellent error handling in setupIndexData.

The method properly handles potential failures and provides sensible fallback data, ensuring the application doesn't break if tag counting fails.


66-78: Consistent error handling pattern in setupShowData.

The error handling follows the same pattern as setupIndexData with appropriate fallbacks for navigation data.

website/modules/case-studies-page/services/NavigationService.js (2)

18-30: Robust slug-to-ID conversion logic.

The implementation correctly handles parallel lookups and filters out null results. Good error handling for missing tags.


118-131: Clean navigation calculation logic.

The previous/next calculation correctly handles edge cases at the beginning and end of the list.

Comment thread website/modules/case-studies-page/services/UrlService.js Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
website/modules/case-studies-page/services/UrlService.js (1)

10-98: Consider functional module pattern over static-only class.

Similar to TagCountService, this static-only class could be better implemented as a module with exported functions, which is more idiomatic in Node.js environments.

🧰 Tools
🪛 Biome (1.9.4)

[error] 9-98: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

website/modules/case-studies-page/services/NavigationService.js (1)

10-178: Excellent modularization but consider functional approach.

The service effectively centralizes navigation logic with good separation of concerns. However, like the other services, this static-only class could benefit from a functional module pattern for better JavaScript idioms.

🧰 Tools
🪛 Biome (1.9.4)

[error] 9-178: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

🧹 Nitpick comments (3)
website/modules/case-studies-page/services/TagCountService.js (1)

10-105: Consider using a module with exported functions instead of a static-only class.

While the current implementation works, a static-only class goes against JavaScript conventions. Consider refactoring to a module with exported functions for better alignment with Node.js patterns.

Example structure:

// TagCountService.js
function createTagMap(casesTags) {
  // current logic
}

function countTagsOfType(tagIds, tagMap, countsForType) {
  // current logic
}

// ... other functions

module.exports = {
  createTagMap,
  countTagsOfType,
  fetchCaseStudiesAndTags,
  processCaseStudies,
  calculateTagCounts
};
🧰 Tools
🪛 Biome (1.9.4)

[error] 9-105: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

website/modules/case-studies-page/services/UrlService.js (1)

74-82: Request object mutation pattern could be improved.

While functional, directly mutating the request object (reqCopy = req) doesn't actually create a copy. Consider making this more explicit about the mutation or using a different pattern.

  static attachIndexData(req, tagCounts) {
-   const reqCopy = req;
-   if (!reqCopy.data) {
-     reqCopy.data = {};
+   if (!req.data) {
+     req.data = {};
    }
-   reqCopy.data.tagCounts = tagCounts;
-   reqCopy.data.buildCaseStudyUrl = (caseStudyUrl) =>
+   req.data.tagCounts = tagCounts;
+   req.data.buildCaseStudyUrl = (caseStudyUrl) =>
      UrlService.buildCaseStudyUrl(caseStudyUrl, req.query);
  }
website/modules/case-studies-page/services/NavigationService.js (1)

111-114: Consider using more descriptive variable names.

The ESLint disable comment suggests awareness of the underscore-prefixed _id field. Consider adding a comment explaining why this is necessary (ApostropheCMS convention).

  static findCurrentIndex(allCaseStudies, currentPiece) {
-   // eslint-disable-next-line no-underscore-dangle
+   // ApostropheCMS uses _id as the document identifier
+   // eslint-disable-next-line no-underscore-dangle
    return allCaseStudies.findIndex((study) => study._id === currentPiece._id);
  }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 407e2c0 and c6359e4.

📒 Files selected for processing (3)
  • website/modules/case-studies-page/services/NavigationService.js (1 hunks)
  • website/modules/case-studies-page/services/TagCountService.js (1 hunks)
  • website/modules/case-studies-page/services/UrlService.js (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
website/modules/case-studies-page/services/NavigationService.js (2)
website/modules/case-studies-page/index.js (1)
  • NavigationService (3-3)
scripts/merged-prs-last-24h.js (1)
  • req (109-167)
website/modules/case-studies-page/services/TagCountService.js (2)
website/modules/case-studies-page/index.js (1)
  • TagCountService (2-2)
scripts/merged-prs-last-24h.js (1)
  • req (109-167)
🪛 Biome (1.9.4)
website/modules/case-studies-page/services/NavigationService.js

[error] 9-178: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

website/modules/case-studies-page/services/TagCountService.js

[error] 9-105: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

website/modules/case-studies-page/services/UrlService.js

[error] 9-98: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: e2e-tests
  • GitHub Check: security-scan
  • GitHub Check: lint
  • GitHub Check: unit-tests
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (6)
website/modules/case-studies-page/services/TagCountService.js (2)

1-22: Well-structured tag mapping logic.

The createTagMap method correctly creates a mapping from tag IDs to slugs, handling the data transformation cleanly.


30-43: Robust tag counting with proper validation.

Good defensive programming with the optional chaining check !tagIds?.length and proper validation before incrementing counts.

website/modules/case-studies-page/services/UrlService.js (2)

17-55: Excellent URL building with proper parameter handling.

The implementation correctly:

  • Uses URLSearchParams for proper encoding
  • Handles both single values and arrays consistently
  • Preserves all relevant query parameters (industry, stack, caseStudyType, search)
  • Returns clean URLs with or without query strings

62-67: Simple and effective array normalization.

The ensureArray utility correctly handles both array and non-array inputs, providing consistent behavior for query parameter processing.

website/modules/case-studies-page/services/NavigationService.js (2)

18-30: Solid slug-to-ID conversion with proper filtering.

The implementation correctly:

  • Uses Promise.all for concurrent tag lookups
  • Filters out null results from failed lookups
  • Maps to the expected aposDocId field

39-80: Comprehensive filter application logic.

The method effectively handles multiple filter types (industry, stack, caseStudyType) and correctly applies MongoDB $in queries with proper conditional logic.

Comment thread website/modules/case-studies-page/services/TagCountService.js
Comment thread website/modules/case-studies-page/services/NavigationService.js
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 5, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
website/modules/case-studies-page/views/show.html (4)

47-54: Add rel="prev" for SEO-friendly pagination
Annotating the “previous project” anchor with rel="prev" helps search engines understand the page sequence.

-<a href="{{ prevUrl }}" class="cs_nav-link cs_nav-link--active" aria-label="Navigate to previous project">
+<a href="{{ prevUrl }}" rel="prev" class="cs_nav-link cs_nav-link--active" aria-label="Navigate to previous project">

64-79: Improve disabled state semantics with ARIA
Assistive technologies will correctly announce this as non-interactive if you include aria-disabled="true".

-<span class="cs_nav-link cs_nav-link--disabled" aria-label="Previous project (unavailable)">
+<span class="cs_nav-link cs_nav-link--disabled" aria-label="Previous project (unavailable)" aria-disabled="true">

83-90: Add rel="next" for SEO-friendly pagination
Similar to the previous link, use rel="next" on the “next project” anchor to signal the logical sequence to crawlers.

-<a href="{{ nextUrl }}" class="cs_nav-link cs_nav-link--active" aria-label="Navigate to next project">
+<a href="{{ nextUrl }}" rel="next" class="cs_nav-link cs_nav-link--active" aria-label="Navigate to next project">

100-115: Improve disabled state semantics with ARIA
For consistency, mark the disabled “next project” span with aria-disabled="true".

-<span class="cs_nav-link cs_nav-link--disabled" aria-label="Next project (unavailable)">
+<span class="cs_nav-link cs_nav-link--disabled" aria-label="Next project (unavailable)" aria-disabled="true">
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c6359e4 and 700f700.

⛔ Files ignored due to path filters (3)
  • website/public/images/arrow-back-desktop.svg is excluded by !**/*.svg
  • website/public/images/arrow-left.svg is excluded by !**/*.svg
  • website/public/images/arrow-right.svg is excluded by !**/*.svg
📒 Files selected for processing (2)
  • website/modules/asset/ui/src/scss/_cases.scss (1 hunks)
  • website/modules/case-studies-page/views/show.html (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • website/modules/asset/ui/src/scss/_cases.scss
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: e2e-tests
  • GitHub Check: security-scan
  • GitHub Check: Analyze (actions)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
website/modules/case-studies-page/views/show.html (1)

18-21: Leverage the new macro on the back link
Using buildQueryString(data.query) here cleanly replaces the previous inline logic and correctly preserves filter state on the “Back to all projects” link.

Comment thread website/modules/case-studies-page/views/show.html Outdated
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 9, 2025
Anton-88
Anton-88 previously approved these changes Jun 10, 2025

@Anton-88 Anton-88 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job!

killev
killev previously approved these changes Jun 11, 2025

@killev killev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 11, 2025

@VitalyyP VitalyyP left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Anton-88 Anton-88 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@sonarqubecloud

Copy link
Copy Markdown

@killev killev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good

@yuramax yuramax left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Anton-88 Anton-88 merged commit e57e1ae into main Jun 11, 2025
12 checks passed
@Anton-88 Anton-88 deleted the 602-pagination-prev-next-case-studies branch June 11, 2025 09:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants