Skip to content

Commit

Permalink
fix: fix saving user and theme
Browse files Browse the repository at this point in the history
  • Loading branch information
sashtje committed Oct 8, 2023
1 parent 6d89687 commit 37652f1
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 22 deletions.
14 changes: 10 additions & 4 deletions src/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import { Suspense, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useSelector } from 'react-redux';

import { Navbar, Sidebar } from '@/widgets';
import { classNames } from '@/shared/lib/classNames';
import { getUserInited, userActions } from '@/entities/User';
import { getUserInited, initAuthData } from '@/entities/User';
import { useAppDispatch } from '@/shared/lib/hooks/useAppDispatch/useAppDispatch';
import { PageLoader } from '@/widgets/PageLoader';

import { AppRouter } from './providers/router';

export function App() {
const dispatch = useDispatch();
const dispatch = useAppDispatch();
const inited = useSelector(getUserInited);

useEffect(() => {
dispatch(userActions.initAuthData());
dispatch(initAuthData());
}, [dispatch]);

if (!inited) {
return <PageLoader />;
}

return (
<div className={classNames('app', {}, [])}>
<Suspense fallback="">
Expand Down
14 changes: 11 additions & 3 deletions src/app/providers/ThemeProvider/ui/ThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ReactNode, useMemo, useState } from 'react';
import { ReactNode, useEffect, useMemo, useState } from 'react';

import { ThemeContext } from '@/shared/lib/context/ThemeContext';
import { Theme } from '@/shared/const/theme';
Expand All @@ -11,8 +11,16 @@ interface ThemeProviderProps {

export const ThemeProvider = (props: ThemeProviderProps) => {
const { children, initialTheme } = props;
const { theme: defaultTheme = Theme.LIGHT } = useJsonSettings();
const [theme, setTheme] = useState<Theme>(initialTheme || defaultTheme);
const { theme: defaultTheme } = useJsonSettings();
const [isThemeInited, setThemeInited] = useState(false);
const [theme, setTheme] = useState<Theme>(initialTheme || defaultTheme || Theme.LIGHT);

useEffect(() => {
if (!isThemeInited && !initialTheme && defaultTheme) {
setTheme(defaultTheme);
setThemeInited(true);
}
}, [defaultTheme, initialTheme, isThemeInited]);

const defaultProps = useMemo(
() => ({
Expand Down
7 changes: 7 additions & 0 deletions src/entities/User/api/userApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@ const userApi = rtkApi.injectEndpoints({
},
}),
}),
getUserDataById: build.query<User, string>({
query: (userId) => ({
url: `/users/${userId}`,
method: 'GET',
}),
}),
}),
});

