diff --git a/.eslintrc.js b/.eslintrc.js index ae67220..2f9ddb7 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -48,6 +48,7 @@ module.exports = { 'react-hooks/exhaustive-deps': 'error', // Checks effect dependencies 'max-len': ['error', { ignoreComments: true, code: 180 }], 'no-param-reassign': 'off', + 'no-undef': 'off', }, globals: { __IS_DEV__: true, diff --git a/src/app/providers/StoreProvider/config/StateSchema.ts b/src/app/providers/StoreProvider/config/StateSchema.ts index 48829c4..8b2501c 100644 --- a/src/app/providers/StoreProvider/config/StateSchema.ts +++ b/src/app/providers/StoreProvider/config/StateSchema.ts @@ -33,10 +33,10 @@ export interface ReduxStoreWithManager extends EnhancedStore { export interface ThunkExtraArg { api: AxiosInstance, - navigate: (to: To, options?: NavigateOptions) => void + navigate?: (to: To, options?: NavigateOptions) => void } export interface ThunkConfig { rejectValue: T, - extra: ThunkExtraArg + extra: ThunkExtraArg, } diff --git a/src/app/providers/StoreProvider/config/store.ts b/src/app/providers/StoreProvider/config/store.ts index 7e62870..b95f644 100644 --- a/src/app/providers/StoreProvider/config/store.ts +++ b/src/app/providers/StoreProvider/config/store.ts @@ -21,7 +21,8 @@ export function createReduxStore( const reducerManager = createReducerManager(rootReducers); const store = configureStore({ - reducer: reducerManager.reduce, + // @ts-ignore + reducer: reducerManager.reduce as ReducersMapObject, devTools: __IS_DEV__, preloadedState: initialState, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ diff --git a/src/app/providers/StoreProvider/ui/StoreProvider.tsx b/src/app/providers/StoreProvider/ui/StoreProvider.tsx index 6511604..1444720 100644 --- a/src/app/providers/StoreProvider/ui/StoreProvider.tsx +++ b/src/app/providers/StoreProvider/ui/StoreProvider.tsx @@ -2,7 +2,7 @@ import { ReactNode } from 'react'; import { Provider } from 'react-redux'; import { createReduxStore } from 'app/providers/StoreProvider/config/store'; import { StateSchema } from 'app/providers/StoreProvider/config/StateSchema'; -import { DeepPartial, ReducersMapObject } from '@reduxjs/toolkit'; +import { ReducersMapObject } from '@reduxjs/toolkit'; import { useNavigate } from 'react-router-dom'; interface StoreProviderProps { diff --git a/src/app/providers/ThemeProvider/lib/useTheme.ts b/src/app/providers/ThemeProvider/lib/useTheme.ts index 81b346b..7853237 100644 --- a/src/app/providers/ThemeProvider/lib/useTheme.ts +++ b/src/app/providers/ThemeProvider/lib/useTheme.ts @@ -2,8 +2,8 @@ import { useContext } from 'react'; import { LOCAL_STORAGE_THEME_KEY, Theme, ThemeContext } from './ThemeContext'; interface UseThemeResult { - toggleTheme: () => void; - theme: Theme; + toggleTheme: () => void; + theme: Theme; } export function useTheme(): UseThemeResult { @@ -11,14 +11,14 @@ export function useTheme(): UseThemeResult { const toggleTheme = () => { const newTheme = theme === Theme.DARK ? Theme.LIGHT : Theme.DARK; - setTheme(newTheme); + setTheme?.(newTheme); // чтобы работали стили в модалках и других частях приложения (используется по умолчанию везде как единая точка входа) document.body.className = newTheme; localStorage.setItem(LOCAL_STORAGE_THEME_KEY, newTheme); }; return { - theme, + theme: theme || Theme.LIGHT, toggleTheme, }; } diff --git a/src/app/types/global.d.ts b/src/app/types/global.d.ts index 145235f..02461b2 100644 --- a/src/app/types/global.d.ts +++ b/src/app/types/global.d.ts @@ -1,20 +1,24 @@ declare module '*.scss' { - interface IClassNames { - [className: string]: string - } - const classNames: IClassNames; - export = classNames; + interface IClassNames { + [className: string]: string + } + const classNames: IClassNames; + export = classNames; } declare module '*.png'; declare module '*.jpg'; declare module '*.jpeg'; declare module '*.svg' { - import React from 'react'; + import React from 'react'; - const SVG: React.VFC>; - export default SVG; + const SVG: React.VFC>; + export default SVG; } declare const __IS_DEV__: boolean; declare const __API__: string; + +type DeepPartial = T extends object ? { + [P in keyof T]?: DeepPartial; +} : T; diff --git a/src/entities/Counter/model/selectors/getCounter/getCounter.test.ts b/src/entities/Counter/model/selectors/getCounter/getCounter.test.ts index 98c226e..8f7475a 100644 --- a/src/entities/Counter/model/selectors/getCounter/getCounter.test.ts +++ b/src/entities/Counter/model/selectors/getCounter/getCounter.test.ts @@ -1,4 +1,3 @@ -import { DeepPartial } from '@reduxjs/toolkit'; import { StateSchema } from 'app/providers/StoreProvider'; import { getCounter } from './getCounter'; diff --git a/src/entities/Counter/model/selectors/getCounterValue/getCounterValue.test.ts b/src/entities/Counter/model/selectors/getCounterValue/getCounterValue.test.ts index 2b98dcf..4aef88d 100644 --- a/src/entities/Counter/model/selectors/getCounterValue/getCounterValue.test.ts +++ b/src/entities/Counter/model/selectors/getCounterValue/getCounterValue.test.ts @@ -1,5 +1,4 @@ import { getCounterValue } from 'entities/Counter/model/selectors/getCounterValue/getCounterValue'; -import { DeepPartial } from '@reduxjs/toolkit'; import { StateSchema } from 'app/providers/StoreProvider'; describe('getCounterValue.test', () => { diff --git a/src/entities/User/model/slice/userSlice.ts b/src/entities/User/model/slice/userSlice.ts index 3726b63..39d5910 100644 --- a/src/entities/User/model/slice/userSlice.ts +++ b/src/entities/User/model/slice/userSlice.ts @@ -12,13 +12,13 @@ export const userSlice = createSlice({ setAuthData: (state, action:PayloadAction) => { state.authData = action.payload; }, - initAuthData: (state, action:PayloadAction) => { + initAuthData: (state) => { const user = localStorage.getItem(USER_LOCALSTORAGE_KEY); if (user) { state.authData = JSON.parse(user); } }, - logout: (state, action:PayloadAction) => { + logout: (state) => { state.authData = undefined; localStorage.removeItem(USER_LOCALSTORAGE_KEY); }, diff --git a/src/features/AuthByUsername/model/selectors/getLoginError/getLoginError.test.ts b/src/features/AuthByUsername/model/selectors/getLoginError/getLoginError.test.ts index 581d81e..3a367b1 100644 --- a/src/features/AuthByUsername/model/selectors/getLoginError/getLoginError.test.ts +++ b/src/features/AuthByUsername/model/selectors/getLoginError/getLoginError.test.ts @@ -1,4 +1,3 @@ -import { DeepPartial } from '@reduxjs/toolkit'; import { StateSchema } from 'app/providers/StoreProvider'; import { getLoginError } from './getLoginError'; diff --git a/src/features/AuthByUsername/model/selectors/getLoginIsLoading/getLoginLoading.test.ts b/src/features/AuthByUsername/model/selectors/getLoginIsLoading/getLoginLoading.test.ts index d1e851a..dcd8d0e 100644 --- a/src/features/AuthByUsername/model/selectors/getLoginIsLoading/getLoginLoading.test.ts +++ b/src/features/AuthByUsername/model/selectors/getLoginIsLoading/getLoginLoading.test.ts @@ -1,4 +1,3 @@ -import { DeepPartial } from '@reduxjs/toolkit'; import { StateSchema } from 'app/providers/StoreProvider'; import { getLoginIsLoading } from './getLoginIsLoading'; diff --git a/src/features/AuthByUsername/model/selectors/getLoginPassword/getLoginPassword.test.ts b/src/features/AuthByUsername/model/selectors/getLoginPassword/getLoginPassword.test.ts index 58764cf..2c7c7a7 100644 --- a/src/features/AuthByUsername/model/selectors/getLoginPassword/getLoginPassword.test.ts +++ b/src/features/AuthByUsername/model/selectors/getLoginPassword/getLoginPassword.test.ts @@ -1,4 +1,3 @@ -import { DeepPartial } from '@reduxjs/toolkit'; import { StateSchema } from 'app/providers/StoreProvider'; import { getLoginPassword } from './getLoginPassword'; diff --git a/src/features/AuthByUsername/model/selectors/getLoginUsername/getLoginUsername.test.ts b/src/features/AuthByUsername/model/selectors/getLoginUsername/getLoginUsername.test.ts index 94740b3..90c8228 100644 --- a/src/features/AuthByUsername/model/selectors/getLoginUsername/getLoginUsername.test.ts +++ b/src/features/AuthByUsername/model/selectors/getLoginUsername/getLoginUsername.test.ts @@ -1,4 +1,3 @@ -import { DeepPartial } from '@reduxjs/toolkit'; import { StateSchema } from 'app/providers/StoreProvider'; import { getLoginUsername } from './getLoginUsername'; diff --git a/src/features/AuthByUsername/model/slice/loginSlice.test.ts b/src/features/AuthByUsername/model/slice/loginSlice.test.ts index 55b94d2..e98d5c8 100644 --- a/src/features/AuthByUsername/model/slice/loginSlice.test.ts +++ b/src/features/AuthByUsername/model/slice/loginSlice.test.ts @@ -1,4 +1,3 @@ -import { DeepPartial } from '@reduxjs/toolkit'; import { LoginSchema } from '../types/loginSchema'; import { loginActions, loginReducer } from './loginSlice'; diff --git a/src/features/AuthByUsername/ui/LoginForm/LoginForm.tsx b/src/features/AuthByUsername/ui/LoginForm/LoginForm.tsx index e2404cd..e1216fe 100644 --- a/src/features/AuthByUsername/ui/LoginForm/LoginForm.tsx +++ b/src/features/AuthByUsername/ui/LoginForm/LoginForm.tsx @@ -52,7 +52,6 @@ const LoginForm = memo(({ className, onSuccess }: LoginFormProps) => { const onLoginClick = useCallback( async () => { const result = await dispatch(loginByUsername({ username, password })); - console.log(result.meta.requestStatus); if (result.meta.requestStatus === 'fulfilled') { onSuccess(); } diff --git a/src/shared/api/api.ts b/src/shared/api/api.ts index 87efb1e..0e1f2c6 100644 --- a/src/shared/api/api.ts +++ b/src/shared/api/api.ts @@ -4,6 +4,6 @@ import { USER_LOCALSTORAGE_KEY } from 'shared/const/localstorage'; export const $api = axios.create({ baseURL: __API__, headers: { - authorization: localStorage.getItem(USER_LOCALSTORAGE_KEY), + authorization: localStorage.getItem(USER_LOCALSTORAGE_KEY) || '', }, }); diff --git a/src/shared/config/storybook/StoreDecorator/StoreDecorator.tsx b/src/shared/config/storybook/StoreDecorator/StoreDecorator.tsx index f007836..8d6b191 100644 --- a/src/shared/config/storybook/StoreDecorator/StoreDecorator.tsx +++ b/src/shared/config/storybook/StoreDecorator/StoreDecorator.tsx @@ -1,17 +1,17 @@ import { Story } from '@storybook/react'; import { StateSchema, StoreProvider } from 'app/providers/StoreProvider'; -import { DeepPartial, ReducersMapObject } from '@reduxjs/toolkit'; import { loginReducer } from 'features/AuthByUsername'; +import { ReducersList } from 'shared/lib/components/DynamicModuleLoared/DynamicModuleLoared'; import { profileReducer } from '../../../../entities/Profile'; -const defaultAsyncReducers: DeepPartial> = { +const defaultAsyncReducers: ReducersList = { loginForm: loginReducer, profile: profileReducer, }; export const StoreDecorator = ( state: DeepPartial, - asyncReducers?: DeepPartial>, + asyncReducers?: ReducersList, ) => (StoryComponent: Story) => ( diff --git a/src/shared/lib/classNames/classNames.ts b/src/shared/lib/classNames/classNames.ts index 78ad399..8de1b47 100644 --- a/src/shared/lib/classNames/classNames.ts +++ b/src/shared/lib/classNames/classNames.ts @@ -1,4 +1,4 @@ -type Mods = Record +export type Mods = Record export function classNames( cls: string, diff --git a/src/shared/lib/components/DynamicModuleLoared/DynamicModuleLoared.tsx b/src/shared/lib/components/DynamicModuleLoared/DynamicModuleLoared.tsx index 9730610..0a80960 100644 --- a/src/shared/lib/components/DynamicModuleLoared/DynamicModuleLoared.tsx +++ b/src/shared/lib/components/DynamicModuleLoared/DynamicModuleLoared.tsx @@ -28,15 +28,15 @@ export const DynamicModuleLoader: FC = (props) => { const dispatch = useDispatch(); useEffect(() => { - Object.entries(reducers).forEach(([name, reducer]: ReducersListEntry) => { - store.reducerManager.add(name, reducer); + Object.entries(reducers).forEach(([name, reducer]) => { + store.reducerManager.add(name as StateSchemaKey, reducer); dispatch({ type: `@INIT ${name} reducer` }); }); return () => { if (removeAfterUnmount) { - Object.entries(reducers).forEach(([name, reducer]: ReducersListEntry) => { - store.reducerManager.remove(name); + Object.entries(reducers).forEach(([name, reducer]) => { + store.reducerManager.remove(name as StateSchemaKey); dispatch({ type: `@DESTROY ${name} reducer` }); }); } diff --git a/src/shared/lib/tests/componentRender/componentRender.tsx b/src/shared/lib/tests/componentRender/componentRender.tsx index 7997aaa..8051698 100644 --- a/src/shared/lib/tests/componentRender/componentRender.tsx +++ b/src/shared/lib/tests/componentRender/componentRender.tsx @@ -4,7 +4,6 @@ import i18nForTests from 'shared/config/i18n/i18nForTests'; import { I18nextProvider } from 'react-i18next'; import { MemoryRouter } from 'react-router-dom'; import { StateSchema, StoreProvider } from 'app/providers/StoreProvider'; -import { DeepPartial } from '@reduxjs/toolkit'; export interface componentRenderOptions { route?: string; diff --git a/src/shared/ui/Button/Button.tsx b/src/shared/ui/Button/Button.tsx index 89aca59..34ca701 100644 --- a/src/shared/ui/Button/Button.tsx +++ b/src/shared/ui/Button/Button.tsx @@ -1,4 +1,4 @@ -import { classNames } from 'shared/lib/classNames/classNames'; +import { classNames, Mods } from 'shared/lib/classNames/classNames'; import { ButtonHTMLAttributes, FC, memo, ReactNode, } from 'react'; @@ -31,14 +31,14 @@ export const Button = memo((props: ButtonProps) => { const { className, children, - theme, + theme = ButtonTheme.OUTLINE, square, isDisabled, size = ButtonSize.M, ...otherProps } = props; - const mods:Record = { + const mods:Mods = { [cls.square]: square, [cls.isDisabled]: isDisabled, }; diff --git a/src/shared/ui/Modal/Modal.tsx b/src/shared/ui/Modal/Modal.tsx index 96635da..60ee426 100644 --- a/src/shared/ui/Modal/Modal.tsx +++ b/src/shared/ui/Modal/Modal.tsx @@ -1,11 +1,12 @@ import React, { + MutableRefObject, ReactNode, useCallback, useEffect, useRef, useState, } from 'react'; -import { classNames } from 'shared/lib/classNames/classNames'; +import { classNames, Mods } from 'shared/lib/classNames/classNames'; import { Portal } from 'shared/ui/Portal/Portal'; import cls from './Modal.module.scss'; @@ -30,7 +31,7 @@ export const Modal = (props: ModalProps) => { const [isClosing, setIsClosing] = useState(false); const [isMounted, setIsMounted] = useState(false); - const timerRef = useRef>(); + const timerRef = useRef() as MutableRefObject>; useEffect(() => { if (isOpen) { @@ -65,7 +66,7 @@ export const Modal = (props: ModalProps) => { }); }, [isOpen, onKeyDown]); - const mods:Record = { + const mods:Mods = { [cls.opened]: isOpen, [cls.isClosing]: isClosing, }; diff --git a/src/widgets/Sidebar/ui/SidebarItem/SidebarItem.tsx b/src/widgets/Sidebar/ui/SidebarItem/SidebarItem.tsx index 2c10ada..2492956 100644 --- a/src/widgets/Sidebar/ui/SidebarItem/SidebarItem.tsx +++ b/src/widgets/Sidebar/ui/SidebarItem/SidebarItem.tsx @@ -12,15 +12,16 @@ interface SidebarItemProps { export const SidebarItem = memo(({ item, collapsed }: SidebarItemProps) => { const { t } = useTranslation(); + return ( - + {item?.Icon && } - {t(item.text)} + {t(item?.text || '')} );