Skip to content

Add product sorting#472

Merged
tomaszpacior merged 7 commits intomainfrom
fix/product-list-issues
Dec 18, 2025
Merged

Add product sorting#472
tomaszpacior merged 7 commits intomainfrom
fix/product-list-issues

Conversation

@tomaszpacior
Copy link
Copy Markdown
Contributor

@tomaszpacior tomaszpacior commented Dec 5, 2025

What does this PR do?

  • New Features

    • Added product sorting by name and price (ascending/descending) for product lists and related products.
  • Improvements

    • Product card descriptions include improved truncation for consistent display.
    • Refined loading state UI for a cleaner experience.
  • Removed

    • Product type filter option.

Summary by CodeRabbit

  • New Features

    • Added product sorting by name and price with ascending/descending options.
  • Changes

    • Removed product type filter option.
    • Product descriptions now limited to 3 lines with ellipsis indicator.
    • Simplified loading state UI for product lists.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 5, 2025

Walkthrough

This PR adds sorting functionality to the mocked product integration with support for name and price sorting in ascending/descending order. The product list request interface is updated to implement an additional interface, property order is adjusted, and product type filtering is removed. The loading UI is simplified and ProductCard description display is refined.

Changes

Cohort / File(s) Summary
Sorting support
packages/framework/src/modules/products/products.request.ts, packages/blocks/product-list/src/api-harmonization/product-list.request.ts
Added optional sort property to GetProductListQuery class; updated GetProductListBlockQuery to implement Products.Request.GetProductListQuery interface alongside existing CMS interface.
Mocked integration sorting & filtering
packages/integrations/mocked/src/modules/products/products.mapper.ts, .changeset/cute-eagles-cheer.md
Implemented sorting logic in mapProducts to support name/price sorting (ASC/DESC) applied to filtered results. Sorting is extracted from options and applied to a separate data array.
Product type filter removal
packages/integrations/mocked/src/modules/cms/mappers/blocks/cms.product-list.mapper.ts
Removed type field mapping and corresponding filter UI entry, eliminating PHYSICAL/VIRTUAL product type filtering options.
UI presentation refinements
packages/ui/src/components/Cards/ProductCard/ProductCard.tsx
Added line clamping and overflow ellipsis CSS classes (line-clamp-3, overflow-ellipsis) to RichText component for product description.
Loading state simplification
packages/blocks/product-list/src/frontend/ProductList.renderer.tsx
Replaced Suspense fallback UI from nested fragment with Container to simplified full-width div; adjusted loading bars configuration to [30, 23].
Configuration
packages/configs/integrations/package.json
Trailing newline adjustment; no functional changes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • packages/integrations/mocked/src/modules/products/products.mapper.ts: Dense sorting logic with data mutation handling and total calculation changes requires careful verification of sort field support and filtered results behavior.
  • packages/blocks/product-list/src/api-harmonization/product-list.request.ts: Interface implementation changes and property reordering may affect downstream consumers; verify compatibility.
  • packages/integrations/mocked/src/modules/cms/mappers/blocks/cms.product-list.mapper.ts: Field mapping removal requires confirmation that dependent code handles missing type filter gracefully.

Suggested reviewers

  • marcinkrasowski

Poem

🐰 Sorting sprints through price and name,
Loading bars trim down their frame,
Type filters fade away so clean,
Product cards with clamps serene—
Product listing, now more refined!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is incomplete against the template; it lacks Related Ticket(s), Key Changes details, How to test steps, and Media sections, which are required by the template structure. Add missing sections: Related Ticket(s) with Notion ticket link, detailed Key Changes explaining how sorting was implemented and side effects, step-by-step testing instructions, and Media if applicable.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add product sorting' clearly and accurately summarizes the main change of this PR—implementing product sorting functionality for product lists and related products.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/product-list-issues

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 65c46b5 and 65a7571.

📒 Files selected for processing (1)
  • .changeset/cute-eagles-cheer.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .changeset/cute-eagles-cheer.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: deploy-preview

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/integrations/mocked/src/modules/products/products.mapper.ts (1)

