Skip to content

Migrate checkout, shipping, and review forms to shadcn primitives and product Data update - #5

Merged
benazeem merged 3 commits into
mainfrom
feat/shadcn-form-primitives-and-Product-data-update
Jul 7, 2026
Merged

Migrate checkout, shipping, and review forms to shadcn primitives and product Data update#5
benazeem merged 3 commits into
mainfrom
feat/shadcn-form-primitives-and-Product-data-update

Conversation

@benazeem

@benazeem benazeem commented Jul 7, 2026

Copy link
Copy Markdown
Owner
  • Replaced raw form controls in checkout, shipping addresses, and product reviews with shadcn/base primitives.
  • Updated the Product Data on Sanity
  • updated shipping policy

Summary by CodeRabbit

  • New Features
    • Added a “Skip to main content” link.
    • Size guide now generates separate Attar and Perfume size sections from catalog data (with graceful fallback).
    • Private pages (checkout/cart/login) are now excluded from search engine indexing.
  • Bug Fixes
    • Shipping is consistently shown as free across cart, checkout, product, and related pages.
    • Contact form input is normalized/validated more reliably, with clearer handling when saving fails vs when email delivery fails.
  • Accessibility / UI Improvements
    • Improved labeling for review/upload and track-order modal controls; simplified gallery/size controls for better accessibility.
  • Style / Content
    • Updated global theme styling and refreshed FAQ + shipping policy copy for express delivery and free-shipping messaging.
    • New UI components (Input/Label/Checkbox/Select/Textarea) are now used in key forms.

@benazeem benazeem self-assigned this Jul 7, 2026
Copilot AI review requested due to automatic review settings July 7, 2026 05:05
@vercel

vercel Bot commented Jul 7, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
ms-signature Ready Ready Preview, Comment Jul 7, 2026 6:29am

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@benazeem, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 53 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a997244d-f134-4457-b337-4a0e2f718bba

📥 Commits

Reviewing files that changed from the base of the PR and between f81413a and 4a2a8e8.

📒 Files selected for processing (2)
  • app/developer/DeveloperCtas.tsx
  • sanity/schemas/product.ts
📝 Walkthrough

Walkthrough

This PR removes shipping fees across checkout, cart, and content pages, migrates form controls to shared UI components, derives product sizes from category data with Sanity validation, and updates API, accessibility, layout, and documentation files.

Changes

Free shipping and size catalog changes

Layer / File(s) Summary
Free shipping logic and copy updates
app/checkout/page.tsx, components/cart/CartSummary.tsx, app/faq/page.tsx, app/shipping-policy/page.tsx
Shipping is forced to free, and related copy now describes free shipping with optional express delivery.
Category-based sizes and validation
lib/data.ts, sanity/schemas/product.ts, components/product/ProductInfo.tsx, components/shop/ProductCard.tsx
Shared size constants, category-based size selection, and Sanity validation now align allowed size values with product category.
Catalog-driven size guide
app/size-guide/page.tsx
The size guide becomes async, loads catalog products, and renders generated attar/perfume size cards.

Shared UI component migration

Layer / File(s) Summary
UI primitives and design-system wiring
components/ui/{Button,input,label,select,checkbox,textarea,Toast}.tsx, lib/utils.ts, package.json, app/globals.css, app/layout.tsx, components.json
New shared UI components are added, class merging and Tailwind theming are updated, and supporting config/dependencies are expanded.
Checkout form migration
app/checkout/page.tsx
Checkout address selection and shipping-details fields switch to shared components, with saved-address loading deferred via queueMicrotask.
Shipping addresses form migration
components/profile/ShippingAddresses.tsx
The address editor replaces native controls with shared Button, Input, Label, Select, and Checkbox components.
Product reviews form migration
components/shop/ProductReviews.tsx
The review form swaps native rating, comment, upload, and submit controls for shared Button, Input, Label, and Textarea components.

Accessibility, API cleanup, and documentation

Layer / File(s) Summary
Auth and contact API updates
app/api/auth/me/route.ts, app/api/contact/route.ts, lib/mail/config.ts, lib/mail/index.ts
The auth route drops its request parameter, and the contact route normalizes inputs and separates persistence/email error handling; mail config and subject handling are updated to match.
Accessibility attribute updates
app/shop/ShopClient.tsx, components/product/ProductGallery.tsx, app/track-order/[id]/page.tsx, components/ui/Toast.tsx
ARIA attributes are added or removed on several interactive controls.
Head tags, layout, and product card wiring
app/{cart,checkout,login}/head.tsx, app/layout.tsx, components/layout/{Navbar,ClientLayout}.tsx, components/shop/{ProductCard,ProductGrid}.tsx, components/home/FeaturedProducts.tsx
Noindex head files are added, the layout gains a skip link and font class composition, Navbar/ClientLayout styling changes land, and ProductCard usages drop the index prop.
Documentation and config
docs/pre-launch-audit.md, docs/pre-launch-implementation-plan.md, eslint.config.mjs
Pre-launch audit and implementation-plan docs are added, and the ESLint override comment is inserted.
Home decorative styling
components/home/BrandStory.tsx, components/home/Hero.tsx, components/home/WhyChooseUs.tsx
Decorative background accent colors change in the home sections.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • benazeem/MS-Signature#1: Modifies the same app/api/auth/me/route.ts and app/api/contact/route.ts handler logic and validation behavior.
  • benazeem/MS-Signature#4: Also touches components/layout/Navbar.tsx and related product-size plumbing that this PR continues through the shared size helper and selector changes.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is clear and broadly matches the main UI and product-data changes in the pull request.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/shadcn-form-primitives-and-Product-data-update

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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR modernizes the storefront UI by migrating several form surfaces to shadcn/base-ui primitives, while also aligning product sizing/shipping policy content and adding launch-readiness audit docs.

Changes:

  • Added shadcn/base-ui primitives (Button/Input/Select/etc.) and updated global Tailwind styling imports.
  • Updated product sizing rules (attar vs perfume) across Sanity schema validation and fallback product data.
  • Made shipping free across checkout/cart UI and updated related policy/FAQ content; added noindex meta for cart/checkout/login via route head.tsx.

Reviewed changes

Copilot reviewed 40 out of 42 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
sanity/schemas/product.ts Adds async validation to restrict allowed sizes based on product category reference.
package.json Adds base-ui/shadcn-related dependencies and Tailwind helper libs.
lib/utils.ts Replaces prior utilities with shadcn-style cn() helper (currently breaks missing exports).
lib/mail/index.ts Normalizes contact email subject before sending.
lib/mail/config.ts Updates ADMIN_EMAIL env fallback/trim behavior.
lib/data.ts Deduplicates size arrays and aligns attar/perfume sizing.
eslint.config.mjs Minor config comment change (currently duplicated).
docs/pre-launch-implementation-plan.md Adds pre-launch implementation plan doc.
docs/pre-launch-audit.md Adds pre-launch audit doc.
components/ui/Toast.tsx Minor toast sizing + a11y label for dismiss button.
components/ui/textarea.tsx Adds shadcn-style Textarea primitive.
components/ui/select.tsx Adds base-ui Select wrapper styled via Tailwind/shadcn patterns.
components/ui/label.tsx Adds shadcn-style Label primitive.
components/ui/input.tsx Adds base-ui Input wrapper.
components/ui/checkbox.tsx Adds base-ui Checkbox wrapper.
components/ui/Button.tsx Reimplements Button using base-ui + CVA variants.
components/shop/ProductReviews.tsx Migrates review form controls to new primitives and adds ARIA labels.
components/shop/ProductGrid.tsx Removes unused index prop from ProductCard usage.
components/shop/ProductCard.tsx Updates sizing selection logic and layout; (currently removes cart add path).
components/profile/ShippingAddresses.tsx Migrates shipping address form to new primitives and base-ui Select/Checkbox.
components/product/ProductInfo.tsx Filters sizes via new helper and adds “free delivery” note.
components/product/ProductGallery.tsx Removes aria-pressed from gallery thumb buttons (a11y regression).
components/layout/Navbar.tsx Updates logo sizing props to address next/image warnings.
components/layout/ClientLayout.tsx Adds skip link and anchors main content for accessibility.
components/home/FeaturedProducts.tsx Removes unused ProductCard index prop.
components/cart/CartSummary.tsx Makes shipping always free and simplifies display.
components.json Adds shadcn config file for generator/aliases.
app/track-order/[id]/page.tsx Adds ARIA labels to review modal controls.
app/size-guide/page.tsx Rebuilds size guide to read sizes/prices from Sanity (fallback to local data).
app/shop/ShopClient.tsx Removes aria-expanded from mobile filter toggle (a11y regression).
app/shipping-policy/page.tsx Updates shipping policy copy to reflect free shipping + express option.
app/login/head.tsx Adds noindex, nofollow meta for login route.
app/layout.tsx Adds Geist font + uses cn() to build html className.
app/globals.css Imports tw-animate + shadcn CSS and adds shadcn theme token layer.
app/faq/page.tsx Updates FAQ to reflect new sizes + free shipping policy.
app/checkout/page.tsx Migrates address controls to new primitives and makes shipping free.
app/checkout/head.tsx Adds noindex, nofollow meta for checkout route.
app/cart/head.tsx Adds noindex, nofollow meta for cart route.
app/api/contact/route.ts Normalizes/sanitizes inputs and improves error handling for email delivery.
app/api/auth/me/route.ts Removes unused request param/import.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/utils.ts
Comment on lines +1 to 6
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"

