Add product sorting#472
Conversation
WalkthroughThis 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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ 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)
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. Comment |
There was a problem hiding this comment.
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 globalMOCK_PRODUCTSarray.Unlike
mapProductswhich correctly creates a copy with[...filteredProducts], this function assignsdata = productsas a direct reference. Callingdata.sort()mutatesMOCK_PRODUCTSin 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 inmapRelatedProducts(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: Verifyoverflow-ellipsisclass and clamping behaviorUsing
RichTextwithline-clamp-3for the description is a good fit for product cards. Please double‑check thatoverflow-ellipsisis a valid utility in your Tailwind/config (commonlytext-ellipsis/truncateare 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 behaviorThe 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
⛔ Files ignored due to path filters (1)
package-lock.jsonis 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 goodThe new single-wrapper +
Loadingskeleton 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?: stringtoGetProductListQueryis consistent with the existingsortparameter inGetRelatedProductListParamsand 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. Theminorversion 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.jsonOnly 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 consistentImplementing
Products.Request.GetProductListQuerytogether with the existing CMS params and exposingoffset,limit,type,category, andsortkeeps 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-exportingdetectContentFormatis appropriateExposing
detectContentFormatalongsideRichTextfrom the index keeps the API cohesive and allows other components to reuse the same format detection logic.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
There was a problem hiding this comment.
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
dangerouslySetInnerHTMLwithout sanitization. This has been correctly fixed by wrapping content withDOMPurify.sanitize(). The static analysis warnings (Biome, ast-grep) are false positives—they detectdangerouslySetInnerHTMLbut 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
📒 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
detectContentFormatfunction 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
classNameand spread props correctly applied.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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
What does this PR do?
New Features
Improvements
Removed
Summary by CodeRabbit
New Features
Changes
✏️ Tip: You can customize this high-level summary in your review settings.