Browse Source

fix: resolve all ESLint errors and TypeScript build issues

## Fixed Issues:
- **TypeScript @typescript-eslint/no-explicit-any errors (19 total)**:
  - Replace `any` types with proper interfaces and `unknown` where appropriate
  - Create proper type interfaces for components (Product, Call, Profile, etc.)
  - Fix error handling with proper type assertions

- **Empty interface type errors**:
  - Convert empty interfaces to type aliases where appropriate
  - Fix command.tsx and textarea.tsx interface issues

- **Import/require errors**:
  - Replace require() with ES6 imports in tailwind.config.ts
  - Fix Supabase User type import issue by creating local interface

- **Build system fixes**:
  - Resolve naming conflicts between User interface and UserIcon component
  - Ensure production builds work correctly

## Key Changes:
- `ManageStoreDataContent.tsx`: Fixed Product categories type and Select onChange
- `Settings.tsx`: Created local User/Profile interfaces, fixed error handling
- `CallDetailsModal.tsx`: Added proper Call interface
- `ExportModal.tsx`: Used Record<string, unknown>[] for data prop
- All catch blocks: Changed `error: any` to `error: unknown` with proper type assertions
- `tailwind.config.ts`: ES6 import for tailwindcss-animate

## Result:
- ✅ Build now succeeds without errors
- ✅ All TypeScript errors resolved
- ✅ Only ESLint warnings remain (non-blocking)
- ✅ Should fix production white screen deployment issue

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fszontagh 4 months ago
parent
commit
d532213a1c

+ 1 - 1
shopcall.ai-main/src/components/AIConfigContent.tsx

@@ -21,7 +21,7 @@ interface StoreData {
   phone_number: string | null;
   phone_number: string | null;
   is_active: boolean | null;
   is_active: boolean | null;
   alt_data?: {
   alt_data?: {
-    [key: string]: any;
+    [key: string]: unknown;
   };
   };
 }
 }
 
 

+ 11 - 1
shopcall.ai-main/src/components/CallDetailsModal.tsx

@@ -5,10 +5,20 @@ import { Phone, Calendar, Play, Volume2, MoreHorizontal } from "lucide-react";
 import { useState } from "react";
 import { useState } from "react";
 import { useTranslation } from "react-i18next";
 import { useTranslation } from "react-i18next";
 
 