url = url.includes("http") ? url : `https://${url}`;
url = url.endsWith("/") ? url.slice(0, -1) : url;
return url;
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
Comment thread components/ui/Button.tsx
Comment on lines +11 to +23
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/80",
outline:
"border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
secondary:
"bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
ghost:
"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
destructive:
"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
link: "text-primary underline-offset-4 hover:underline",
},
Comment thread components/ui/Button.tsx
Comment on lines 65 to +70
if (href) {
return (
<Link href={href} className={classes} id={id} target={target} rel={rel}>
<Link href={href} className={classes} target={target} rel={rel}>
{children}
</Link>
);
)
Comment on lines 99 to 109
@@ -101,7 +106,6 @@ export function ProductInfo({ product }: { product: Product }) {
: "border border-border text-text-muted hover:border-gold hover:text-gold"
}`}
id={`size-${size.value}`}
aria-pressed={selectedSize.value === size.value}
>
Comment on lines 33 to 43
<button
key={i}
onClick={() => setActiveIndex(i)}
className={`relative w-20 h-20 overflow-hidden transition-all duration-300 ${
i === activeIndex
? "border-2 border-gold"
: "border border-border opacity-60 hover:opacity-100"
}`}
id={`gallery-thumb-${i}`}
aria-label={`Select image ${i + 1} for ${name}`}
aria-pressed={i === activeIndex}
>
Comment thread lib/mail/config.ts
Comment on lines +41 to +43
export const ADMIN_EMAIL = (
process.env.ADMIN_EMAIL || process.env.WEBSITE_EMAIL || ""
).trim();
Comment thread package.json
Comment on lines 32 to +36
"sanity": "^5.21.0",
"tailwindcss": "^4"
"shadcn": "^4.13.0",
"tailwind-merge": "^3.6.0",
"tailwindcss": "^4",
"tw-animate-css": "^1.4.0"
Comment thread app/globals.css Outdated
Comment on lines +1 to +5
@import "tailwindcss";
@import "tw-animate-css";
@import "shadcn/tailwind.css";

@custom-variant dark (&:is(.dark *));
Comment thread eslint.config.mjs
Comment on lines 8 to +9
// Override default ignores of eslint-config-next.
// Override default ignores of eslint-config-next.
Comment on lines +20 to +24
const { /*addItem,*/ removeItem, updateQuantity, items } = useCart();

const hasSizes = product.sizes && product.sizes.length > 0;
const initialSize = hasSizes ? product.sizes![0].value : "";
const availableSizes = getAllowedProductSizes(product.category, product.sizes ?? []);
const hasSizes = availableSizes && availableSizes.length > 0;
const initialSize = hasSizes ? availableSizes[0].value : "";

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

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

⚠️ Outside diff range comments (5)
app/api/contact/route.ts (1)

24-58: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Persistence failures are silently swallowed and the user is told the submission succeeded.

If prisma.contactSubmission.create fails, the error is only logged (Line 34) and execution continues; as long as the email send succeeds, the handler returns { success: true } at Line 55-58. The submission is permanently lost with no durable record, no alert, and no indication to the user or admin that the DB write failed.

Consider at minimum: alerting/monitoring on this log line, or reflecting a partial-failure state to the caller so the loss isn't completely silent.

🤖 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/api/contact/route.ts` around lines 24 - 58, The contact submission
handler currently swallows failures from prisma.contactSubmission.create and
still returns success if sendContactNotificationEmail works, so the user is
misled and the write loss is silent. Update the route in contactSubmission
persistence and the email flow so a database write failure is not treated as a
successful request: either propagate the dbError and return an
error/partial-failure response, or explicitly surface the degraded state to the
caller, and keep the logging/monitoring tied to the create call and the final
NextResponse.json path.
app/checkout/page.tsx (1)

463-583: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fixed h-8 height on Input/SelectTrigger conflicts with the floating-label pt-6 pb-2 padding, causing content overflow/clipping.

All migrated fields here (pincode, city, name, email, phone, address) apply pt-6 pb-2 (32px vertical padding) on top of the shared Input component's base h-8 (32px fixed height, per components/ui/input.tsx), leaving no room for line-height/text content within the box. The same applies to the checkout-state SelectTrigger, whose base classes include data-[size=default]:h-8. Since neither custom className includes a height override, h-8 survives the cn()/tailwind-merge pass and the floating-label design (label shrinks to top, value renders below it) can't actually fit inside a 32px box — text will be visually clipped or overflow the box.

This regression is introduced by wrapping these fields with the shared Input/SelectTrigger primitives, which weren't a concern before migration since the previous native <input>/<select> had no forced height.

🐛 Suggested fix: override height for floating-label fields
-                            <Input
-                              id="checkout-pincode"
-                              ...
-                              className={`peer w-full bg-white/5 border ${pincodeError ? "border-red-500/50 focus:border-red-500" : "border-white/10 focus:border-gold"} rounded-xl px-4 pt-6 pb-2 text-text-light placeholder-transparent focus:outline-none transition-all`}
+                            <Input
+                              id="checkout-pincode"
+                              ...
+                              className={`peer h-14 w-full bg-white/5 border ${pincodeError ? "border-red-500/50 focus:border-red-500" : "border-white/10 focus:border-gold"} rounded-xl px-4 pt-6 pb-2 text-text-light placeholder-transparent focus:outline-none transition-all`}

Apply the same h-14 (or h-auto) override to the city, name, email, phone, address Inputs and the checkout-state SelectTrigger.

