mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-30 02:23:47 +00:00
refactor: full codebase cleanup, dependency updates, and lint fixes
Phase 0: Remove ~920 lines of dead code (ThemeBentoPicker, PromoDiscountBadge, AdminLayout, SettingsSidebar, MovingGradient, EmptyState, miniapp API, unused types/functions/transitions/skeleton helpers). Fix API barrel file (add 20 missing exports). Phase 1: Add ErrorBoundary (app/page/widget levels), centralize constants, add axios timeout, fix staleTime:0 in React Query. Phase 2: Consolidate hexToHsl, extract email validation, fix duplicate code. Phase 3: Fix auth race condition (await checkAdminStatus), memoize useCurrency, add WebSocket message validation. Phase 4: Extract useBranding, useFeatureFlags, useScrollRestoration from AppShell. Phase 5: Remove all eslint-disable react-hooks/exhaustive-deps (14 total), simplify logger, remove deprecated hooks (useBackButton, useTelegramDnd, useTelegramWebApp). Dependencies: React 19, react-router 7, zustand 5, i18next 25, react-i18next 16, eslint-plugin-react-refresh 0.5. Remove unused @lottiefiles/dotlottie-react. Convert vite manualChunks to function-based approach for react-router v7 compat. Lint: Fix logger.ts no-unused-expressions, fix react-refresh/only-export-components in 6 Radix primitive files (const re-exports → direct re-exports), fix WebSocketProvider exhaustive-deps. Result: 0 errors, 0 warnings. Add CLAUDE.md to .gitignore.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Link } from 'react-router';
|
||||
import { usePlatform } from '@/platform';
|
||||
import { BackIcon } from './icons';
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
interface AdminLayoutProps {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* AdminLayout - wrapper for all admin pages.
|
||||
* Animations removed to prevent black flash during transitions.
|
||||
*/
|
||||
export function AdminLayout({ children, className }: AdminLayoutProps) {
|
||||
return <div className={className}>{children}</div>;
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { brandingApi, setCachedBranding } from '../../api/branding';
|
||||
import { setCachedAnimationEnabled } from '../AnimatedBackground';
|
||||
import { setCachedFullscreenEnabled } from '../../hooks/useTelegramWebApp';
|
||||
import { setCachedFullscreenEnabled } from '../../hooks/useTelegramSDK';
|
||||
import { UploadIcon, TrashIcon, PencilIcon, CheckIcon, CloseIcon } from './icons';
|
||||
import { Toggle } from './Toggle';
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { AdminBackButton, StarIcon, CloseIcon, MENU_SECTIONS } from './index';
|
||||
|
||||
interface SettingsSidebarProps {
|
||||
activeSection: string;
|
||||
setActiveSection: (section: string) => void;
|
||||
mobileMenuOpen: boolean;
|
||||
setMobileMenuOpen: (open: boolean) => void;
|
||||
favoritesCount: number;
|
||||
}
|
||||
|
||||
export function SettingsSidebar({
|
||||
activeSection,
|
||||
setActiveSection,
|
||||
mobileMenuOpen,
|
||||
setMobileMenuOpen,
|
||||
favoritesCount,
|
||||
}: SettingsSidebarProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<aside
|
||||
className={`fixed inset-y-0 left-0 z-50 h-screen w-64 flex-shrink-0 transform border-r border-dark-700/50 bg-dark-900 transition-transform duration-200 ease-in-out lg:sticky lg:top-0 ${mobileMenuOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0'} `}
|
||||
>
|
||||
{/* Header */}
|
||||
<div className="border-b border-dark-700/50 p-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<AdminBackButton className="rounded-xl bg-dark-800 p-2 transition-colors hover:bg-dark-700" />
|
||||
<h1 className="text-lg font-bold text-dark-100">{t('admin.settings.title')}</h1>
|
||||
<button
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
className="ml-auto rounded-xl bg-dark-800 p-2 transition-colors hover:bg-dark-700 lg:hidden"
|
||||
>
|
||||
<CloseIcon />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Menu */}
|
||||
<nav className="max-h-[calc(100vh-80px)] space-y-1 overflow-y-auto p-2">
|
||||
{MENU_SECTIONS.map((section, sectionIdx) => (
|
||||
<div key={section.id}>
|
||||
{sectionIdx > 0 && <div className="my-3 border-t border-dark-700/50" />}
|
||||
{section.items.map((item) => {
|
||||
const isActive = activeSection === item.id;
|
||||
const hasIcon = item.iconType === 'star';
|
||||
return (
|
||||
<button
|
||||
key={item.id}
|
||||
onClick={() => {
|
||||
setActiveSection(item.id);
|
||||
setMobileMenuOpen(false);
|
||||
}}
|
||||
className={`flex w-full items-center gap-3 rounded-xl px-3 py-2.5 transition-all ${
|
||||
isActive
|
||||
? 'bg-accent-500/10 text-accent-400'
|
||||
: 'text-dark-400 hover:bg-dark-800/50 hover:text-dark-200'
|
||||
}`}
|
||||
>
|
||||
{hasIcon && <StarIcon filled={isActive && item.id === 'favorites'} />}
|
||||
<span className="font-medium">{t(`admin.settings.${item.id}`)}</span>
|
||||
{item.id === 'favorites' && favoritesCount > 0 && (
|
||||
<span className="ml-auto rounded-full bg-warning-500/20 px-2 py-0.5 text-xs text-warning-400">
|
||||
{favoritesCount}
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
@@ -59,6 +59,8 @@ export function ThemeTab() {
|
||||
// Local draft state
|
||||
const [draftColors, setDraftColors] = useState<ThemeColors>(DEFAULT_THEME_COLORS);
|
||||
const savedColorsRef = useRef<ThemeColors>(DEFAULT_THEME_COLORS);
|
||||
const draftColorsRef = useRef(draftColors);
|
||||
draftColorsRef.current = draftColors;
|
||||
|
||||
// Sync server data into draft and saved snapshot when it arrives
|
||||
useEffect(() => {
|
||||
@@ -79,14 +81,14 @@ export function ThemeTab() {
|
||||
};
|
||||
// Only sync if saved snapshot matches current draft (no unsaved changes)
|
||||
if (
|
||||
colorsEqual(savedColorsRef.current, draftColors) ||
|
||||
colorsEqual(savedColorsRef.current, draftColorsRef.current) ||
|
||||
colorsEqual(savedColorsRef.current, DEFAULT_THEME_COLORS)
|
||||
) {
|
||||
setDraftColors(colors);
|
||||
}
|
||||
savedColorsRef.current = colors;
|
||||
}
|
||||
}, [serverColors]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
}, [serverColors]);
|
||||
|
||||
const hasUnsavedChanges = !colorsEqual(draftColors, savedColorsRef.current);
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Components
|
||||
export * from './AdminBackButton';
|
||||
export * from './AdminLayout';
|
||||
export * from './icons';
|
||||
export * from './Toggle';
|
||||
export * from './SettingInput';
|
||||
@@ -10,7 +9,6 @@ export * from './BrandingTab';
|
||||
export * from './ThemeTab';
|
||||
export * from './FavoritesTab';
|
||||
export * from './SettingsTab';
|
||||
export * from './SettingsSidebar';
|
||||
export * from './SettingsMobileTabs';
|
||||
export * from './SettingsSearch';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user