Skip to content

feat: Custom Pizza Feature and Code Optimizations - #2

Open
itxSaaad wants to merge 105 commits into
mainfrom
dev
Open

feat: Custom Pizza Feature and Code Optimizations#2
itxSaaad wants to merge 105 commits into
mainfrom
dev

Conversation

@itxSaaad

@itxSaaad itxSaaad commented Feb 22, 2026

Copy link
Copy Markdown
Owner

Pull Request Summary: Custom Pizza + Stripe Checkout Migration & Code Hardening

1) Core Changes

Payments: Razorpay → Stripe Checkout (session + webhook)

  • Backend
    • Replaced Razorpay order creation with Stripe Checkout session creation (createStripeCheckoutSession) and added Stripe webhook handling (handleStripeWebhook) to update order payment state based on Stripe events.
    • Added admin endpoint updateOrderPaymentStatus to manage COD payment status and trigger “payment received” notification behavior.
    • Updated order/payment persistence to include Stripe session/intent identifiers and unified payment state.
    • Removed/disabled Razorpay-specific controller flow (e.g., removed the Razorpay checkout controller export) and re-wired order checkout route to the new Stripe session endpoint.
  • Frontend
    • Removed Razorpay client checkout/payment component and related cart/order payment state.
    • Checkout now submits only the selected payment method and uses Stripe redirect URL (stripeCheckoutUrl) stored in Redux.
    • Added CheckoutSuccessScreen (countdown + redirect) and CheckoutCancelScreen (retry/back navigation).

Custom Pizza: size-aware pricing + size-aware cart identity

  • Refactored custom pizza UX into a more modular, category-driven selection flow with validation and an order summary.
  • Implemented size multipliers and made the cart/order model size-aware:
    • Cart items now include size.
    • addToCart computes calculatedPrice = basePrice * getPizzaSizeMultiplier(size) and stores basePrice, size, and derived price.
    • Cart updates (quantity changes/removal) now key by {id}-{size} semantics via new updateCartItemQuantity.

Order correctness: inventory safeguards + deduction rollback

  • Order creation now:
    • Checks inventory availability before committing (checkInventoryAvailability).
    • Deducts ingredient inventories using executeInventoryDeductions.
    • Performs rollback (rollbackInventoryDeductions) when deductions fail to prevent partial inventory states.

Admin inventory alerts (low stock)

  • Added admin-only endpoints to run low-stock checks and send alerts:
    • POST /api/inventory/check-alerts
    • GET /api/inventory/low-stock
  • Alert sending is handled server-side by computing deficits across Base/Sauce/Cheese/Veggie and emailing approved admins.

Pricing authority hardening (server-side recomputation)

  • Introduced server-side trusted pricing logic (pricingUtils.calculateOrderPricing) to recompute totals using stored pizza base prices + size multipliers, including sales tax and delivery charge rules.

2) Architecture Impact

Constants-driven synchronization (front/back)

  • Added/extended mirrored constant registries on both sides:
    • Order statuses, payment methods/statuses, pizza sizes, inventory types, user roles, and error codes.
  • Frontend UI and routing/table logic was refactored to use these enums instead of hard-coded strings.

Standardized middleware/utilities

  • Validation pipeline
    • New backend validationHandler to translate express-validator results into consistent 400 responses with field-level details.
    • Added request validators for pizzas, orders, inventory, users, and admin operations.
  • Error standardization
    • New backend ApiError + improved errorMiddlewares that maps common failures (mongoose validation/cast/duplicate/JWT) into structured error payloads with requestId, code, details, etc.
    • New frontend errorUtils to normalize varied error payload shapes into message + field error structures consumed by the UI.
  • Operational hardening
    • MongoDB connection caching + /health and /ready endpoints using getConnectionStatus.
    • Security middleware: helmet (including CSP) and express-mongo-sanitize.
    • Centralized rate limiting via multiple express-rate-limit instances (API/auth/registration/payment/password-reset).
    • Environment validation at boot (validateEnv).
  • Frontend route architecture
    • Added/introduced route guards: ProtectedRoute, UserRoute, AdminRoute.

Analytics layer expansion

  • Added admin analytics routing/controllers with Mongo aggregation utilities:
    • order statistics, popular pizzas, inventory usage trends, user analytics, daily revenue, low stock alerts, new users, dashboard summary.

3) Key Features / Fixes (Main Additions)

  • Size-aware ordering UX:
    • Pizza menu and custom pizza flows now allow selecting size and display computed price.
    • Cart and checkout operate with size propagated through updates/removals.
  • Checkout UX improvements:
    • Replaced Razorpay flow with Stripe redirect flow and dedicated success/cancel screens.
    • Checkout steps simplified to method submission while redirect is handled via Redux state.
  • Admin order management improvements:
    • Centralized status constants for filtering/status display.
    • Added paymentStatus column and an update flow that supports payment status changes via a dedicated thunk for COD.
  • UI robustness
    • New/updated UI primitives (Message, Badge, Button, Card, Input, etc.) to support variant-based messaging, field-level errors, and better UX feedback.

4) Security & Performance

Security improvements / notable concerns

  • CSP + CORS allowlist: production origin enforcement with credentials.
  • NoSQL injection protection: express-mongo-sanitize.
  • Rate limiting across sensitive endpoints.
  • Webhook security: Stripe webhook verification is implemented (via raw body + signature verification in the server).
  • JWT protection hardening: rewritten protect and improved admin authorization using centralized role utilities.

Review concern: ensure Stripe webhook handlers are idempotent (duplicate webhook delivery should not double-update payment state or send duplicate emails).

Performance improvements

  • Added/updated MongoDB indexes across schemas (notably users/orders/inventory subtypes and order query patterns).
  • MongoDB connection caching reduces connection churn.
  • Analytics endpoints use aggregation pipelines and include pagination/limit behaviors where applicable.

5) Breaking Changes

Data/API contract changes

  • Order model changes
    • orderItems[].pizza.size is now required with a fixed enum of sizes.
    • Payment method/status enums updated to reflect Stripe + COD.
    • Order payment now stores Stripe session/intent identifiers in addition to payment status.
  • Pizza model changes
    • Pizza schema removes size; size is handled at the line-item/cart/order level.

Checkout/payment flow changes

  • Razorpay endpoints/components removed; checkout is now Stripe Checkout session based.
  • Cart/order state shape changed to remove Razorpay-specific fields and add Stripe-specific fields (stripeCheckoutUrl, etc.).

Compatibility risk

  • Existing persisted data/orders that lack orderItems[].pizza.size or payment fields may fail schema validation or UI rendering unless migrated/backfilled.

6) Testing Coverage

  • No explicit automated test code additions are reflected in the provided summary.
  • Docs/TESTING.md adds detailed manual/API/browser/payment testing guidance and includes test credential references, but reviewer should verify:
    • Stripe webhook correctness and idempotency
    • inventory deduction/rollback correctness under concurrent order placement
    • end-to-end flow coverage: custom pizza → cart → Stripe redirect → webhook → order details rendering

