ajustes eslint y diseño#119
Conversation
|
Warning Review limit reached
Next review available in: 33 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (22)
📝 WalkthroughWalkthroughSe añade internacionalización completa a checkout, carrito, página de producto y menú de usuario mediante diccionarios es/cat. Se incorporan ChangesPedidos: unitPrice, imagen y páginas rediseñadas
Internacionalización de checkout, carrito y páginas de producto
Configuración ESLint, dependencias y ajuste menor
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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: 13
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
shared/ui/tag-list.tsx (1)
94-101: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
aria-labeldel botón eliminar no describe la acción.
aria-label={tag}solo anuncia el valor de la etiqueta, sin indicar que el botón la elimina. Para lectores de pantalla sería más claro combinar la acción con el valor, p. ej. usandodict.common.removeFromCart.♿ Propuesta de fix
- aria-label={tag} + aria-label={`${dict.common.removeFromCart}: ${tag}`}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@shared/ui/tag-list.tsx` around lines 94 - 101, The remove button in TagList does not announce its action clearly because aria-label only uses the tag value. Update the button in tag-list.tsx to use an action-oriented accessible label in the TagList render logic, combining the remove action with the tag name (similar to dict.common.removeFromCart) so screen readers hear that the button removes that specific tag.modules/orders/infrastructure/prisma-order-repository.ts (1)
163-185: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
productImageUrlnunca se persiste ensaveOrderLineItems.El
createManysolo añadeunitPrice;productImageUrlno forma parte del payload pese a que el modelo Prisma lo define (productImageUrl String?) yOrderLineItemEntitylo documenta como "Product image URL (snapshot at checkout time)". Esto implica que la columna siempre quedará enNULL, y tantofindPaginatedcomofindByIdacabarán resolviendo siempreitem.product?.images?.[0]?.url(imagen actual del producto) en el fallback?? item.productImageUrl, nunca la imagen histórica del momento de la compra. Si el vendedor cambia la foto del producto, el historial de pedidos mostrará silenciosamente una imagen distinta a la que el cliente compró.Confirmé además que ni
create-order-use-case.ts(línea 93) nihandle-cart-checked-out.ts(línea 161) rellenanproductImageUrlal construir elOrderLineItemEntity, por lo que el campo está completamente desconectado de extremo a extremo.La descripción de esta capa indica que se mapea "productName/productImageUrl/unitPrice tanto en findPaginated como en findById y saveOrderLineItems", pero el código de
saveOrderLineItemssolo cubreunitPrice.🛠️ Fix propuesto (mínimo, requiere además poblar el campo en los casos de uso)
await tx.orderLineItem.createMany({ data: lineItems.map((item) => ({ id: item.id, orderId: orderId, productId: item.productId, quantity: item.quantity, unitPrice: item.unitPrice, + productImageUrl: item.productImageUrl ?? null, customizationIdList: item.customizationIdList, customizationSnapshot: (item.customizationSnapshot ?? Prisma.JsonNull) as unknown as Prisma.InputJsonValue, })), });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@modules/orders/infrastructure/prisma-order-repository.ts` around lines 163 - 185, `saveOrderLineItems` no está persistiendo `productImageUrl`, así que el snapshot de imagen queda perdido y los lectores posteriores caen en el fallback de la imagen actual del producto. Actualiza el payload del `tx.orderLineItem.createMany` para incluir `productImageUrl` desde `OrderLineItemEntity`, y verifica que los puntos que construyen esos entities, como `create-order-use-case` y `handle-cart-checked-out`, asignen ese campo al momento del checkout.
🧹 Nitpick comments (9)
app/[locale]/products/[id]/mockup-canvas-control.tsx (1)
292-296: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
String.fromCharCodeinnecesario: no evita ningún lint real.La regla
i18next/no-literal-stringestá configurada en modojsx-text-only, que "solo prohíbe escribir texto plano dentro del markup JSX" y no se aplica a template literals dentro de unuseMemo. Este cambio no aporta beneficio de linting y solo reduce la legibilidad.♻️ Revertir a literales simples
const positionReadout = useMemo( - () => - `${Math.round(position.x * 100)}${String.fromCharCode(37)} ${String.fromCharCode(47)} ${Math.round(position.y * 100)}${String.fromCharCode(37)}`, + () => + `${Math.round(position.x * 100)}% / ${Math.round(position.y * 100)}%`, [position.x, position.y], );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/products/[id]/mockup-canvas-control.tsx around lines 292 - 296, The String.fromCharCode change in useMemo for positionReadout is unnecessary because the i18next/no-literal-string rule only targets JSX text, not this template literal. Revert the expression in mockup-canvas-control.tsx to simple literal punctuation while keeping the same positionReadout calculation, and use the useMemo block as the place to restore readability.package.json (1)
118-123: 🔒 Security & Privacy | 🔵 TrivialRevisar el alcance de
allowScripts.Habilitar la ejecución de scripts de instalación amplía la superficie de confianza de la cadena de suministro. Dado que son paquetes nativos conocidos (prisma, bcrypt, esbuild, sharp), es razonable, pero conviene fijar versiones exactas y revisar periódicamente advisories de estas dependencias antes de actualizar.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@package.json` around lines 118 - 123, Review the allowScripts whitelist in package.json and keep it narrowly scoped to the exact native packages and versions already intended here (`@prisma/engines`@7.8.0, prisma@7.8.0, bcrypt@6.0.0, esbuild@0.28.1, sharp@0.34.5); avoid broadening it to ranges or additional packages, and ensure any future updates are paired with a manual security/advisory review before changing this list.app/[locale]/checkout/page.module.css (2)
62-70: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRevisar el color de texto en
.warning.El bloque usa
border-color: var(--color-warning)pero el texto usavar(--color-green-dark), lo que resulta semánticamente inconsistente para un mensaje de advertencia. Verificar si se pretendía usar una variable de advertencia (p. ej.--color-warning-darko similar) en lugar de un tono verde.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/checkout/page.module.css around lines 62 - 70, The `.warning` style uses a green text color that is inconsistent with its warning border, so update the text color in the checkout page CSS to a warning-appropriate token instead of `var(--color-green-dark)`. Locate the `.warning` rule in `page.module.css` and align its `color` with the existing warning palette, using the corresponding warning/darker warning variable if available so the message reads consistently with the border styling.
13-13: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueNombres de clase en camelCase (kebab-case esperado por Stylelint).
Stylelint señala que
.checkoutCard,.sellerSection,.sellerNamee.itemCustomizationRemovedno siguen kebab-case, pero esto coincide con el patrón camelCase ya usado en el resto de clases del archivo (p. ej..itemCustomization,.totals), por lo que no es una regresión introducida por este cambio.Also applies to: 19-19, 24-24, 56-56
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/checkout/page.module.css at line 13, The CSS module selectors in page.module.css use camelCase names like checkoutCard, sellerSection, sellerName, and itemCustomizationRemoved, which triggers Stylelint’s kebab-case rule. Update these class selectors to the project’s expected kebab-case naming and keep the corresponding className references in sync wherever these symbols are used, or otherwise align the lint rule with the established convention in this file.Source: Linters/SAST tools
modules/cart/presentation/components/add-to-cart-button.tsx (1)
632-632: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winTexto incorrecto: se reutiliza
labels.addingpara el estado de guardado de diseño.
labels.addingestá destinado al flujo de "añadir al carrito" (ver uso enfeedbackLabel, línea 577). Reutilizarlo aquí parasavingDesignmostrará un texto semánticamente incorrecto (p. ej. "Añadiendo..." mientras se guarda un diseño, no se añade al carrito).💬 Ejemplo de ajuste propuesto
interface CartButtonLabels { addToCart: string; removeFromCart: string; adding: string; added: string; error: string; + savingDesign?: string; ... }- {savingDesign ? labels.adding : labels.saveDesign} + {savingDesign ? (labels.savingDesign ?? labels.adding) : labels.saveDesign}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@modules/cart/presentation/components/add-to-cart-button.tsx` at line 632, The `add-to-cart-button` render branch is reusing `labels.adding` for the `savingDesign` state, which shows the wrong copy for a design save flow. Update the conditional text in `AddToCartButton` so `savingDesign` uses a dedicated save-design label/message instead of the add-to-cart label, and keep `labels.adding` only for the actual cart-adding path (as already reflected in `feedbackLabel`).modules/cart/presentation/components/cart-view.tsx (1)
8-8: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winInconsistencia: mezcla de
labels(props) yuseDictionary()(contexto) en el mismo componente.
CartViewrecibe todos sus textos vía el proplabels, pero ahora estas nuevas cadenas (customizationDesignImageAlt,customizationColor,price) se obtienen directamente del contexto conuseDictionary(). Esto introduce una segunda fuente de traducción en un componente que hasta ahora era completamente controlado por props, dificultando pruebas unitarias (requierenDictionaryProvidero dependen del fallback a español) y la coherencia del componente.Sugerencia: añadir estas claves a
CartViewLabelsy pasarlas desde el padre, igual que el resto de textos.Also applies to: 130-130, 303-303, 323-323, 356-358
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@modules/cart/presentation/components/cart-view.tsx` at line 8, `CartView` is mixing two translation sources by using `useDictionary()` for a few new strings while the rest still comes from the `labels` prop. Update `CartViewLabels` to include `customizationDesignImageAlt`, `customizationColor`, and `price`, then pass them in from the parent so `CartView` stays fully prop-driven. Remove the `useDictionary()` dependency from `CartView` and replace the affected usages with `labels` fields, keeping the component consistent and easier to test.app/[locale]/orders/[orderId]/page.tsx (1)
66-73: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winEl código
'cat'no es el subtag BCP-47 canónico para catalán.
new Date(order.createdAt).toLocaleDateString(locale)recibelocaletal cual (puede ser'cat'). El código ISO 639-1 de catalán esca;cates sintácticamente válido paraIntlpero no está registrado como subtag canónico, por lo que el formato de fecha resultante puede no corresponder realmente a las convenciones catalanas (comportamiento dependiente del motor JS). Conviene mapear'cat'→'ca'antes de pasarlo atoLocaleDateString.🌍 Fix sugerido
+const INTL_LOCALE_MAP: Record<string, string> = { es: 'es', cat: 'ca' }; ... - {new Date(order.createdAt).toLocaleDateString(locale)} + {new Date(order.createdAt).toLocaleDateString(INTL_LOCALE_MAP[locale] ?? locale)}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/`[locale]/orders/[orderId]/page.tsx around lines 66 - 73, The date formatting in the order page uses locale directly in the `order.createdAt` display, so normalize the locale before calling `toLocaleDateString`. Update the `page.tsx` logic around the `order.createdAt` render to map the non-canonical `'cat'` locale to the canonical `'ca'` code, and pass that normalized value to `new Date(order.createdAt).toLocaleDateString(...)` so Catalan dates use the correct locale behavior.prisma/schema.prisma (1)
82-83: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winEl índice sobre
nameno acelera las búsquedascontains.El nuevo filtro
qusaname: { contains: filter.q }, que PostgreSQL traduce aLIKE '%valor%'. Un índice B-tree estándar no sirve para patrones con comodín inicial; solo ayuda conLIKE 'valor%'. Para que la búsqueda escale con el catálogo, considera un índice GIN conpg_trgm.@@index([name(ops: raw("gin_trgm_ops"))], type: Gin)(requiere
CREATE EXTENSION IF NOT EXISTS pg_trgm;en una migración)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@prisma/schema.prisma` around lines 82 - 83, The current `@@index([name])` in the Prisma schema does not help the new `q` search path because `name: { contains: filter.q }` becomes a leading-wildcard match. Update the `Product` model indexing strategy to use a trigram-based GIN index on `name` instead of the plain B-tree index, and ensure the schema references the appropriate `pg_trgm` operator class so `contains` queries in the search/filter logic scale better with the catalog.modules/orders/infrastructure/prisma-order-repository.ts (1)
47-100: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicación entre
findPaginatedyfindById.El bloque
translationLocale, elincludedeproduct.translations/images, y el mapeo delineItems(productName,productImageUrl,unitPrice) están duplicados casi de forma idéntica entre ambos métodos. Extraer un helper privado (p. ej.buildLineItemInclude(locale)ymapLineItem(item)) reduciría el riesgo de que ambos métodos diverjan al corregir el fallback de traducción u otros ajustes futuros.Also applies to: 187-232
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@modules/orders/infrastructure/prisma-order-repository.ts` around lines 47 - 100, The `findPaginated` and `findById` paths in `PrismaOrderRepository` duplicate the same `translationLocale`, product `include`, and line-item mapping logic, which risks the two methods drifting apart. Extract shared private helpers in this repository, such as a helper that builds the product include for a locale and a helper that maps a line item into the response shape, then have both `findPaginated` and `findById` use them so the translation fallback and image/unit-price handling stay consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/`[locale]/orders/[orderId]/page.module.css:
- Around line 17-134: The new CSS module classes in this order page are using
camelCase for TSX access, but `selector-class-pattern` is still enforcing
kebab-case and will fail lint. Update the Stylelint configuration to allow
camelCase selectors in `*.module.css` (preferred for `styles.itemRow`-style
usage), or rename the selectors and corresponding references in `page.tsx`
consistently. Use the module classes like `detailRow`, `itemsCard`, `itemRow`,
and `retryButton` to locate the affected styling.
In `@app/`[locale]/orders/[orderId]/page.tsx:
- Around line 88-90: The line total calculation in the order item rendering is
using a truthy check on item.unitPrice, which treats 0 as missing and hides
valid free-item totals. Update the logic in the page component where lineTotal
is derived so it checks explicitly for a defined numeric value (for example,
against null/undefined) before multiplying by item.quantity, keeping the
undefined fallback only when the price is actually absent.
In `@app/`[locale]/orders/page.tsx:
- Around line 181-183: The empty-state Card in the orders page is using the
wrong localization key and currently shows the page title instead of the
no-orders message. Update the fallback in the orders empty-state rendering
within the page component so it uses the dedicated empty-state text key from the
orders dictionary rather than dict.orders?.myOrders, keeping the same Card
structure but swapping to the proper “No orders yet” message source.
In `@app/`[locale]/seller/orders/page.module.css:
- Line 14: The CSS module class selectors use camelCase and are failing
selector-class-pattern; rename the affected classes in page.module.css to
kebab-case and update all corresponding references in page.tsx to use the new
names via styles[...] access. If these CSS Modules are intended to keep
camelCase, instead adjust the Stylelint selector-class-pattern rule to allow
them, but keep the naming consistent across the module and the page component.
In `@app/`[locale]/seller/orders/page.tsx:
- Around line 178-206: The filter labels in the seller orders page are not
associated with their select controls, so update the form in the orders page to
connect each <label> with its corresponding <select> by using matching
identifiers (or by nesting the control inside the label). Apply this to the
status and sort controls in the filter form so the labels for
dict.orders?.filterStatus and dict.orders?.sortBy are properly tied to the
selects.
- Around line 240-241: The empty-state in the seller orders page is using the
page title key instead of the dedicated no-results message, so update the render
in the seller orders component to use the empty-state translation key from the
orders dictionary rather than sellerOrdersTitle. Locate the empty-state branch
in the page component that renders the Card and switch it to the correct key so
the message shows “No orders yet” or its localized equivalent.
In `@app/api/orders/`[orderId]/status/route.ts:
- Around line 63-66: The redirect in the order status route is using the
client-controlled referer directly, which can cause an open redirect after the
authenticated POST. Update the logic in the status handler to validate the
referer in the request flow before calling NextResponse.redirect, allowing only
same-origin URLs (or otherwise falling back to a safe JSON response) and keep
the change localized around the referer handling in the route.
In `@modules/orders/domain/entities/order-line-item.ts`:
- Around line 14-19: Persist the checkout snapshot for product images by wiring
productImageUrl through the order line item flow. Update buildLineItems so it
populates productImageUrl from the source product data when constructing line
items, and update saveOrderLineItems to persist that field when creating
records. Make sure the OrderLineItem entity and the save/build logic stay
aligned so productImageUrl is stored and later usable as the fallback.
In `@modules/orders/infrastructure/prisma-order-repository.ts`:
- Line 58: La relación de imágenes en Prisma está limitando a una sola (`images:
{ take: 1 }`) pero sin orden determinista, así que la “primera” imagen puede
variar entre consultas. Actualiza el include en `PrismaOrderRepository` para que
la consulta de `images` use un `orderBy` explícito y estable (por ejemplo
`isPrimary`, `createdAt` u otro campo de prioridad), manteniendo `take: 1` para
que siempre se devuelva la misma imagen esperada.
- Around line 33-45: The q filter in prisma-order-repository’s where.lineItems
query is currently case-sensitive, so searches can miss matches like lowercase
and uppercase variants. Update the name.contains condition in the order
repository query to use case-insensitive matching, and keep the fix localized to
the filter.q branch in the repository logic that builds the Prisma where clause.
In `@modules/orders/presentation/schemas/order-schemas.ts`:
- Line 16: The search field q in the order schema is currently passed through
without normalization, so update the Zod definition in the order-schemas schema
to trim whitespace and cap the maximum length before it reaches the Prisma
contains filter. Use the existing q field definition in the order schema to
apply the normalization and validation there, so only a cleaned, reasonably
sized search term is accepted.
In `@prisma/schema.prisma`:
- Around line 178-179: The new unitPrice default in the Prisma schema can leave
historical order lines with invalid $0 pricing because findPaginated and
findById now read unitPrice directly and the UI uses it to compute line totals.
Update the schema/migration flow around unitPrice to backfill existing rows
before relying on the default, using an appropriate source such as
Product.basePrice or a per-order allocation from Order.total and quantity so
preexisting orders keep meaningful line amounts.
In `@shared/ui/tag-list.tsx`:
- Around line 19-26: The fallback labels in TagList are pointing to the wrong
dictionary keys, so the defaults resolve to undefined. Update the TagList
component to use existing dictionary entries from useDictionary for
addLabelValue and emptyLabelValue, and verify the fallback properties come from
the correct nested sections rather than dict.common. Keep the fix localized in
TagListProps handling so the component still prefers passed-in labels and only
falls back to valid dictionary values.
---
Outside diff comments:
In `@modules/orders/infrastructure/prisma-order-repository.ts`:
- Around line 163-185: `saveOrderLineItems` no está persistiendo
`productImageUrl`, así que el snapshot de imagen queda perdido y los lectores
posteriores caen en el fallback de la imagen actual del producto. Actualiza el
payload del `tx.orderLineItem.createMany` para incluir `productImageUrl` desde
`OrderLineItemEntity`, y verifica que los puntos que construyen esos entities,
como `create-order-use-case` y `handle-cart-checked-out`, asignen ese campo al
momento del checkout.
In `@shared/ui/tag-list.tsx`:
- Around line 94-101: The remove button in TagList does not announce its action
clearly because aria-label only uses the tag value. Update the button in
tag-list.tsx to use an action-oriented accessible label in the TagList render
logic, combining the remove action with the tag name (similar to
dict.common.removeFromCart) so screen readers hear that the button removes that
specific tag.
---
Nitpick comments:
In `@app/`[locale]/checkout/page.module.css:
- Around line 62-70: The `.warning` style uses a green text color that is
inconsistent with its warning border, so update the text color in the checkout
page CSS to a warning-appropriate token instead of `var(--color-green-dark)`.
Locate the `.warning` rule in `page.module.css` and align its `color` with the
existing warning palette, using the corresponding warning/darker warning
variable if available so the message reads consistently with the border styling.
- Line 13: The CSS module selectors in page.module.css use camelCase names like
checkoutCard, sellerSection, sellerName, and itemCustomizationRemoved, which
triggers Stylelint’s kebab-case rule. Update these class selectors to the
project’s expected kebab-case naming and keep the corresponding className
references in sync wherever these symbols are used, or otherwise align the lint
rule with the established convention in this file.
In `@app/`[locale]/orders/[orderId]/page.tsx:
- Around line 66-73: The date formatting in the order page uses locale directly
in the `order.createdAt` display, so normalize the locale before calling
`toLocaleDateString`. Update the `page.tsx` logic around the `order.createdAt`
render to map the non-canonical `'cat'` locale to the canonical `'ca'` code, and
pass that normalized value to `new
Date(order.createdAt).toLocaleDateString(...)` so Catalan dates use the correct
locale behavior.
In `@app/`[locale]/products/[id]/mockup-canvas-control.tsx:
- Around line 292-296: The String.fromCharCode change in useMemo for
positionReadout is unnecessary because the i18next/no-literal-string rule only
targets JSX text, not this template literal. Revert the expression in
mockup-canvas-control.tsx to simple literal punctuation while keeping the same
positionReadout calculation, and use the useMemo block as the place to restore
readability.
In `@modules/cart/presentation/components/add-to-cart-button.tsx`:
- Line 632: The `add-to-cart-button` render branch is reusing `labels.adding`
for the `savingDesign` state, which shows the wrong copy for a design save flow.
Update the conditional text in `AddToCartButton` so `savingDesign` uses a
dedicated save-design label/message instead of the add-to-cart label, and keep
`labels.adding` only for the actual cart-adding path (as already reflected in
`feedbackLabel`).
In `@modules/cart/presentation/components/cart-view.tsx`:
- Line 8: `CartView` is mixing two translation sources by using
`useDictionary()` for a few new strings while the rest still comes from the
`labels` prop. Update `CartViewLabels` to include `customizationDesignImageAlt`,
`customizationColor`, and `price`, then pass them in from the parent so
`CartView` stays fully prop-driven. Remove the `useDictionary()` dependency from
`CartView` and replace the affected usages with `labels` fields, keeping the
component consistent and easier to test.
In `@modules/orders/infrastructure/prisma-order-repository.ts`:
- Around line 47-100: The `findPaginated` and `findById` paths in
`PrismaOrderRepository` duplicate the same `translationLocale`, product
`include`, and line-item mapping logic, which risks the two methods drifting
apart. Extract shared private helpers in this repository, such as a helper that
builds the product include for a locale and a helper that maps a line item into
the response shape, then have both `findPaginated` and `findById` use them so
the translation fallback and image/unit-price handling stay consistent.
In `@package.json`:
- Around line 118-123: Review the allowScripts whitelist in package.json and
keep it narrowly scoped to the exact native packages and versions already
intended here (`@prisma/engines`@7.8.0, prisma@7.8.0, bcrypt@6.0.0,
esbuild@0.28.1, sharp@0.34.5); avoid broadening it to ranges or additional
packages, and ensure any future updates are paired with a manual
security/advisory review before changing this list.
In `@prisma/schema.prisma`:
- Around line 82-83: The current `@@index([name])` in the Prisma schema does not
help the new `q` search path because `name: { contains: filter.q }` becomes a
leading-wildcard match. Update the `Product` model indexing strategy to use a
trigram-based GIN index on `name` instead of the plain B-tree index, and ensure
the schema references the appropriate `pg_trgm` operator class so `contains`
queries in the search/filter logic scale better with the catalog.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: b5ae0eee-68e7-48bb-a483-a0e92432943b
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (48)
app/[locale]/checkout/page.module.cssapp/[locale]/checkout/page.tsxapp/[locale]/layout.tsxapp/[locale]/orders/[orderId]/page.module.cssapp/[locale]/orders/[orderId]/page.tsxapp/[locale]/orders/page.module.cssapp/[locale]/orders/page.tsxapp/[locale]/products/[id]/mockup-canvas-control.tsxapp/[locale]/products/[id]/page.tsxapp/[locale]/seller/orders/page.module.cssapp/[locale]/seller/orders/page.tsxapp/api/orders/[orderId]/status/route.tseslint.config.mjsmodules/cart/presentation/components/add-to-cart-button.tsxmodules/cart/presentation/components/cart-popup.tsxmodules/cart/presentation/components/cart-view.tsxmodules/cart/presentation/components/checkout-confirm-button.module.cssmodules/cart/presentation/components/checkout-confirm-button.tsxmodules/orders/application/create-order-use-case.tsmodules/orders/application/handle-cart-checked-out.tsmodules/orders/application/list-customer-orders-use-case.tsmodules/orders/application/list-seller-orders-use-case.tsmodules/orders/domain/entities/order-line-item.tsmodules/orders/domain/order-repository.tsmodules/orders/infrastructure/prisma-order-repository.tsmodules/orders/presentation/schemas/order-schemas.tsmodules/products/presentation/components/product-customization-config-editor.tsxpackage.jsonprisma/migrations/20260705193304_add_order_line_item_unit_price/migration.sqlprisma/schema.prismashared/i18n/locales/cat.jsonshared/i18n/locales/es.jsonshared/layout/user-menu-dropdown.tsxshared/ui/price-field.tsxshared/ui/status-badge.module.cssshared/ui/tag-list.tsxtests/integration/orders.integration.test.tstests/integration/orders/prisma-order-repository.integration.test.tstests/unit/app/[locale]/orders/[orderId]/page.test.tsxtests/unit/app/[locale]/orders/page.test.tsxtests/unit/app/[locale]/seller/orders/page.test.tsxtests/unit/app/checkout/checkout-confirm-button.test.tsxtests/unit/modules/orders/application/assign-to-production-use-case.test.tstests/unit/modules/orders/application/mark-as-paid-use-case.test.tstests/unit/modules/presentation/components/cart-popup.test.tsxtests/unit/modules/presentation/components/user-menu-dropdown.test.tsxverify-report-cart-pr1.mdverify-report-customizations-pr4.md
💤 Files with no reviewable changes (4)
- verify-report-customizations-pr4.md
- modules/products/presentation/components/product-customization-config-editor.tsx
- tests/unit/modules/presentation/components/user-menu-dropdown.test.tsx
- verify-report-cart-pr1.md
| .detailRow { | ||
| display: flex; | ||
| justify-content: space-between; | ||
| align-items: center; | ||
| padding: var(--spacing-sm) 0; | ||
| } | ||
|
|
||
| .detailRow + .detailRow { | ||
| border-top: 1px solid var(--color-border); | ||
| } | ||
|
|
||
| .detailLabel { | ||
| color: var(--color-text-secondary); | ||
| font-size: 0.9rem; | ||
| } | ||
|
|
||
| .detailValue { | ||
| font-weight: var(--font-weight-medium); | ||
| font-size: 0.95rem; | ||
| } | ||
|
|
||
| .itemsCard { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: var(--spacing-md); | ||
| } | ||
|
|
||
| .itemsTitle { | ||
| margin: 0; | ||
| font-size: 1.05rem; | ||
| font-weight: var(--font-weight-semibold); | ||
| color: var(--color-green-dark); | ||
| } | ||
|
|
||
| .itemsList { | ||
| display: flex; | ||
| flex-direction: column; | ||
| } | ||
|
|
||
| .itemRow { | ||
| display: flex; | ||
| align-items: center; | ||
| gap: var(--spacing-md); | ||
| padding: var(--spacing-sm) 0; | ||
| } | ||
|
|
||
| .itemRow + .itemRow { | ||
| border-top: 1px solid var(--color-border); | ||
| } | ||
|
|
||
| .itemImage { | ||
| border-radius: var(--radius-sm); | ||
| object-fit: cover; | ||
| flex-shrink: 0; | ||
| } | ||
|
|
||
| .itemInfo { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 0.15rem; | ||
| min-width: 0; | ||
| flex: 1; | ||
| } | ||
|
|
||
| .itemName { | ||
| font-weight: var(--font-weight-medium); | ||
| font-size: 0.95rem; | ||
| } | ||
|
|
||
| .itemCustomization { | ||
| font-size: 0.8rem; | ||
| color: var(--color-text-secondary); | ||
| } | ||
|
|
||
| .itemRight { | ||
| display: flex; | ||
| align-items: center; | ||
| gap: var(--spacing-sm); | ||
| flex-shrink: 0; | ||
| } | ||
|
|
||
| .itemQty { | ||
| color: var(--color-text-secondary); | ||
| font-size: 0.9rem; | ||
| } | ||
|
|
||
| .itemLineTotal { | ||
| font-weight: var(--font-weight-semibold); | ||
| font-size: 0.95rem; | ||
| min-width: 5rem; | ||
| text-align: right; | ||
| } | ||
|
|
||
| .noItems { | ||
| color: var(--color-text-secondary); | ||
| font-size: 0.9rem; | ||
| margin: 0; | ||
| } | ||
|
|
||
| .retrySection { | ||
| margin: 0; | ||
| } | ||
|
|
||
| .retryButton { | ||
| width: 100%; | ||
| padding: 0.75rem; | ||
| background: var(--color-coral); | ||
| color: var(--color-white); | ||
| border: none; | ||
| border-radius: var(--radius-sm); | ||
| cursor: pointer; | ||
| font-size: 1rem; | ||
| font-weight: var(--font-weight-medium); | ||
| } | ||
|
|
||
| .retryButton:hover { | ||
| opacity: 0.85; | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Conflicto entre convención camelCase y la regla Stylelint selector-class-pattern.
Todas las clases nuevas de este módulo (.detailRow, .itemsCard, .itemRow, .retryButton, etc.) usan camelCase para permitir el acceso styles.itemRow en el TSX, pero Stylelint las marca como error por no ser kebab-case. Esto probablemente hará fallar el paso de lint en CI. Dado que este PR trata justamente de "ajustes eslint" (ver PR objectives), conviene resolverlo: o se ajusta selector-class-pattern en la config de Stylelint para permitir camelCase en archivos *.module.css, o se renombran las clases a kebab-case y se actualiza el acceso en page.tsx (styles['detail-row']).
🔧 Opción recomendada: excepción en la configuración de Stylelint
// stylelint.config.js (ejemplo)
rules: {
- 'selector-class-pattern': '^[a-z][a-zA-Z0-9]*$',
+ 'selector-class-pattern': [
+ '^[a-z][a-zA-Z0-9]*$',
+ { message: 'Se espera camelCase para CSS Modules' },
+ ],
}🧰 Tools
🪛 Stylelint (17.14.0)
[error] 17-17: Expected class selector ".detailRow" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 24-24: Expected class selector ".detailRow" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 24-24: Expected class selector ".detailRow" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 28-28: Expected class selector ".detailLabel" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 33-33: Expected class selector ".detailValue" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 38-38: Expected class selector ".itemsCard" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 44-44: Expected class selector ".itemsTitle" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 51-51: Expected class selector ".itemsList" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 56-56: Expected class selector ".itemRow" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 63-63: Expected class selector ".itemRow" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 63-63: Expected class selector ".itemRow" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 67-67: Expected class selector ".itemImage" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 73-73: Expected class selector ".itemInfo" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 81-81: Expected class selector ".itemName" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 86-86: Expected class selector ".itemCustomization" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 91-91: Expected class selector ".itemRight" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 98-98: Expected class selector ".itemQty" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 103-103: Expected class selector ".itemLineTotal" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 110-110: Expected class selector ".noItems" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 116-116: Expected class selector ".retrySection" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 120-120: Expected class selector ".retryButton" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
[error] 132-132: Expected class selector ".retryButton" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/`[locale]/orders/[orderId]/page.module.css around lines 17 - 134, The new
CSS module classes in this order page are using camelCase for TSX access, but
`selector-class-pattern` is still enforcing kebab-case and will fail lint.
Update the Stylelint configuration to allow camelCase selectors in
`*.module.css` (preferred for `styles.itemRow`-style usage), or rename the
selectors and corresponding references in `page.tsx` consistently. Use the
module classes like `detailRow`, `itemsCard`, `itemRow`, and `retryButton` to
locate the affected styling.
Source: Linters/SAST tools
| margin-bottom: var(--spacing-lg); | ||
| } | ||
|
|
||
| .headerLead { |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Alinea los selectores con selector-class-pattern.
Stylelint está rechazando las clases camelCase de este CSS module. Renómbralas a kebab-case y actualiza las referencias en page.tsx, o ajusta la regla si CSS Modules deben permitir camelCase.
Ejemplo de cambio
-.headerLead {
+.header-lead {Luego referenciarla como styles['header-lead'].
Also applies to: 29-29, 40-40, 46-46, 54-54, 65-65, 77-77, 81-81, 87-87, 93-93, 100-100, 104-104, 116-116, 120-120, 124-124
🧰 Tools
🪛 Stylelint (17.14.0)
[error] 14-14: Expected class selector ".headerLead" to be kebab-case (selector-class-pattern)
(selector-class-pattern)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/`[locale]/seller/orders/page.module.css at line 14, The CSS module class
selectors use camelCase and are failing selector-class-pattern; rename the
affected classes in page.module.css to kebab-case and update all corresponding
references in page.tsx to use the new names via styles[...] access. If these CSS
Modules are intended to keep camelCase, instead adjust the Stylelint
selector-class-pattern rule to allow them, but keep the naming consistent across
the module and the page component.
Source: Linters/SAST tools
| unitPrice Decimal @default(0) | ||
| productImageUrl String? |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
unitPrice con DEFAULT 0 sin backfill corrompe datos históricos.
La migración añade unitPrice con valor por defecto 0 para las filas existentes, sin backfill. Según el contexto (findPaginated/findById mapean unitPrice: Number(item.unitPrice) y las páginas rediseñadas calculan el total por línea con unitPrice * quantity), todos los pedidos creados antes de este cambio mostrarán $0 en el importe de sus líneas, aunque el total del pedido (Order.total) siga siendo correcto.
Considera un backfill (ej. aproximar unitPrice a partir de Product.basePrice o de order.total / SUM(quantity) por pedido) antes de asumir el default 0 como válido para datos preexistentes.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@prisma/schema.prisma` around lines 178 - 179, The new unitPrice default in
the Prisma schema can leave historical order lines with invalid $0 pricing
because findPaginated and findById now read unitPrice directly and the UI uses
it to compute line totals. Update the schema/migration flow around unitPrice to
backfill existing rows before relying on the default, using an appropriate
source such as Product.basePrice or a per-order allocation from Order.total and
quantity so preexisting orders keep meaningful line amounts.
ajustes eslint y diseño
Summary by CodeRabbit
New Features
Bug Fixes