export const setJsonSettingsMutation = userApi.endpoints.setJsonSettings.initiate;
export const getUserDataByIdQuery = userApi.endpoints.getUserDataById.initiate;
1 change: 1 addition & 0 deletions src/entities/User/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export {
export { UserRole } from './model/consts/consts';
export { useJsonSettingByKey, useJsonSettings } from './model/selectors/jsonSettings/jsonSettings';
export { saveJsonSettings } from './model/services/saveJsonSettings';
export { initAuthData } from './model/services/initAuthData';
29 changes: 29 additions & 0 deletions src/entities/User/model/services/initAuthData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { createAsyncThunk } from '@reduxjs/toolkit';

import { ThunkConfig } from '@/app/providers/StoreProvider';
import { USER_LOCALSTORAGE_KEY } from '@/shared/const/localStorage';

import { getUserDataByIdQuery } from '../../api/userApi';
import { User } from '../types/user';

export const initAuthData = createAsyncThunk<User, void, ThunkConfig<string>>(
'user/initAuthData',
async (_, thunkAPI) => {
const { rejectWithValue, dispatch } = thunkAPI;

const userId = localStorage.getItem(USER_LOCALSTORAGE_KEY);

if (!userId) {
return rejectWithValue('');
}

try {
const response = await dispatch(getUserDataByIdQuery(userId)).unwrap();

return response;
} catch (e) {
console.log(e);
return rejectWithValue('');
}
},
);
21 changes: 11 additions & 10 deletions src/entities/User/model/slice/userSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { USER_LOCALSTORAGE_KEY } from '@/shared/const/localStorage';
import { setFeatureFlags } from '@/shared/lib/features';

import { initAuthData } from '../services/initAuthData';
import { saveJsonSettings } from '../services/saveJsonSettings';
import { User, UserSchema } from '../types/user';
import { JsonSettings } from '../types/jsonSettings';
Expand All @@ -18,16 +19,7 @@ export const userSlice = createSlice({
setAuthData: (state, action: PayloadAction<User>) => {
state.authData = action.payload;
setFeatureFlags(action.payload.features);
},
initAuthData: (state) => {
const userData = localStorage.getItem(USER_LOCALSTORAGE_KEY);

if (userData) {
const user = JSON.parse(userData) as User;
state.authData = user;
setFeatureFlags(user.features);
}
state._inited = true;
localStorage.setItem(USER_LOCALSTORAGE_KEY, action.payload.id);
},
logout: (state) => {
state.authData = undefined;
Expand All @@ -44,6 +36,15 @@ export const userSlice = createSlice({
}
},
);
builder
.addCase(initAuthData.fulfilled, (state, { payload }: PayloadAction<User>) => {
state.authData = payload;
setFeatureFlags(payload.features);
state._inited = true;
})
.addCase(initAuthData.rejected, (state) => {
state._inited = true;
});
},
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { createAsyncThunk } from '@reduxjs/toolkit';

import { User, userActions } from '@/entities/User';
import { USER_LOCALSTORAGE_KEY } from '@/shared/const/localStorage';
import { ThunkConfig } from '@/app/providers/StoreProvider';

interface LoginByUsernameProps {
Expand All @@ -21,8 +20,6 @@ export const loginByUsername = createAsyncThunk<User, LoginByUsernameProps, Thun
throw new Error();
}

localStorage.setItem(USER_LOCALSTORAGE_KEY, JSON.stringify(response.data));

dispatch(userActions.setAuthData(response.data));

return response.data;
Expand Down
7 changes: 6 additions & 1 deletion src/features/authByUsername/ui/LoginForm/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ReducersList,
} from '@/shared/lib/components/DynamicModuleLoader/DynamicModuleLoader';
import { useAppDispatch } from '@/shared/lib/hooks/useAppDispatch/useAppDispatch';
import { useTheme } from '@/shared/lib/hooks/useTheme/useTheme';

import { getLoginUsername } from '../../model/selectors/getLoginUsername/getLoginUsername';
import { getLoginPassword } from '../../model/selectors/getLoginPassword/getLoginPassword';
Expand Down Expand Up @@ -40,6 +41,7 @@ export const LoginForm = memo((props: LoginFormProps) => {
const password = useSelector(getLoginPassword);
const isLoading = useSelector(getLoginIsLoading);
const error = useSelector(getLoginError);
const { setTheme } = useTheme();

const onChangeUsername = useCallback(
(value: string) => {
Expand All @@ -59,9 +61,12 @@ export const LoginForm = memo((props: LoginFormProps) => {
const result = await dispatch(loginByUsername({ username, password }));

if (result.meta.requestStatus === 'fulfilled') {
if (typeof result?.payload === 'object' && result?.payload?.jsonSettings?.theme) {
setTheme?.(result.payload.jsonSettings.theme);
}
onSuccess();
}
}, [onSuccess, dispatch, password, username]);
}, [onSuccess, dispatch, password, username, setTheme]);

return (
<DynamicModuleLoader reducers={initialReducers} removeAfterUnmount>
Expand Down
3 changes: 2 additions & 1 deletion src/shared/lib/hooks/useTheme/useTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ThemeContext } from '../../context/ThemeContext';
interface UseThemeResult {
toggleTheme: (saveAction: (theme: Theme) => void) => void;
theme: Theme;
setTheme?: (theme: Theme) => void;
}

export function useTheme(): UseThemeResult {
Expand Down Expand Up @@ -38,5 +39,5 @@ export function useTheme(): UseThemeResult {
saveAction?.(newTheme);
};

return { theme: theme || Theme.LIGHT, toggleTheme };
return { theme: theme || Theme.LIGHT, toggleTheme, setTheme };
}

0 comments on commit 37652f1

Please sign in to comment.