7) Review Focus Areas

  1. Stripe webhook correctness & idempotency
    • Verify signature verification, metadata → order mapping, and safe handling of duplicate events.
  2. Price authority / tamper resistance
    • Confirm server recomputes totals using pricingUtils and that checkout/order creation cannot be manipulated via client-side prices.
  3. Inventory consistency under concurrency
    • Ensure availability check + deduction + rollback logic prevents overselling/partial deductions when multiple checkouts happen simultaneously.
  4. Enum/schema migration safety
    • Validate handling of orders and payment fields that may predate enum enforcement.
  5. Admin authorization & route guarding
    • Confirm role checks and Redux-backed route guards cannot be bypassed.
  6. CSP/CORS production compatibility
    • Ensure CSP doesn’t block Stripe redirect behavior, and CORS allowlist matches deployment origins.
  7. Error normalization consistency
    • Validate that new frontend errorUtils mappings align with backend ApiError payloads for both validation and operational errors.

Muhammad Saad added 19 commits February 22, 2026 10:50
Added .env.example files for both server and client to simplify initial project configuration and deployment setup.
Implemented a comprehensive constants system for both frontend and backend to ensure consistency across the application. Includes order status, payment methods, user roles, inventory types, pizza sizes, currency, and error codes.
Implemented comprehensive utility functions including ApiError/ApiResponse classes for standardized responses, error code mapping, pagination helpers, inventory deduction logic, inventory alert system, analytics calculations, and environment variable validation.
Implemented express-validator based validation for all endpoints and rate limiting middleware for authentication, registration, payment, and password reset endpoints to enhance security.
Implemented error handling utilities for standardized error extraction and route protection components (ProtectedRoute, AdminRoute) for secure navigation.
Created detailed documentation covering setup, API reference, architecture, error handling, testing, deployment, constants reference, and contribution guidelines.
Implemented OrderDetailScreen for viewing order details, ResetPasswordScreen and VerifyEmailScreen for account management, and CheckoutSuccessScreen/CheckoutCancelScreen for payment flow feedback.
Implemented analytics controller and routes to provide key metrics including total users, orders, revenue, and low inventory items for the admin dashboard.
Implemented inventory alert controller with endpoints to check low stock items and send automated email alerts when inventory falls below threshold levels.
Replaced Razorpay payment integration with Stripe for better payment processing. Added Cash on Delivery (COD) option, implemented Stripe checkout session creation, webhook handling for payment confirmation, and updated all related frontend components and backend controllers.
Integrated centralized constants in schemas, added database indexes for frequently queried fields, removed size field from pizza schema (moved to order items), and updated order schema to support multiple payment methods with proper status tracking.
Simplified controller logic by removing nested conditionals, integrated ApiError/ApiResponse utilities, added pagination support, used centralized constants, and updated error middleware to handle new error format.
Integrated express-validator based validation middleware and rate limiting for authentication, registration, payment, and password reset endpoints across all routes.
Updated inventory prices to realistic values, added new ingredients (Garlic, Oregano, Eggs, Bacon, Gorgonzola), created diverse pizza options with high-quality images, improved seeder to properly link pizzas with inventory IDs, and enhanced console output with test credentials display.
Modified database configuration to export connectDb as named export for consistency with modern ES6 patterns.
Integrated error utility functions across all Redux thunks to extract and handle errors consistently, support new API response format with nested data property, and added new thunk for updating order payment status.
Integrated centralized constants across all components, enhanced Message component to display field-level validation errors with error codes, added payment status column to orders list, and improved overall component consistency.
Redesigned custom pizza creation screen with better ingredient selection UI, integrated constants for user roles and pizza sizes, improved checkout screen navigation, and updated main.jsx with new route configurations.
…stack section, and improve error handling documentation
@vercel

vercel Bot commented Feb 22, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
pizza-palette-app-mern Ready Ready Preview Aug 3, 2026 10:03am
pizza-palette-app-mern-backend Ready Ready Preview Aug 3, 2026 10:03am

@coderabbitai

coderabbitai Bot commented Feb 22, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This pull request expands Pizza Palette with reusable client UI, centralized constants and error handling, Stripe checkout, inventory and analytics services, authentication flows, route protection, operational middleware, and extensive setup and project documentation.

Changes

Pizza Palette platform

