From 23efcab80c069db81a85f1f4d66c561a0379ffb6 Mon Sep 17 00:00:00 2001 From: ianshaloom Date: Sun, 8 Mar 2026 00:45:57 +0300 Subject: [PATCH] fix: resolve CI and workspace lint errors (admin + storefront) - Allow require() in next.config.js (eslint-disable) for both apps - Replace all catch (e: any) with catch (e: unknown) and proper error handling - Remove no-explicit-any: add types (PreviewProduct, ProductImage, Id, ProductDetailReview, error payloads) across admin and storefront - Admin: use next/image in ImageUploadSection and ProductImageCarousel; remove unused layout fonts and sidebar imports; fix products page useMemo deps - Storefront: use Link for /sign-in in header actions; fix useAddressMutations and product detail types; remove unused imports/vars and fix useMemo deps Made-with: Cursor --- apps/admin/next.config.js | 1 + .../admin/src/app/(dashboard)/images/page.tsx | 7 +++-- .../(dashboard)/products/[id]/edit/page.tsx | 8 +++--- .../src/app/(dashboard)/products/new/page.tsx | 4 +-- .../src/app/(dashboard)/products/page.tsx | 13 +++++---- apps/admin/src/app/layout.tsx | 14 ++-------- .../components/images/ImageUploadSection.tsx | 27 ++++++++++++------- .../images/ProductImageCarousel.tsx | 10 ++++--- .../images/ProductSearchSection.tsx | 2 +- .../components/layout/sidebar/app-sidebar.tsx | 2 -- .../orders/actions/AcceptReturnButton.tsx | 4 +-- .../orders/actions/CreateLabelButton.tsx | 4 +-- .../orders/actions/IssueRefundButton.tsx | 4 +-- .../actions/MarkReturnReceivedButton.tsx | 4 +-- .../orders/actions/UpdateStatusDialog.tsx | 4 +-- .../shared/ProductSearchSection.tsx | 2 +- .../variants/CreateVariantDialog.tsx | 4 +-- .../components/variants/EditVariantDialog.tsx | 4 +-- .../src/components/variants/VariantsTable.tsx | 8 +++--- apps/storefront/next.config.js | 1 + .../checkout/content/AddressSelector.tsx | 2 +- .../header/desktop/HeaderUserAction.tsx | 5 ++-- .../header/mobile/MobileHeaderUserAction.tsx | 5 ++-- .../reviews/ProductDetailReviewsPanel.tsx | 4 +-- .../sections/ProductDetailHeroSection.tsx | 5 +++- .../ProductDetailHeroSectionWrapper.tsx | 2 +- .../sections/ProductDetailSectionsWrapper.tsx | 1 - .../src/components/shop/ShopFilterContent.tsx | 10 ------- .../src/components/shop/ShopFilterSidebar.tsx | 1 - .../src/components/shop/ShopToolbar.tsx | 1 - .../components/wishlist/WishlistPageView.tsx | 3 +-- .../wishlist/state/WishlistEmptyState.tsx | 1 - .../src/lib/checkout/useAddressMutations.ts | 7 ++--- .../src/lib/search/useClickOutside.test.tsx | 2 +- 34 files changed, 87 insertions(+), 89 deletions(-) diff --git a/apps/admin/next.config.js b/apps/admin/next.config.js index 77df6d7..5155e0c 100644 --- a/apps/admin/next.config.js +++ b/apps/admin/next.config.js @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-require-imports -- Next.js config commonly uses require */ const path = require("path"); /** @type {import('next').NextConfig} */ diff --git a/apps/admin/src/app/(dashboard)/images/page.tsx b/apps/admin/src/app/(dashboard)/images/page.tsx index 3c301fb..6e70e79 100644 --- a/apps/admin/src/app/(dashboard)/images/page.tsx +++ b/apps/admin/src/app/(dashboard)/images/page.tsx @@ -5,7 +5,10 @@ import { useQuery } from "convex/react" import { api } from "../../../../../../convex/_generated/api" import type { Id } from "../../../../../../convex/_generated/dataModel" import { ProductSearchSection } from "../../../components/shared/ProductSearchSection" -import { ProductImageCarousel } from "../../../components/images/ProductImageCarousel" +import { + ProductImageCarousel, + type ProductImage, +} from "../../../components/images/ProductImageCarousel" import { ImageUploadSection } from "../../../components/images/ImageUploadSection" import { Skeleton } from "@/components/ui/skeleton" import { Separator } from "@/components/ui/separator" @@ -79,7 +82,7 @@ export default function ImagesPage() { ) : ( setShowUpload(true)} /> )} diff --git a/apps/admin/src/app/(dashboard)/products/[id]/edit/page.tsx b/apps/admin/src/app/(dashboard)/products/[id]/edit/page.tsx index 08affc5..e063890 100644 --- a/apps/admin/src/app/(dashboard)/products/[id]/edit/page.tsx +++ b/apps/admin/src/app/(dashboard)/products/[id]/edit/page.tsx @@ -53,8 +53,8 @@ export default function EditProductPage() { categoryId: payload.categoryId as Id<"categories">, }) router.push("/products") - } catch (e: any) { - setError(e?.message ?? "Failed to save product. Please try again.") + } catch (e: unknown) { + setError(e instanceof Error ? e.message : "Failed to save product. Please try again.") setIsSubmitting(false) } } @@ -64,8 +64,8 @@ export default function EditProductPage() { try { await archiveProduct({ id: productId }) router.push("/products") - } catch (e: any) { - setError(e?.message ?? "Failed to archive product.") + } catch (e: unknown) { + setError(e instanceof Error ? e.message : "Failed to archive product.") setIsArchiving(false) } } diff --git a/apps/admin/src/app/(dashboard)/products/new/page.tsx b/apps/admin/src/app/(dashboard)/products/new/page.tsx index c52eeb0..166e184 100644 --- a/apps/admin/src/app/(dashboard)/products/new/page.tsx +++ b/apps/admin/src/app/(dashboard)/products/new/page.tsx @@ -33,8 +33,8 @@ export default function NewProductPage() { categoryId: payload.categoryId as Id<"categories">, }) router.push("/products") - } catch (e: any) { - setError(e?.message ?? "Failed to create product. Please try again.") + } catch (e: unknown) { + setError(e instanceof Error ? e.message : "Failed to create product. Please try again.") setIsSubmitting(false) } } diff --git a/apps/admin/src/app/(dashboard)/products/page.tsx b/apps/admin/src/app/(dashboard)/products/page.tsx index 7d9584b..80de090 100644 --- a/apps/admin/src/app/(dashboard)/products/page.tsx +++ b/apps/admin/src/app/(dashboard)/products/page.tsx @@ -199,11 +199,14 @@ export default function ProductsPage() { ? searchResults === undefined : listStatus === "LoadingFirstPage" - const rawProducts = isSearching ? (searchResults ?? []) : listResults + const rawProducts = useMemo( + () => (isSearching ? (searchResults ?? []) : listResults), + [isSearching, searchResults, listResults], + ) const products = useMemo(() => { if (!sortField) return rawProducts - return [...rawProducts].sort((a: any, b: any) => { + return [...rawProducts].sort((a: PreviewProduct, b: PreviewProduct) => { const aVal: string = sortField === "name" ? (a.name ?? "") @@ -235,8 +238,8 @@ export default function ProductsPage() { setVisibleCols((prev) => ({ ...prev, [key]: checked })) } - function openPreview(product: any) { - setPreviewProduct(product as PreviewProduct) + function openPreview(product: PreviewProduct) { + setPreviewProduct(product) setPreviewOpen(true) } @@ -374,7 +377,7 @@ export default function ProductsPage() { ) : ( - products.map((product: any) => { + products.map((product: PreviewProduct) => { const statusCfg = STATUS_CONFIG[product.status as keyof typeof STATUS_CONFIG] return ( diff --git a/apps/admin/src/app/layout.tsx b/apps/admin/src/app/layout.tsx index aef44ec..bde81e9 100644 --- a/apps/admin/src/app/layout.tsx +++ b/apps/admin/src/app/layout.tsx @@ -1,21 +1,11 @@ import type { Metadata } from "next"; -import { DM_Sans, Geist, Geist_Mono } from "next/font/google"; +import { DM_Sans } from "next/font/google"; import { ClerkProvider } from "@clerk/nextjs"; import { ConvexClientProvider } from "@repo/convex"; import { Toaster } from "sonner"; import "./globals.css"; -const dmSans = DM_Sans({subsets:['latin'],variable:'--font-sans'}); - -const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], -}); - -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", - subsets: ["latin"], -}); +const dmSans = DM_Sans({ subsets: ["latin"], variable: "--font-sans" }); export const metadata: Metadata = { title: { diff --git a/apps/admin/src/components/images/ImageUploadSection.tsx b/apps/admin/src/components/images/ImageUploadSection.tsx index fb7a528..8e51939 100644 --- a/apps/admin/src/components/images/ImageUploadSection.tsx +++ b/apps/admin/src/components/images/ImageUploadSection.tsx @@ -1,6 +1,7 @@ "use client" import { useState, useRef } from "react" +import Image from "next/image" import { useMutation } from "convex/react" import { api } from "../../../../../convex/_generated/api" import type { Id } from "../../../../../convex/_generated/dataModel" @@ -61,8 +62,8 @@ export function ImageUploadSection({ }) if (!res.ok) { - const errJson = await res.json().catch(() => ({})) - throw new Error((errJson as any).detail ?? "Background removal failed") + const errJson = (await res.json().catch(() => ({}))) as { detail?: string } + throw new Error(errJson.detail ?? "Background removal failed") } const blob = await res.blob() @@ -100,8 +101,8 @@ export function ImageUploadSection({ }) if (!uploadRes.ok) { - const errJson = await uploadRes.json().catch(() => ({})) - throw new Error((errJson as any).error ?? "Upload failed") + const errJson = (await uploadRes.json().catch(() => ({}))) as { error?: string } + throw new Error(errJson.error ?? "Upload failed") } const { url } = await uploadRes.json() @@ -188,8 +189,14 @@ export function ImageUploadSection({

Original

{localUrl && ( -
- Original +
+ Original
)}
@@ -199,11 +206,13 @@ export function ImageUploadSection({ {isProcessing ? ( ) : processedUrl ? ( -
- + Background removed
) : processingError ? ( diff --git a/apps/admin/src/components/images/ProductImageCarousel.tsx b/apps/admin/src/components/images/ProductImageCarousel.tsx index 644328b..925b28d 100644 --- a/apps/admin/src/components/images/ProductImageCarousel.tsx +++ b/apps/admin/src/components/images/ProductImageCarousel.tsx @@ -1,6 +1,7 @@ "use client" import { useState, useEffect } from "react" +import Image from "next/image" import { DndContext, closestCenter, @@ -35,7 +36,7 @@ import { Button } from "@/components/ui/button" import { HugeiconsIcon } from "@hugeicons/react" import { Delete02Icon, ImageAdd01Icon, DragDropVerticalIcon } from "@hugeicons/core-free-icons" -interface ProductImage { +export interface ProductImage { _id: Id<"productImages"> url: string alt?: string @@ -105,11 +106,12 @@ function SortableImageCard({ {/* Row 2 in DOM → Row 2 visually (middle stays middle) */} {/* Image — appears in CENTER */} -
- + {image.alt
diff --git a/apps/admin/src/components/images/ProductSearchSection.tsx b/apps/admin/src/components/images/ProductSearchSection.tsx index 415d31c..6f57aaa 100644 --- a/apps/admin/src/components/images/ProductSearchSection.tsx +++ b/apps/admin/src/components/images/ProductSearchSection.tsx @@ -84,7 +84,7 @@ export function ProductSearchSection({ onSelect, onClear, selectedId }: ProductS {!isLoading && results && results.length > 0 && (
    - {results.map((product: any) => ( + {results.map((product: { _id: string; name: string }) => (