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

Review Result ?

jattin01/avriti · 4c8515a5
This commit introduces frontend enhancements including a banner and service-related features. It adds service support in the checkout and my-order pages, fetches and displays banners, and builds a detailed service detail page with tabs and consultation fee display. The code generally follows React and Next.js conventions with appropriate type usage and state handling. Some parts use dangerouslySetInnerHTML which presents potential security risks if data isn't sanitized server-side. There is no explicit input validation or error handling in fetch calls beyond basic try/catch. Shipping logic update for all-service orders is a good business optimization.
Quality ?
85%
Security ?
60%
Business Value ?
90%
Maintainability ?
83%
Issues & Suggested Fixes ?
1AI detects the issue
2Shows file, line, or evidence
3Suggests the fix to apply
Usage Of Dangerouslysetinnerhtml
Where app/services/[slug]/page.tsx:100
Issue / Evidence usage of dangerouslySetInnerHTML
Suggested Fix ensure server-side sanitization of HTML to prevent XSS vulnerabilities
Fetch Error Handling
Where app/services/[slug]/page.tsx:42
Issue / Evidence fetch error handling
Suggested Fix add user-visible error feedback in UI on fetch failure to improve UX
Empty Catch Block In Banner Fetch
Where app/page.tsx:123
Issue / Evidence empty catch block in banner fetch
Suggested Fix log or handle error to aid debugging and user experience
Shipping Logic
Where app/checkout/page.tsx:388-391
Issue / Evidence shipping logic
Suggested Fix consider adding unit tests to cover the isAllService branch for reliability
Button Disabling Logic
Where app/checkout/page.tsx:840
Issue / Evidence button disabling logic
Suggested Fix confirm all conditions correctly disable placement to prevent invalid state
Minor Issue
Where commit message
Issue / Evidence minor issue
Suggested Fix expand message with more details about changes to assist reviewers and future maintenance
Code Change Preview · app/checkout/page.tsx ?
Removed / Before Commit
- type CheckoutItem = {
- product_id: number | null;
- combo_product_id?: number | null;
- is_combo?: boolean;
- title: string;
- thumbnail?: string;
- attribute_name: string;
- setItems([{
- product_id: parsed.product_id ?? null,
- combo_product_id: parsed.combo_product_id ?? null,
- is_combo: !!parsed.is_combo,
- title: parsed.title,
- thumbnail: parsed.thumbnail ?? "",
-             attribute_name: parsed.attribute_name,
-             attribute_value: parsed.attribute_value,
- variant_name: parsed.variant_name,
- sku: parsed.sku ?? "",
- selling_price: parsed.selling_price ?? 0,
Added / After Commit
+ type CheckoutItem = {
+ product_id: number | null;
+ combo_product_id?: number | null;
+   service_detail_id?: number | null;
+ is_combo?: boolean;
+   is_service?: boolean;
+ title: string;
+ thumbnail?: string;
+ attribute_name: string;
+ setItems([{
+ product_id: parsed.product_id ?? null,
+ combo_product_id: parsed.combo_product_id ?? null,
+             service_detail_id: parsed.service_detail_id ?? null,
+ is_combo: !!parsed.is_combo,
+             is_service: !!parsed.is_service,
+ title: parsed.title,
+ thumbnail: parsed.thumbnail ?? "",
+             attribute_name: parsed.attribute_name ?? "",
Removed / Before Commit
- quantity: number;
- total: number;
- product_image: string | null;
- }
- 
- interface OrderData {
- 
- <div className="min-w-0">
- <p className="truncate text-[15px] font-semibold text-[#111827]">
-                       {item.product_name}
- </p>
- {formatAttributeLabel(item) && (
- <p className="mt-1 text-[12px] text-[#7A7A7A]">
Added / After Commit
+ quantity: number;
+ total: number;
+ product_image: string | null;
+   is_service?: boolean;
+ }
+ 
+ interface OrderData {
+ 
+ <div className="min-w-0">
+ <p className="truncate text-[15px] font-semibold text-[#111827]">
+                       {item.product_name}{item.is_service ? " (Service)" : ""}
+ </p>
+ {formatAttributeLabel(item) && (
+ <p className="mt-1 text-[12px] text-[#7A7A7A]">
Removed / Before Commit
- "from-[#F4F0E8] to-[#EDE4DC]",
- ];
- 
- const offerBanners = ["/offerBanner1.png", "/offerBanner1.png", "/offerBanner1.png"];
- 
- export default function Home() {
- const [home, setHome] = useState<HomeData | null>(null);
- const [featuredProducts, setFeaturedProducts] = useState<FeaturedProduct[]>([]);
- const [activeOfferIndex, setActiveOfferIndex] = useState(0);
- 
- useEffect(() => {
- Promise.all([
- }, []);
- 
- useEffect(() => {
- const intervalId = window.setInterval(() => {
-       setActiveOfferIndex((current) => (current + 1) % offerBanners.length);
- }, 4000);
Added / After Commit
+ "from-[#F4F0E8] to-[#EDE4DC]",
+ ];
+ 
+ type BannerItem = { id: number; image: string; url: string };
+ 
+ export default function Home() {
+ const [home, setHome] = useState<HomeData | null>(null);
+ const [featuredProducts, setFeaturedProducts] = useState<FeaturedProduct[]>([]);
+ const [activeOfferIndex, setActiveOfferIndex] = useState(0);
+   const [banners, setBanners] = useState<BannerItem[]>([]);
+ 
+ useEffect(() => {
+ Promise.all([
+ }, []);
+ 
+ useEffect(() => {
+     fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/banners`)
+       .then((res) => res.json())
Removed / Before Commit
- import Link from "next/link";
- import { notFound } from "next/navigation";
- import { CalendarDays, Check, MessageCircle } from "lucide-react";
- import { Badge } from "@/components/ui/badge";
- import { Button } from "@/components/ui/button";
- import { Card } from "@/components/ui/card";
- import { services } from "@/lib/data";
- 
- export function generateStaticParams() {
-   return services.map((service) => ({ slug: service.slug }));
- }
- 
- export default async function ServiceDetailPage({
-   params,
- }: {
-   params: Promise<{ slug: string }>;
- }) {
-   const { slug } = await params;
Added / After Commit
+ "use client";
+ 
+ import { useEffect, useState } from "react";
+ import { useParams } from "next/navigation";
+ import Link from "next/link";
+ import { isLoggedIn } from "@/lib/cart";
+ 
+ type OtherDetail = {
+   sno: number;
+   section_name: string;
+   details: string;
+ };
+ 
+ type ServiceDetail = {
+   id: number;
+   name: string;
+   slug: string;
+   short_description: string;
Removed / Before Commit
- 
- import { useEffect, useState } from "react";
- import Image from "next/image";
- import { PdfBrowserFrame } from "@/components/pdf-browser-frame";
- 
- type ServiceCard = {
- cards: ServiceCard[];
- };
- 
- export default function ServicesPage() {
- const [serviceData, setServiceData] = useState<ServiceData | null>(null);
- const cards = serviceData?.cards ?? [];
- 
- useEffect(() => {
- fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/services`)
- .then((res) => res.json())
-       .then((data) => {
-         if (data.success && data.data) {
Added / After Commit
+ 
+ import { useEffect, useState } from "react";
+ import Image from "next/image";
+ import Link from "next/link";
+ import { PdfBrowserFrame } from "@/components/pdf-browser-frame";
+ 
+ type ServiceCard = {
+ cards: ServiceCard[];
+ };
+ 
+ type ServiceDetailCard = {
+   id: number;
+   name: string;
+   slug: string;
+   short_description: string;
+   icon: string | null;
+   image: string | null;
+   consultation_fee: string;
Removed / Before Commit
- whatToExpect,
- }: ProductAccordionProps) {
- const sections: AccordionItem[] = [
-     ...(disclaimer
-       ? [
-           {
-             title: "Disclaimer",
-             defaultOpen: false,
-             content: (
-               <div
-                 className="prose prose-sm max-w-none [&_p]:mb-3 [&_p:last-child]:mb-0"
-                 dangerouslySetInnerHTML={{ __html: disclaimer }}
-               />
-             ),
-           },
-         ]
-       : []),
- ...(chakraAlignment
Added / After Commit
+ whatToExpect,
+ }: ProductAccordionProps) {
+ const sections: AccordionItem[] = [
+ ...(chakraAlignment
+ ? [{ title: "Chakra Alignment", defaultOpen: false, content: <p>{chakraAlignment}</p> }]
+ : []),
+ </div>
+ ),
+ },
+     ...(disclaimer
+       ? [
+           {
+             title: "Disclaimer",
+             defaultOpen: false,
+             content: (
+               <div
+                 className="prose prose-sm max-w-none [&_p]:mb-3 [&_p:last-child]:mb-0"
+                 dangerouslySetInnerHTML={{ __html: disclaimer }}
Removed / Before Commit
- 
- 
- 
- 
- 
- 
- // "use client";
- 
- // import { useState } from "react";
- 
- // 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." }}
- //     />
Added / After Commit
+ 
+ 
+ 
Removed / Before Commit
- export type LocalCartItem = {
- product_id?: number | null;
- combo_product_id?: number | null;
- slug: string;
- title: string;
- thumbnail: string;
- mrp: number;
- quantity: number;
- is_combo?: boolean;
- };
- 
- const CART_KEY = "avriti_cart";
- export async function apiAddToCart(item: {
- product_id?: number;
- combo_product_id?: number;
- attribute_name?: string;
- attribute_value?: string;
- quantity: number;
Added / After Commit
+ export type LocalCartItem = {
+ product_id?: number | null;
+ combo_product_id?: number | null;
+   service_detail_id?: number | null;
+ slug: string;
+ title: string;
+ thumbnail: string;
+ mrp: number;
+ quantity: number;
+ is_combo?: boolean;
+   is_service?: boolean;
+ };
+ 
+ const CART_KEY = "avriti_cart";
+ export async function apiAddToCart(item: {
+ product_id?: number;
+ combo_product_id?: number;
+   service_detail_id?: number;