Layer / File(s) Summary
Client UI and presentation foundation
client/index.html, client/tailwind.config.js, client/src/components/ui/*, client/src/constants/*, client/src/utils/errorUtils.js, client/src/index.css
Adds reusable UI components, theme tokens, status constants, normalized error utilities, and enhanced message, loading, input, button, card, and badge behavior.
Server contracts, security, and data flows
server/controllers/*, server/middlewares/*, server/routes/*, server/schemas/*, server/utils/*, server/validators/*
Adds structured API errors, validation, pagination, centralized constants, authentication handling, schema indexes, inventory utilities, analytics endpoints, startup checks, health endpoints, and security middleware.
Commerce and authentication flows
client/src/redux/*, client/src/screens/User/*, server/controllers/orderControllers.js, server/routes/orderRoutes.js
Replaces Razorpay checkout wiring with Stripe sessions and webhooks, adds server-side pricing and inventory deduction, supports COD payment updates, and updates authentication, verification, password reset, and order access flows.
Setup and project documentation
.env.example, README.md, docs/*, client/package.json, server/package.json, package.json, .gitignore
Adds environment templates, Node.js runtime constraints, Stripe setup guidance, and documentation for setup, APIs, architecture, testing, deployment, constants, errors, and contribution.
Client data access and verification
client/src/redux/asyncThunks/*, client/src/screens/User/VerifyEmailScreen.jsx
Normalizes thunk responses and error payloads and adds verification loading, success, invalid-token, and failure states.

Estimated code review effort: 5 (Critical) | ~120 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main theme: custom pizza work plus broad code and documentation optimizations.
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 dev

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.

@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: 12

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

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

⚠️ Outside diff range comments (21)
server/utils/inventoryUtils.js (2)

10-11: ⚠️ Potential issue | 🟡 Minor

qty is never validated — zero or negative values silently corrupt stock.

item.quantity >= qty is always true when qty <= 0, so passing 0 is a no-op and passing a negative value actually increases stock.

🛡️ Proposed guard
 const updateInventoryQuantity = async (pizza, qty) => {
+  if (!qty || qty <= 0) {
+    throw new Error('Quantity must be a positive integer');
+  }
   const { bases, sauces, cheeses, veggies } = pizza;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/utils/inventoryUtils.js` around lines 10 - 11, Validate the incoming
qty before mutating item.quantity: ensure qty is a positive integer (e.g.,
Number.isInteger(qty) && qty > 0) and reject or throw (or return a failure) for
zero/negative/non-integer values so they cannot pass the subsequent check; only
then perform the existing stock check item.quantity >= qty and decrement. Also
update any caller expectations if they relied on zero/no-op behavior.

8-45: ⚠️ Potential issue | 🟠 Major

No transaction/rollback — inventory corruption on partial failure.

The function deducts inventory across four collections (bases, sauces, cheeses, veggies) in serial without a MongoDB session/transaction. If, say, a Sauce item is out of stock after the Base was already decremented, the base quantity is permanently reduced even though the order ultimately fails. With enough concurrent orders this will silently corrupt stock levels.

Fix: wrap the entire operation in a mongoose.startSession() transaction so every item.save() is part of the same atomic unit and the whole thing rolls back on any failure.

🔒 Proposed fix — wrap in a Mongoose transaction
+const mongoose = require('mongoose');
 const { Base, Sauce, Cheese, Veggie } = require('../schemas/inventorySchema');

 const updateInventoryQuantity = async (pizza, qty) => {
   const { bases, sauces, cheeses, veggies } = pizza;

-  const updateQuantity = async (item) => {
+  const updateQuantity = async (item, session) => {
     if (item) {
       if (item.quantity >= qty) {
         item.quantity -= qty;
-        const updateditem = await item.save();
+        const updateditem = await item.save({ session });
         return updateditem;
       } else {
         throw new Error(
           `Not enough ${item.item} in inventory! Please update inventory!`
         );
       }
     } else {
       throw new Error('Item Not Found!');
     }
   };

+  const session = await mongoose.startSession();
+  session.startTransaction();
+  try {
     for (const baseId of bases) {
-      const baseItem = await Base.findById(baseId);
-      await updateQuantity(baseItem);
+      const baseItem = await Base.findById(baseId).session(session);
+      await updateQuantity(baseItem, session);
     }
     for (const sauceId of sauces) {
-      const sauceItem = await Sauce.findById(sauceId);
-      await updateQuantity(sauceItem);
+      const sauceItem = await Sauce.findById(sauceId).session(session);
+      await updateQuantity(sauceItem, session);
     }
     for (const cheeseId of cheeses) {
-      const cheeseItem = await Cheese.findById(cheeseId);
-      await updateQuantity(cheeseItem);
+      const cheeseItem = await Cheese.findById(cheeseId).session(session);
+      await updateQuantity(cheeseItem, session);
     }
     for (const veggieId of veggies) {
-      const veggieItem = await Veggie.findById(veggieId);
-      await updateQuantity(veggieItem);
+      const veggieItem = await Veggie.findById(veggieId).session(session);
+      await updateQuantity(veggieItem, session);
     }
+    await session.commitTransaction();
+  } catch (err) {
+    await session.abortTransaction();
+    throw err;
+  } finally {
+    session.endSession();
+  }
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/utils/inventoryUtils.js` around lines 8 - 45, The inventory updates
currently call updateQuantity and Model.findById on Base, Sauce, Cheese, Veggie
without a transaction, so partial failures permanently mutate stock; wrap the
entire sequence in a mongoose.startSession() and session.startTransaction(), use
session-aware reads and writes (e.g., Base.findById(id).session(session) or pass
{ session } to queries and call item.save({ session }) inside updateQuantity),
commit the transaction on success and abortTransaction() on any thrown error,
and always end the session in a finally block so all item saves (in
updateQuantity) are atomic and roll back on failure.
client/src/redux/asyncThunks/inventoryThunks.js (2)

115-136: ⚠️ Potential issue | 🔴 Critical

updateStockById passes the Axios config object as the request body — auth header is dropped and update data is never sent.

Line 129:

const { data } = await axios.put(`${import.meta.env.VITE_SERVER_URL}/stocks/${id}`, config);

axios.put(url, data, config) takes data as the second argument and config as the third. Passing config as the second argument means:

  1. The Authorization header is silently placed in the request body instead of the request headers — the server will reject this as unauthenticated.
  2. No actual stock update payload is ever sent.
  3. The thunk argument is only id (Line 117) — there is no provision for accepting update fields at all.
🐛 Proposed fix
-export const updateStockById = createAsyncThunk(
-  'inventory/updateStockById',
-  async (id, { rejectWithValue, getState }) => {
+export const updateStockById = createAsyncThunk(
+  'inventory/updateStockById',
+  async ({ id, ...updateData }, { rejectWithValue, getState }) => {
     try {
       const {
         admin: { adminUserInfo },
       } = getState();

       const config = {
         headers: {
           Authorization: `Bearer ${adminUserInfo.token}`,
         },
       };

-      const { data } = await axios.put(`${import.meta.env.VITE_SERVER_URL}/stocks/${id}`, config);
+      const { data } = await axios.put(
+        `${import.meta.env.VITE_SERVER_URL}/stocks/${id}`,
+        updateData,
+        config
+      );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/src/redux/asyncThunks/inventoryThunks.js` around lines 115 - 136, The
thunk updateStockById is incorrectly treating the Axios config as the request
body and doesn't accept update payloads; change the async thunk signature to
accept an object like ({ id, updates }) or (payload) so you have both id and
update data, then call axios.put with axios.put(url, updates, config) (ensure
config contains Authorization from adminUserInfo.token). Also update the
returned value to return data.data || data and keep
rejectWithValue(extractErrorMessage(error)) unchanged.

1-3: ⚠️ Potential issue | 🔴 Critical

extractErrorMessage is used but never imported — all error paths will throw ReferenceError.

Every catch block in this file calls extractErrorMessage(error) (Lines 35, 72, 109, 133, 160), but the function is not imported. The only imports are createAsyncThunk and axios. At runtime, any failed request will crash with ReferenceError: extractErrorMessage is not defined rather than dispatching the rejection.

🐛 Proposed fix — add the missing import
 import { createAsyncThunk } from '@reduxjs/toolkit';
 import axios from 'axios';
+import { extractErrorMessage } from '../../utils/errorUtils';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/src/redux/asyncThunks/inventoryThunks.js` around lines 1 - 3, The file
uses extractErrorMessage in every catch block (within async thunks created by
createAsyncThunk) but it is not imported, causing a ReferenceError on failures;
fix by adding an import for extractErrorMessage at the top of inventoryThunks.js
(alongside createAsyncThunk and axios) importing it from the module that exports
it (the same utils/error helper module used elsewhere in the codebase) so all
calls to extractErrorMessage(error) in the catch blocks resolve correctly.
server/schemas/inventorySchema.js (1)

3-61: 🛠️ Refactor suggestion | 🟠 Major

All four schemas are structurally identical — extract a factory function.

Every schema has the same fields, options, and index calls repeated four times. Any future field addition (e.g., unit, sku) requires four parallel changes.

♻️ Proposed refactor
 const mongoose = require('mongoose');

+function createInventorySchema() {
+  const schema = new mongoose.Schema(
+    {
+      item: { type: String, required: true },
+      quantity: { type: Number, required: true },
+      price: { type: Number, required: true },
+      threshold: { type: Number, default: 10 },
+    },
+    { timestamps: true }
+  );
+  schema.index({ item: 1 });
+  schema.index({ quantity: 1 });
+  return schema;
+}
+
-const baseSchema = new mongoose.Schema( ... );
-baseSchema.index({ item: 1 });
-baseSchema.index({ quantity: 1 });
-
-const sauceSchema = new mongoose.Schema( ... );
-sauceSchema.index({ item: 1 });
-sauceSchema.index({ quantity: 1 });
-
-const cheeseSchema = new mongoose.Schema( ... );
-cheeseSchema.index({ item: 1 });
-cheeseSchema.index({ quantity: 1 });
-
-const veggieSchema = new mongoose.Schema( ... );
-veggieSchema.index({ item: 1 });
-veggieSchema.index({ quantity: 1 });

 module.exports = {
-  Base: mongoose.model('Base', baseSchema),
-  Sauce: mongoose.model('Sauce', sauceSchema),
-  Cheese: mongoose.model('Cheese', cheeseSchema),
-  Veggie: mongoose.model('Veggie', veggieSchema),
+  Base: mongoose.model('Base', createInventorySchema()),
+  Sauce: mongoose.model('Sauce', createInventorySchema()),
+  Cheese: mongoose.model('Cheese', createInventorySchema()),
+  Veggie: mongoose.model('Veggie', createInventorySchema()),
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/schemas/inventorySchema.js` around lines 3 - 61, The four schemas
(baseSchema, sauceSchema, cheeseSchema, veggieSchema) are identical; create a
factory function (e.g., createInventorySchema or buildInventorySchema) that
returns a new mongoose.Schema with the shared fields, options (timestamps), and
index calls, and then replace the duplicated declarations with four calls to
this factory to produce baseSchema, sauceSchema, cheeseSchema, and veggieSchema
so future field changes only need to be made in one place.
server/controllers/inventoryControllers.js (1)

86-122: ⚠️ Potential issue | 🟡 Minor

updateStockById only updates quantity, ignoring other fields from the request body.

The createStock handler accepts item, price, quantity, and threshold, but updateStockById hardcodes only quantity = req.body.quantity. If an admin needs to correct a price or threshold, there's no path to do so without a delete-and-recreate. This smells like an incomplete implementation.

Also, the nested if (updatedBase) / if (updatedSauce) checks are unreachable failure paths — save() either succeeds or throws in Mongoose, so the implicit else (no response sent) is dead code that would leave the request hanging if somehow reached.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/controllers/inventoryControllers.js` around lines 86 - 122,
updateStockById currently only sets quantity and has redundant post-save
truthiness checks that are unnecessary; update it to apply all updatable fields
from req.body (at minimum item, price, quantity, threshold) to the found
document (Base, Sauce, Cheese, or Veggie) before saving, e.g. merge/assign only
allowed keys from req.body into the model instance, call await instance.save(),
then send a single res.status(200).json(...) response with an appropriate
message; remove the unreachable if (updatedX) branches and ensure the 404 path
remains when none of Base/Sauce/Cheese/Veggie is found.
client/src/components/ui/Admin/Dashboard/Modals/StockCreateModal.jsx (1)

51-54: ⚠️ Potential issue | 🟠 Major

Bug: Modal closes and inventory refreshes even when createStock fails.

With Redux Toolkit's createAsyncThunk, dispatch(createStock(stockData)) returns a promise that always resolves — even when the thunk calls rejectWithValue. The .then() callback therefore fires unconditionally, closing the modal and refreshing inventory regardless of whether the creation succeeded.

You need .unwrap() to re-throw on rejection:

🐛 Fix: use unwrap() for proper error propagation
-    dispatch(createStock(stockData)).then(() => {
-      dispatch(listInventory({}));
-      handleModalClose();
-    });
+    dispatch(createStock(stockData))
+      .unwrap()
+      .then(() => {
+        dispatch(listInventory({}));
+        handleModalClose();
+      })
+      .catch(() => {
+        // Error is already in Redux state; modal stays open for user to retry
+      });

This is a common RTK gotcha — dispatch(thunk()) fulfills with either a fulfilled or rejected action object, so .then() always runs. .unwrap() converts rejected actions into thrown errors.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/src/components/ui/Admin/Dashboard/Modals/StockCreateModal.jsx` around
lines 51 - 54, The current dispatch(createStock(stockData)).then(...) always
runs even on thunk rejection; change to await
dispatch(createStock(stockData)).unwrap() (or
dispatch(createStock(stockData)).unwrap().then(...).catch(...)) so rejected
createStock re-throws and you only call dispatch(listInventory({})) and
handleModalClose() on success; wrap in try/catch (or add .catch) to handle
errors and avoid closing the modal or refreshing inventory when createStock
fails, referencing the createStock thunk, dispatch call, listInventory dispatch,
and handleModalClose.
client/src/redux/asyncThunks/pizzaThunks.js (2)

36-45: ⚠️ Potential issue | 🟡 Minor

NPE risk if both adminUserInfo and userInfo are null/undefined.

Line 43: adminUserInfo ? adminUserInfo.token : userInfo.token — if a user is somehow logged out (both state slices cleared) and this thunk fires, userInfo.token throws a TypeError. Compare with updatePizzaById (line 109) and deletePizzaById (line 147) which only reference adminUserInfo.token without any fallback — same NPE risk if the admin session is cleared.

A defensive pattern:

const token = adminUserInfo?.token || userInfo?.token;
if (!token) {
  return rejectWithValue({ code: 'AUTH_ERROR', message: 'Not authenticated' });
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/src/redux/asyncThunks/pizzaThunks.js` around lines 36 - 45, The thunk
builds Authorization header using adminUserInfo ? adminUserInfo.token :
userInfo.token which can throw when both adminUserInfo and userInfo are null;
update the token acquisition to use optional chaining (e.g. adminUserInfo?.token
|| userInfo?.token) and if token is falsy call rejectWithValue({ code:
'AUTH_ERROR', message: 'Not authenticated' }) before creating the config object,
and apply the same defensive pattern to the other thunks referenced
(updatePizzaById and deletePizzaById) that currently access adminUserInfo.token
directly so they also early-reject when no token is present.

47-61: ⚠️ Potential issue | 🟠 Major

Fix field name inconsistency: updatePizzaById must send bases (plural), not base (singular).

The backend schema, controller, and validators all expect bases (plural). Line 99 destructures base (singular) and line 118 sends base, causing the update request to silently fail—req.body.bases will be undefined, and the controller will preserve the old value instead of updating it.

Change line 99 from base to bases in the destructuring, and line 118 will then correctly send the plural field name matching the createPizza behavior and backend expectations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/src/redux/asyncThunks/pizzaThunks.js` around lines 47 - 61, In
updatePizzaById, fix the inconsistent field name by changing the destructured
variable from base to bases (so use "bases" where you extract values from
pizzaData) and ensure the payload sent in the axios request uses bases (plural)
instead of base; update the destructuring and the object you pass in the
axios.post/put call (referencing updatePizzaById and the payload object) so the
request matches createPizza and the backend schema expecting req.body.bases.
client/src/redux/asyncThunks/userThunks.js (2)

142-175: ⚠️ Potential issue | 🟠 Major

Remove misleading multipart/form-data header—only JSON fields are sent.

Line 152 declares 'Content-Type': 'multipart/form-data', but the server's updateUserProfile handler (server/controllers/userControllers.js, lines 287–321) accepts only text fields (name, email, phoneNumber, address, password) from req.body—no file uploads or multipart parsing. Axios serializes the plain JavaScript object as JSON regardless of the header, so the request works in practice, but the incorrect header is misleading and violates HTTP semantics. Change to 'application/json' to match the actual request format and server expectations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/src/redux/asyncThunks/userThunks.js` around lines 142 - 175, The
request header in the updateUserProfile async thunk incorrectly sets
'Content-Type' to 'multipart/form-data' even though the payload is a plain JSON
object; update the headers in the config object inside updateUserProfile (the
createAsyncThunk for 'user/userUpdateProfile') to use 'application/json' (or
remove the explicit Content-Type so axios sets it) so the header matches the
actual JSON payload and server expectations.

65-91: ⚠️ Potential issue | 🟠 Major

VerifyEmailScreen.jsx sends incomplete request to verifyEmail thunk—missing required email parameter.

Line 28 dispatches verifyEmail({ verificationCode: token }) without the email field. The thunk expects both parameters (line 67), and the server enforces email as required via verifyUserValidation (server/validators/userValidators.js:51–56). This request will fail server-side validation with "Email is required."

The correct pattern is shown in VerficationModal.jsx (line 38), which dispatches verifyEmail({ email, verificationCode }). Update VerifyEmailScreen to retrieve email from userInfo via getState() (as the thunk already does) or pass it explicitly.

Additionally, there's a state key mismatch: the reducer updates state.userVerifyEmailSuccess and state.userVerifyEmailError (userSlice.js:180–186), but VerifyEmailScreen destructures userVerifySuccess and userVerifyError (line 23), causing success/error states to remain undefined in the UI.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/src/redux/asyncThunks/userThunks.js` around lines 65 - 91,
VerifyEmailScreen.jsx is dispatching verifyEmail with only { verificationCode:
token } causing the server "Email is required" error and also destructures wrong
state keys; update VerifyEmailScreen.jsx to supply the email (either pass email
from the component by reading it from the Redux userInfo state or ensure the
thunk uses getState to fill email) when calling the verifyEmail thunk, and fix
the state destructuring to match the reducer’s keys (use userVerifyEmailSuccess
and userVerifyEmailError instead of userVerifySuccess/userVerifyError) so
success/error UI reacts correctly.
client/src/components/ui/Admin/Dashboard/Table.jsx (3)

56-59: ⚠️ Potential issue | 🟡 Minor

Remove console.log debug statement before merging.

Line 58 has a leftover debug log: console.log('Id', row._id, 'Value', e.target.value). This will pollute the browser console in production. Clean it up or replace with a proper logging utility if needed for diagnostics.

🧹 Proposed fix
                        onChange={(e) => {
                          handleChange(row._id, e.target.value);
-                          console.log('Id', row._id, 'Value', e.target.value);
                        }}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/src/components/ui/Admin/Dashboard/Table.jsx` around lines 56 - 59,
Remove the leftover console.log in the onChange handler inside Table.jsx: within
the onChange that calls handleChange(row._id, e.target.value), delete the
console.log('Id', row._id, 'Value', e.target.value) (or replace it with a proper
logging utility call such as logger.debug if you need diagnostics) so the
browser console is not polluted in production; ensure only handleChange(row._id,
e.target.value) remains in that handler.

53-85: ⚠️ Potential issue | 🟡 Minor

defaultValue on <select> conflicts with selected on <option> — React anti-pattern.

Lines 55 uses defaultValue={row[column]} on the <select>, while lines 63, 69, 75, and 81 also set selected={...} on individual <option> elements. React explicitly warns against this combination — defaultValue (or value) on <select> is the idiomatic approach, and selected on <option> is the legacy HTML way. Using both is redundant and may produce console warnings.

Remove the selected attributes from all <option> elements:

♻️ Proposed fix
                        <option
                          value={ORDER_STATUS.RECEIVED}
-                          selected={row[column] === ORDER_STATUS.RECEIVED}
                        >
                          {ORDER_STATUS.RECEIVED}
                        </option>
                        <option
                          value={ORDER_STATUS.IN_KITCHEN}
-                          selected={row[column] === ORDER_STATUS.IN_KITCHEN}
                        >
                          {ORDER_STATUS.IN_KITCHEN}
                        </option>
                        <option
                          value={ORDER_STATUS.OUT_FOR_DELIVERY}
-                          selected={row[column] === ORDER_STATUS.OUT_FOR_DELIVERY}
                        >
                          {ORDER_STATUS.OUT_FOR_DELIVERY}
                        </option>
                        <option
                          value={ORDER_STATUS.DELIVERED}
-                          selected={row[column] === ORDER_STATUS.DELIVERED}
                        >
                          {ORDER_STATUS.DELIVERED}
                        </option>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/src/components/ui/Admin/Dashboard/Table.jsx` around lines 53 - 85, The
select uses defaultValue={row[column]} while each option also sets
selected={...}, which is an anti-pattern; remove all selected={...} attributes
from the option elements and rely on the select's defaultValue (or convert the
select to a controlled component by replacing defaultValue with
value={row[column]} and keeping onChange/handleChange) so ORDER_STATUS options
only use value={ORDER_STATUS.*} and selection is driven by the select element;
update the JSX in the select block that renders options referencing
ORDER_STATUS, row[column], and handleChange accordingly.

24-30: ⚠️ Potential issue | 🟠 Major

React key warning: key must be on the outermost element in .map().

The key={column} is placed on <th> (line 26), but <th> is wrapped in a shorthand Fragment <> (line 25), which is the actual outermost element returned from .map(). Shorthand fragments cannot accept props like key. This will produce a React warning about missing keys.

Either use React.Fragment with a key, or simply remove the unnecessary fragment since there's only one child:

🐛 Proposed fix
              {columns.map((column) => (
-                <>
-                  <th key={column}>
-                    {column.replace(/([A-Z])/g, ' $1').trim()}
-                  </th>
-                </>
+                <th key={column}>
+                  {column.replace(/([A-Z])/g, ' $1').trim()}
+                </th>
              ))}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/src/components/ui/Admin/Dashboard/Table.jsx` around lines 24 - 30, The
map callback that renders columns uses a shorthand fragment wrapping a single
<th>, so the key={column} placed on <th> is not on the outermost element and
causes a React key warning; fix by removing the unnecessary fragment around the
<th> so the <th key={column}> is the top-level element returned from columns.map
(or alternatively replace the shorthand fragment with <React.Fragment
key={column}> if a wrapper is required), updating the code around columns.map
and the <th> element accordingly.
server/index.js (2)

88-93: ⚠️ Potential issue | 🟠 Major

Redundant body parsing — express.json() and bodyParser.json() do the same thing.

Since Express 4.16+, express.json() is a re-export of body-parser's JSON middleware. Having both means every request body is parsed twice — unnecessary CPU overhead and a potential source of subtle bugs if options diverge.

Remove one. Since you already use express.json(), drop bodyParser.json() and either convert the URL-encoded call to express.urlencoded() or keep bodyParser for that alone.

Suggested cleanup
 // Parse incoming JSON data
 app.use(express.json());

 // Parse incoming form data
-app.use(bodyParser.urlencoded({ extended: true }));
-app.use(bodyParser.json());
+app.use(express.urlencoded({ extended: true }));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/index.js` around lines 88 - 93, Remove the redundant JSON parsing
middleware: keep app.use(express.json()) and delete the
app.use(bodyParser.json()) call; for URL-encoded parsing either switch
bodyParser.urlencoded to express.urlencoded by replacing bodyParser.urlencoded({
extended: true }) with express.urlencoded({ extended: true }) or keep bodyParser
for only urlencoded usage so the code uses a single JSON parser (express.json)
and a single urlencoded parser (express.urlencoded or bodyParser.urlencoded) to
avoid double-parsing.

163-168: ⚠️ Potential issue | 🟡 Minor

console.log is the second argument to app.listen, not the callback.

console.log(...) is evaluated immediately (before the server is actually listening) and its return value (undefined) is passed as the callback. This means the log fires before the port is bound. Use an arrow function wrapper so it executes when the server is ready.

Fix
 app.listen(
   PORT,
-  console.log(
-    `Server running in ${process.env.NODE_ENV} mode on port ${PORT}`.yellow.bold
-  )
+  () => {
+    console.log(
+      `Server running in ${process.env.NODE_ENV} mode on port ${PORT}`.yellow.bold
+    );
+  }
 );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/index.js` around lines 163 - 168, The current call to app.listen uses
console.log(...) as the second argument which executes immediately and passes
undefined as the callback; change the second argument to a function so the log
runs once the server is actually listening. Locate the app.listen invocation
(symbols: app.listen, PORT, process.env.NODE_ENV, console.log) and replace the
immediate console.log(...) with an arrow function wrapper that calls console.log
with the same message so the message prints only after the server is bound.
client/src/components/ui/CheckoutSteps/PlaceOrderStep.jsx (1)

34-80: 🛠️ Refactor suggestion | 🟠 Major

cartItems.reduce(...) is computed 5 times identically — extract to a variable.

The same reduction cartItems.reduce((acc, item) => acc + item.price * item.qty, 0) is repeated across the orderSummary array. This hurts readability and does redundant work on every render. Extract it once:

♻️ Suggested refactor
+ const itemsPrice = cartItems
+   ? cartItems.reduce((acc, item) => acc + item.price * item.qty, 0)
+   : 0;
+ const deliveryCharges = itemsPrice > 100 ? 0 : 10;
+ const salesTax = Number((0.15 * itemsPrice).toFixed(2));
+ const totalPrice = Math.round((itemsPrice + deliveryCharges + salesTax) * 100) / 100;
+
  const orderSummary = [
-   {
-     name: 'Items Price',
-     value: cartItems && cartItems.reduce((acc, item) => acc + item.price * item.qty, 0),
-   },
-   // ...repeated reduce calls...
+   { name: 'Items Price', value: itemsPrice },
+   { name: 'Delivery Charges', value: deliveryCharges },
+   { name: 'Sales Tax', value: salesTax },
+   { name: 'Total', value: totalPrice },
  ];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/src/components/ui/CheckoutSteps/PlaceOrderStep.jsx` around lines 34 -
80, The repeated computation of cartItems total inside orderSummary (the
repeated cartItems.reduce((acc, item) => acc + item.price * item.qty, 0) used
for 'Items Price', 'Delivery Charges', 'Sales Tax', and 'Total') should be
extracted to a single variable (e.g., itemsPrice or cartTotal) before the
orderSummary definition; then use that variable in the objects and compute
delivery (0 or 10), salesTax (0.15 * itemsPrice rounded/formatted), and Total
(itemsPrice + delivery + salesTax) from those values instead of re-running the
reduce each time.
server/routes/inventoryRoutes.js (1)

35-47: ⚠️ Potential issue | 🔴 Critical

Route ordering bug: GET /low-stock will never be reached — it's shadowed by GET /:id.

Express evaluates routes in registration order. router.get('/:id', ...) on line 36 matches any path segment, including low-stock. So a GET /low-stock request will be handled by getStockById with req.params.id = 'low-stock', which will likely return a 404 or a cast error — never reaching getLowInventoryItems on line 47.

Move the static paths above the parameterized /:id routes:

🐛 Proposed fix
 // Public Routes

+// Inventory Alert Routes (must be above /:id to avoid shadowing)
+router.post('/check-alerts', protect, admin, checkAndSendAlerts);
+router.get('/low-stock', protect, admin, getLowInventoryItems);
+
 // Private Routes
 router.get('/', protect, getAllStocks);
 router.get('/:id', protect, getStockById);

 // Admin + Private Routes
 router.post('/', protect, admin, createStockValidation, validationHandler, createStock);
 router
   .route('/:id')
   .put(protect, admin, updateStockValidation, validationHandler, updateStockById)
   .delete(protect, admin, deleteStockById);

-// Inventory Alert Routes
-router.post('/check-alerts', protect, admin, checkAndSendAlerts);
-router.get('/low-stock', protect, admin, getLowInventoryItems);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/routes/inventoryRoutes.js` around lines 35 - 47, The route ordering is
wrong: the parameterized route router.get('/:id', protect, getStockById) will
catch requests like '/low-stock' before the static handler getLowInventoryItems;
move the Inventory Alert Routes (router.post('/check-alerts', protect, admin,
checkAndSendAlerts) and router.get('/low-stock', protect, admin,
getLowInventoryItems)) so they are registered before any router.get('/:id', ...)
or router.route('/:id') declarations, keeping router.get('/', protect,
getAllStocks) where it is.
client/src/components/ui/Admin/Dashboard/Lists/OrdersList.jsx (1)

112-112: ⚠️ Potential issue | 🔴 Critical

orderList.length will throw a TypeError when orderList is null or undefined.

If the API call fails (or hasn't completed yet), orderList can be falsy. The loading guard on Line 99 won't protect you if loading finishes but the fetch errored out — you'll land in the else branch with orderList still being null.

🐛 Proposed fix
-           {orderList.length > 0 ? (
+           {orderList && orderList.length > 0 ? (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/src/components/ui/Admin/Dashboard/Lists/OrdersList.jsx` at line 112,
The conditional rendering currently uses orderList.length which throws if
orderList is null/undefined; change the check to guard for non-null array (e.g.,
use Array.isArray(orderList) && orderList.length > 0 or orderList?.length > 0)
in the JSX where orderList is used, and/or ensure the state that holds orderList
is initialized to an empty array so OrdersList rendering (and any map calls)
never run on null; update the condition around the JSX (the ternary that starts
with {orderList.length > 0 ?) to use the safe check and keep the existing
empty/error branch.
client/src/redux/slices/cartSlice.js (1)

166-183: ⚠️ Potential issue | 🟠 Major

Cart quantity can exceed the 10-item cap when adding the same pizza+size.

addToCart.fulfilled (line 176) does existItem.qty += item.qty, but there's no upper-bound check. If a user adds 6 of a pizza, then adds 6 more, qty becomes 12 — exceeding the qty <= 10 validation applied during localStorage hydration (line 71) and updateCartItemQuantity (line 110).

🐛 Proposed fix — clamp the quantity
       if (existItem) {
-        // Update quantity for existing item
-        existItem.qty += item.qty;
+        // Update quantity for existing item, clamped to max 10
+        existItem.qty = Math.min(existItem.qty + item.qty, 10);
       } else {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/src/redux/slices/cartSlice.js` around lines 166 - 183, The
addToCart.fulfilled handler allows existItem.qty to grow unbounded by doing
existItem.qty += item.qty, which can exceed the intended cap of 10; modify the
addToCart.fulfilled branch (the existItem handling inside the reducer) to clamp
the resulting quantity to the maximum allowed (e.g., Math.min(existingQty +
item.qty, 10)) before assigning existItem.qty, then continue to persist
state.cartItems to localStorage as before so hydration and
updateCartItemQuantity invariants are preserved.
client/src/redux/asyncThunks/adminThunks.js (1)

1-3: ⚠️ Potential issue | 🔴 Critical

Critical: Missing import of extractErrorMessage — every error path will throw ReferenceError.

The function is called at lines 25, 49, 79, 103, 127, 151, 180, and 204 throughout this file, but no import exists. Any API failure will crash the thunk before the error can propagate to the UI.

Add the missing import at the top:

 import { createAsyncThunk } from '@reduxjs/toolkit';
 import axios from 'axios';
+import { extractErrorMessage } from '../../utils/errorUtils';

Follow the pattern already established in userThunks.js and orderThunks.js, which import extractErrorMessage from errorUtils. This ensures consistency across your thunk files and guarantees proper error string extraction from API responses.

Minor: Line 131 has a typo — "Admin USer Details By ID" should be "Admin User Details By ID".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/src/redux/asyncThunks/adminThunks.js` around lines 1 - 3, Add the
missing import for extractErrorMessage at the top of adminThunks.js (following
the same import pattern used in userThunks.js and orderThunks.js, e.g. import {
extractErrorMessage } from the module where error utilities live) so all
try/catch blocks can call extractErrorMessage without throwing ReferenceError;
also fix the typo "Admin USer Details By ID" to "Admin User Details By ID" in
the thunk/comment that contains that string.

Comment thread client/src/components/ui/Admin/Dashboard/Modals/PizzaCreateModal.jsx Outdated
import { createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';

import { extractErrorMessage } from '../../utils/errorUtils';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify which thunk files have local extractErrorMessage vs. import
echo "=== Searching for extractErrorMessage references in asyncThunks ==="
rg -n "extractErrorMessage" client/src/redux/asyncThunks/ --type=js -A 2

echo -e "\n=== Checking errorUtils.js ==="
rg -n "extractErrorMessage" client/src/utils/errorUtils.js --type=js -A 5

Repository: itxSaaad/pizza-palette-app-mern-OIBSIP-task-1

Length of output: 8774


🏁 Script executed:

#!/bin/bash
# Check the first 15 lines of each thunk file to see import statements
echo "=== inventoryThunks.js (first 15 lines) ==="
head -n 15 client/src/redux/asyncThunks/inventoryThunks.js

echo -e "\n=== adminThunks.js (first 15 lines) ==="
head -n 15 client/src/redux/asyncThunks/adminThunks.js

echo -e "\n=== pizzaThunks.js (first 30 lines) ==="
head -n 30 client/src/redux/asyncThunks/pizzaThunks.js

Repository: itxSaaad/pizza-palette-app-mern-OIBSIP-task-1

Length of output: 1553


🏁 Script executed:

#!/bin/bash
# Check if inventoryThunks and adminThunks have local extractErrorMessage implementations
echo "=== Checking inventoryThunks.js for extractErrorMessage definition ==="
rg -n "const extractErrorMessage|export.*extractErrorMessage" client/src/redux/asyncThunks/inventoryThunks.js

echo -e "\n=== Checking adminThunks.js for extractErrorMessage definition ==="
rg -n "const extractErrorMessage|export.*extractErrorMessage" client/src/redux/asyncThunks/adminThunks.js

echo -e "\n=== Checking if they import it ==="
head -n 10 client/src/redux/asyncThunks/inventoryThunks.js | grep -i import
head -n 10 client/src/redux/asyncThunks/adminThunks.js | grep -i import

Repository: itxSaaad/pizza-palette-app-mern-OIBSIP-task-1

Length of output: 423


🏁 Script executed:

#!/bin/bash
# Verify if inventoryThunks and adminThunks actually use extractErrorMessage
echo "=== inventoryThunks.js - lines where extractErrorMessage is used ==="
rg -n "extractErrorMessage" client/src/redux/asyncThunks/inventoryThunks.js -B 2

echo -e "\n=== adminThunks.js - lines where extractErrorMessage is used ==="
rg -n "extractErrorMessage" client/src/redux/asyncThunks/adminThunks.js -B 2

Repository: itxSaaad/pizza-palette-app-mern-OIBSIP-task-1

Length of output: 1853


🏁 Script executed:

#!/bin/bash
# Final verification: check the actual implementation in errorUtils to confirm what should be shared
echo "=== errorUtils.js - full extractErrorMessage implementation ==="
sed -n '15,30p' client/src/utils/errorUtils.js

Repository: itxSaaad/pizza-palette-app-mern-OIBSIP-task-1

Length of output: 544


Fix extractErrorMessage usage across thunks—missing imports and duplicate implementation.

pizzaThunks.js duplicates the extractErrorMessage implementation that should be imported from errorUtils.js, violating DRY. More critically, inventoryThunks.js and adminThunks.js call extractErrorMessage without importing or defining it, which causes ReferenceErrors at runtime.

All three files should import extractErrorMessage from errorUtils.js:

  • pizzaThunks.js: Remove the local implementation (lines 7–26) and add the import
  • inventoryThunks.js: Add import { extractErrorMessage } from '../../utils/errorUtils';
  • adminThunks.js: Add import { extractErrorMessage } from '../../utils/errorUtils';

This ensures consistent error handling across all thunks and eliminates the code duplication.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@client/src/redux/asyncThunks/userThunks.js` at line 4, Multiple thunk files
misuse or duplicate the error helper: remove the duplicated local
extractErrorMessage implementation in pizzaThunks.js and import the shared
helper instead, and add missing imports of extractErrorMessage from
../../utils/errorUtils in inventoryThunks.js and adminThunks.js so all thunks
call the same extractErrorMessage function; update the import lines in those
modules and delete the redundant implementation block (the local function in
pizzaThunks.js) to restore DRY and prevent ReferenceErrors.

Comment thread client/src/screens/User/UserCreateCustomPizzaScreen.jsx Outdated
Comment thread client/src/screens/User/VerifyEmailScreen.jsx Outdated
Comment thread client/src/utils/errorUtils.js
Comment thread server/controllers/userControllers.js
Comment thread server/index.js
Comment thread server/package.json Outdated
"razorpay": "^2.9.2"
"razorpay": "^2.9.2",
"stripe": "^20.3.1",
"uuid": "^13.0.0"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for uuid imports/requires in the server directory
rg -n "require.*uuid|import.*uuid" server --type=js -A 2

Repository: itxSaaad/pizza-palette-app-mern-OIBSIP-task-1

Length of output: 358


🌐 Web query:

uuid@13 CommonJS support ECMAScript modules

💡 Result:

uuid@13 is ESM-only. CommonJS (require) is not supported (CommonJS support was removed starting in uuid@12). [1], [2]

What to do:

  • Use ESM imports:

    import { v4 as uuidv4 } from 'uuid';

    [1]

  • If your project is CommonJS and you can’t migrate:

    • Pin to uuid@11.x (last line with CommonJS support), because uuid@12 removed it. [2]
    • Or switch your code to load it via ESM (e.g., dynamic import()), rather than require. [1]

uuid@13 drops CommonJS support — will break require() at runtime.

The server's errorMiddlewares.js uses const { v4: uuidv4 } = require('uuid'), which will fail under uuid@13 (ESM-only since v12). This is a startup blocker.

Pin to "^11.0.0" (the last CommonJS-compatible major) or migrate the server to ESM.

🐛 Proposed fix (maintain CJS compatibility)
-    "uuid": "^13.0.0"
+    "uuid": "^11.0.0"
📝 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
"uuid": "^13.0.0"
"uuid": "^11.0.0"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/package.json` at line 41, The package.json currently depends on
uuid@13 which is ESM-only and will break the CommonJS usage in
errorMiddlewares.js (see the require('uuid') / const { v4: uuidv4 } =
require('uuid') statement); fix by pinning the uuid dependency to a
CommonJS-compatible major (change the package.json entry for "uuid" to
"^11.0.0") or alternatively migrate the server to ESM and update all requires
accordingly—prefer the quick fix of pinning to ^11.0.0 to restore runtime
compatibility with errorMiddlewares.js.

Comment thread server/routes/orderRoutes.js Outdated
Comment on lines +57 to +60
// Add indexes for frequently queried fields
pizzaSchema.index({ createdBy: 1 });
pizzaSchema.index({ price: 1 });
pizzaSchema.index({ createdAt: -1 });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's check the pizzaSchema.js file to confirm the size field removal
cat -n server/schemas/pizzaSchema.js

Repository: itxSaaad/pizza-palette-app-mern-OIBSIP-task-1

Length of output: 1681


🏁 Script executed:

#!/bin/bash
# Search for any remaining references to pizza 'size' in controllers, routes, or frontend code
rg -n --type js -C 2 'pizza.*size|size.*pizza' \
  --glob '!**/node_modules/**' \
  --glob '!**/schemas/**'

Repository: itxSaaad/pizza-palette-app-mern-OIBSIP-task-1

Length of output: 4032


🏁 Script executed:

#!/bin/bash
# Search more broadly for 'size' references in non-schema files
rg -n --type js '\bsize\b' \
  --glob '!**/node_modules/**' \
  --glob '!**/schemas/**' | head -50

Repository: itxSaaad/pizza-palette-app-mern-OIBSIP-task-1

Length of output: 6428


🏁 Script executed:

#!/bin/bash
# Look for migration-related files
find . -type f \( -name "*migrat*" -o -name "*migration*" \) \
  ! -path '*/node_modules/*' | head -20

Repository: itxSaaad/pizza-palette-app-mern-OIBSIP-task-1

Length of output: 71


Size field removal breaks order and cart management — critical functionality failure.

The size field was removed from the schema, but active code throughout the application still depends on it:

  • Order creation (server/controllers/orderControllers.js, lines 36, 56, 347, 367, 407) directly accesses item.size when processing orders
  • Cart deduplication (client/src/redux/slices/cartSlice.js, line 172) checks x.size === item.size to prevent duplicate entries
  • Pizza filtering (server/controllers/pizzaControllers.js, lines 24-25) filters by size from query parameters
  • Frontend state (client/src/screens/User/UserCreateCustomPizzaScreen.jsx) manages size selection and validates it before submission
  • Price calculation relies on size multipliers from server/constants/pizzaSizes.js

All size accesses will now return undefined, silently breaking order placement, cart logic, and price calculations. No migration script exists to handle existing documents. Either restore the size field to the schema or remove all references to it and refactor price handling to use a different mechanism (e.g., base price + size multiplier lookup table).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/schemas/pizzaSchema.js` around lines 57 - 60, The schema no longer
defines the size field but many parts of the app still read/write it
(pizzaSchema, orderControllers.js where item.size is used, client cartSlice
deduplication, pizzaControllers query filtering, UserCreateCustomPizzaScreen,
and price calculation via server/constants/pizzaSizes.js), causing undefined
behavior; fix by either restoring a typed/enumerated size field to pizzaSchema
(with allowed values and a sensible default and keep the index if needed) and
add a one-off migration to backfill existing pizza documents with a default
size, or remove all size usages and refactor price logic to use basePrice +
explicit multiplier lookups (update orderControllers, cartSlice dedupe logic,
pizzaControllers filter parsing, and frontend UserCreateCustomPizzaScreen
validation) so every place references the new pricing mechanism consistently.

Copilot AI review requested due to automatic review settings July 17, 2026 21:33

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.

Copilot wasn't able to review this pull request because it exceeds the maximum number of lines (20,000). Try reducing the number of changed lines and requesting a review from Copilot again.

Muhammad Saad and others added 16 commits July 18, 2026 23:42
…rLoginScreen/UserRegisterScreen, remove redundant padding
…ed by merged AuthLoginForm/AuthRegisterForm
…o fix), migrate onto shared Modal primitive
…rate to Input primitive, fix Resend OTP accessibility
…okens, add timer cleanup

- Fixed critical bug: use correct Redux field names userVerifyEmailSuccess/userVerifyEmailError
  (brief's code mistakenly used userVerifySuccess/userVerifyError, which were already renamed in userSlice.js)
- Migrated from hardcoded colors (orange-200, red-500, green-500) to design tokens (neutral-50, error-500, accent-green-500)
- Replaced div container with Card component using lg padding
- Updated typography to use design tokens (font-display, text-h3, text-neutral-900)
- Added proper cleanup function for 3-second timer to prevent memory leak on unmount
…tives, fix resetPassword dispatch payload (missing email/wrong keys) and forgot-password route link
…ted IngredientCard, fix placeholder image path

Preserves the existing addToCart useRef double-dispatch guard rather than
reintroducing the brief's stale ungated version.
express-rate-limit's default handler sends a plain-text body, which
the frontend's extractErrorMessage can't parse (no error.response.data
to read), so users saw axios's generic "Request failed with status
code 429" instead of a real message. All 5 limiters now use a custom
handler returning the same { success, error: { code, message } }
shape as every other API error.
Muhammad Saad and others added 10 commits July 19, 2026 01:07
…put primitive, remove incorrect unused PropTypes entry
…mapping with Badge.OrderStatus, fix missing Cancelled status in legend
…n mapping with Badge.OrderStatus, migrate to Card
…oating-point subtotal display

- orderSlice's orderInfo initial state is {} (truthy), so the
  !orderDetails guard never fired and the first render showed
  undefined fields with PropTypes warnings from the new
  required-status Badge; now also requires _id
- Subtotal computed as totalPrice - salesTax - deliveryCharges
  rendered raw float artifacts ($6.030000000000001); now .toFixed(2)
The Input-primitive migration dropped the original sr-only labels; the
name and email fields ended up with no accessible name at all (no label,
no placeholder), leaving screen-reader users nothing to announce. All six
fields now carry aria-label (plus placeholders on name/email), and email/
phone use their semantically correct input types (email, tel).

Found by the Phase 2e whole-branch review.
Redesign Phase 2e: Profile, Orders & Order Detail
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants