diff --git a/client/pages/AdminPage.jsx b/client/pages/AdminPage.tsx similarity index 78% rename from client/pages/AdminPage.jsx rename to client/pages/AdminPage.tsx index 130cb17..9d7e904 100644 --- a/client/pages/AdminPage.jsx +++ b/client/pages/AdminPage.tsx @@ -1,6 +1,7 @@ -import React, { useState, useEffect, useCallback } from 'react'; +import { useState, useEffect, useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; import { api } from '@/api'; +import { errMessage } from '@/lib/utils'; import AppNavigation from '@/components/layout/Sidebar'; import OnboardingWizard from '@/components/admin/OnboardingWizard'; import EmailNotifCard from '@/components/admin/EmailNotifCard'; @@ -11,20 +12,21 @@ import UsersTable from '@/components/admin/UsersTable'; import AddUserCard from '@/components/admin/AddUserCard'; import BackupManagementCard from '@/components/admin/BackupManagementCard'; import CleanupPanel from '@/components/admin/CleanupPanel'; +import type { User } from '@/hooks/useAuth'; export default function AdminPage() { const navigate = useNavigate(); - const [me, setMe] = useState(null); - const [hasUsers, setHasUsers] = useState(null); + const [me, setMe] = useState(null); + const [hasUsers, setHasUsers] = useState(null); const [loadError, setLoadError] = useState(''); - const [users, setUsers] = useState([]); + const [users, setUsers] = useState([]); const [authMode, setAuthMode] = useState('multi'); const loadMe = useCallback(async () => { try { - const d = await api.me(); - setMe(d.user); + const d = await api.me() as { user?: User }; + setMe(d.user ?? null); } catch { navigate('/login', { replace: true }); } @@ -32,18 +34,18 @@ export default function AdminPage() { const loadUsers = useCallback(async () => { try { - const d = await api.adminUsers(); - setUsers(d.users || d); - } catch {} + const d = await api.adminUsers() as { users?: unknown[] } | unknown[]; + setUsers(Array.isArray(d) ? d : (d.users || [])); + } catch { /* ignore */ } }, []); const loadHasUsers = useCallback(async () => { try { - const d = await api.hasUsers(); - setHasUsers(d.has_users); + const d = await api.hasUsers() as { has_users?: boolean }; + setHasUsers(!!d.has_users); if (d.has_users) loadUsers(); } catch (err) { - setLoadError(err.message || 'Failed to load admin page'); + setLoadError(errMessage(err, 'Failed to load admin page')); setHasUsers(false); } }, [loadUsers]); diff --git a/client/pages/SubscriptionCatalogPage.jsx b/client/pages/SubscriptionCatalogPage.tsx similarity index 88% rename from client/pages/SubscriptionCatalogPage.jsx rename to client/pages/SubscriptionCatalogPage.tsx index 6c2601c..35e51eb 100644 --- a/client/pages/SubscriptionCatalogPage.jsx +++ b/client/pages/SubscriptionCatalogPage.tsx @@ -3,26 +3,28 @@ import { Link } from 'react-router-dom'; import { ArrowLeft, Link2, RefreshCw } from 'lucide-react'; import { toast } from 'sonner'; import { api } from '@/api'; +import { errMessage } from '@/lib/utils'; import { Button } from '@/components/ui/button'; import BillModal from '@/components/BillModal'; import SubscriptionCatalogSection from '@/components/SubscriptionCatalogSection'; +import type { Bill, Category } from '@/types'; export default function SubscriptionCatalogPage() { const [catalogKey, setCatalogKey] = useState(0); - const [subscriptions, setSubscriptions] = useState([]); - const [categories, setCategories] = useState([]); - const [modal, setModal] = useState(null); + const [subscriptions, setSubscriptions] = useState([]); + const [categories, setCategories] = useState([]); + const [modal, setModal] = useState<{ bill: Bill } | null>(null); const refreshSubscriptions = useCallback(async () => { try { const [subscriptionData, categoryData] = await Promise.all([ - api.subscriptions(), + api.subscriptions() as Promise<{ subscriptions?: Bill[] }>, api.categories(), ]); setSubscriptions(subscriptionData?.subscriptions || []); setCategories(Array.isArray(categoryData) ? categoryData : []); } catch (err) { - toast.error(err.message || 'Subscriptions could not be refreshed.'); + toast.error(errMessage(err, 'Subscriptions could not be refreshed.')); } }, []); @@ -30,8 +32,8 @@ export default function SubscriptionCatalogPage() { refreshSubscriptions(); }, [refreshSubscriptions]); - function openBillEditor(billId) { - const bill = subscriptions.find(item => item.id === billId) || { id: billId }; + function openBillEditor(billId: number) { + const bill = subscriptions.find(item => item.id === billId) || ({ id: billId } as Bill); setModal({ bill }); }