Skip to content

Commit fdd808f

Browse files
committed
fix: improve react code based on @eslint-react plugin
Add some TODO for some legacy code
1 parent 02a3188 commit fdd808f

File tree

27 files changed

+607
-70
lines changed

27 files changed

+607
-70
lines changed

.eslintrc.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"next/core-web-vitals",
66
"plugin:storybook/recommended"
77
],
8+
"plugins": ["@eslint-react/eslint-plugin"],
89
"rules": {
910
"react/no-unescaped-entities": "off",
1011
"@typescript-eslint/no-unused-vars": [
@@ -18,6 +19,10 @@
1819
"sonarjs/prefer-immediate-return": "warn"
1920
},
2021
"overrides": [
22+
{
23+
"files": ["**/*.{ts,tsx}"],
24+
"extends": ["plugin:@eslint-react/recommended-legacy"]
25+
},
2126
{
2227
"files": ["./src/**/*.*"],
2328
"rules": {

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
"@babel/eslint-parser": "7.24.7",
107107
"@babel/parser": "7.24.7",
108108
"@chakra-ui/cli": "2.4.1",
109+
"@eslint-react/eslint-plugin": "1.14.3",
109110
"@next/eslint-plugin-next": "14.2.4",
110111
"@playwright/test": "1.45.1",
111112
"@storybook/addon-actions": "8.1.11",

pnpm-lock.yaml

Lines changed: 471 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/ConfirmMenuItem/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,9 @@ export const ConfirmMenuItem = forwardRef<ConfirmMenuItemProps, 'button'>(
179179
},
180180
},
181181
icon: icon
182-
? React.cloneElement(icon, { color: 'transparent' })
182+
? // TODO @eslint-react rule
183+
// eslint-disable-next-line @eslint-react/no-clone-element
184+
React.cloneElement(icon, { color: 'transparent' })
183185
: icon,
184186
}
185187
: {};

src/components/ConfirmModal/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,16 @@ export const ConfirmModal: React.FC<
4343
!title && !message ? t('components:confirmModal.heading') : title;
4444

4545
if (!isEnabled) {
46+
// TODO @eslint-react rule
47+
// eslint-disable-next-line @eslint-react/no-clone-element
4648
const childrenWithOnClick = React.cloneElement(children, {
4749
onClick: onConfirm,
4850
});
4951
return <>{childrenWithOnClick}</>;
5052
}
5153

54+
// TODO @eslint-react rule
55+
// eslint-disable-next-line @eslint-react/no-clone-element
5256
const childrenWithOnOpen = React.cloneElement(children, {
5357
onClick: confirmModal.onOpen,
5458
});

src/components/ConfirmPopover/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ export const ConfirmPopover: React.FC<
5050
const initialFocusRef = useRef<HTMLButtonElement>(null);
5151

5252
if (!isEnabled) {
53+
// TODO @eslint-react rule
54+
// eslint-disable-next-line @eslint-react/no-clone-element
5355
const childrenWithOnClick = React.cloneElement(children, {
5456
onClick: onConfirm,
5557
});

src/components/DateAgo/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ export type DateAgoProps = Omit<TooltipProps, 'children'> & {
2222
};
2323

2424
export const DateAgo: FC<React.PropsWithChildren<DateAgoProps>> = forwardRef(
25-
function DateAgo({ date = new Date(), format, ...rest }, ref) {
25+
function DateAgo({ date, format, ...rest }, ref) {
2626
const { t } = useTranslation(['components']);
2727
const [, setForceUpdate] = useState(0);
28-
const dayjsDate = dayjs(date);
28+
const dayjsDate = dayjs(date ?? new Date());
2929
const dateFormatted = dayjsDate.format();
3030

3131
useEffect(() => {

src/components/DayPicker/_partials/DayPickerContent.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ export const DayPickerContent = forwardRef<
134134
selected={value ?? undefined}
135135
onSelect={handleDaySelect}
136136
components={{
137+
// TODO @eslint-react rule
138+
// eslint-disable-next-line @eslint-react/no-nested-components
137139
Caption: (props) => (
138140
<Caption
139141
{...props}

src/components/DayPicker/hooks/useDayPickerInputManagement.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,12 @@ export const useDayPickerInputManagement = (
3131
// Pour mettre à jour l'input selon la value
3232
useEffect(() => {
3333
if (!!dateValue) {
34+
// TODO @eslint-react rule
35+
// eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
3436
setInputValue(dayjs(dateValue).format(dateFormat));
3537
} else {
38+
// TODO @eslint-react rule
39+
// eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
3640
setInputValue('');
3741
}
3842
}, [dateFormat, dateValue]);

src/components/DayPicker/index.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ export const DayPicker: FC<DayPickerProps> = ({
4848
id,
4949
value,
5050
onChange,
51-
onClose = () => {},
51+
onClose,
5252
popperPlacement = 'bottom-start',
5353
dateFormat = DATE_FORMAT,
5454
placeholder = 'JJ/MM/AAAA',
55-
inputProps = {},
55+
inputProps,
5656
isDisabled = false,
5757
autoFocus = false,
58-
onMonthChange = () => {},
58+
onMonthChange,
5959
...rest
6060
}) => {
6161
const containerRef = useRef<HTMLDivElement>(null);
@@ -69,7 +69,7 @@ export const DayPicker: FC<DayPickerProps> = ({
6969

7070
// Popper management
7171
const onClosePopper = () => {
72-
onClose(value);
72+
onClose?.(value);
7373
setMode('DAY');
7474
};
7575

@@ -112,21 +112,21 @@ export const DayPicker: FC<DayPickerProps> = ({
112112
const { setMode, setMonth, selectMonth } = hookMonthNavigation;
113113

114114
const handleChangeMonth = (date?: Date | null) => {
115-
onMonthChange(date);
115+
onMonthChange?.(date);
116116
setMonth(date);
117117
};
118118

119119
// Change to day view once we have selected a month on the month picker
120120
const handleSelectMonth = (date: Date) => {
121-
onMonthChange(date);
121+
onMonthChange?.(date);
122122
selectMonth(date);
123123
};
124124

125125
const valueRef = useRef(value);
126126
valueRef.current = value;
127127

128128
return (
129-
<InputGroup ref={containerRef} size={size} width={inputProps.width}>
129+
<InputGroup ref={containerRef} size={size} width={inputProps?.width}>
130130
<InputLeftElement pointerEvents="none">
131131
<Icon
132132
icon={FiCalendar}

src/components/Form/FieldOtp/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ export const FieldOtp = <
102102
<PinInputField
103103
ref={index === 0 ? inputRef : undefined}
104104
flex={1}
105+
// eslint-disable-next-line @eslint-react/no-array-index-key
105106
key={index}
106107
{...props.pinInputFieldProps}
107108
/>

src/components/Form/form-test-utils.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { Form } from '.';
1414
export const FormMocked = <T extends Schema>({
1515
children,
1616
schema,
17-
useFormOptions = {},
17+
useFormOptions,
1818
onSubmit,
1919
}: {
2020
children(options: { form: UseFormReturn<z.infer<T>> }): ReactNode;

src/components/Icons/docs.stories.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ const CustomIcon = ({
3232
name: string;
3333
}) => {
3434
const { hasCopied, onCopy } = useClipboard(name);
35+
// TODO @eslint-react rule
36+
// eslint-disable-next-line @eslint-react/no-clone-element
3537
const icon = React.cloneElement(children, { onClick: onCopy });
3638

3739
return (

src/components/InputNumber/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export const InputNumber = forwardRef<InputNumberProps, 'input'>(
5757
max,
5858
clampValueOnBlur = true,
5959
fixedPrecision = false,
60-
onChange = () => undefined,
60+
onChange,
6161
placeholder,
6262
showButtons = false,
6363
inputGroupProps,

src/components/MonthPicker/MonthPicker.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,21 @@ interface MonthPickerProps {
1313
export const MonthPicker: React.FC<
1414
React.PropsWithChildren<MonthPickerProps>
1515
> = ({
16-
year = new Date().getFullYear(),
16+
year,
1717
onMonthClick,
1818
onTodayButtonClick,
1919
onYearChange,
20-
selectedMonths = [],
20+
selectedMonths,
2121
}) => {
2222
return (
23-
<YearProvider year={year} onYearChange={onYearChange}>
23+
<YearProvider
24+
year={year ?? new Date().getFullYear()}
25+
onYearChange={onYearChange}
26+
>
2427
<MonthPickerProvider
2528
onMonthClick={onMonthClick}
2629
onTodayButtonClick={onTodayButtonClick}
27-
selectedMonths={selectedMonths}
30+
selectedMonths={selectedMonths ?? []}
2831
>
2932
<Content />
3033
</MonthPickerProvider>

src/components/MonthPicker/MonthPickerContext.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createContext, useContext } from 'react';
1+
import { createContext, useContext, useMemo } from 'react';
22

33
type MonthPickerContextType = {
44
onMonthClick?(month: Date): void;
@@ -12,14 +12,16 @@ export const useMonthPickerContext = () => useContext(MonthPickerContext);
1212
export const MonthPickerProvider: React.FC<
1313
React.PropsWithChildren<MonthPickerContextType>
1414
> = ({ onMonthClick, onTodayButtonClick, selectedMonths, children }) => {
15+
const contextValue = useMemo(
16+
() => ({
17+
onMonthClick,
18+
onTodayButtonClick,
19+
selectedMonths,
20+
}),
21+
[onMonthClick, onTodayButtonClick, selectedMonths]
22+
);
1523
return (
16-
<MonthPickerContext.Provider
17-
value={{
18-
onMonthClick,
19-
onTodayButtonClick,
20-
selectedMonths,
21-
}}
22-
>
24+
<MonthPickerContext.Provider value={contextValue}>
2325
{children}
2426
</MonthPickerContext.Provider>
2527
);

src/components/MonthPicker/YearContext.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
createContext,
55
useContext,
66
useEffect,
7+
useMemo,
78
useState,
89
} from 'react';
910

@@ -29,21 +30,24 @@ export const YearProvider: React.FC<
2930
const [year, setYear] = useState(yearProp);
3031

3132
useEffect(() => {
33+
// TODO @eslint-react rule
34+
// eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
3235
setYear(yearProp);
3336
}, [yearProp]);
3437

3538
useEffect(() => {
3639
onYearChange?.(year);
3740
}, [onYearChange, year]);
3841

42+
const contextValue = useMemo(
43+
() => ({
44+
year,
45+
setYear,
46+
}),
47+
[year]
48+
);
49+
3950
return (
40-
<YearContext.Provider
41-
value={{
42-
year,
43-
setYear,
44-
}}
45-
>
46-
{children}
47-
</YearContext.Provider>
51+
<YearContext.Provider value={contextValue}>{children}</YearContext.Provider>
4852
);
4953
};

src/components/Nav/index.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,12 @@ export const Nav = ({ children, breakpoint = 'lg', ...rest }: NavProps) => {
4646
});
4747

4848
const [active, setActive] = useState<ReactNode>(<>-</>);
49+
const contextValue = useMemo(
50+
() => ({ active, setActive, isMenu: !!isMenu }),
51+
[active, isMenu]
52+
);
4953
return (
50-
<NavContext.Provider value={{ active, setActive, isMenu: !!isMenu }}>
54+
<NavContext.Provider value={contextValue}>
5155
<Menu matchWidth {...rest}>
5256
{!isMenu && (
5357
<Stack spacing="1" opacity={!isHydrated ? 0 : undefined}>

src/components/Pagination/index.tsx

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { FC, useContext } from 'react';
1+
import React, { FC, useContext, useMemo } from 'react';
22

33
import {
44
Box,
@@ -202,18 +202,44 @@ export const Pagination = ({
202202
isLoadingPage = false,
203203
...rest
204204
}: PaginationProps) => {
205-
const pagination = getPaginationInfo({ page, pageSize, totalItems });
205+
const {
206+
firstItemOnPage,
207+
firstPage,
208+
isFirstPage,
209+
isLastPage,
210+
lastItemOnPage,
211+
lastPage,
212+
} = getPaginationInfo({ page, pageSize, totalItems });
213+
const contextValue = useMemo(
214+
() => ({
215+
setPage,
216+
page,
217+
pageSize,
218+
totalItems,
219+
isLoadingPage,
220+
firstItemOnPage,
221+
firstPage,
222+
isFirstPage,
223+
isLastPage,
224+
lastItemOnPage,
225+
lastPage,
226+
}),
227+
[
228+
isLoadingPage,
229+
page,
230+
pageSize,
231+
firstItemOnPage,
232+
firstPage,
233+
isFirstPage,
234+
isLastPage,
235+
lastItemOnPage,
236+
lastPage,
237+
setPage,
238+
totalItems,
239+
]
240+
);
206241
return (
207-
<PaginationContext.Provider
208-
value={{
209-
setPage,
210-
page,
211-
pageSize,
212-
totalItems,
213-
isLoadingPage,
214-
...pagination,
215-
}}
216-
>
242+
<PaginationContext.Provider value={contextValue}>
217243
<HStack w="full" {...rest} />
218244
</PaginationContext.Provider>
219245
);

src/components/ResponsiveIconButton/index.tsx

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,15 @@ export const ResponsiveIconButton = forwardRef<
1919
'button'
2020
>(
2121
(
22-
{
23-
hideTextBreakpoints = {
24-
base: true,
25-
md: false,
26-
},
27-
children,
28-
icon,
29-
iconPosition = 'left',
30-
...rest
31-
},
22+
{ hideTextBreakpoints, children, icon, iconPosition = 'left', ...rest },
3223
ref
3324
) => {
34-
const responsiveStates = useBreakpointValue(hideTextBreakpoints);
25+
const responsiveStates = useBreakpointValue(
26+
hideTextBreakpoints ?? {
27+
base: true,
28+
md: false,
29+
}
30+
);
3531

3632
const buttonProps =
3733
iconPosition === 'right' ? { rightIcon: icon } : { leftIcon: icon };

src/components/SearchInput/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ export const SearchInput = forwardRef<SearchInputProps, 'input'>(
6666

6767
useEffect(() => {
6868
if (externalValue !== searchRef.current) {
69+
// TODO @eslint-react rule
70+
// eslint-disable-next-line @eslint-react/hooks-extra/no-direct-set-state-in-use-effect
6971
setSearch(externalValue);
7072
}
7173
}, [externalValue]);

0 commit comments

Comments
 (0)