Showing AI reviews for avriti
Project AI Score ?
63%
Quality Avg ?
68%
Security Avg ?
45%
Reviews ?
56

Review Result ?

jattin01/avriti · 8bb9c632
The commit adds functionality for card checkout and order management, including mapping product attributes, formatting attribute labels, and navigation to checkout or login. It improves user experience by handling UI state (wishlist, cart) and redirects based on login status. However, it relies on any typed parameters without strict types, and there is some code repetition in formatting functions across files. Security score is moderate due to localStorage usage without encryption and redirect using window.location.href, which could lead to open redirect risks if input is not sanitized.
Quality ?
75%
Security ?
60%
Business Value ?
80%
Maintainability ?
78%
Issues & Suggested Fixes ?
1AI detects the issue
2Shows file, line, or evidence
3Suggests the fix to apply
Loose Typing With 'Any' Used In Mapping Pr...
Where app/cart/page.tsx:88
Issue / Evidence loose typing with 'any' used in mapping product attributes
Suggested Fix define and use specific TypeScript interfaces to reduce runtime errors and improve maintainability
Insecure Redirect Via Window.location.href...
Where app/cart/page.tsx:168
Issue / Evidence insecure redirect via window.location.href with user-controlled redirect
Suggested Fix sanitize redirect paths to avoid open redirect vulnerabilities
Duplicate Logic
Where app/checkout/page.tsx:274
Issue / Evidence duplicate code in formatAttributeLabel function present in multiple files
Suggested Fix extract to a shared utility function to reduce duplication and improve maintainability
Missing Validation
Where app/login/page.tsx:38
Issue / Evidence redirection after login without validation may allow open redirect
Suggested Fix validate or constrain redirect URLs to internal paths only
Missing Validation
Where app/register/page.tsx:26
Issue / Evidence inline validation only sets error without deeper input sanitation
Suggested Fix consider more robust validation and sanitize inputs to prevent invalid data entry
Multiple Async Handlers Modifying Global S...
Where app/shop/page.tsx:73
Issue / Evidence multiple async handlers modifying global state and performing side effects
Suggested Fix ensure proper error handling and possibly debounce or throttle user actions to avoid race conditions
Too Brief And Generic
Where commit message
Issue / Evidence too brief and generic
Suggested Fix provide more details about what 'complete card checkout and order' entails, including key changes and intent, to improve code review and future reference
Code Change Preview · app/cart/page.tsx ?
Removed / Before Commit
- .then((data) => {
- if (data.success && Array.isArray(data.data)) {
- setFeaturedProducts(
-             data.data.map((p: any, i: number) => ({
-               slug: p.slug,
-               name: p.title,
-               attrValue: p.attributes?.find((a: any) => a.sr_no === 1)?.value ?? "",
-               variantName: p.variant?.name ?? "",
-               sellingPrice: p.attributes?.find((a: any) => a.sr_no === 1)?.selling_price ?? null,
-               mrp: p.attributes?.find((a: any) => a.sr_no === 1)?.mrp ?? null,
-               image: p.thumbnail?.[0]
-                 ? `${process.env.NEXT_PUBLIC_API_URL}/${p.thumbnail[0]}`
-                 : "/product2.jpeg",
-               tone: tones[i % tones.length],
-               category: p.category?.name ?? "",
-               badge: "New",
-               description: p.short_description ?? "",
-             }))
Added / After Commit
+ .then((data) => {
+ if (data.success && Array.isArray(data.data)) {
+ setFeaturedProducts(
+             data.data.map((p: any, i: number) => {
+               const attr = p.attributes?.find((a: any) => a.in_stock) ?? p.attributes?.find((a: any) => a.sr_no === 1);
+ 
+               return {
+                 slug: p.slug,
+                 name: p.title,
+                 productId: p.id,
+                 attrValue: attr?.value ?? "",
+                 attributeName: attr?.name ?? "",
+                 variantName: p.variant?.name ?? "",
+                 sellingPrice: attr?.selling_price ?? null,
+                 mrp: attr?.mrp ?? null,
+                 image: p.thumbnail?.[0]
+                   ? `${process.env.NEXT_PUBLIC_API_URL}/${p.thumbnail[0]}`
+                   : "/product2.jpeg",
Removed / Before Commit
- 
- import { useEffect, useState } from "react";
- import InnerBanner from "@/components/inner-banner";
- import { apiGetCart, getToken } from "@/lib/cart";
- 
- type CheckoutItem = {
- product_id: number;
- title: string;
- attribute_name: string;
- attribute_value: string;
- selling_price: number;
- mrp: number;
- quantity: number;
- 
- // ── load cart items ─────────────────────────────────────────
- useEffect(() => {
- // prefill email from localStorage
- try {
Added / After Commit
+ 
+ import { useEffect, useState } from "react";
+ import InnerBanner from "@/components/inner-banner";
+ import { apiGetCart, getToken, isLoggedIn } from "@/lib/cart";
+ 
+ type CheckoutItem = {
+ product_id: number;
+ title: string;
+ attribute_name: string;
+ attribute_value: string;
+   variant_name?: string;
+ selling_price: number;
+ mrp: number;
+ quantity: number;
+ 
+ // ── load cart items ─────────────────────────────────────────
+ useEffect(() => {
+     if (!isLoggedIn()) {
Removed / Before Commit
- }
- try {
- // const name = data.customer.email.split("@")[0];
-         localStorage.setItem("avriti_customer", JSON.stringify({ name:data.customer.full_name, email: data.customer.email, token: data.token }));
- } catch {}
- await mergeLocalCartToApi();
-       window.location.href = "/";
- } catch {
- setError(" Please try again.");
- } finally {
Added / After Commit
+ }
+ try {
+ // const name = data.customer.email.split("@")[0];
+         localStorage.setItem("avriti_customer", JSON.stringify({ name:data.customer.full_name, email: data.customer.email, phone: data.customer.phone, token: data.token }));
+ } catch {}
+ await mergeLocalCartToApi();
+       const redirectTo = new URLSearchParams(window.location.search).get("redirect") || "/";
+       window.location.href = redirectTo.startsWith("/") ? redirectTo : "/";
+ } catch {
+ setError(" Please try again.");
+ } finally {
Removed / Before Commit
- "use client";
- 
- import { useEffect, useState } from "react";
- import { useSearchParams } from "next/navigation";
- import Image from "next/image";
- import { CreditCard, Home, MapPin, Phone, User } from "lucide-react";
- interface OrderItem {
- id: number;
- product_name: string;
- price: number;
- quantity: number;
- total: number;
- return <span>&#8377;{value}</span>;
- }
- 
- const statusClassMap: Record<string, string> = {
- pending:    "bg-[#E7F4D9] text-[#26732F]",
- confirmed:  "bg-[#E9F4FF] text-[#1068A9]",
Added / After Commit
+ "use client";
+ 
+ import { Suspense, useEffect, useState } from "react";
+ import { useSearchParams } from "next/navigation";
+ import Image from "next/image";
+ import { CreditCard, Home, MapPin, Phone, User } from "lucide-react";
+ interface OrderItem {
+ id: number;
+ product_name: string;
+   variant_name: string | null;
+   attribute_value: string | null;
+ price: number;
+ quantity: number;
+ total: number;
+ return <span>&#8377;{value}</span>;
+ }
+ 
+ const formatAttributeLabel = (item: OrderItem) => {
Removed / Before Commit
- 
- const API_BASE = process.env.NEXT_PUBLIC_API_URL;
- 
- export default function OrderlistPage() {
- const [orders, setOrders] = useState<Order[]>([]);
- const [loading, setLoading] = useState(true);
- id: String(order.id),
- orderNumber: order.order_number,
- items: order.items.length,
-                     date: new Date(order.created_at).toLocaleString("en-IN"),
- status: order.order_status as
- | "pending"
- | "processing"
Added / After Commit
+ 
+ const API_BASE = process.env.NEXT_PUBLIC_API_URL;
+ 
+ const formatOrderDate = (value: string) =>
+   new Intl.DateTimeFormat("en-IN", {
+     day: "2-digit",
+     month: "short",
+     year: "numeric",
+     hour: "numeric",
+     minute: "2-digit",
+     hour12: true,
+     timeZone: "Asia/Kolkata",
+   }).format(new Date(value));
+ 
+ export default function OrderlistPage() {
+ const [orders, setOrders] = useState<Order[]>([]);
+ const [loading, setLoading] = useState(true);
+ id: String(order.id),
Removed / Before Commit
- .then((res) => res.json())
- .then((data) => {
- if (data.success && Array.isArray(data.data)) {
-           const mapped: FeaturedProduct[] = data.data.map((p: any, i: number) => ({
-             slug: p.slug,
-             name: p.title,
-             attrValue: p.attributes?.find((a: any) => a.sr_no === 1)?.value ?? "",
-             variantName: p.variant?.name ?? "",
-             sellingPrice: p.attributes?.find((a: any) => a.sr_no === 1)?.selling_price ?? null,
-             mrp: p.attributes?.find((a: any) => a.sr_no === 1)?.mrp ?? null,
-             image: p.thumbnail?.[0]
-               ? `${process.env.NEXT_PUBLIC_API_URL}/${p.thumbnail[0]}`
-               : "/product2.jpeg",
-             tone: tones[i % tones.length],
-             category: p.category?.name ?? "",
-             badge: "New",
-             description: p.short_description ?? "",
-           }));
Added / After Commit
+ .then((res) => res.json())
+ .then((data) => {
+ if (data.success && Array.isArray(data.data)) {
+           const mapped: FeaturedProduct[] = data.data.map((p: any, i: number) => {
+             const attr = p.attributes?.find((a: any) => a.in_stock) ?? p.attributes?.find((a: any) => a.sr_no === 1);
+ 
+             return {
+               slug: p.slug,
+               name: p.title,
+               productId: p.id,
+               attrValue: attr?.value ?? "",
+               attributeName: attr?.name ?? "",
+               variantName: p.variant?.name ?? "",
+               sellingPrice: attr?.selling_price ?? null,
+               mrp: attr?.mrp ?? null,
+               image: p.thumbnail?.[0]
+                 ? `${process.env.NEXT_PUBLIC_API_URL}/${p.thumbnail[0]}`
+                 : "/product2.jpeg",
Removed / Before Commit
- if (password.length < 8) { setError("Password must be at least 8 characters."); return; }
- if (!confirmPassword) { setError("Please confirm your password."); return; }
- if (password !== confirmPassword) { setError("Passwords do not match."); return; }
-     if (phone && !/^[0-9]{10}$/.test(phone)) { setError("Enter a valid 10-digit phone number."); return; }
- setLoading(true);
- try {
- const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/customer/register`, {
- }
- try {
- 
-         localStorage.setItem("avriti_customer", JSON.stringify({ name: data.customer.full_name, email: data.customer.email, token: data.token }));
- } catch {}
- window.location.href = "/";
- } catch {
- 
- <div className="mb-3 fade-up-3">
- <label style={{ display: "block", fontSize: "13px", fontWeight: "500", color: "#000", marginBottom: "6px" }}>
-     Phone <span style={{ color: "#9E9890", fontWeight: "400" }}>(optional)</span>
Added / After Commit
+ if (password.length < 8) { setError("Password must be at least 8 characters."); return; }
+ if (!confirmPassword) { setError("Please confirm your password."); return; }
+ if (password !== confirmPassword) { setError("Passwords do not match."); return; }
+     if (!phone.trim()) { setError("Phone number is required."); return; }
+     if (!/^[0-9]{10}$/.test(phone)) { setError("Enter a valid 10-digit phone number."); return; }
+ setLoading(true);
+ try {
+ const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/customer/register`, {
+ }
+ try {
+ 
+         localStorage.setItem("avriti_customer", JSON.stringify({ name: data.customer.full_name, email: data.customer.email, phone: data.customer.phone, token: data.token }));
+ } catch {}
+ window.location.href = "/";
+ } catch {
+ 
+ <div className="mb-3 fade-up-3">
+ <label style={{ display: "block", fontSize: "13px", fontWeight: "500", color: "#000", marginBottom: "6px" }}>
Removed / Before Commit
- type FeaturedProduct = {
- slug: string;
- name: string;
- attrValue: string;
- variantName: string;
- sellingPrice: number | null;
- mrp: number | null;
- .then((res) => res.json())
- .then((data) => {
- if (data.success && Array.isArray(data.data)) {
-           const mapped: FeaturedProduct[] = data.data.map((p: any, i: number) => ({
-             slug: p.slug,
-             name: p.title,
-             attrValue: p.attributes?.find((a: any) => a.sr_no === 1)?.value ?? "",
-             variantName: p.variant?.name ?? "",
-             sellingPrice: p.attributes?.find((a: any) => a.sr_no === 1)?.selling_price ?? null,
-             mrp: p.attributes?.find((a: any) => a.sr_no === 1)?.mrp ?? null,
-             image: p.thumbnail?.[0]
Added / After Commit
+ type FeaturedProduct = {
+ slug: string;
+ name: string;
+   productId?: number;
+ attrValue: string;
+   attributeName?: string;
+ variantName: string;
+ sellingPrice: number | null;
+ mrp: number | null;
+ .then((res) => res.json())
+ .then((data) => {
+ if (data.success && Array.isArray(data.data)) {
+           const mapped: FeaturedProduct[] = data.data.map((p: any, i: number) => {
+             const attr = p.attributes?.find((a: any) => a.in_stock) ?? p.attributes?.find((a: any) => a.sr_no === 1);
+ 
+             return {
+               slug: p.slug,
+               name: p.title,
Removed / Before Commit
- "use client";
- 
- import { useState, useEffect } from "react";
- import Image from "next/image";
- import Link from "next/link";
- import { PdfBrowserFrame } from "@/components/pdf-browser-frame";
- 
- interface Category {
- id: number;
- const [categories, setCategories] = useState<Category[]>([]);
- const [products, setProducts] = useState<Product[]>([]);
- const [loading, setLoading] = useState(false);
- 
- useEffect(() => {
- const fetchCategories = async () => {
- fetchProducts();
- }, [selected]);
- 
Added / After Commit
+ "use client";
+ 
+ import { useState, useEffect } from "react";
+ import type React from "react";
+ import Image from "next/image";
+ import Link from "next/link";
+ import { PdfBrowserFrame } from "@/components/pdf-browser-frame";
+ import { addToLocalCart, apiAddToCart, isLoggedIn } from "@/lib/cart";
+ import { apiGetWishlist, apiToggleWishlist } from "@/lib/wishlist";
+ import { shareProduct } from "@/lib/share";
+ 
+ interface Category {
+ id: number;
+ const [categories, setCategories] = useState<Category[]>([]);
+ const [products, setProducts] = useState<Product[]>([]);
+ const [loading, setLoading] = useState(false);
+   const [wishlistIds, setWishlistIds] = useState<number[]>([]);
+ 
Removed / Before Commit

                                                
Added / After Commit
+ "use client";
+ 
+ import { useEffect, useState } from "react";
+ import Link from "next/link";
+ import InnerBanner from "@/components/inner-banner";
+ import { addToLocalCart, apiAddToCart, isLoggedIn } from "@/lib/cart";
+ import { apiGetWishlist, apiRemoveWishlist, WishlistItem } from "@/lib/wishlist";
+ import { shareProduct } from "@/lib/share";
+ 
+ const formatAttributeLabel = (item: WishlistItem) => {
+   if (!item.attribute_value) return "";
+ 
+   const numericValue = Number(item.attribute_value);
+   const value = Number.isFinite(numericValue)
+     ? Number.isInteger(numericValue)
+       ? String(numericValue)
+       : String(numericValue).replace(/0+$/, "").replace(/\.$/, "")
+     : item.attribute_value;
Removed / Before Commit
- import Link from "next/link";
- import { Button } from "@/components/ui/button";
- import { Card } from "@/components/ui/card";
- 
- type ProductCardProps = {
- slug: string;
- category?: string;
- badge?: string;
- description?: string;
- };
- 
- export function ProductCard({ product }: { product: ProductCardProps }) {
- return (
-     <Card className="overflow-hidden">
- <Link href={`/shop/${product.slug}`} className="block h-full flex flex-col justify-between">
-        <div className="mt-2 mb-[20px] flex gap-2 items-center justify-between">
-         <h3 className="text-lg  text-[var(--textcolor)] font-normal">
-           {product.name}
Added / After Commit
+ "use client";
+ 
+ import Link from "next/link";
+ import type React from "react";
+ import { useEffect, useState } from "react";
+ import { Button } from "@/components/ui/button";
+ import { Card } from "@/components/ui/card";
+ import { addToLocalCart, apiAddToCart, isLoggedIn } from "@/lib/cart";
+ import { apiGetWishlist, apiToggleWishlist } from "@/lib/wishlist";
+ import { shareProduct } from "@/lib/share";
+ 
+ type ProductCardProps = {
+ slug: string;
+ category?: string;
+ badge?: string;
+ description?: string;
+   productId?: number;
+   attributeName?: string;
Removed / Before Commit
- <button
- disabled={!selectedAttr?.in_stock}
- onClick={() => {
-                   if (!isLoggedIn()) { window.location.href = "/login"; return; }
- if (!product || !selectedAttr) return;
- const buyNowItem = {
- product_id: product.id,
- quantity,
- };
- localStorage.setItem("avriti_buy_now", JSON.stringify(buyNowItem));
-                   window.location.href = "/checkout";
- }} className="bg-[var(--color-primary-700)] inline-flex items-center justify-center gap-2 px-5 py-2.5 text-sm font-semibold transition border-[var(--color-primary-300)] text-[#fff] hover:bg-[var(--color-primary-100)]/35 hover:text-[var(--color-primary-700)] min-h-11 uppercase pl-[10px] pr-[0px] rounded-[10px] border-[1px] w-full addtocartButton relative cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed">
- Buy Now
- </button>
Added / After Commit
+ <button
+ disabled={!selectedAttr?.in_stock}
+ onClick={() => {
+ if (!product || !selectedAttr) return;
+ const buyNowItem = {
+ product_id: product.id,
+ quantity,
+ };
+ localStorage.setItem("avriti_buy_now", JSON.stringify(buyNowItem));
+                   window.location.href = isLoggedIn()
+                     ? "/checkout"
+                     : "/login?redirect=/checkout";
+ }} className="bg-[var(--color-primary-700)] inline-flex items-center justify-center gap-2 px-5 py-2.5 text-sm font-semibold transition border-[var(--color-primary-300)] text-[#fff] hover:bg-[var(--color-primary-100)]/35 hover:text-[var(--color-primary-700)] min-h-11 uppercase pl-[10px] pr-[0px] rounded-[10px] border-[1px] w-full addtocartButton relative cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed">
+ Buy Now
+ </button>
Removed / Before Commit
- import { useState, useEffect, useRef } from "react";
- import { CartButton } from "@/components/ui/cart-button";
- import { localCartCount, apiGetCart, isLoggedIn } from "@/lib/cart";
- import { cn } from "@/lib/utils";
- import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
- import { faUser } from "@fortawesome/free-solid-svg-icons";
- const [user, setUser] = useState<{ name?: string; email?: string } | null>(null);
- const [acctOpen, setAcctOpen] = useState(false);
- const [cartCount, setCartCount] = useState(0);
- const [toast, setToast] = useState(false);
- const accountMenuRef = useRef<HTMLDivElement>(null);
- 
- useEffect(() => {
- } catch {}
- };
- 
- useEffect(() => {
- refreshCartCount();
Added / After Commit
+ import { useState, useEffect, useRef } from "react";
+ import { CartButton } from "@/components/ui/cart-button";
+ import { localCartCount, apiGetCart, isLoggedIn } from "@/lib/cart";
+ import { apiGetWishlist } from "@/lib/wishlist";
+ import { cn } from "@/lib/utils";
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+ import { faUser } from "@fortawesome/free-solid-svg-icons";
+ const [user, setUser] = useState<{ name?: string; email?: string } | null>(null);
+ const [acctOpen, setAcctOpen] = useState(false);
+ const [cartCount, setCartCount] = useState(0);
+   const [wishlistCount, setWishlistCount] = useState(0);
+ const [toast, setToast] = useState(false);
+   const [wishlistToast, setWishlistToast] = useState(false);
+   const [shareToast, setShareToast] = useState(false);
+ const accountMenuRef = useRef<HTMLDivElement>(null);
+ 
+ useEffect(() => {
+ } catch {}
Removed / Before Commit

                                                
Added / After Commit
+ export async function shareProduct(slug: string, title: string): Promise<void> {
+   const url = `${window.location.origin}/shop/${slug}`;
+ 
+   if (navigator.share) {
+     await navigator.share({ title, url });
+   } else {
+     await navigator.clipboard.writeText(url);
+   }
+ 
+   window.dispatchEvent(new Event("product-shared"));
+ }
Removed / Before Commit

                                                
Added / After Commit
+ import { getToken } from "@/lib/cart";
+ 
+ export type WishlistItem = {
+   id: number;
+   product_id: number;
+   slug: string;
+   title: string;
+   thumbnail: string | null;
+   attribute_name: string | null;
+   attribute_value: string | null;
+   variant_name?: string | null;
+   selling_price: number;
+   mrp: number;
+   category?: string | null;
+ };
+ 
+ const API = process.env.NEXT_PUBLIC_API_URL ?? "";
+