401-426: Sorting mutates the global MOCK_PRODUCTS array.

Unlike mapProducts which correctly creates a copy with [...filteredProducts], this function assigns data = products as a direct reference. Calling data.sort() mutates MOCK_PRODUCTS in place, causing non-deterministic behavior across all subsequent calls.

Apply this diff to create a copy before sorting:

-    const data = products;
+    const data = [...products];
🧹 Nitpick comments (3)
packages/integrations/mocked/src/modules/products/products.mapper.ts (1)

362-380: Consider extracting the sorting logic into a reusable helper.

The sorting logic in mapProducts (lines 362-380) is duplicated in mapRelatedProducts (lines 407-425). Extracting it into a shared helper function would improve maintainability and ensure consistent behavior.

Example helper:

const sortProducts = (
    products: Products.Model.Product[],
    sort: string
): Products.Model.Product[] => {
    const [field, order] = sort.split('_');
    const isAscending = order === 'ASC';
    
    return [...products].sort((a, b) => {
        if (field === 'name') {
            return isAscending ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name);
        } else if (field === 'price') {
            return isAscending ? a.price.value - b.price.value : b.price.value - a.price.value;
        }
        const aValue = a[field as keyof Products.Model.Product];
        const bValue = b[field as keyof Products.Model.Product];
        if (typeof aValue === 'string' && typeof bValue === 'string') {
            return isAscending ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
        } else if (typeof aValue === 'number' && typeof bValue === 'number') {
            return isAscending ? aValue - bValue : bValue - aValue;
        }
        return 0;
    });
};
packages/ui/src/components/Cards/ProductCard/ProductCard.tsx (1)

60-63: Verify overflow-ellipsis class and clamping behavior

Using RichText with line-clamp-3 for the description is a good fit for product cards. Please double‑check that overflow-ellipsis is a valid utility in your Tailwind/config (commonly text-ellipsis/truncate are used) so the intended truncation actually applies.

packages/ui/src/components/RichText/RichText.tsx (1)

12-29: Content format detection is fine, but JSDoc slightly overstates behavior

The HTML/Markdown detection via a simple HTML tag regex is reasonable for this use case. The JSDoc mentions detecting Markdown syntax, but the implementation only checks for HTML tags and otherwise defaults to 'markdown'; consider tightening the comment so it matches the actual logic.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2032f12 and d9733f3.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • .changeset/cute-eagles-cheer.md (1 hunks)
  • packages/blocks/product-list/src/api-harmonization/product-list.request.ts (1 hunks)
  • packages/blocks/product-list/src/frontend/ProductList.renderer.tsx (1 hunks)
  • packages/configs/integrations/package.json (1 hunks)
  • packages/framework/src/modules/products/products.request.ts (1 hunks)
  • packages/integrations/mocked/src/modules/cms/mappers/blocks/cms.product-list.mapper.ts (0 hunks)
  • packages/integrations/mocked/src/modules/products/products.mapper.ts (2 hunks)
  • packages/ui/src/components/Cards/ProductCard/ProductCard.tsx (1 hunks)
  • packages/ui/src/components/RichText/RichText.tsx (3 hunks)
  • packages/ui/src/components/RichText/index.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/integrations/mocked/src/modules/cms/mappers/blocks/cms.product-list.mapper.ts
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-11-13T15:40:10.528Z
Learnt from: marcinkrasowski
Repo: o2sdev/openselfservice PR: 348
File: packages/blocks/notification-summary/src/frontend/NotificationSummary.renderer.tsx:1-15
Timestamp: 2025-11-13T15:40:10.528Z
Learning: In next-intl 3.0+, hook-style APIs like useLocale(), useTranslations(), and useFormatter() can be used in non-async Server Components without the 'use client' directive. The library provides server-optimized implementations automatically. Only async Server Components need to use the await-based APIs like getLocale() from next-intl/server.

Applied to files:

  • packages/blocks/product-list/src/frontend/ProductList.renderer.tsx