🤖 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/checkout/page.tsx` around lines 463 - 583, The floating-label checkout
fields are still inheriting the shared fixed height from Input and
SelectTrigger, which conflicts with the pt-6 pb-2 layout and causes clipped or
overflowing text. Update the checkout form fields in the checkout page so the
pincode, city, name, email, phone, address Inputs and the checkout-state
SelectTrigger explicitly override the default h-8 sizing with a taller height
such as h-14 or h-auto, while keeping the existing floating-label padding and
label positioning intact.
components/shop/ProductCard.tsx (1)

102-113: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Cart-count badge may clip for two-digit quantities.

The badge is a fixed w-6 h-6 circle; adding min-w-4 doesn't help since it's smaller than the existing fixed width. Once cartQty reaches double digits, the number can overflow/clip.

🎨 Suggested fix to allow the badge to grow
-                  className="absolute top-3 right-12 w-6 h-6 bg-gold text-primary text-[10px] font-bold rounded-full flex items-center justify-center shadow-lg min-w-4"
+                  className="absolute top-3 right-12 min-w-6 h-6 px-1 bg-gold text-primary text-[10px] font-bold rounded-full flex items-center justify-center shadow-lg"
🤖 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 `@components/shop/ProductCard.tsx` around lines 102 - 113, The cart-count badge
in ProductCard’s AnimatePresence/motion.div is fixed at a circular size, so
double-digit cartQty values can clip. Update the badge styling to allow the
element to expand with the content by replacing the fixed width/height behavior
with size that can grow naturally while keeping the centered badge layout and
animation intact.
components/product/ProductInfo.tsx (2)

99-109: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

aria-pressed removed from toggle-style size buttons.

The size buttons behave like a toggle group (one selected at a time, visually indicated by classes), but the aria-pressed state that previously exposed this to assistive tech was removed with no replacement (e.g., role="radiogroup"/aria-checked).

♿ Suggested restore
               <button
                 key={size.value}
                 onClick={() => setSelectedSize(size)}
+                aria-pressed={selectedSize.value === size.value}
                 className={`px-6 py-3 text-xs tracking-wider uppercase transition-all duration-300 ${
🤖 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 `@components/product/ProductInfo.tsx` around lines 99 - 109, The size selector
buttons in ProductInfo are acting like a single-select toggle group, but their
accessible selected state was removed. Update the button rendered in the
availableSizes.map block so assistive tech can tell which size is selected by
restoring an appropriate pressed/checked state on the size button or by
converting the group to a proper radiogroup/radio pattern. Use the existing
selectedSize state and size.value comparison in ProductInfo to keep the
accessibility state in sync with the visual selection.

24-27: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Restore the react-hooks/set-state-in-effect suppression. eslint.config.mjs uses the Next.js core-web-vitals preset, and components/shop/ProductCard.tsx still needs the same setMounted(true) exception.

🤖 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 `@components/product/ProductInfo.tsx` around lines 24 - 27, The ProductInfo
component’s useEffect still triggers the react-hooks/set-state-in-effect rule,
so restore the same suppression used in ProductCard for the setMounted(true)
call. Update the ProductInfo useEffect block to match the existing exception
pattern in ProductCard, keeping the mounted state initialization while
preventing the lint error under the Next.js core-web-vitals config.
🧹 Nitpick comments (11)
docs/pre-launch-implementation-plan.md (1)

22-27: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Update the noindex task to the actual route files.

This plan still points future work at page.tsx metadata exports, but the branch summary shows the noindex change is being implemented via route head.tsx files. If any of these routes are client components, metadata exports won't be valid, so this guidance will send the next implementer to the wrong place. Please verify the server/client boundary and rewrite the file list accordingly.

Also applies to: 57-63

🤖 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 `@docs/pre-launch-implementation-plan.md` around lines 22 - 27, Update the
SEO-002 plan to point at the actual route-level implementation used in this
branch instead of assuming metadata exports in page components. Verify the
server/client boundary for the `/checkout`, `/cart`, and `/login` routes, and
rewrite the Files/Approach guidance to reference the correct `head.tsx` or other
server-side route files rather than `app/*/page.tsx` with `metadata`. Keep the
task aligned with the route files currently used for the noindex change so the
next implementer lands in the right place.
docs/pre-launch-audit.md (1)

5-8: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Surface the payment blocker in the summary.

The executive summary says there are no critical blockers, but the ecommerce section later marks payment/checkout verification as critical. That mismatch buries the highest-risk item for skimmers. Reword the summary to call out the payment path explicitly.

Also applies to: 177-185

🤖 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 `@docs/pre-launch-audit.md` around lines 5 - 8, The executive summary in the
pre-launch audit is downplaying a critical risk because it says there are no
immediate blockers while the ecommerce section flags payment/checkout
verification as critical. Update the summary text to explicitly call out the
payment path or checkout verification as the highest-risk item, keeping the
wording consistent with the later ecommerce assessment in the same document.
components/shop/ProductReviews.tsx (3)

48-52: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Unclear benefit from queueMicrotask wrapper.

fetchReviews is already async and invoked inside useEffect; wrapping the call in queueMicrotask just defers scheduling by one microtask tick without changing behavior meaningfully (state updates still happen asynchronously either way). This same pattern appears in the checkout and shipping-address forms in this cohort — if it's addressing a specific issue (e.g., Strict Mode double-invoke, hydration timing), a comment explaining the rationale would help future maintainers; otherwise this adds indirection with no observable benefit.

♻️ Simplify if no specific issue is being worked around
   useEffect(() => {
-    queueMicrotask(() => {
-      fetchReviews();
-    });
+    fetchReviews();
   }, [fetchReviews]);
🤖 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 `@components/shop/ProductReviews.tsx` around lines 48 - 52, The useEffect in
ProductReviews wraps fetchReviews in queueMicrotask without a clear need, adding
indirection for no observable benefit. Remove the queueMicrotask wrapper and
call fetchReviews directly from the effect, unless this is intentionally working
around a specific issue; if so, keep the wrapper but add a brief rationale
comment in ProductReviews and apply the same clarification to the matching
checkout and shipping-address patterns.

228-270: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Duplicate aria-label across multiple remove-image buttons.

Every remove button in the images loop shares the same aria-label="Remove uploaded image" (Line 239). With multiple images, screen reader users can't distinguish which image a given "Remove uploaded image" button will delete.

♿ Proposed fix to disambiguate labels
                         <Button
                           type="button"
                           onClick={() => removeImage(index)}
-                          aria-label="Remove uploaded image"
+                          aria-label={`Remove uploaded image ${index + 1}`}
                           variant="ghost"
                           size="icon-xs"
                           className="absolute top-1 right-1 bg-black/50 hover:bg-red-500"
                         >
🤖 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 `@components/shop/ProductReviews.tsx` around lines 228 - 270, The remove-image
buttons in ProductReviews are accessible but not distinguishable because every
button in the images loop uses the same aria-label. Update the image preview
controls in the images.map block so each remove button includes a unique label
that identifies the specific image it will delete, using the loop data (for
example the index or a filename/description if available) while keeping the
removeImage handler behavior unchanged.

192-213: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add aria-pressed to the rating buttons Add aria-pressed={star <= rating} so the selected rating is exposed to assistive tech instead of only via color/fill.

🤖 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 `@components/shop/ProductReviews.tsx` around lines 192 - 213, The rating
controls in ProductReviews use icon buttons but do not expose the selected state
to assistive tech. Update the Button inside the star map in ProductReviews so
each rating button includes aria-pressed based on whether that star is selected,
using the existing star/rating values to keep the pressed state synchronized
with the current rating.
lib/mail/index.ts (1)

39-44: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate default-subject logic.

The "General Inquiry" fallback here duplicates the same normalization already performed by the caller (normalizedSubject in app/api/contact/route.ts). Not a bug since it's idempotent, but consider consolidating to a single source of truth if other callers of sendContactNotificationEmail don't pre-normalize.

🤖 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 `@lib/mail/index.ts` around lines 39 - 44, The subject fallback logic in
sendContactNotificationEmail duplicates normalization already done by the
caller, so consolidate to a single source of truth. Update the
sendContactNotificationEmail flow in lib/mail/index.ts to trust the normalized
subject passed in (or centralize the fallback in a shared helper used by both
app/api/contact/route.ts and this mail helper) so the "General Inquiry" default
is handled consistently across all callers.
lib/data.ts (1)

3-9: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Shared array references across products.

ATTAR_SIZES/PERFUME_SIZES are single array instances now reused by reference across many product entries (Lines 35-291). No current code mutates product.sizes, but any future feature that mutates a size array (sort, push, price override, etc.) would silently affect every product sharing the reference.

♻️ Defensive fix: clone per product
-    sizes: ATTAR_SIZES,
+    sizes: [...ATTAR_SIZES],
🤖 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 `@lib/data.ts` around lines 3 - 9, The shared ATTAR_SIZES and PERFUME_SIZES
arrays are being reused by reference across many products, so a mutation in one
product could affect others. Update the product construction in the data module
so each product receives its own sizes array copy instead of the shared
constants, using the existing ATTAR_SIZES and PERFUME_SIZES definitions as the
source but cloning them wherever they are assigned to product.sizes.
app/faq/page.tsx (1)

14-17: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Hardcoded size list may drift from the catalog-driven source of truth.

This FAQ answer hardcodes "6ml and 12ml" for attars and "30ml" for perfumes. This PR's other layers introduce category-based, Sanity-driven size validation (getAllowedProductSizes, shared size constants in lib/data.ts) and a catalog-driven size-guide page. If the canonical sizes change in Sanity/lib/data.ts in the future, this static FAQ text won't update automatically and could become inaccurate.

🤖 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/faq/page.tsx` around lines 14 - 17, The FAQ entry in the page component
is hardcoding attar and perfume sizes, which can drift from the catalog-driven
source of truth. Update the answer to derive sizes from the shared size
constants or category-based helpers used elsewhere, such as
getAllowedProductSizes and the values in lib/data.ts, so the FAQ stays aligned
with Sanity-driven size rules. Keep the FAQ text consistent with the same
canonical size source used by the size-guide page and product validation.
components/profile/ShippingAddresses.tsx (1)

17-28: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Inconsistent casing across new ui/ primitive imports.

Button is imported from @/components/ui/Button (capitalized) while Checkbox, Input, Label, Select come from lowercase filenames. Functionally fine on case-sensitive filesystems since it matches the actual file names, but the mixed convention is worth aligning for consistency across the new design-system components.

🤖 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 `@components/profile/ShippingAddresses.tsx` around lines 17 - 28, The new ui
primitive imports in ShippingAddresses are using mixed filename casing, which
should be aligned for consistency. Update the imports in the ShippingAddresses
component so the design-system primitives all follow the same casing convention
as their actual file names, and keep the import paths for Button, Checkbox,
Input, Label, and Select consistent with the rest of the ui/ primitives.
app/globals.css (1)

2-5: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Stylelint @custom-variant/@theme warnings are false positives.

Both at-rules are valid Tailwind CSS v4 syntax; the Stylelint config's scss/at-rule-no-unknown rule doesn't recognize them. Consider adding the official Tailwind Stylelint plugin/config or extending ignoreAtRules to silence this noise in CI.

Also applies to: 303-426

🤖 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/globals.css` around lines 2 - 5, The Stylelint warning is a false
positive because the Tailwind v4 at-rules used in globals.css are valid. Update
the Stylelint configuration to recognize Tailwind-specific at-rules by either
adding the official Tailwind Stylelint plugin/config or extending
scss/at-rule-no-unknown ignoreAtRules to include `@custom-variant` and `@theme`.
Make sure the fix applies globally so other Tailwind declarations in the
stylesheet are not flagged.

Source: Linters/SAST tools

package.json (1)

33-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider moving shadcn to devDependencies.

shadcn is a CLI/scaffolding tool consumed via npx shadcn ..., not imported by application code. Keeping it in dependencies means it gets installed in production installs (e.g., npm ci --omit=dev), adding unnecessary install time/surface.

♻️ Proposed fix
   "dependencies": {
     "`@base-ui/react`": "^1.6.0",
     ...
-    "shadcn": "^4.13.0",
     "tailwind-merge": "^3.6.0",
     "tailwindcss": "^4",
     "tw-animate-css": "^1.4.0"
   },
+  "devDependencies": {
+    "shadcn": "^4.13.0"
+  }
🤖 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` at line 33, Move the shadcn package from dependencies to
devDependencies in package.json, since it is only used as a CLI via npx shadcn
and not imported by runtime code. Keep the existing version specifier unchanged,
and update the manifest so production installs do not include this tooling
dependency.
🤖 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/cart/head.tsx`:
- Around line 1-7: The robots meta in Head is not being rendered in this App
Router setup, so move the noindex/nofollow directive into the Metadata API for
the affected routes. Remove the Head-based meta from the cart, checkout, and
login segments, and add robots: { index: false, follow: false } in the
appropriate route segment exports instead, using the existing layout/page entry
points like cart/layout, login/layout, and checkout/page or checkout/layout.

In `@app/size-guide/page.tsx`:
- Around line 28-32: Update the page metadata in the size guide component so it
matches the new “Attar and Perfume” content. In the exported metadata object for
the page, change the title from the attar-only wording and revise the
description to mention both attar and perfume, keeping it aligned with the page
heading and dedicated perfume section.
- Around line 123-166: The “From ₹X” value in buildGuideCards is taken from the
first product in a category instead of the lowest available price, so update the
pricing source to use the true minimum across categoryProducts before passing it
into buildCard. Also make sure the size selection logic in buildGuideCards still
deduplicates by size value, but the displayed price is derived from the
category’s minimum product price rather than categoryProducts[0]?.price.
- Around line 78-121: Handle unexpected attar sizes in the attar branch of the
size guide helper so they do not fall through to the generic spray copy. In the
size mapping logic in app/size-guide/page.tsx, update the attar-specific
handling around the category === "attar" switch to return an attar fallback
object for unknown size.value cases instead of the shared default; keep the
fallback copy, title, applications, duration, and description aligned with attar
products, while preserving the existing 6ml and 12ml entries in the same
function.

In `@components/product/ProductInfo.tsx`:
- Line 6: The import in ProductInfo.tsx is unresolved because
getAllowedProductSizes is not exported from lib/utils.ts. Update the utils
module to export getAllowedProductSizes alongside the existing helper exports,
and make sure any shared re-exports used by ProductInfo and ProductCard remain
consistent so both imports resolve correctly.

In `@components/profile/ShippingAddresses.tsx`:
- Around line 92-102: The ShippingAddresses useEffect currently wraps
fetchAddresses and setLoading(false) in queueMicrotask, which adds an
unnecessary extra tick. Remove the queueMicrotask wrapper inside
ShippingAddresses and let the effect call fetchAddresses or setLoading directly,
and if there is a concern about updates after unmount, handle that with cleanup
or abort logic in the effect itself.

In `@components/ui/Button.tsx`:
- Around line 65-71: The Button component’s href branch drops forwarded props,
so link-styled buttons lose attributes like id, event handlers, and aria-* from
the Button API. Update the href path in Button to pass through the remaining
props to Link while still setting className, target, and rel, matching the
non-href branch behavior.

In `@lib/utils.ts`:
- Around line 1-6: Restore the missing utility export in lib/utils.ts by
reintroducing formatPrice alongside cn, since CartSummary, CartItem,
ProductInfo, and ProductCard still import it from `@/lib/utils`. Update the utils
module so formatPrice is exported again with the same name/signature expected by
those components, and keep the existing cn helper intact.

In `@sanity/schemas/product.ts`:
- Around line 106-132: The size validator in the product schema currently fails
open in the catRef/category lookup path, so invalid sizes can slip through
whenever the fetch fails or the category is unrecognized. Update the validation
logic around the anonymous validator in product.ts to treat missing catRef or
lookup errors as a hard validation failure (or an explicit flagged state), and
only return true when the category is known and matches the allowed size rules
for attar/perfume. Also add logging or a clear error path in the catch block so
bypasses are visible for auditing.

---

Outside diff comments:
In `@app/api/contact/route.ts`:
- Around line 24-58: The contact submission handler currently swallows failures
from prisma.contactSubmission.create and still returns success if
sendContactNotificationEmail works, so the user is misled and the write loss is
silent. Update the route in contactSubmission persistence and the email flow so
a database write failure is not treated as a successful request: either
propagate the dbError and return an error/partial-failure response, or
explicitly surface the degraded state to the caller, and keep the
logging/monitoring tied to the create call and the final NextResponse.json path.

In `@app/checkout/page.tsx`:
- Around line 463-583: The floating-label checkout fields are still inheriting
the shared fixed height from Input and SelectTrigger, which conflicts with the
pt-6 pb-2 layout and causes clipped or overflowing text. Update the checkout
form fields in the checkout page so the pincode, city, name, email, phone,
address Inputs and the checkout-state SelectTrigger explicitly override the
default h-8 sizing with a taller height such as h-14 or h-auto, while keeping
the existing floating-label padding and label positioning intact.

In `@components/product/ProductInfo.tsx`:
- Around line 99-109: The size selector buttons in ProductInfo are acting like a
single-select toggle group, but their accessible selected state was removed.
Update the button rendered in the availableSizes.map block so assistive tech can
tell which size is selected by restoring an appropriate pressed/checked state on
the size button or by converting the group to a proper radiogroup/radio pattern.
Use the existing selectedSize state and size.value comparison in ProductInfo to
keep the accessibility state in sync with the visual selection.
- Around line 24-27: The ProductInfo component’s useEffect still triggers the
react-hooks/set-state-in-effect rule, so restore the same suppression used in
ProductCard for the setMounted(true) call. Update the ProductInfo useEffect
block to match the existing exception pattern in ProductCard, keeping the
mounted state initialization while preventing the lint error under the Next.js
core-web-vitals config.

In `@components/shop/ProductCard.tsx`:
- Around line 102-113: The cart-count badge in ProductCard’s
AnimatePresence/motion.div is fixed at a circular size, so double-digit cartQty
values can clip. Update the badge styling to allow the element to expand with
the content by replacing the fixed width/height behavior with size that can grow
naturally while keeping the centered badge layout and animation intact.

---

Nitpick comments:
In `@app/faq/page.tsx`:
- Around line 14-17: The FAQ entry in the page component is hardcoding attar and
perfume sizes, which can drift from the catalog-driven source of truth. Update
the answer to derive sizes from the shared size constants or category-based
helpers used elsewhere, such as getAllowedProductSizes and the values in
lib/data.ts, so the FAQ stays aligned with Sanity-driven size rules. Keep the
FAQ text consistent with the same canonical size source used by the size-guide
page and product validation.

In `@app/globals.css`:
- Around line 2-5: The Stylelint warning is a false positive because the
Tailwind v4 at-rules used in globals.css are valid. Update the Stylelint
configuration to recognize Tailwind-specific at-rules by either adding the
official Tailwind Stylelint plugin/config or extending scss/at-rule-no-unknown
ignoreAtRules to include `@custom-variant` and `@theme`. Make sure the fix applies
globally so other Tailwind declarations in the stylesheet are not flagged.

In `@components/profile/ShippingAddresses.tsx`:
- Around line 17-28: The new ui primitive imports in ShippingAddresses are using
mixed filename casing, which should be aligned for consistency. Update the
imports in the ShippingAddresses component so the design-system primitives all
follow the same casing convention as their actual file names, and keep the
import paths for Button, Checkbox, Input, Label, and Select consistent with the
rest of the ui/ primitives.

In `@components/shop/ProductReviews.tsx`:
- Around line 48-52: The useEffect in ProductReviews wraps fetchReviews in
queueMicrotask without a clear need, adding indirection for no observable
benefit. Remove the queueMicrotask wrapper and call fetchReviews directly from
the effect, unless this is intentionally working around a specific issue; if so,
keep the wrapper but add a brief rationale comment in ProductReviews and apply
the same clarification to the matching checkout and shipping-address patterns.
- Around line 228-270: The remove-image buttons in ProductReviews are accessible
but not distinguishable because every button in the images loop uses the same
aria-label. Update the image preview controls in the images.map block so each
remove button includes a unique label that identifies the specific image it will
delete, using the loop data (for example the index or a filename/description if
available) while keeping the removeImage handler behavior unchanged.
- Around line 192-213: The rating controls in ProductReviews use icon buttons
but do not expose the selected state to assistive tech. Update the Button inside
the star map in ProductReviews so each rating button includes aria-pressed based
on whether that star is selected, using the existing star/rating values to keep
the pressed state synchronized with the current rating.

In `@docs/pre-launch-audit.md`:
- Around line 5-8: The executive summary in the pre-launch audit is downplaying
a critical risk because it says there are no immediate blockers while the
ecommerce section flags payment/checkout verification as critical. Update the
summary text to explicitly call out the payment path or checkout verification as
the highest-risk item, keeping the wording consistent with the later ecommerce
assessment in the same document.

In `@docs/pre-launch-implementation-plan.md`:
- Around line 22-27: Update the SEO-002 plan to point at the actual route-level
implementation used in this branch instead of assuming metadata exports in page
components. Verify the server/client boundary for the `/checkout`, `/cart`, and
`/login` routes, and rewrite the Files/Approach guidance to reference the
correct `head.tsx` or other server-side route files rather than `app/*/page.tsx`
with `metadata`. Keep the task aligned with the route files currently used for
the noindex change so the next implementer lands in the right place.

In `@lib/data.ts`:
- Around line 3-9: The shared ATTAR_SIZES and PERFUME_SIZES arrays are being
reused by reference across many products, so a mutation in one product could
affect others. Update the product construction in the data module so each
product receives its own sizes array copy instead of the shared constants, using
the existing ATTAR_SIZES and PERFUME_SIZES definitions as the source but cloning
them wherever they are assigned to product.sizes.

In `@lib/mail/index.ts`:
- Around line 39-44: The subject fallback logic in sendContactNotificationEmail
duplicates normalization already done by the caller, so consolidate to a single
source of truth. Update the sendContactNotificationEmail flow in
lib/mail/index.ts to trust the normalized subject passed in (or centralize the
fallback in a shared helper used by both app/api/contact/route.ts and this mail
helper) so the "General Inquiry" default is handled consistently across all
callers.

In `@package.json`:
- Line 33: Move the shadcn package from dependencies to devDependencies in
package.json, since it is only used as a CLI via npx shadcn and not imported by
runtime code. Keep the existing version specifier unchanged, and update the
manifest so production installs do not include this tooling dependency.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2d51cae4-c7fd-4f87-96e4-d55e5709cc9f

📥 Commits

Reviewing files that changed from the base of the PR and between 0beeb8f and ea5ef48.

⛔ Files ignored due to path filters (2)
  • app/favicon.ico is excluded by !**/*.ico
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (40)
  • app/api/auth/me/route.ts
  • app/api/contact/route.ts
  • app/cart/head.tsx
  • app/checkout/head.tsx
  • app/checkout/page.tsx
  • app/faq/page.tsx
  • app/globals.css
  • app/layout.tsx
  • app/login/head.tsx
  • app/shipping-policy/page.tsx
  • app/shop/ShopClient.tsx
  • app/size-guide/page.tsx
  • app/track-order/[id]/page.tsx
  • components.json
  • components/cart/CartSummary.tsx
  • components/home/FeaturedProducts.tsx
  • components/layout/ClientLayout.tsx
  • components/layout/Navbar.tsx
  • components/product/ProductGallery.tsx
  • components/product/ProductInfo.tsx
  • components/profile/ShippingAddresses.tsx
  • components/shop/ProductCard.tsx
  • components/shop/ProductGrid.tsx
  • components/shop/ProductReviews.tsx
  • components/ui/Button.tsx
  • components/ui/Toast.tsx
  • components/ui/checkbox.tsx
  • components/ui/input.tsx
  • components/ui/label.tsx
  • components/ui/select.tsx
  • components/ui/textarea.tsx
  • docs/pre-launch-audit.md
  • docs/pre-launch-implementation-plan.md
  • eslint.config.mjs
  • lib/data.ts
  • lib/mail/config.ts
  • lib/mail/index.ts
  • lib/utils.ts
  • package.json
  • sanity/schemas/product.ts
💤 Files with no reviewable changes (2)
  • app/shop/ShopClient.tsx
  • components/product/ProductGallery.tsx

Comment thread app/cart/head.tsx
Comment on lines +1 to +7
export default function Head() {
return (
<>
<meta name="robots" content="noindex, nofollow" />
</>
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## package.json / lockfile next version\n'
rg -n '"next"|next@|nextjs' package.json pnpm-lock.yaml yarn.lock package-lock.json 2>/dev/null || true

printf '\n## app router head files\n'
git ls-files 'app/**/head.tsx' 'app/**/head.ts' 'app/**/layout.tsx' 'app/**/page.tsx' | sed -n '1,120p'

printf '\n## metadata usage\n'
rg -n 'generateMetadata|export const metadata|robots:' app --glob '!**/*.map' || true

Repository: benazeem/MS-Signature

Length of output: 2717


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## app/cart/layout.tsx\n'
cat -n app/cart/layout.tsx

printf '\n## app/login/layout.tsx\n'
cat -n app/login/layout.tsx

printf '\n## app/layout.tsx metadata section\n'
sed -n '1,120p' app/layout.tsx | cat -n

printf '\n## app/cart/head.tsx\n'
cat -n app/cart/head.tsx

printf '\n## app/checkout/head.tsx\n'
cat -n app/checkout/head.tsx

printf '\n## app/login/head.tsx\n'
cat -n app/login/head.tsx

Repository: benazeem/MS-Signature

Length of output: 5721


🌐 Web query:

Next.js 16 App Router head.tsx supported special file metadata API app router docs

💡 Result:

In the Next.js App Router (including version 16), there is no head.tsx special file [1][2]. The head.js/head.tsx pattern was an early, experimental feature that has been deprecated and replaced by the Metadata API [2][3]. Instead of using a head.tsx file, you should manage document head elements using the built-in Metadata API [1][2]. Key points for managing metadata in the App Router: 1. Static Metadata: You can export a static metadata object from any layout.tsx or page.tsx file to define metadata such as title, description, and Open Graph tags [2][4]. This metadata cascades down the layout tree [2]. 2. Dynamic Metadata: For pages that require data fetching (e.g., blog posts), export an async generateMetadata function from your page.tsx or layout.tsx [2][4]. This function receives route parameters and can fetch data, allowing you to generate dynamic tags [2]. 3. Direct HTML tags: If you need to include static elements directly in the <head> (such as custom <script> or <link> tags that are not covered by the Metadata API), you can add them directly to your layout.tsx file [1]. Next.js will render these elements in the order they appear in your layout hierarchy [1]. 4. Migration: If you were previously using next/head (a Pages Router component), you should migrate fully to the Metadata API [2]. Using next/head in the App Router is not supported and will result in errors or conflicting tags [5][6][3].

Citations:


Move these robots tags into Metadata API exports. app/cart/head.tsx, app/checkout/head.tsx, and app/login/head.tsx won’t render in this App Router setup, so the noindex, nofollow directive is being dropped. Add robots: { index: false, follow: false } to the route segment metadata instead (app/cart/layout.tsx, app/login/layout.tsx, and app/checkout/page.tsx or layout.tsx).

🤖 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/cart/head.tsx` around lines 1 - 7, The robots meta in Head is not being
rendered in this App Router setup, so move the noindex/nofollow directive into
the Metadata API for the affected routes. Remove the Head-based meta from the
cart, checkout, and login segments, and add robots: { index: false, follow:
false } in the appropriate route segment exports instead, using the existing
layout/page entry points like cart/layout, login/layout, and checkout/page or
checkout/layout.

Comment thread app/size-guide/page.tsx
Comment on lines 28 to 32
export const metadata: Metadata = {
title: "Attar Size Guide",
description:
"Learn which attar size is right for you. Compare 3ml, 6ml, and 12ml bottle sizes and how long they last.",
"Learn which attar and perfume size is right for you. Compare the current Sanity catalog sizes and how long they last.",
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Metadata title/description not updated for the new Perfume section.

The page heading is now "Attar and Perfume Size Guide" with a dedicated perfume section, but metadata.title still reads "Attar Size Guide" and the description doesn't mention perfume either.

✏️ Suggested fix
 export const metadata: Metadata = {
-  title: "Attar Size Guide",
+  title: "Attar and Perfume Size Guide",
   description:
-    "Learn which attar and perfume size is right for you. Compare the current Sanity catalog sizes and how long they last.",
+    "Learn which attar and perfume size is right for you. Compare the current attar and perfume catalog sizes and how long they last.",
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const metadata: Metadata = {
title: "Attar Size Guide",
description:
"Learn which attar size is right for you. Compare 3ml, 6ml, and 12ml bottle sizes and how long they last.",
"Learn which attar and perfume size is right for you. Compare the current Sanity catalog sizes and how long they last.",
};
export const metadata: Metadata = {
title: "Attar and Perfume Size Guide",
description:
"Learn which attar and perfume size is right for you. Compare the current attar and perfume catalog sizes and how long they last.",
};
🤖 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/size-guide/page.tsx` around lines 28 - 32, Update the page metadata in
the size guide component so it matches the new “Attar and Perfume” content. In
the exported metadata object for the page, change the title from the attar-only
wording and revise the description to mention both attar and perfume, keeping it
aligned with the page heading and dedicated perfume section.

Comment thread app/size-guide/page.tsx
Comment on lines +78 to +121
if (category === "attar") {
switch (size.value) {
case "6ml":
return {
size: size.label,
title: "Discovery",
price: `From ${formatRupees(totalPrice)}`,
ideal: "First-time buyers, travel, sampling new scents",
applications: "~120-150 applications",
duration: "1-2 months (daily use)",
gift: false,
description:
"Compact and easy to carry. The 6ml size is ideal when you want to try a fragrance before moving up to a larger bottle.",
};
case "12ml":
return {
size: size.label,
title: "Essential",
price: `From ${formatRupees(totalPrice)}`,
ideal: "Regular users, everyday wear, gifting",
applications: "~250-300 applications",
duration: "3-5 months (daily use)",
gift: true,
description:
"The balanced everyday option. 12ml gives you more room to wear a favourite fragrance often without moving to a collector size.",
popular: true,
};
default:
break;
}
}

return {
size: size.label,
title: "Standard Spray",
price: `From ${formatRupees(totalPrice)}`,
ideal: "Everyday wear, gifting, travel",
applications: "~250-300 sprays",
duration: "2-4 months (daily use)",
gift: true,
description:
"Perfumes in the current catalog are stocked as spray bottles. Use this size when you want a clean, easy-to-wear daily fragrance.",
};
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## Files\n'
git ls-files app/size-guide/page.tsx sanity/schemas/product.ts

printf '\n## Relevant excerpts: app/size-guide/page.tsx\n'
nl -ba app/size-guide/page.tsx | sed -n '1,220p'

printf '\n## Relevant excerpts: sanity/schemas/product.ts\n'
nl -ba sanity/schemas/product.ts | sed -n '1,260p'

printf '\n## Search for attar size/value validation\n'
rg -n '"6ml"|"12ml"|size\.value|attar|fail-open|validator|validation' app/size-guide/page.tsx sanity/schemas/product.ts

Repository: benazeem/MS-Signature

Length of output: 306


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## app/size-guide/page.tsx (around buildCard)\n'
awk 'NR>=1 && NR<=220 {printf "%4d  %s\n", NR, $0}' app/size-guide/page.tsx

printf '\n## sanity/schemas/product.ts\n'
awk 'NR>=1 && NR<=260 {printf "%4d  %s\n", NR, $0}' sanity/schemas/product.ts

printf '\n## Search for size validation and attar references\n'
rg -n '"6ml"|"12ml"|size\.value|attar|fail-open|validation|validator' app/size-guide/page.tsx sanity/schemas/product.ts

Repository: benazeem/MS-Signature

Length of output: 17396


Handle unexpected attar sizes in the attar branch. Unknown attar sizes fall back to the generic “Standard Spray” copy, which is misleading for attar products. The Sanity rule can still allow bad data when category lookup fails, so this path can surface the wrong description; use an attar-specific fallback instead.

🤖 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/size-guide/page.tsx` around lines 78 - 121, Handle unexpected attar sizes
in the attar branch of the size guide helper so they do not fall through to the
generic spray copy. In the size mapping logic in app/size-guide/page.tsx, update
the attar-specific handling around the category === "attar" switch to return an
attar fallback object for unknown size.value cases instead of the shared
default; keep the fallback copy, title, applications, duration, and description
aligned with attar products, while preserving the existing 6ml and 12ml entries
in the same function.

Comment thread app/size-guide/page.tsx
Comment on lines +123 to +166
function buildGuideCards(
products: CatalogProduct[],
category: "attar" | "perfume",
fallbackCards: GuideCard[],
) {
const categoryProducts = products.filter(
(product) => product.category === category,
);
const basePrice =
categoryProducts[0]?.price ?? (category === "attar" ? 349 : 449);

const sizeMap = new Map<
string,
{ label: string; value: string; price: number }
>();

for (const product of categoryProducts) {
for (const size of product.sizes ?? []) {
if (!sizeMap.has(size.value)) {
sizeMap.set(size.value, size);
}
}
}

const sizes = Array.from(sizeMap.values()).sort((left, right) => {
const leftPriority = sizeLabelPriority.indexOf(left.value);
const rightPriority = sizeLabelPriority.indexOf(right.value);

if (leftPriority !== rightPriority) {
return (
(leftPriority === -1 ? Number.MAX_SAFE_INTEGER : leftPriority) -
(rightPriority === -1 ? Number.MAX_SAFE_INTEGER : rightPriority)
);
}

return parseSizeValue(left.value) - parseSizeValue(right.value);
});

if (sizes.length === 0) {
return fallbackCards;
}

return sizes.map((size) => buildCard(category, size, basePrice));
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

"From ₹X" pricing derived from the first product in the category, not the minimum.

basePrice uses categoryProducts[0]?.price, and sizeMap keeps the first-encountered size object per unique value across all products in the category. If products in the same category have different base prices, the guide's "From ₹X" figures reflect an arbitrary first product rather than an actual minimum/representative price, which could be misleading as the catalog grows beyond today's uniformly-priced set.

💡 Suggested fix to use the true minimum
-  const basePrice =
-    categoryProducts[0]?.price ?? (category === "attar" ? 349 : 449);
+  const basePrice =
+    categoryProducts.length > 0
+      ? Math.min(...categoryProducts.map((p) => p.price))
+      : (category === "attar" ? 349 : 449);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function buildGuideCards(
products: CatalogProduct[],
category: "attar" | "perfume",
fallbackCards: GuideCard[],
) {
const categoryProducts = products.filter(
(product) => product.category === category,
);
const basePrice =
categoryProducts[0]?.price ?? (category === "attar" ? 349 : 449);
const sizeMap = new Map<
string,
{ label: string; value: string; price: number }
>();
for (const product of categoryProducts) {
for (const size of product.sizes ?? []) {
if (!sizeMap.has(size.value)) {
sizeMap.set(size.value, size);
}
}
}
const sizes = Array.from(sizeMap.values()).sort((left, right) => {
const leftPriority = sizeLabelPriority.indexOf(left.value);
const rightPriority = sizeLabelPriority.indexOf(right.value);
if (leftPriority !== rightPriority) {
return (
(leftPriority === -1 ? Number.MAX_SAFE_INTEGER : leftPriority) -
(rightPriority === -1 ? Number.MAX_SAFE_INTEGER : rightPriority)
);
}
return parseSizeValue(left.value) - parseSizeValue(right.value);
});
if (sizes.length === 0) {
return fallbackCards;
}
return sizes.map((size) => buildCard(category, size, basePrice));
}
function buildGuideCards(
products: CatalogProduct[],
category: "attar" | "perfume",
fallbackCards: GuideCard[],
) {
const categoryProducts = products.filter(
(product) => product.category === category,
);
const basePrice =
categoryProducts.length > 0
? Math.min(...categoryProducts.map((p) => p.price))
: (category === "attar" ? 349 : 449);
const sizeMap = new Map<
string,
{ label: string; value: string; price: number }
>();
for (const product of categoryProducts) {
for (const size of product.sizes ?? []) {
if (!sizeMap.has(size.value)) {
sizeMap.set(size.value, size);
}
}
}
const sizes = Array.from(sizeMap.values()).sort((left, right) => {
const leftPriority = sizeLabelPriority.indexOf(left.value);
const rightPriority = sizeLabelPriority.indexOf(right.value);
if (leftPriority !== rightPriority) {
return (
(leftPriority === -1 ? Number.MAX_SAFE_INTEGER : leftPriority) -
(rightPriority === -1 ? Number.MAX_SAFE_INTEGER : rightPriority)
);
}
return parseSizeValue(left.value) - parseSizeValue(right.value);
});
if (sizes.length === 0) {
return fallbackCards;
}
return sizes.map((size) => buildCard(category, size, basePrice));
}
🤖 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/size-guide/page.tsx` around lines 123 - 166, The “From ₹X” value in
buildGuideCards is taken from the first product in a category instead of the
lowest available price, so update the pricing source to use the true minimum
across categoryProducts before passing it into buildCard. Also make sure the
size selection logic in buildGuideCards still deduplicates by size value, but
the displayed price is derived from the category’s minimum product price rather
than categoryProducts[0]?.price.

Comment thread components/product/ProductInfo.tsx
Comment on lines 92 to 102
useEffect(() => {
if (email) {
fetchAddresses();
queueMicrotask(() => {
fetchAddresses();
});
} else {
setLoading(false);
queueMicrotask(() => {
setLoading(false);
});
}
}, [email, fetchAddresses]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if similar queueMicrotask deferral pattern is documented anywhere
rg -n 'queueMicrotask' -C2 --type=ts --type=tsx
rg -n 'queueMicrotask' docs/

Repository: benazeem/MS-Signature

Length of output: 187


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== file list ==\n'
git ls-files 'components/profile/ShippingAddresses.tsx' 'components/**' | sed -n '1,20p'

printf '\n== outline ==\n'
ast-grep outline components/profile/ShippingAddresses.tsx --view expanded || true

printf '\n== queueMicrotask search ==\n'
rg -n 'queueMicrotask' .

printf '\n== ShippingAddresses.tsx excerpt ==\n'
cat -n components/profile/ShippingAddresses.tsx | sed -n '1,220p'

Repository: benazeem/MS-Signature

Length of output: 8730


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== fetchAddresses references ==\n'
rg -n 'fetchAddresses|setLoading\(|setAddresses\(' components/profile/ShippingAddresses.tsx

printf '\n== nearby effects in file ==\n'
python3 - <<'PY'
from pathlib import Path
p = Path('components/profile/ShippingAddresses.tsx')
text = p.read_text()
for needle in ['useEffect(() => {', 'queueMicrotask', 'fetchAddresses', 'setLoading(false)']:
    print(f'-- {needle} --')
    idx = text.find(needle)
    if idx != -1:
        start = max(0, text.rfind('\n', 0, idx-120))
        end = text.find('\n', idx+len(needle)+200)
        print(text[start:end if end!=-1 else len(text)])
        print()
PY

Repository: benazeem/MS-Signature

Length of output: 2152


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== queueMicrotask call sites ==\n'
for f in app/checkout/page.tsx components/shop/ProductReviews.tsx components/profile/ShippingAddresses.tsx; do
  printf '\n-- %s --\n' "$f"
  cat -n "$f" | sed -n '1,180p' | rg -n 'queueMicrotask|useEffect|fetch|setLoading|setState|cleanup|return \(\) =>'
done

printf '\n== ShippingAddresses cleanup-related patterns ==\n'
rg -n 'return \(\) =>|AbortController|isMounted|cancel|cleanup' components/profile/ShippingAddresses.tsx

Repository: benazeem/MS-Signature

Length of output: 2478


Remove the queueMicrotask wrapper here. useEffect already runs after commit, so this extra tick is redundant; if you need to avoid a post-unmount state update, add cleanup/abort handling instead.

🤖 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 `@components/profile/ShippingAddresses.tsx` around lines 92 - 102, The
ShippingAddresses useEffect currently wraps fetchAddresses and setLoading(false)
in queueMicrotask, which adds an unnecessary extra tick. Remove the
queueMicrotask wrapper inside ShippingAddresses and let the effect call
fetchAddresses or setLoading directly, and if there is a concern about updates
after unmount, handle that with cleanup or abort logic in the effect itself.

Comment thread components/ui/Button.tsx
Comment on lines 65 to 71
if (href) {
return (
<Link href={href} className={classes} id={id} target={target} rel={rel}>
<Link href={href} className={classes} target={target} rel={rel}>
{children}
</Link>
);
)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Button component ==\n'
git ls-files 'components/ui/Button.tsx' 'app/checkout/page.tsx' 'components/home/FeaturedProducts.tsx'
printf '\n-- Button.tsx outline --\n'
ast-grep outline components/ui/Button.tsx --view expanded || true
printf '\n-- Button.tsx relevant lines --\n'
sed -n '1,220p' components/ui/Button.tsx | cat -n

printf '\n== Button call sites ==\n'
rg -n "<Button[^>]*href=|id=" app/checkout/page.tsx components/home/FeaturedProducts.tsx || true
printf '\n-- checkout excerpt --\n'
sed -n '1,220p' app/checkout/page.tsx | cat -n | sed -n '1,220p'
printf '\n-- featured excerpt --\n'
sed -n '1,220p' components/home/FeaturedProducts.tsx | cat -n | sed -n '1,220p'

Repository: benazeem/MS-Signature

Length of output: 16375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Search for Link props/typing in repo ==\n'
rg -n "ComponentPropsWithoutRef<typeof ButtonPrimitive>|ButtonProps|href\\s*\\?|target=|rel=" components/ui app components -g '!**/*.map' || true

printf '\n== Search for other Button usage with href and extra props ==\n'
rg -n "<Button[^>]*href=.*(id=|onClick=|aria-|data-)" . -g '!**/*.map' || true

Repository: benazeem/MS-Signature

Length of output: 2669


Forward props in the href branch

<Link> only receives className, target, and rel; ...props is dropped. That strips id, handlers, and aria-* from link-styled buttons, including existing href call sites in this PR.

Suggested fix
-      <Link href={href} className={classes} target={target} rel={rel}>
+      <Link href={href} className={classes} target={target} rel={rel} {...props}>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (href) {
return (
<Link href={href} className={classes} id={id} target={target} rel={rel}>
<Link href={href} className={classes} target={target} rel={rel}>
{children}
</Link>
);
)
}
if (href) {
return (
<Link href={href} className={classes} target={target} rel={rel} {...props}>
{children}
</Link>
)
}
🤖 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 `@components/ui/Button.tsx` around lines 65 - 71, The Button component’s href
branch drops forwarded props, so link-styled buttons lose attributes like id,
event handlers, and aria-* from the Button API. Update the href path in Button
to pass through the remaining props to Link while still setting className,
target, and rel, matching the non-href branch behavior.

Comment thread lib/utils.ts
Comment thread sanity/schemas/product.ts
Comment on lines +106 to +132
if (!catRef) return true;
try {
const client = context.getClient({ apiVersion: "2024-01-01" });
const cat = await client.getDocument(catRef);
const attarAllowed = ["6ml", "12ml"];
const perfumeAllowed = ["30ml"];

if (cat?.slug?.current === "attar" || (cat?.name && String(cat.name).toLowerCase() === "attar")) {
const invalid = (sizes || []).filter((s: unknown) => {
const val = typeof s === "object" && s !== null && "value" in s ? (s as { value?: unknown }).value : undefined;
return typeof val !== "string" || !attarAllowed.includes(val);
});
if (invalid.length) return "Attar products can only have sizes 6ml or 12ml.";
}

if (cat?.slug?.current === "perfume" || (cat?.name && String(cat.name).toLowerCase() === "perfume")) {
const invalid = (sizes || []).filter((s: unknown) => {
const val = typeof s === "object" && s !== null && "value" in s ? (s as { value?: unknown }).value : undefined;
return typeof val !== "string" || !perfumeAllowed.includes(val);
});
if (invalid.length) return "Perfume products can only have size 30ml.";
}

return true;
} catch {
return true;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Validator fails open on any lookup error.

If catRef is missing, the category fetch throws, or the category document lacks a recognizable slug/name, the validator returns true and silently allows any size values. A transient network blip or a mis-set category reference bypasses the intended enforcement entirely, and there's no logged trace of the bypass for later auditing.

🛡️ Suggested tweak to fail safer / log bypass
           } catch {
-            return true;
+            console.error("sizes validation: failed to fetch category", catRef);
+            return true;
           }

Also worth checking that a missing catRef (line 106) is truly a valid "no restriction" case rather than a data issue that should itself be flagged.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!catRef) return true;
try {
const client = context.getClient({ apiVersion: "2024-01-01" });
const cat = await client.getDocument(catRef);
const attarAllowed = ["6ml", "12ml"];
const perfumeAllowed = ["30ml"];
if (cat?.slug?.current === "attar" || (cat?.name && String(cat.name).toLowerCase() === "attar")) {
const invalid = (sizes || []).filter((s: unknown) => {
const val = typeof s === "object" && s !== null && "value" in s ? (s as { value?: unknown }).value : undefined;
return typeof val !== "string" || !attarAllowed.includes(val);
});
if (invalid.length) return "Attar products can only have sizes 6ml or 12ml.";
}
if (cat?.slug?.current === "perfume" || (cat?.name && String(cat.name).toLowerCase() === "perfume")) {
const invalid = (sizes || []).filter((s: unknown) => {
const val = typeof s === "object" && s !== null && "value" in s ? (s as { value?: unknown }).value : undefined;
return typeof val !== "string" || !perfumeAllowed.includes(val);
});
if (invalid.length) return "Perfume products can only have size 30ml.";
}
return true;
} catch {
return true;
}
if (!catRef) return true;
try {
const client = context.getClient({ apiVersion: "2024-01-01" });
const cat = await client.getDocument(catRef);
const attarAllowed = ["6ml", "12ml"];
const perfumeAllowed = ["30ml"];
if (cat?.slug?.current === "attar" || (cat?.name && String(cat.name).toLowerCase() === "attar")) {
const invalid = (sizes || []).filter((s: unknown) => {
const val = typeof s === "object" && s !== null && "value" in s ? (s as { value?: unknown }).value : undefined;
return typeof val !== "string" || !attarAllowed.includes(val);
});
if (invalid.length) return "Attar products can only have sizes 6ml or 12ml.";
}
if (cat?.slug?.current === "perfume" || (cat?.name && String(cat.name).toLowerCase() === "perfume")) {
const invalid = (sizes || []).filter((s: unknown) => {
const val = typeof s === "object" && s !== null && "value" in s ? (s as { value?: unknown }).value : undefined;
return typeof val !== "string" || !perfumeAllowed.includes(val);
});
if (invalid.length) return "Perfume products can only have size 30ml.";
}
return true;
} catch {
console.error("sizes validation: failed to fetch category", catRef);
return true;
}
🤖 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 `@sanity/schemas/product.ts` around lines 106 - 132, The size validator in the
product schema currently fails open in the catRef/category lookup path, so
invalid sizes can slip through whenever the fetch fails or the category is
unrecognized. Update the validation logic around the anonymous validator in
product.ts to treat missing catRef or lookup errors as a hard validation failure
(or an explicit flagged state), and only return true when the category is known
and matches the allowed size rules for attar/perfume. Also add logging or a
clear error path in the catch block so bypasses are visible for auditing.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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/globals.css`:
- Around line 362-367: Remove the redundant background-color declaration in the
:root block of globals.css so the variable is assigned only once. Update the
root theme variables near the repeated background-color line, keeping the first
background-color: var(--color-primary) and deleting the duplicate later
declaration to avoid unnecessary duplication.
- Around line 360-425: The theme variables in :root are incomplete, so utilities
like bg-primary, bg-accent, and bg-popover have no values because app/layout.tsx
never applies the .dark class. Update the :root block in globals.css to define
the missing tokens (--primary, --primary-foreground, --accent, --popover, and
--popover-foreground) to match the dark theme values, or alternatively ensure
the root element gets the .dark class. Keep the existing .dark definitions in
sync with those token names.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6f301210-728a-4131-b251-bd17f51f4007

📥 Commits

Reviewing files that changed from the base of the PR and between ea5ef48 and f81413a.

📒 Files selected for processing (9)
  • app/globals.css
  • app/layout.tsx
  • components/home/BrandStory.tsx
  • components/home/Hero.tsx
  • components/home/WhyChooseUs.tsx
  • components/layout/ClientLayout.tsx
  • components/layout/Navbar.tsx
  • components/ui/Button.tsx
  • lib/utils.ts
✅ Files skipped from review due to trivial changes (4)
  • components/home/WhyChooseUs.tsx
  • components/home/BrandStory.tsx
  • components/home/Hero.tsx
  • components/layout/Navbar.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/ui/Button.tsx

Comment thread app/globals.css
Comment on lines +360 to +425
:root {
min-height: 100%;
background-color: var(--color-primary);
--background: #070707;
--foreground: #f0f0f0;
--card: #0d0d0d;
--card-foreground: #ededed;
background-color: var(--color-primary);
--secondary: #121212;
--secondary-foreground: #ededed;
--muted: #101010;
--muted-foreground: #999999;
--accent-foreground: #ededed;
--destructive: oklch(0.577 0.245 27.325);
--border: #222222;
--input: #222222;
--ring: #d4af37;
--chart-1: #d4af37;
--chart-2: #f5d98a;
--chart-3: #999999;
--chart-4: #2a2a2a;
--chart-5: #1a1a1a;
--radius: 0.625rem;
--sidebar: #0d0d0d;
--sidebar-foreground: #ededed;
--sidebar-primary: #d4af37;
--sidebar-primary-foreground: #0a0a0a;
--sidebar-accent: #121212;
--sidebar-accent-foreground: #ededed;
--sidebar-border: #222222;
--sidebar-ring: #d4af37;
}

.dark {
--background: #070707;
--foreground: #f0f0f0;
--card: #0d0d0d;
--card-foreground: #ededed;
--popover: #0d0d0d;
--popover-foreground: #ededed;
--primary: #d4af37;
--primary-foreground: #0a0a0a;
--secondary: #121212;
--secondary-foreground: #ededed;
--muted: #101010;
--muted-foreground: #999999;
--accent: #121212;
--accent-foreground: #ededed;
--destructive: oklch(0.704 0.191 22.216);
--border: #222222;
--input: #222222;
--ring: #d4af37;
--chart-1: #d4af37;
--chart-2: #f5d98a;
--chart-3: #999999;
--chart-4: #2a2a2a;
--chart-5: #1a1a1a;
--sidebar: #0d0d0d;
--sidebar-foreground: #ededed;
--sidebar-primary: #d4af37;
--sidebar-primary-foreground: #0a0a0a;
--sidebar-accent: #121212;
--sidebar-accent-foreground: #ededed;
--sidebar-border: #222222;
--sidebar-ring: #d4af37;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Is a `.dark` class applied to html/body anywhere, or a theme provider used?
echo "--- .dark class on root element / theme provider ---"
rg -nP 'className=.*\bdark\b|dark:class|next-themes|ThemeProvider|classList\.(add|toggle)\(.?dark' -g '!node_modules'
echo "--- tokens defined in :root vs .dark ---"
rg -nP '^\s*--(primary|primary-foreground|accent|popover|popover-foreground)\b' app/globals.css
echo "--- usages of the affected semantic utilities ---"
rg -nP 'bg-(primary|accent|popover)|text-(primary|accent|popover)-foreground' -g '!node_modules' -g '*.tsx'

Repository: benazeem/MS-Signature

Length of output: 212


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "--- files of interest ---"
git ls-files | rg '^(app/(layout|globals)\.css|.*theme.*|.*provider.*|.*layout.*\.tsx)$'

echo "--- root layout ---"
if [ -f app/layout.tsx ]; then
  cat -n app/layout.tsx
fi

echo "--- theme token definitions in app/globals.css ---"
rg -n '^(?:\s*--(primary|primary-foreground|accent|popover|popover-foreground)\b|:root|\.dark\b|`@theme` inline)' app/globals.css

echo "--- .dark / theme provider references ---"
rg -n 'next-themes|ThemeProvider|classList\.(add|toggle)\(\s*[`"'"'"']dark|className=.*\bdark\b|<html[^>]*className|<body[^>]*className' app