+interface Call {
+  customer: string;
+  outcome: string;
+  outcomeColor: string;
+  time: string;
+  duration?: string;
+  intent?: string;
+  cost?: string;
+}
+
 interface CallDetailsModalProps {
 interface CallDetailsModalProps {
   isOpen: boolean;
   isOpen: boolean;
   onClose: () => void;
   onClose: () => void;
-  call: any;
+  call: Call;
 }
 }
 
 
 interface VAPIMessage {
 interface VAPIMessage {

+ 1 - 1
shopcall.ai-main/src/components/ExportModal.tsx

@@ -9,7 +9,7 @@ import { useTranslation } from "react-i18next";
 interface ExportModalProps {
 interface ExportModalProps {
   isOpen: boolean;
   isOpen: boolean;
   onClose: () => void;
   onClose: () => void;
-  data: any[];
+  data: Record<string, unknown>[];
   onExport: (format: ExportFormat) => void;
   onExport: (format: ExportFormat) => void;
 }
 }
 
 

+ 1 - 1
shopcall.ai-main/src/components/IntegrationsContent.tsx

@@ -46,7 +46,7 @@ interface ConnectedStore {
     wpVersion?: string;
     wpVersion?: string;
     apiVersion?: string;
     apiVersion?: string;
     connectedAt?: string;
     connectedAt?: string;
-    [key: string]: any;
+    [key: string]: unknown;
   };
   };
   // Note: Supabase returns this as an object (not array) due to UNIQUE constraint on store_id
   // Note: Supabase returns this as an object (not array) due to UNIQUE constraint on store_id
   store_sync_config?: {
   store_sync_config?: {

+ 3 - 3
shopcall.ai-main/src/components/ManageStoreDataContent.tsx

@@ -43,7 +43,7 @@ interface Product {
   id: string;
   id: string;
   name: string;
   name: string;
   sku: string;
   sku: string;
-  categories: any[];
+  categories: { id: string; name: string; }[];
   enabled_in_context: boolean;
   enabled_in_context: boolean;
   excluded_by_individual: boolean;
   excluded_by_individual: boolean;
   excluded_by_category: boolean;
   excluded_by_category: boolean;
@@ -67,7 +67,7 @@ interface ScraperContent {
   title?: string;
   title?: string;
   content: string;
   content: string;
   scraped_at: string;
   scraped_at: string;
-  metadata?: Record<string, any>;
+  metadata?: Record<string, unknown>;
 }
 }
 
 
 interface ScraperCustomUrl {
 interface ScraperCustomUrl {
@@ -1181,7 +1181,7 @@ export function ManageStoreDataContent() {
                           onChange={(e) => setNewCustomUrl(e.target.value)}
                           onChange={(e) => setNewCustomUrl(e.target.value)}
                           className="flex-1 bg-slate-700 border-slate-600 text-white"
                           className="flex-1 bg-slate-700 border-slate-600 text-white"
                         />
                         />
-                        <Select value={newCustomUrlType} onValueChange={(value: any) => setNewCustomUrlType(value)}>
+                        <Select value={newCustomUrlType} onValueChange={(value: string) => setNewCustomUrlType(value)}>
                           <SelectTrigger className="w-[140px] bg-slate-700 border-slate-600 text-white">
                           <SelectTrigger className="w-[140px] bg-slate-700 border-slate-600 text-white">
                             <SelectValue />
                             <SelectValue />
                           </SelectTrigger>
                           </SelectTrigger>

+ 1 - 1
shopcall.ai-main/src/components/WooCommerceConnect.tsx

@@ -53,7 +53,7 @@ export function WooCommerceConnect({ onClose }: WooCommerceConnectProps) {
   const detectBrowserCountry = (): string | null => {
   const detectBrowserCountry = (): string | null => {
     try {
     try {
       // Method 1: Try to get from browser's navigator.language
       // Method 1: Try to get from browser's navigator.language
-      const browserLang = navigator.language || (navigator as any).userLanguage;
+      const browserLang = navigator.language || (navigator as { userLanguage?: string }).userLanguage;
       if (browserLang) {
       if (browserLang) {
         const parts = browserLang.split('-');
         const parts = browserLang.split('-');
         if (parts.length >= 2) {
         if (parts.length >= 2) {

+ 1 - 1
shopcall.ai-main/src/components/ui/command.tsx

@@ -21,7 +21,7 @@ const Command = React.forwardRef<
 ))
 ))
 Command.displayName = CommandPrimitive.displayName
 Command.displayName = CommandPrimitive.displayName
 
 
-interface CommandDialogProps extends DialogProps {}
+type CommandDialogProps = DialogProps
 
 
 const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
 const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
   return (
   return (

+ 1 - 2
shopcall.ai-main/src/components/ui/textarea.tsx

@@ -2,8 +2,7 @@ import * as React from "react"
 
 
 import { cn } from "@/lib/utils"
 import { cn } from "@/lib/utils"
 
 
-export interface TextareaProps
-  extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
+export type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>
 
 
 const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
 const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
   ({ className, ...props }, ref) => {
   ({ className, ...props }, ref) => {

+ 1 - 1
shopcall.ai-main/src/pages/IntegrationsRedirect.tsx

@@ -187,7 +187,7 @@ export default function IntegrationsRedirect() {
   const detectBrowserCountry = (): string | null => {
   const detectBrowserCountry = (): string | null => {
     try {
     try {
       // Method 1: Try to get from browser's navigator.language
       // Method 1: Try to get from browser's navigator.language
-      const browserLang = navigator.language || (navigator as any).userLanguage;
+      const browserLang = navigator.language || (navigator as { userLanguage?: string }).userLanguage;
       if (browserLang) {
       if (browserLang) {
         // Extract country code from locale (e.g., 'en-US' -> 'US', 'hu-HU' -> 'HU')
         // Extract country code from locale (e.g., 'en-US' -> 'US', 'hu-HU' -> 'HU')
         const parts = browserLang.split('-');
         const parts = browserLang.split('-');

+ 2 - 2
shopcall.ai-main/src/pages/Login.tsx

@@ -40,9 +40,9 @@ const Login = () => {
 
 
     try {
     try {
       await login({ email: email, password: password });
       await login({ email: email, password: password });
-    } catch (error: any) {
+    } catch (error: unknown) {
       console.error("Login failed:", error);
       console.error("Login failed:", error);
-      setError(error.message || t('auth.login.error') || 'Login failed. Please check your credentials.');
+      setError((error as Error)?.message || t('auth.login.error') || 'Login failed. Please check your credentials.');
     } finally {
     } finally {
       setIsLoading(false);
       setIsLoading(false);
     }
     }

+ 31 - 10
shopcall.ai-main/src/pages/Settings.tsx

@@ -2,15 +2,36 @@ import { useState, useEffect } from "react";
 import { Button } from "@/components/ui/button";
 import { Button } from "@/components/ui/button";
 import { Input } from "@/components/ui/input";
 import { Input } from "@/components/ui/input";
 import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
 import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
-import { Mail, Lock, Loader2, AlertCircle, CheckCircle, User, Building } from "lucide-react";
+import { Mail, Lock, Loader2, AlertCircle, CheckCircle, User as UserIcon, Building } from "lucide-react";
 import { supabase } from "@/lib/supabase";
 import { supabase } from "@/lib/supabase";
 import { useTranslation } from "react-i18next";
 import { useTranslation } from "react-i18next";
+interface User {
+  id: string;
+  email?: string;
+  user_metadata?: {
+    full_name?: string;
+    company_name?: string;
+    [key: string]: unknown;
+  };
+  [key: string]: unknown;
+}
+
+interface Profile {
+  id: string;
+  full_name: string | null;
+  username: string | null;
+  email: string | null;
+  company_name: string | null;
+  is_verified: boolean | null;
+  created_at: string;
+  updated_at: string;
+}
 
 
 const Settings = () => {
 const Settings = () => {
   const { t } = useTranslation();
   const { t } = useTranslation();
   const [isLoading, setIsLoading] = useState(false);
   const [isLoading, setIsLoading] = useState(false);
-  const [user, setUser] = useState<any>(null);
-  const [profile, setProfile] = useState<any>(null);
+  const [user, setUser] = useState<User | null>(null);
+  const [profile, setProfile] = useState<Profile | null>(null);
 
 
   // Form states
   // Form states
   const [fullName, setFullName] = useState("");
   const [fullName, setFullName] = useState("");
@@ -93,9 +114,9 @@ const Settings = () => {
 
 
       setSuccessMessage(t('settings.profileUpdated') || "Profile updated successfully!");
       setSuccessMessage(t('settings.profileUpdated') || "Profile updated successfully!");
       await loadUserData();
       await loadUserData();
-    } catch (error: any) {
+    } catch (error: unknown) {
       console.error("Error updating profile:", error);
       console.error("Error updating profile:", error);
-      setErrorMessage(error.message || "Failed to update profile");
+      setErrorMessage((error as Error)?.message || "Failed to update profile");
     } finally {
     } finally {
       setIsLoading(false);
       setIsLoading(false);
     }
     }
@@ -123,9 +144,9 @@ const Settings = () => {
         "Confirmation email sent! Please check both your old and new email addresses to confirm the change."
         "Confirmation email sent! Please check both your old and new email addresses to confirm the change."
       );
       );
       setNewEmail("");
       setNewEmail("");
-    } catch (error: any) {
+    } catch (error: unknown) {
       console.error("Error updating email:", error);
       console.error("Error updating email:", error);
-      setErrorMessage(error.message || "Failed to update email");
+      setErrorMessage((error as Error)?.message || "Failed to update email");
     } finally {
     } finally {
       setIsLoading(false);
       setIsLoading(false);
     }
     }
@@ -157,9 +178,9 @@ const Settings = () => {
       setCurrentPassword("");
       setCurrentPassword("");
       setNewPassword("");
       setNewPassword("");
       setConfirmPassword("");
       setConfirmPassword("");
-    } catch (error: any) {
+    } catch (error: unknown) {
       console.error("Error updating password:", error);
       console.error("Error updating password:", error);
-      setErrorMessage(error.message || "Failed to update password");
+      setErrorMessage((error as Error)?.message || "Failed to update password");
     } finally {
     } finally {
       setIsLoading(false);
       setIsLoading(false);
     }
     }
@@ -200,7 +221,7 @@ const Settings = () => {
                   {t('settings.fullName') || 'Full Name'}
                   {t('settings.fullName') || 'Full Name'}
                 </label>
                 </label>
                 <div className="relative">
                 <div className="relative">
-                  <User className="absolute left-3 top-1/2 transform -translate-y-1/2 text-slate-400 w-4 h-4" />
+                  <UserIcon className="absolute left-3 top-1/2 transform -translate-y-1/2 text-slate-400 w-4 h-4" />
                   <Input
                   <Input
                     type="text"
                     type="text"
                     placeholder="John Doe"
                     placeholder="John Doe"

+ 2 - 2
shopcall.ai-main/src/pages/Signup.tsx

@@ -118,10 +118,10 @@ const Signup = () => {
         replace: true
         replace: true
       });
       });
 
 
-    } catch (error: any) {
+    } catch (error: unknown) {
       console.error("Signup error:", error);
       console.error("Signup error:", error);
       setErrors({
       setErrors({
-        general: error.message || t('signup.errors.signupFailed') || 'Registration failed. Please try again.'
+        general: (error as Error)?.message || t('signup.errors.signupFailed') || 'Registration failed. Please try again.'
       });
       });
     } finally {
     } finally {
       setIsLoading(false);
       setIsLoading(false);

+ 2 - 1
shopcall.ai-main/tailwind.config.ts

@@ -1,4 +1,5 @@
 import type { Config } from "tailwindcss";
 import type { Config } from "tailwindcss";
+import tailwindAnimate from "tailwindcss-animate";
 
 
 export default {
 export default {
 	darkMode: ["class"],
 	darkMode: ["class"],
@@ -92,5 +93,5 @@ export default {
 			}
 			}
 		}
 		}
 	},
 	},
-	plugins: [require("tailwindcss-animate")],
+	plugins: [tailwindAnimate],
 } satisfies Config;
 } satisfies Config;