Skip to content

Commit bb97832

Browse files
authored
Apply React best practices and resolve TypeScript issues (#58)
1 parent 8ec6971 commit bb97832

21 files changed

+46
-43
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"dev": "vite",
88
"format": "prettier --write resources/",
99
"format:check": "prettier --check resources/",
10-
"lint": "eslint . --fix"
10+
"lint": "eslint . --fix",
11+
"types": "tsc --noEmit"
1112
},
1213
"devDependencies": {
1314
"@eslint/js": "^9.19.0",

resources/js/components/app-content.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { SidebarInset } from '@/components/ui/sidebar';
22
import * as React from 'react';
33

4-
interface AppContentProps extends React.ComponentProps<'div'> {
4+
interface AppContentProps extends React.ComponentProps<'main'> {
55
variant?: 'header' | 'sidebar';
66
}
77

resources/js/components/heading.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
export default function Heading({ title, description }: { title: string; description?: string }) {
22
return (
3-
<>
4-
<div className="mb-8 space-y-0.5">
5-
<h2 className="text-xl font-semibold tracking-tight">{title}</h2>
6-
{description && <p className="text-muted-foreground text-sm">{description}</p>}
7-
</div>
8-
</>
3+
<div className="mb-8 space-y-0.5">
4+
<h2 className="text-xl font-semibold tracking-tight">{title}</h2>
5+
{description && <p className="text-muted-foreground text-sm">{description}</p>}
6+
</div>
97
);
108
}

resources/js/components/icon.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { cn } from '@/lib/utils';
22
import { type LucideProps } from 'lucide-react';
3+
import { type ComponentType } from 'react';
34

45
interface IconProps extends Omit<LucideProps, 'ref'> {
5-
iconNode: React.ComponentType<LucideProps>;
6+
iconNode: ComponentType<LucideProps>;
67
}
78

89
export function Icon({ iconNode: IconComponent, className, ...props }: IconProps) {

resources/js/components/input-error.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { cn } from '@/lib/utils';
2-
import { HTMLAttributes } from 'react';
2+
import { type HTMLAttributes } from 'react';
33

44
export default function InputError({ message, className = '', ...props }: HTMLAttributes<HTMLParagraphElement> & { message?: string }) {
55
return message ? (

resources/js/components/nav-footer.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { Icon } from '@/components/icon';
22
import { SidebarGroup, SidebarGroupContent, SidebarMenu, SidebarMenuButton, SidebarMenuItem } from '@/components/ui/sidebar';
33
import { type NavItem } from '@/types';
4+
import { type ComponentPropsWithoutRef } from 'react';
45

56
export function NavFooter({
67
items,
78
className,
89
...props
9-
}: React.ComponentPropsWithoutRef<typeof SidebarGroup> & {
10+
}: ComponentPropsWithoutRef<typeof SidebarGroup> & {
1011
items: NavItem[];
1112
}) {
1213
return (

resources/js/hooks/use-appearance.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useState } from 'react';
1+
import { useCallback, useEffect, useState } from 'react';
22

33
export type Appearance = 'light' | 'dark' | 'system';
44

@@ -29,18 +29,18 @@ export function initializeTheme() {
2929
export function useAppearance() {
3030
const [appearance, setAppearance] = useState<Appearance>('system');
3131

32-
const updateAppearance = (mode: Appearance) => {
32+
const updateAppearance = useCallback((mode: Appearance) => {
3333
setAppearance(mode);
3434
localStorage.setItem('appearance', mode);
3535
applyTheme(mode);
36-
};
36+
}, []);
3737

3838
useEffect(() => {
3939
const savedAppearance = localStorage.getItem('appearance') as Appearance | null;
4040
updateAppearance(savedAppearance || 'system');
4141

4242
return () => mediaQuery.removeEventListener('change', handleSystemThemeChange);
43-
}, []);
43+
}, [updateAppearance]);
4444

45-
return { appearance, updateAppearance };
45+
return { appearance, updateAppearance } as const;
4646
}

resources/js/hooks/use-initials.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import { useCallback } from 'react';
2+
13
export function useInitials() {
2-
const getInitials = (fullName: string): string => {
4+
const getInitials = useCallback((fullName: string): string => {
35
const names = fullName.trim().split(' ');
46

57
if (names.length === 0) return '';
@@ -9,7 +11,7 @@ export function useInitials() {
911
const lastInitial = names[names.length - 1].charAt(0);
1012

1113
return `${firstInitial}${lastInitial}`.toUpperCase();
12-
};
14+
}, []);
1315

1416
return getInitials;
1517
}

resources/js/hooks/use-mobile.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useEffect, useState } from 'react';
33
const MOBILE_BREAKPOINT = 768;
44

55
export function useIsMobile() {
6-
const [isMobile, setIsMobile] = useState<boolean | undefined>(undefined);
6+
const [isMobile, setIsMobile] = useState<boolean>();
77

88
useEffect(() => {
99
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);

resources/js/layouts/app-layout.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import AppLayoutTemplate from '@/layouts/app/app-sidebar-layout';
22
import { type BreadcrumbItem } from '@/types';
3+
import { type ReactNode } from 'react';
34

45
interface AppLayoutProps {
5-
children: React.ReactNode;
6+
children: ReactNode;
67
breadcrumbs?: BreadcrumbItem[];
78
}
89

0 commit comments

Comments
 (0)