echo "--- semantic utility usages ---"
rg -n 'bg-(primary|accent|popover)(/[\d]+)?|text-(primary|accent|popover)-foreground' app --glob '*.tsx' --glob '*.ts' --glob '*.jsx' --glob '*.js'

Repository: benazeem/MS-Signature

Length of output: 10107


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "--- app/globals.css around theme mappings and token blocks ---"
sed -n '300,430p' app/globals.css | cat -n

echo "--- all custom-property declarations for theme colors in app/globals.css ---"
rg -n '^\s*--(background|foreground|card|card-foreground|popover|popover-foreground|primary|primary-foreground|secondary|secondary-foreground|muted|muted-foreground|accent|accent-foreground|destructive|border|input|ring|chart-[1-5]|sidebar|sidebar-foreground|sidebar-primary|sidebar-primary-foreground|sidebar-accent|sidebar-accent-foreground|sidebar-border|sidebar-ring)\b' app/globals.css

Repository: benazeem/MS-Signature

Length of output: 6959


Add the missing theme tokens to :root

app/layout.tsx does not apply a .dark class, so --primary, --primary-foreground, --accent, --popover, and --popover-foreground never resolve outside .dark. That leaves bg-primary / bg-accent / bg-popover utilities without values. Add those tokens to :root or switch the root element to .dark.

