diff --git a/package.json b/package.json index 11a63af22..8621dbe24 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "dev": "vite", "format": "prettier --write resources/", "format:check": "prettier --check resources/", - "lint": "eslint . --fix" + "lint": "eslint . --fix", + "types": "tsc --noEmit" }, "devDependencies": { "@eslint/js": "^9.19.0", diff --git a/resources/js/components/app-content.tsx b/resources/js/components/app-content.tsx index ae43d9e6b..e5d04cd69 100644 --- a/resources/js/components/app-content.tsx +++ b/resources/js/components/app-content.tsx @@ -1,7 +1,7 @@ import { SidebarInset } from '@/components/ui/sidebar'; import * as React from 'react'; -interface AppContentProps extends React.ComponentProps<'div'> { +interface AppContentProps extends React.ComponentProps<'main'> { variant?: 'header' | 'sidebar'; } diff --git a/resources/js/components/heading.tsx b/resources/js/components/heading.tsx index 40b398250..d59163ea7 100644 --- a/resources/js/components/heading.tsx +++ b/resources/js/components/heading.tsx @@ -1,10 +1,8 @@ export default function Heading({ title, description }: { title: string; description?: string }) { return ( - <> -
-

{title}

- {description &&

{description}

} -
- +
+

{title}

+ {description &&

{description}

} +
); } diff --git a/resources/js/components/icon.tsx b/resources/js/components/icon.tsx index fe958b46e..0f81d9c13 100644 --- a/resources/js/components/icon.tsx +++ b/resources/js/components/icon.tsx @@ -1,8 +1,9 @@ import { cn } from '@/lib/utils'; import { type LucideProps } from 'lucide-react'; +import { type ComponentType } from 'react'; interface IconProps extends Omit { - iconNode: React.ComponentType; + iconNode: ComponentType; } export function Icon({ iconNode: IconComponent, className, ...props }: IconProps) { diff --git a/resources/js/components/input-error.tsx b/resources/js/components/input-error.tsx index be62fef9e..bb48d71cc 100644 --- a/resources/js/components/input-error.tsx +++ b/resources/js/components/input-error.tsx @@ -1,5 +1,5 @@ import { cn } from '@/lib/utils'; -import { HTMLAttributes } from 'react'; +import { type HTMLAttributes } from 'react'; export default function InputError({ message, className = '', ...props }: HTMLAttributes & { message?: string }) { return message ? ( diff --git a/resources/js/components/nav-footer.tsx b/resources/js/components/nav-footer.tsx index e27a2ba1b..870cacded 100644 --- a/resources/js/components/nav-footer.tsx +++ b/resources/js/components/nav-footer.tsx @@ -1,12 +1,13 @@ import { Icon } from '@/components/icon'; import { SidebarGroup, SidebarGroupContent, SidebarMenu, SidebarMenuButton, SidebarMenuItem } from '@/components/ui/sidebar'; import { type NavItem } from '@/types'; +import { type ComponentPropsWithoutRef } from 'react'; export function NavFooter({ items, className, ...props -}: React.ComponentPropsWithoutRef & { +}: ComponentPropsWithoutRef & { items: NavItem[]; }) { return ( diff --git a/resources/js/hooks/use-appearance.tsx b/resources/js/hooks/use-appearance.tsx index 897e8a075..e4194feed 100644 --- a/resources/js/hooks/use-appearance.tsx +++ b/resources/js/hooks/use-appearance.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; export type Appearance = 'light' | 'dark' | 'system'; @@ -29,18 +29,18 @@ export function initializeTheme() { export function useAppearance() { const [appearance, setAppearance] = useState('system'); - const updateAppearance = (mode: Appearance) => { + const updateAppearance = useCallback((mode: Appearance) => { setAppearance(mode); localStorage.setItem('appearance', mode); applyTheme(mode); - }; + }, []); useEffect(() => { const savedAppearance = localStorage.getItem('appearance') as Appearance | null; updateAppearance(savedAppearance || 'system'); return () => mediaQuery.removeEventListener('change', handleSystemThemeChange); - }, []); + }, [updateAppearance]); - return { appearance, updateAppearance }; + return { appearance, updateAppearance } as const; } diff --git a/resources/js/hooks/use-initials.tsx b/resources/js/hooks/use-initials.tsx index 6c3b8c6ad..cf7943d69 100644 --- a/resources/js/hooks/use-initials.tsx +++ b/resources/js/hooks/use-initials.tsx @@ -1,5 +1,7 @@ +import { useCallback } from 'react'; + export function useInitials() { - const getInitials = (fullName: string): string => { + const getInitials = useCallback((fullName: string): string => { const names = fullName.trim().split(' '); if (names.length === 0) return ''; @@ -9,7 +11,7 @@ export function useInitials() { const lastInitial = names[names.length - 1].charAt(0); return `${firstInitial}${lastInitial}`.toUpperCase(); - }; + }, []); return getInitials; } diff --git a/resources/js/hooks/use-mobile.tsx b/resources/js/hooks/use-mobile.tsx index de2453af1..8272d8eb9 100644 --- a/resources/js/hooks/use-mobile.tsx +++ b/resources/js/hooks/use-mobile.tsx @@ -3,7 +3,7 @@ import { useEffect, useState } from 'react'; const MOBILE_BREAKPOINT = 768; export function useIsMobile() { - const [isMobile, setIsMobile] = useState(undefined); + const [isMobile, setIsMobile] = useState(); useEffect(() => { const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); diff --git a/resources/js/layouts/app-layout.tsx b/resources/js/layouts/app-layout.tsx index 29b27ae2c..1457c51ee 100644 --- a/resources/js/layouts/app-layout.tsx +++ b/resources/js/layouts/app-layout.tsx @@ -1,8 +1,9 @@ import AppLayoutTemplate from '@/layouts/app/app-sidebar-layout'; import { type BreadcrumbItem } from '@/types'; +import { type ReactNode } from 'react'; interface AppLayoutProps { - children: React.ReactNode; + children: ReactNode; breadcrumbs?: BreadcrumbItem[]; } diff --git a/resources/js/layouts/app/app-header-layout.tsx b/resources/js/layouts/app/app-header-layout.tsx index d3616aff2..9cde5da62 100644 --- a/resources/js/layouts/app/app-header-layout.tsx +++ b/resources/js/layouts/app/app-header-layout.tsx @@ -2,13 +2,9 @@ import { AppContent } from '@/components/app-content'; import { AppHeader } from '@/components/app-header'; import { AppShell } from '@/components/app-shell'; import { type BreadcrumbItem } from '@/types'; +import type { PropsWithChildren } from 'react'; -interface AppHeaderLayoutProps { - children: React.ReactNode; - breadcrumbs?: BreadcrumbItem[]; -} - -export default function AppHeaderLayout({ children, breadcrumbs }: AppHeaderLayoutProps) { +export default function AppHeaderLayout({ children, breadcrumbs }: PropsWithChildren<{ breadcrumbs?: BreadcrumbItem[] }>) { return ( diff --git a/resources/js/layouts/app/app-sidebar-layout.tsx b/resources/js/layouts/app/app-sidebar-layout.tsx index 2ef677700..4a066cc94 100644 --- a/resources/js/layouts/app/app-sidebar-layout.tsx +++ b/resources/js/layouts/app/app-sidebar-layout.tsx @@ -3,8 +3,9 @@ import { AppShell } from '@/components/app-shell'; import { AppSidebar } from '@/components/app-sidebar'; import { AppSidebarHeader } from '@/components/app-sidebar-header'; import { type BreadcrumbItem } from '@/types'; +import { type PropsWithChildren } from 'react'; -export default function AppSidebarLayout({ children, breadcrumbs = [] }: { children: React.ReactNode; breadcrumbs?: BreadcrumbItem[] }) { +export default function AppSidebarLayout({ children, breadcrumbs = [] }: PropsWithChildren<{ breadcrumbs?: BreadcrumbItem[] }>) { return ( diff --git a/resources/js/layouts/auth/auth-card-layout.tsx b/resources/js/layouts/auth/auth-card-layout.tsx index 83da435c7..9884423d5 100644 --- a/resources/js/layouts/auth/auth-card-layout.tsx +++ b/resources/js/layouts/auth/auth-card-layout.tsx @@ -1,17 +1,17 @@ import AppLogoIcon from '@/components/app-logo-icon'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Link } from '@inertiajs/react'; +import { type PropsWithChildren } from 'react'; export default function AuthCardLayout({ children, title, description, -}: { - children: React.ReactNode; +}: PropsWithChildren<{ name?: string; title?: string; description?: string; -}) { +}>) { return (
diff --git a/resources/js/layouts/auth/auth-simple-layout.tsx b/resources/js/layouts/auth/auth-simple-layout.tsx index 015e333c1..428fd9cc7 100644 --- a/resources/js/layouts/auth/auth-simple-layout.tsx +++ b/resources/js/layouts/auth/auth-simple-layout.tsx @@ -1,14 +1,14 @@ import AppLogoIcon from '@/components/app-logo-icon'; import { Link } from '@inertiajs/react'; +import { type PropsWithChildren } from 'react'; interface AuthLayoutProps { - children: React.ReactNode; name?: string; title?: string; description?: string; } -export default function AuthSimpleLayout({ children, title, description }: AuthLayoutProps) { +export default function AuthSimpleLayout({ children, title, description }: PropsWithChildren) { return (
diff --git a/resources/js/layouts/auth/auth-split-layout.tsx b/resources/js/layouts/auth/auth-split-layout.tsx index 2544f4ffc..ddced1cde 100644 --- a/resources/js/layouts/auth/auth-split-layout.tsx +++ b/resources/js/layouts/auth/auth-split-layout.tsx @@ -1,14 +1,14 @@ import AppLogoIcon from '@/components/app-logo-icon'; import { type SharedData } from '@/types'; import { Link, usePage } from '@inertiajs/react'; +import { type PropsWithChildren } from 'react'; interface AuthLayoutProps { - children: React.ReactNode; title?: string; description?: string; } -export default function AuthSplitLayout({ children, title, description }: AuthLayoutProps) { +export default function AuthSplitLayout({ children, title, description }: PropsWithChildren) { const { name, quote } = usePage().props; return ( diff --git a/resources/js/layouts/settings/layout.tsx b/resources/js/layouts/settings/layout.tsx index 2a50de967..0c35cfa43 100644 --- a/resources/js/layouts/settings/layout.tsx +++ b/resources/js/layouts/settings/layout.tsx @@ -4,6 +4,7 @@ import { Separator } from '@/components/ui/separator'; import { cn } from '@/lib/utils'; import { type NavItem } from '@/types'; import { Link } from '@inertiajs/react'; +import { type PropsWithChildren } from 'react'; const sidebarNavItems: NavItem[] = [ { @@ -23,7 +24,7 @@ const sidebarNavItems: NavItem[] = [ }, ]; -export default function SettingsLayout({ children }: { children: React.ReactNode }) { +export default function SettingsLayout({ children }: PropsWithChildren) { const currentPath = window.location.pathname; return ( diff --git a/resources/js/pages/auth/login.tsx b/resources/js/pages/auth/login.tsx index 0c329cd7b..a3f176165 100644 --- a/resources/js/pages/auth/login.tsx +++ b/resources/js/pages/auth/login.tsx @@ -10,11 +10,11 @@ import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import AuthLayout from '@/layouts/auth-layout'; -interface LoginForm { +type LoginForm = { email: string; password: string; remember: boolean; -} +}; interface LoginProps { status?: string; diff --git a/resources/js/pages/auth/register.tsx b/resources/js/pages/auth/register.tsx index 39fd41178..8dc8393c0 100644 --- a/resources/js/pages/auth/register.tsx +++ b/resources/js/pages/auth/register.tsx @@ -9,12 +9,12 @@ import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import AuthLayout from '@/layouts/auth-layout'; -interface RegisterForm { +type RegisterForm = { name: string; email: string; password: string; password_confirmation: string; -} +}; export default function Register() { const { data, setData, post, processing, errors, reset } = useForm({ diff --git a/resources/js/pages/auth/reset-password.tsx b/resources/js/pages/auth/reset-password.tsx index 220d2ff9f..34e8d85a7 100644 --- a/resources/js/pages/auth/reset-password.tsx +++ b/resources/js/pages/auth/reset-password.tsx @@ -13,12 +13,12 @@ interface ResetPasswordProps { email: string; } -interface ResetPasswordForm { +type ResetPasswordForm = { token: string; email: string; password: string; password_confirmation: string; -} +}; export default function ResetPassword({ token, email }: ResetPasswordProps) { const { data, setData, post, processing, errors, reset } = useForm({ diff --git a/resources/js/pages/settings/profile.tsx b/resources/js/pages/settings/profile.tsx index 718a807b0..f454606ee 100644 --- a/resources/js/pages/settings/profile.tsx +++ b/resources/js/pages/settings/profile.tsx @@ -79,13 +79,13 @@ export default function Profile({ mustVerifyEmail, status }: { mustVerifyEmail: {mustVerifyEmail && auth.user.email_verified_at === null && (
-

+

Your email address is unverified.{' '} Click here to resend the verification email. diff --git a/resources/js/pages/welcome.tsx b/resources/js/pages/welcome.tsx index 35bebdaae..3f3afc1b2 100644 --- a/resources/js/pages/welcome.tsx +++ b/resources/js/pages/welcome.tsx @@ -218,6 +218,7 @@ export default function Welcome() { />