📚 Learning: 2025-12-03T12:34:20.707Z
Learnt from: marcinkrasowski
Repo: o2sdev/openselfservice PR: 419
File: apps/frontend/package.json:52-52
Timestamp: 2025-12-03T12:34:20.707Z
Learning: In the openselfservice repository, the application does not use Next.js cache components (use cache/cacheComponents), so next-intl compatibility limitations related to those experimental features are not a concern.

Applied to files:

  • packages/blocks/product-list/src/frontend/ProductList.renderer.tsx
📚 Learning: 2025-11-26T11:57:00.632Z
Learnt from: marcinkrasowski
Repo: o2sdev/openselfservice PR: 411
File: packages/framework/src/modules/cms/models/blocks/product-list.model.ts:29-46
Timestamp: 2025-11-26T11:57:00.632Z
Learning: In the framework layer (packages/framework/src/modules/cms/models/blocks/*.model.ts), block classes like ProductListBlock should NOT include explicit __typename discriminators. The __typename field is added at the API harmonization layer (packages/blocks/*/src/api-harmonization/*.model.ts) where it's needed for discriminated unions. The framework maintains normalized data models without these discriminators.

Applied to files:

  • packages/blocks/product-list/src/api-harmonization/product-list.request.ts
🧬 Code graph analysis (2)
packages/blocks/product-list/src/api-harmonization/product-list.request.ts (3)
packages/framework/src/modules/cms/cms.request.ts (1)
  • GetCmsEntryParams (5-8)
packages/framework/src/modules/products/products.model.ts (1)
  • Products (26-26)
packages/framework/src/modules/products/products.request.ts (1)
  • GetProductListQuery (4-9)
packages/integrations/mocked/src/modules/products/products.mapper.ts (1)
packages/framework/src/modules/products/products.model.ts (1)
  • Products (26-26)
🪛 ast-grep (0.40.0)
packages/ui/src/components/RichText/RichText.tsx

[warning] 82-82: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.1.2)
packages/ui/src/components/RichText/RichText.tsx

[error] 83-83: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: deploy-preview
🔇 Additional comments (8)
packages/blocks/product-list/src/frontend/ProductList.renderer.tsx (1)

16-18: Simplified loading fallback looks good

The new single-wrapper + Loading skeleton keeps behavior intact while reducing layout complexity; no functional or UX regressions are apparent here.

packages/framework/src/modules/products/products.request.ts (1)

4-9: LGTM!

The addition of sort?: string to GetProductListQuery is consistent with the existing sort parameter in GetRelatedProductListParams and provides a clean API for the sorting functionality implemented in the mapper.

packages/integrations/mocked/src/modules/products/products.mapper.ts (1)

344-387: LGTM on mapProducts implementation.

The sorting logic correctly handles name, price, and generic string/number fields. The shallow copy on line 356 ([...filteredProducts]) properly prevents mutation of the original array.

.changeset/cute-eagles-cheer.md (2)

18-22: LGTM: Sorting feature documentation is clear.

The sorting feature addition is well-documented with clear format specification (name_ASC, name_DESC, price_ASC, price_DESC) and notes that sorting is applied post-filtering. No concerns with this section.


1-7: All package names are valid and version bump severity is correct.

All five packages (@o2s/configs.integrations, @o2s/blocks.product-list, @o2s/integrations.mocked, @o2s/framework, @o2s/ui) exist in the monorepo and match their actual package configurations. The minor version bump is appropriate since these are feature additions to established packages, not new package releases.

packages/configs/integrations/package.json (1)

33-33: No functional change in package.json

Only formatting/newline on the closing brace; no functional or configuration impact.

packages/blocks/product-list/src/api-harmonization/product-list.request.ts (1)

3-11: GetProductListBlockQuery interface extension looks consistent

Implementing Products.Request.GetProductListQuery together with the existing CMS params and exposing offset, limit, type, category, and sort keeps this query structurally aligned with the framework request types; nothing stands out as problematic.

packages/ui/src/components/RichText/index.ts (1)

1-1: Publicly re-exporting detectContentFormat is appropriate

Exposing detectContentFormat alongside RichText from the index keeps the API cohesive and allows other components to reuse the same format detection logic.

Comment thread .changeset/cute-eagles-cheer.md Outdated
Comment thread packages/ui/src/components/RichText/RichText.tsx Outdated
@tomaszpacior tomaszpacior changed the title Fix/product list issues Enhance RichText with format detection and add product sorting Dec 8, 2025
@vercel
Copy link
Copy Markdown

vercel Bot commented Dec 8, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
o2s-docs Skipped Skipped Dec 9, 2025 10:17am

@vercel vercel Bot temporarily deployed to Preview – o2s-docs December 8, 2025 11:34 Inactive
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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 (1)
packages/ui/src/components/RichText/RichText.tsx (1)

78-86: XSS concern from past review has been addressed.

The previous review flagged the use of dangerouslySetInnerHTML without sanitization. This has been correctly fixed by wrapping content with DOMPurify.sanitize(). The static analysis warnings (Biome, ast-grep) are false positives—they detect dangerouslySetInnerHTML but cannot recognize that sanitization is applied.

Note: This approval is contingent on resolving the SSR compatibility issue with DOMPurify mentioned above.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d9733f3 and 9620e60.

📒 Files selected for processing (1)
  • packages/ui/src/components/RichText/RichText.tsx (4 hunks)
🧰 Additional context used
🪛 ast-grep (0.40.0)
packages/ui/src/components/RichText/RichText.tsx

[warning] 83-83: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.1.2)
packages/ui/src/components/RichText/RichText.tsx

[error] 84-84: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: deploy-preview
🔇 Additional comments (2)
packages/ui/src/components/RichText/RichText.tsx (2)

17-29: LGTM!

The detectContentFormat function correctly identifies HTML content using a reasonable tag pattern. The fallback to 'markdown' for empty/falsy content is appropriate.


280-284: LGTM!

The wrapper div ensures consistent structure between HTML and Markdown rendering paths, with className and spread props correctly applied.

Comment thread packages/ui/src/components/RichText/RichText.tsx Outdated
Comment thread packages/ui/src/components/RichText/RichText.tsx Outdated
@tomaszpacior tomaszpacior changed the title Enhance RichText with format detection and add product sorting Add product sorting Dec 9, 2025
@vercel vercel Bot temporarily deployed to Preview – o2s-docs December 9, 2025 10:00 Inactive
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9620e60 and 65c46b5.

📒 Files selected for processing (1)
  • packages/ui/src/components/RichText/RichText.tsx (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-12-03T14:01:47.549Z
Learnt from: marcinkrasowski
Repo: o2sdev/openselfservice PR: 419
File: packages/blocks/quick-links/package.json:51-51
Timestamp: 2025-12-03T14:01:47.549Z
Learning: In the openselfservice repository, next-intl 4.1.0 (and the version ^4.1.0 used in peerDependencies) works correctly with Next.js 16, despite general community concerns about partial compatibility.

Applied to files:

  • packages/ui/src/components/RichText/RichText.tsx
📚 Learning: 2025-12-03T14:01:47.549Z
Learnt from: marcinkrasowski
Repo: o2sdev/openselfservice PR: 419
File: packages/blocks/quick-links/package.json:51-51
Timestamp: 2025-12-03T14:01:47.549Z
Learning: In the openselfservice repository, next/bundle-analyzer does not support Turbopack yet (as of PR #419), but this is acceptable since it's a development tool and doesn't block core functionality.

Applied to files:

  • packages/ui/src/components/RichText/RichText.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: deploy-preview

Comment thread packages/ui/src/components/RichText/RichText.tsx Outdated
@vercel vercel Bot temporarily deployed to Preview – o2s-docs December 9, 2025 10:17 Inactive
@tomaszpacior tomaszpacior merged commit e78c11a into main Dec 18, 2025
7 checks passed
@tomaszpacior tomaszpacior deleted the fix/product-list-issues branch December 18, 2025 11:07
@coderabbitai coderabbitai Bot mentioned this pull request Jan 15, 2026
1 task
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.

2 participants