🧰 Tools
🪛 Stylelint (17.14.0)

[error] 362-362: Duplicate property "background-color" (declaration-block-no-duplicate-properties)

(declaration-block-no-duplicate-properties)


[error] 367-367: Expected empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)

🤖 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/globals.css` around lines 360 - 425, The theme variables in :root are
incomplete, so utilities like bg-primary, bg-accent, and bg-popover have no
values because app/layout.tsx never applies the .dark class. Update the :root
block in globals.css to define the missing tokens (--primary,
--primary-foreground, --accent, --popover, and --popover-foreground) to match
the dark theme values, or alternatively ensure the root element gets the .dark
class. Keep the existing .dark definitions in sync with those token names.

Comment thread app/globals.css
Comment on lines +362 to +367
background-color: var(--color-primary);
--background: #070707;
--foreground: #f0f0f0;
--card: #0d0d0d;
--card-foreground: #ededed;
background-color: var(--color-primary);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the duplicate background-color declaration. :root sets background-color: var(--color-primary) twice (lines 362 and 367); the second is redundant.

🧹 Proposed cleanup
 :root {
   min-height: 100%;
   background-color: var(--color-primary);
   --background: `#070707`;
   --foreground: `#f0f0f0`;
   --card: `#0d0d0d`;
   --card-foreground: `#ededed`;
-  background-color: var(--color-primary);
   --secondary: `#121212`;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
background-color: var(--color-primary);
--background: #070707;
--foreground: #f0f0f0;
--card: #0d0d0d;
--card-foreground: #ededed;
background-color: var(--color-primary);
background-color: var(--color-primary);
--background: `#070707`;
--foreground: `#f0f0f0`;
--card: `#0d0d0d`;
--card-foreground: `#ededed`;
🧰 Tools
🪛 Stylelint (17.14.0)

[error] 362-362: Duplicate property "background-color" (declaration-block-no-duplicate-properties)

(declaration-block-no-duplicate-properties)


[error] 367-367: Expected empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)

🤖 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/globals.css` around lines 362 - 367, Remove the redundant
background-color declaration in the :root block of globals.css so the variable
is assigned only once. Update the root theme variables near the repeated
background-color line, keeping the first background-color: var(--color-primary)
and deleting the duplicate later declaration to avoid unnecessary duplication.

Source: Linters/SAST tools

@benazeem
benazeem merged commit 5650352 into main Jul 7, 2026
3 checks passed
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