Fix IDE errors from ESLint cleanup

This commit is contained in:
Dwindi Ramadhana
2026-03-12 04:08:57 +07:00
parent 90169b508d
commit ab10c25c28
34 changed files with 155 additions and 258 deletions

View File

@@ -291,13 +291,6 @@ export default function Addresses() {
}
};
// Check if a field should be wide (full width)
const isFieldWide = (field: CheckoutField): boolean => {
const fieldName = field.key.replace(/^billing_/, '');
return ['address_1', 'address_2', 'email'].includes(fieldName) ||
field.class?.includes('form-row-wide') || false;
};
if (loading) {
return (
<div className="flex items-center justify-center py-12">

View File

@@ -1,9 +1,8 @@
import React, { useState, useEffect } from 'react';
import { Download, Loader2, FileText, ExternalLink } from 'lucide-react';
import { Download, Loader2, FileText } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { api } from '@/lib/api/client';
import { toast } from 'sonner';
import { formatPrice } from '@/lib/currency';
import SEOHead from '@/components/SEOHead';
interface DownloadItem {

View File

@@ -49,6 +49,7 @@ export default function OrderDetails() {
if (orderId) {
loadOrder();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [orderId]);
const loadOrder = async () => {

View File

@@ -22,6 +22,7 @@ export default function Orders() {
useEffect(() => {
loadOrders();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [page]);
const loadOrders = async () => {

View File

@@ -2,7 +2,6 @@ import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { Heart, ShoppingCart, Trash2, X } from 'lucide-react';
import { api } from '@/lib/api/client';
import { useCartStore } from '@/lib/cart/store';
import { Button } from '@/components/ui/button';
import { formatPrice } from '@/lib/currency';
import { toast } from 'sonner';
@@ -26,15 +25,20 @@ interface WishlistItem {
export default function Wishlist() {
const navigate = useNavigate();
const { addItem } = useCartStore();
const [items, setItems] = useState<WishlistItem[]>([]);
const [loading, setLoading] = useState(true);
const { isEnabled, isLoading: modulesLoading } = useModules();
const { settings: wishlistSettings } = useModuleSettings('wishlist');
useEffect(() => {
if (isEnabled('wishlist')) {
loadWishlist();
}
}, [isEnabled]);
if (modulesLoading) {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="flex items-center justify-center min-h-screen">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"></div>
</div>
);
@@ -57,10 +61,6 @@ export default function Wishlist() {
);
}
useEffect(() => {
loadWishlist();
}, []);
const loadWishlist = async () => {
try {
const data = await api.get<WishlistItem[]>('/account/wishlist');
@@ -91,7 +91,7 @@ export default function Wishlist() {
}
try {
const response = await api.post('/cart/add', {
await api.post('/cart/add', {
product_id: item.product_id,
quantity: 1,
});

View File

@@ -84,7 +84,7 @@ export function AccountLayout({ children }: AccountLayoutProps) {
// Full page reload to clear cookies and refresh state
const basePath = (window as any).woonoowCustomer?.basePath || '/store';
window.location.href = window.location.origin + basePath + '/';
} catch (error) {
} catch {
// Even on error, try to redirect and let server handle session
const basePath = (window as any).woonoowCustomer?.basePath || '/store';
window.location.href = window.location.origin + basePath + '/';
@@ -99,7 +99,7 @@ export function AccountLayout({ children }: AccountLayoutProps) {
};
// Logout Button with AlertDialog
const LogoutButton = () => (
const renderLogoutButton = () => (
<AlertDialog>
<AlertDialogTrigger asChild>
<button
@@ -131,7 +131,7 @@ export function AccountLayout({ children }: AccountLayoutProps) {
);
// Sidebar Navigation
const SidebarNav = () => (
const renderSidebarNav = () => (
<aside className="bg-white rounded-lg border p-4">
<div className="mb-6">
<div className="flex items-center gap-3 pb-4 border-b">
@@ -171,13 +171,13 @@ export function AccountLayout({ children }: AccountLayoutProps) {
);
})}
<LogoutButton />
{renderLogoutButton()}
</nav>
</aside>
);
// Tab Navigation (Mobile)
const TabNav = () => (
const renderTabNav = () => (
<div className="bg-white rounded-lg border mb-6 lg:hidden">
<nav className="flex overflow-x-auto">
{menuItems.map((item) => {
@@ -201,23 +201,21 @@ export function AccountLayout({ children }: AccountLayoutProps) {
);
// Responsive layout: Tabs on mobile, Sidebar on desktop
return (
<div className="py-8">
{/* Mobile: Tab Navigation */}
<TabNav />
<div className="py-8">
{/* Mobile: Tab Navigation */}
{renderTabNav()}
{/* Desktop: Sidebar + Content */}
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
<div className="hidden lg:block lg:col-span-1">
<SidebarNav />
</div>
<div className="lg:col-span-3">
<div className="bg-white rounded-lg border p-6">
{children}
</div>
{/* Desktop: Sidebar + Content */}
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
<div className="hidden lg:block lg:col-span-1">
{renderSidebarNav()}
</div>
<div className="lg:col-span-3">
<div className="bg-white rounded-lg border p-6">
{children}
</div>
</div>
</div>
);
</div>
}

View File

@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
import { useCartStore, type CartItem } from '@/lib/cart/store';
import { useCartSettings } from '@/hooks/useAppearanceSettings';
import { updateCartItemQuantity, removeCartItem, clearCartAPI, fetchCart, applyCoupon, removeCoupon } from '@/lib/cart/api';

View File

@@ -8,7 +8,7 @@ import { DynamicCheckoutField, type CheckoutField } from '@/components/DynamicCh
import Container from '@/components/Layout/Container';
import SEOHead from '@/components/SEOHead';
import { formatPrice } from '@/lib/currency';
import { ArrowLeft, ShoppingBag, MapPin, Check, Edit2, Loader2, X, Tag } from 'lucide-react';
import { ArrowLeft, ShoppingBag, MapPin, Edit2, Loader2, X, Tag } from 'lucide-react';
import { toast } from 'sonner';
import { apiClient } from '@/lib/api/client';
import { api } from '@/lib/api/client';
@@ -104,7 +104,6 @@ export default function Checkout() {
// Countries and states data
const [countries, setCountries] = useState<{ code: string; name: string }[]>([]);
const [states, setStates] = useState<Record<string, Record<string, string>>>({});
const [defaultCountry, setDefaultCountry] = useState('');
// Load countries and states
useEffect(() => {
@@ -117,7 +116,6 @@ export default function Checkout() {
}>('/countries');
setCountries(data.countries || []);
setStates(data.states || {});
setDefaultCountry(data.default_country || '');
// Set default country if not already set
if (!billingData.country && data.default_country) {
@@ -131,6 +129,7 @@ export default function Checkout() {
}
};
loadCountries();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// Country/state options for SearchableSelect
@@ -146,7 +145,8 @@ export default function Checkout() {
setBillingData(prev => ({ ...prev, state: '' }));
}
}
}, [billingData.country, states]);
}, [billingData.country, billingData.state, states]);
useEffect(() => {
if (shippingData.country && shippingData.state) {
@@ -155,7 +155,8 @@ export default function Checkout() {
setShippingData(prev => ({ ...prev, state: '' }));
}
}
}, [shippingData.country, states]);
}, [shippingData.country, shippingData.state, states]);
// Dynamic checkout fields from API
const [checkoutFields, setCheckoutFields] = useState<CheckoutField[]>([]);
@@ -298,9 +299,6 @@ export default function Checkout() {
quantity: item.quantity,
}));
const destinationId = shipToDifferentAddress
? customFieldData['shipping_destination_id']
: customFieldData['billing_destination_id'];
const response = await api.post<{ ok: boolean; rates: ShippingRate[]; zone_name?: string }>('/checkout/shipping-rates', {
shipping: {
@@ -308,7 +306,7 @@ export default function Checkout() {
state: addressData.state,
city: addressData.city,
postcode: addressData.postcode,
destination_id: destinationId || undefined,
destination_id: undefined,
},
items,
});
@@ -332,9 +330,6 @@ export default function Checkout() {
// Trigger shipping rate fetch when address or destination changes
useEffect(() => {
const addressData = shipToDifferentAddress ? shippingData : billingData;
const destinationId = shipToDifferentAddress
? customFieldData['shipping_destination_id']
: customFieldData['billing_destination_id'];
// Debounce the fetch
const timeoutId = setTimeout(() => {
@@ -344,12 +339,12 @@ export default function Checkout() {
}, 500);
return () => clearTimeout(timeoutId);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
billingData.country, billingData.state, billingData.city, billingData.postcode,
shippingData.country, shippingData.state, shippingData.city, shippingData.postcode,
shipToDifferentAddress,
customFieldData['billing_destination_id'],
customFieldData['shipping_destination_id'],
customFieldData,
cart.items.length,
]);
@@ -393,6 +388,7 @@ export default function Checkout() {
};
loadAddresses();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [user, isVirtualOnly]);
// Helper functions to fill forms from saved addresses
@@ -461,7 +457,8 @@ export default function Checkout() {
country: user.shipping.country || '',
});
}
}, [user]);
}, [user, savedAddresses.length]);
const handleApplyCoupon = async () => {
if (!couponCode.trim()) return;

View File

@@ -3,7 +3,6 @@ import { useParams, useNavigate } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query';
import { api } from '@/lib/api/client';
import { Helmet } from 'react-helmet-async';
import { cn } from '@/lib/utils';
// Section Components
import { HeroSection } from './sections/HeroSection';
@@ -23,6 +22,7 @@ interface SectionProp {
interface SectionStyles {
backgroundColor?: string;
backgroundImage?: string;
backgroundType?: 'color' | 'image' | 'gradient';
backgroundOverlay?: number;
paddingTop?: string;
paddingBottom?: string;
@@ -164,6 +164,7 @@ export function DynamicPageRenderer({ slug: propSlug }: DynamicPageRendererProps
// Handle 404
useEffect(() => {
if (error) {
// eslint-disable-next-line react-hooks/set-state-in-effect
setNotFound(true);
}
}, [error]);

View File

@@ -92,7 +92,7 @@ export function ContactFormSection({
});
window.location.href = finalUrl;
}
} catch (err) {
} catch {
setError('Failed to submit form. Please try again.');
} finally {
setSubmitting(false);

View File

@@ -28,12 +28,6 @@ const COLOR_SCHEMES: Record<string, { bg: string; text: string }> = {
muted: { bg: 'bg-gray-50', text: 'text-gray-700' },
};
const WIDTH_CLASSES: Record<string, string> = {
default: 'max-w-screen-xl mx-auto',
contained: 'max-w-screen-md mx-auto',
full: 'w-full',
};
const fontSizeToCSS = (className?: string) => {
switch (className) {
case 'text-xs': return '0.75rem';
@@ -164,10 +158,10 @@ const generateScopedStyles = (sectionId: string, elementStyles: Record<string, a
return styles.join('\n');
};
export function ContentSection({ section, content: propContent, cta_text: propCtaText, cta_url: propCtaUrl, outerPadding = false }: ContentSectionProps & { outerPadding?: boolean }) {
export function ContentSection({ section, content: propContent, cta_text: propCtaText, cta_url: propCtaUrl }: ContentSectionProps & { outerPadding?: boolean }) {
const scheme = COLOR_SCHEMES[section.colorScheme || 'default'] ?? COLOR_SCHEMES['default'];
// Default to 'default' width if not specified
const layout = section.layoutVariant || 'default';
const _layout = section.layoutVariant || 'default';
const heightPreset = section.styles?.heightPreset || 'default';

View File

@@ -16,7 +16,6 @@ interface HeroSectionProps {
export function HeroSection({
id,
layout = 'default',
colorScheme = 'default',
title,
subtitle,
image,
@@ -38,7 +37,6 @@ export function HeroSection({
const isImageRight = layout === 'hero-right-image' || layout === 'image-right';
const isCentered = layout === 'centered' || layout === 'default';
const hasCustomBackground = !!styles?.backgroundColor || !!styles?.backgroundImage || styles?.backgroundType === 'gradient';
const sectionBg = getSectionBackground(styles);
// Helper to get text styles (including font family)
@@ -73,7 +71,7 @@ export function HeroSection({
// Helper to get background style for dynamic schemes
const getBackgroundStyle = (): React.CSSProperties | undefined => {
/* const getBackgroundStyle = (): React.CSSProperties | undefined => {
// If user set custom bg via Design tab, use that
if (hasCustomBackground) return sectionBg.style;
if (colorScheme === 'primary') {
@@ -83,9 +81,7 @@ export function HeroSection({
return { backgroundColor: 'var(--wn-secondary, #6b7280)' };
}
return undefined;
};
const isDynamicScheme = ['primary', 'secondary'].includes(colorScheme) && !hasCustomBackground;
}; */
return (
<section

View File

@@ -24,7 +24,6 @@ export function ImageTextSection({
elementStyles,
styles,
}: ImageTextSectionProps & { styles?: Record<string, any>, cta_text?: string, cta_url?: string }) {
const isImageLeft = layout === 'image-left' || layout === 'left';
const isImageRight = layout === 'image-right' || layout === 'right';
// Helper to get text styles (including font family)

View File

@@ -83,7 +83,7 @@ export default function Login() {
credentials: 'include',
body: JSON.stringify({ product_id: productId }),
});
} catch (e) {
} catch {
// Skip if product already in wishlist or other error
console.debug('Wishlist merge skipped for product:', productId);
}

View File

@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import { useParams, useNavigate, useSearchParams } from 'react-router-dom';
import { useParams, useSearchParams } from 'react-router-dom';
import { api } from '@/lib/api/client';
import { toast } from 'sonner';
import SubscriptionTimeline from '../../components/SubscriptionTimeline';
@@ -52,7 +52,7 @@ const OrderPay: React.FC = () => {
const { orderId } = useParams<{ orderId: string }>();
const [searchParams] = useSearchParams();
const orderKey = searchParams.get('key');
const navigate = useNavigate();
// const navigate = useNavigate();
const [order, setOrder] = useState<OrderDetailsResponse | null>(null);
const [loading, setLoading] = useState(true);
@@ -63,6 +63,7 @@ const OrderPay: React.FC = () => {
if (orderId) {
fetchOrder();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [orderId]);
const fetchOrder = async () => {
@@ -123,7 +124,7 @@ const OrderPay: React.FC = () => {
minimumFractionDigits: 0,
maximumFractionDigits: 0,
}).format(amount);
} catch (e) {
} catch {
// Fallback
return `${currency} ${amount.toFixed(0)}`;
}

View File

@@ -26,7 +26,7 @@ export default function Product() {
const [selectedAttributes, setSelectedAttributes] = useState<Record<string, string>>({});
const thumbnailsRef = useRef<HTMLDivElement>(null);
const { addItem } = useCartStore();
const { isEnabled: wishlistEnabled, isInWishlist, toggleWishlist, isLoggedIn } = useWishlist();
const { isEnabled: wishlistEnabled, isInWishlist, toggleWishlist } = useWishlist();
const { isEnabled: isModuleEnabled } = useModules();
// Apply white background to <main> in flat mode so the full viewport width is white
@@ -86,6 +86,7 @@ export default function Product() {
if (product && !selectedImage) {
setSelectedImage(product.image || product.images?.[0]);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [product]);
// AUTO-SELECT FIRST VARIATION (Issue #2 from report)
@@ -103,6 +104,7 @@ export default function Product() {
setSelectedAttributes(initialAttributes);
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [product]);
// Find matching variation when attributes change
@@ -114,7 +116,6 @@ export default function Product() {
(product.variations as any[]).forEach(v => {
if (!v.attributes) return;
let isMatch = true;
let score = 0;
const attributesMatch = Object.entries(selectedAttributes).every(([attrName, attrValue]) => {
@@ -230,7 +231,7 @@ export default function Product() {
// Construct variation params using keys from the matched variation
// but filling in values from user selection (handles "Any" variations with empty values)
let variation_params: Record<string, string> = {};
const variation_params: Record<string, string> = {};
if (product.type === 'variable' && selectedVariation?.attributes) {
// Get keys from the variation's attributes (these are the correct WooCommerce keys)
Object.keys(selectedVariation.attributes).forEach(key => {

View File

@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { Link, useSearchParams, useNavigate } from 'react-router-dom';
import { Link } from 'react-router-dom';
import { toast } from 'sonner';
import Container from '@/components/Layout/Container';
import { Button } from '@/components/ui/button';
@@ -8,9 +8,7 @@ import { Label } from '@/components/ui/label';
import { KeyRound, ArrowLeft, Eye, EyeOff, CheckCircle, AlertCircle, Loader2 } from 'lucide-react';
export default function ResetPassword() {
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const searchParams = new URLSearchParams(window.location.search);
const key = searchParams.get('key') || '';
const login = searchParams.get('login') || '';
@@ -53,7 +51,7 @@ export default function ResetPassword() {
} else {
setError(data.message || 'This password reset link has expired or is invalid.');
}
} catch (err) {
} catch {
setError('Unable to validate reset link. Please try again later.');
} finally {
setIsValidating(false);
@@ -61,7 +59,8 @@ export default function ResetPassword() {
};
validateKey();
}, [key, login]);
}, [login]);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();

View File

@@ -8,15 +8,12 @@ import { Button } from '@/components/ui/button';
import Container from '@/components/Layout/Container';
import { ProductCard } from '@/components/ProductCard';
import { toast } from 'sonner';
import { useTheme, useLayout } from '@/contexts/ThemeContext';
import { useShopSettings } from '@/hooks/useAppearanceSettings';
import SEOHead from '@/components/SEOHead';
import type { ProductsResponse, ProductCategory, Product } from '@/types/product';
import type { ProductsResponse, ProductCategory } from '@/types/product';
export default function Shop() {
const navigate = useNavigate();
const { config } = useTheme();
const { layout } = useLayout();
const { layout: shopLayout, elements } = useShopSettings();
const [page, setPage] = useState(1);
const [search, setSearch] = useState('');
@@ -96,7 +93,7 @@ export default function Shop() {
const handleAddToCart = async (product: any) => {
try {
const response = await apiClient.post(apiClient.endpoints.cart.add, {
await apiClient.post(apiClient.endpoints.cart.add, {
product_id: product.id,
quantity: 1,
});

View File

@@ -12,11 +12,11 @@ export default function ThankYou() {
const { orderId } = useParams<{ orderId: string }>();
const [searchParams] = useSearchParams();
const orderKey = searchParams.get('key');
const { template, headerVisibility, footerVisibility, backgroundColor, customMessage, elements, isLoading: settingsLoading } = useThankYouSettings();
const { template, backgroundColor, customMessage, elements, isLoading: settingsLoading } = useThankYouSettings();
const [order, setOrder] = useState<any>(null);
const [relatedProducts, setRelatedProducts] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [, setError] = useState<string | null>(null);
const isLoggedIn = (window as any).woonoowCustomer?.user?.isLoggedIn;
useEffect(() => {