AI Review Center
Commit Review Workspace ?
Select a commit on the left to inspect quality, security, business value, findings, and suggested code changes.
Project AI Score
?
63%
Quality Avg
?
68%
Security Avg
?
45%
Reviews
?
56
Review Result ?
jattin01/avriti · 0b2ae90b
This commit adds a profile page with customer profile management including profile image upload and address display. It includes appropriate states, API calls with authentication headers, and form handling. The user can edit and save their profile information, which is reflected in localStorage for persistence. The UI supports both display and edit modes with clear feedback messages. The profile image upload uses FormData and updates the UI upon success. Some improvements in security checks, input validation, and error handling are recommended.
Quality
?
85%
Security
?
50%
Business Value
?
85%
Maintainability
?
83%
Issues & Suggested Fixes
?
1AI detects the issue
2Shows file, line, or evidence
3Suggests the fix to apply
Missing Validation
Where
app/profile/page.tsx:170
Issue / Evidence
Sending auth headers directly without validation
Suggested Fix
add validation or refresh tokens before API calls to improve security and bug risk
Empty Catch Block On Localstorage Set
Where
app/profile/page.tsx:134
Issue / Evidence
Empty catch block on localStorage set
Suggested Fix
add error logging or handling to debug issues on localStorage failures
Missing Validation
Where
app/profile/page.tsx:264
Issue / Evidence
Email input missing type and validation aside from placeholder
Suggested Fix
add proper email validation on client side to improve quality and reduce bug risks
Missing Validation
Where
app/profile/page.tsx:210
Issue / Evidence
No validation of uploaded image file
Suggested Fix
add client-side file type and size validation to reduce bug risks and security issues (e.g. large files or invalid types)
Redirect To Login On Missing Headers
Where
app/profile/page.tsx:109
Issue / Evidence
Redirect to login on missing headers
Suggested Fix
add a user feedback before redirect or handle with route guards to improve user experience and business value
Non Descriptive Message
Where
commit message
Issue / Evidence
non-descriptive message
Suggested Fix
replace with a more detailed commit message explaining what profile page features and fixes are included to improve traceability and business value
Code Change Preview · app/checkout/page.tsx
?
Removed / Before Commit
- }; - - const saveAddress = async () => { - if (!modalForm.full_name || !modalForm.phone || !modalForm.address_line1 || - !modalForm.city || !modalForm.state || !modalForm.pincode || !modalForm.country) { - setModalError("Please fill all required fields."); - return; - )} - - <div className="grid gap-4 sm:grid-cols-2"> - <label className="block"> - <span className={labelCls}>Full Name *</span> - <input type="text" value={ship.full_name} onChange={e => setShip(s => ({ ...s, full_name: e.target.value }))} placeholder="John Doe" className={inputCls} /> - </label> - <label className="block"> - <span className={labelCls}>Phone *</span> - <input type="tel" value={ship.phone} onChange={e => setShip(s => ({ ...s, phone: e.target.value }))} placeholder="+91 98765 43210" className={inputCls} /> - </label>
Added / After Commit
+ }; + + const saveAddress = async () => { + if (!modalForm.full_name || !modalForm.phone || !modalForm.email || !modalForm.address_line1 || + !modalForm.city || !modalForm.state || !modalForm.pincode || !modalForm.country) { + setModalError("Please fill all required fields."); + return; + )} + + <div className="grid gap-4 sm:grid-cols-2"> + {[ + ["Full Name", ship.full_name], + ["Phone", ship.phone], + ["Email", ship.email], + ["Country", ship.country], + ["Address Line 1", ship.address_line1, "sm:col-span-2"], + ["Address Line 2", ship.address_line2, "sm:col-span-2"], + ["Landmark", ship.landmark],
Removed / Before Commit
- import type { ReactNode } from "react"; - import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; - import { - faBoxOpen, faPen, faTrash, faPlus, - } from "@fortawesome/free-solid-svg-icons"; - - - interface Address { - id: number; - type: string; - full_name: string; - phone: string; - email?: string; - address_line1: string; - address_line2?: string; - city: string; - state: string; - pincode: string;
Added / After Commit
+ import type { ReactNode } from "react"; + import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + import { + faBoxOpen, faPen, + } from "@fortawesome/free-solid-svg-icons"; + import { CustomerAddresses } from "@/components/customer-addresses"; + + + interface Address { + id: number; + full_name: string; + phone: string; + email?: string; + address_line1: string; + address_line2?: string; + landmark?: string; + city: string; + state: string;
Removed / Before Commit
- category: string; - badge: string; - description: string; - }; - - export default function ProductDetailPage() { - const params = useParams(); - const slug = Array.isArray(params?.slug) ? params.slug[0] : (params?.slug ?? ""); - - const [featuredProducts, setFeaturedProducts] = useState<FeaturedProduct[]>([]); - - useEffect(() => { - fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/product?featured=true`) - .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);
Added / After Commit
+ category: string; + badge: string; + description: string; + longdescription: string; + }; + + export default function ProductDetailPage() { + const params = useParams(); + const slug = Array.isArray(params?.slug) ? params.slug[0] : (params?.slug ?? ""); + + const [featuredProducts, setFeaturedProducts] = useState<FeaturedProduct[]>([]); + const [description, setDescription] = useState(""); + + useEffect(() => { + fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/product`) + .then((res) => res.json()) + .then((data) => { + if (data.success && Array.isArray(data.data)) {
Removed / Before Commit
Added / After Commit
+ "use client"; + + import { useState } from "react"; + + export interface CustomerAddress { + id: number; + full_name: string; + phone: string; + email?: string; + address_line1: string; + address_line2?: string; + landmark?: string; + city: string; + state: string; + pincode: string; + country: string; + address_type: string; + is_default: boolean;
Removed / Before Commit
- {product.attrValue ? ` - ${product.attrValue}${product.variantName ? ` ${product.variantName}` : ''}` : ''} - </h3> - <button type="button" onClick={handleWishlist} aria-label="Add to wishlist" className="cursor-pointer"> - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill={wishlisted ? "#0b3dba" : "none"} stroke="#0b3dba" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> - <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/> - </svg> - </button>
Added / After Commit
+ {product.attrValue ? ` - ${product.attrValue}${product.variantName ? ` ${product.variantName}` : ''}` : ''} + </h3> + <button type="button" onClick={handleWishlist} aria-label="Add to wishlist" className="cursor-pointer"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill={wishlisted ? "#FF0000" : "none"} stroke="#FF0000" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> + <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/> + </svg> + </button>
Removed / Before Commit
- - const tabs = ["Description", "Reviews", "Shipping"]; - - const tabContent: Record<string, React.ReactNode> = { - Description: ( - <p className="text-gray-600 text-sm leading-relaxed"> - The world is loud. Notifications, deadlines, demands. Everyone wants your attention, your time, your energy. Somewhere in that noise, you lose yourself.The world is loud. Notifications, deadlines, demands. Everyone wants your attention, your time, your energy. Somewhere in that noise, you lose yourself.The world is loud. Notifications, deadlines, demands. Everyone wants your attention, your time, your energy. Somewhere in that noise, you lose yourself. - </p> - ), - Reviews: ( - <p className="text-gray-600 text-sm leading-relaxed"> - Free delivery on orders above ₹499. Standard delivery in 3-5 business days. - </p> - ), - }; - - export default function ProductTabs() { - const [activeTab, setActiveTab] = useState("Description");
Added / After Commit
+ + const tabs = ["Description", "Reviews", "Shipping"]; + + const tabContent = (description?: string): Record<string, React.ReactNode> => ({ + Description: ( + <div + className="text-gray-600 text-sm leading-relaxed" + dangerouslySetInnerHTML={{ __html: description || "No description available." }} + /> + ), + Reviews: ( + <p className="text-gray-600 text-sm leading-relaxed"> + Free delivery on orders above ₹499. Standard delivery in 3-5 business days. + </p> + ), + }); + + export default function ProductTabs({ description }: { description?: string }) {
Removed / Before Commit
- title: string; - slug: string; - short_description?: string; - attributes?: Attribute[]; - thumbnail?: string[]; - category?: { name: string }; - )}</div> - {/* Attribute Pills */} - {product.attributes && product.attributes.length > 0 && ( - <div className="mb-5 flex gap-2 items-center"> - <p className="text-xs font-semibold uppercase text-[#000]">Select {product.variant?.name ?? "Variant"} :</p> - - <div className="flex flex-wrap gap-2"> - {/* // Old: no out-of-stock strikethrough on variant pills */} - {product.attributes.map((attr) => ( - <button
Added / After Commit
+ title: string; + slug: string; + short_description?: string; + + attributes?: Attribute[]; + thumbnail?: string[]; + category?: { name: string }; + )}</div> + {/* Attribute Pills */} + {product.attributes && product.attributes.length > 0 && ( + <div className="mb-5 flex gap-2 items-center "> + <p className="text-xs font-semibold uppercase shrink-0 text-[#000]">Select {product.variant?.name ?? "Variant"} :</p> + + <div className="flex overflow-x-auto whitespace-nowrap gap-2 scrollbar-hide [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]"> + {/* // Old: no out-of-stock strikethrough on variant pills */} + {product.attributes.map((attr) => ( + <button
Removed / Before Commit
- category?: string | null; - }; - - const API = process.env.NEXT_PUBLIC_API_URL ?? ""; - - export async function apiGetWishlist(): Promise<WishlistItem[]> { - const token = getToken();
Added / After Commit
+ category?: string | null; + }; + + const API = process.env.NEXT_PUBLIC_API_URL; + + export async function apiGetWishlist(): Promise<WishlistItem[]> { + const token = getToken();