Skip to content

Commit

Permalink
feat: add AppLoaderLayout
Browse files Browse the repository at this point in the history
  • Loading branch information
sashtje committed Oct 16, 2023
1 parent 0a811ff commit 4c00445
Show file tree
Hide file tree
Showing 12 changed files with 113 additions and 12 deletions.
2 changes: 1 addition & 1 deletion json-server/db.json
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,7 @@
"isAppRedesigned": true
},
"jsonSettings": {
"theme": "app_light_theme",
"theme": "app_orange_theme",
"isFirstVisit": true,
"settingsPageHasBeenOpen": false,
"isArticlesPageWasOpened": true
Expand Down
16 changes: 13 additions & 3 deletions src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { Navbar, Sidebar } from '@/widgets';
import { classNames } from '@/shared/lib/classNames';
import { getUserInited, initAuthData } from '@/entities/User';
import { useAppDispatch } from '@/shared/lib/hooks/useAppDispatch/useAppDispatch';
import { PageLoader } from '@/widgets/PageLoader';
import { ToggleFeatures } from '@/shared/lib/features';
import { MainLayout } from '@/shared/layouts';
import { AppLoaderLayout, MainLayout } from '@/shared/layouts';
import { PageLoader } from '@/widgets/PageLoader';

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

Expand All @@ -22,7 +22,17 @@ export function App() {
}, [dispatch, inited]);

if (!inited) {
return <PageLoader />;
return (
<ToggleFeatures
feature="isAppRedesigned"
on={
<div className={classNames('app_redesigned', {}, [])}>
<AppLoaderLayout />
</div>
}
off={<PageLoader />}
/>
);
}

return (
Expand Down
11 changes: 9 additions & 2 deletions src/app/providers/ThemeProvider/ui/ThemeProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,33 @@ import { ReactNode, useEffect, useMemo, useState } from 'react';
import { ThemeContext } from '@/shared/lib/context/ThemeContext';
import { Theme } from '@/shared/const/theme';
import { useJsonSettings } from '@/entities/User';
import { LOCAL_STORAGE_THEME_KEY } from '@/shared/const/localStorage';

interface ThemeProviderProps {
children: ReactNode;
initialTheme?: Theme;
}

const fallbackTheme = localStorage.getItem(LOCAL_STORAGE_THEME_KEY) as Theme;

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

useEffect(() => {
if (!isThemeInited && !initialTheme && defaultTheme) {
setTheme(defaultTheme);
setThemeInited(true);
(document.childNodes[1] as HTMLElement).className = defaultTheme;
}
}, [defaultTheme, initialTheme, isThemeInited]);

useEffect(() => {
(document.childNodes[1] as HTMLElement).className = theme;
localStorage.setItem(LOCAL_STORAGE_THEME_KEY, theme);
}, [theme]);

const defaultProps = useMemo(
() => ({
theme,
Expand Down
10 changes: 9 additions & 1 deletion src/entities/User/model/services/initAuthData.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { createAsyncThunk } from '@reduxjs/toolkit';

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

import { getUserDataByIdQuery } from '../../api/userApi';
import { User } from '../types/user';
Expand All @@ -20,6 +23,11 @@ export const initAuthData = createAsyncThunk<User, void, ThunkConfig<string>>(
try {
const response = await dispatch(getUserDataByIdQuery(userId)).unwrap();

localStorage.setItem(
LOCAL_STORAGE_LAST_DESIGN_THEME_KEY,
response.features?.isAppRedesigned ? 'new' : 'old',
);

return response;
} catch (e) {
console.log(e);
Expand Down
9 changes: 8 additions & 1 deletion src/entities/User/model/slice/userSlice.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

import { USER_LOCALSTORAGE_KEY } from '@/shared/const/localStorage';
import {
LOCAL_STORAGE_LAST_DESIGN_THEME_KEY,
USER_LOCALSTORAGE_KEY,
} from '@/shared/const/localStorage';
import { setFeatureFlags } from '@/shared/lib/features';

import { initAuthData } from '../services/initAuthData';
Expand All @@ -20,6 +23,10 @@ export const userSlice = createSlice({
state.authData = action.payload;
setFeatureFlags(action.payload.features);
localStorage.setItem(USER_LOCALSTORAGE_KEY, action.payload.id);
localStorage.setItem(
LOCAL_STORAGE_LAST_DESIGN_THEME_KEY,
action.payload.features?.isAppRedesigned ? 'new' : 'old',
);
},
logout: (state) => {
state.authData = undefined;
Expand Down
1 change: 1 addition & 0 deletions src/shared/const/localStorage.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const USER_LOCALSTORAGE_KEY = 'user';
export const ARTICLES_VIEW_LOCALSTORAGE_KEY = 'articles_view';
export const LOCAL_STORAGE_THEME_KEY = 'theme';
export const LOCAL_STORAGE_LAST_DESIGN_THEME_KEY = 'last_design';
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.header {
padding: 16px;
}

.content {
height: 100%;
}
16 changes: 16 additions & 0 deletions src/shared/layouts/AppLoaderLayout/AppLoaderLayout.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { ComponentMeta, ComponentStory } from '@storybook/react';

import { AppLoaderLayout } from './AppLoaderLayout';

export default {
title: 'shared/AppLoaderLayout',
component: AppLoaderLayout,
argTypes: {
backgroundColor: { control: 'color' },
},
} as ComponentMeta<typeof AppLoaderLayout>;

const Template: ComponentStory<typeof AppLoaderLayout> = (args) => <AppLoaderLayout {...args} />;

export const Normal = Template.bind({});
Normal.args = {};
40 changes: 40 additions & 0 deletions src/shared/layouts/AppLoaderLayout/AppLoaderLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { memo } from 'react';

import { classNames } from '@/shared/lib/classNames';
import { HStack, VStack } from '@/shared/ui/redesigned/Stack';
import { Skeleton } from '@/shared/ui/redesigned/Skeleton';

import { MainLayout } from '../MainLayout/MainLayout';
import cls from './AppLoaderLayout.module.scss';

interface AppLoaderLayoutProps {
className?: string;
}

export const AppLoaderLayout = memo((props: AppLoaderLayoutProps) => {
const { className } = props;

return (
<MainLayout
className={classNames(cls.appLoaderLayout, {}, [className])}
header={
<HStack className={cls.header}>
<Skeleton width={40} height={40} borderRadius="50%" />
</HStack>
}
content={
<VStack gap="16" className={cls.content}>
<Skeleton width="70%" height={32} borderRadius="16px" />
<Skeleton width="40%" height={20} borderRadius="16px" />
<Skeleton width="50%" height={20} borderRadius="16px" />
<Skeleton width="30%" height={32} borderRadius="16px" />
<Skeleton width="80%" height="40%" borderRadius="16px" />
<Skeleton width="80%" height="40%" borderRadius="16px" />
</VStack>
}
sidebar={<Skeleton width={220} height="100%" borderRadius="32px" />}
/>
);
});

AppLoaderLayout.displayName = 'AppLoaderLayout';
1 change: 1 addition & 0 deletions src/shared/layouts/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { MainLayout } from './MainLayout/MainLayout';
export { StickyContentLayout } from './StickyContentLayout/StickyContentLayout';
export { AppLoaderLayout } from './AppLoaderLayout/AppLoaderLayout';
8 changes: 7 additions & 1 deletion src/shared/lib/features/lib/setGetFeatures.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { FeatureFlags } from '@/shared/types/featureFlags';
import { LOCAL_STORAGE_LAST_DESIGN_THEME_KEY } from '@/shared/const/localStorage';

const defaultFeatures: FeatureFlags = {
isAppRedesigned: localStorage.getItem(LOCAL_STORAGE_LAST_DESIGN_THEME_KEY) === 'new',
};
// so far features doesn't change during one session
let featureFlags: FeatureFlags = {};
let featureFlags: FeatureFlags = {
...defaultFeatures,
};

export function setFeatureFlags(newFeatureFlags?: FeatureFlags) {
if (newFeatureFlags) {
Expand Down
4 changes: 1 addition & 3 deletions src/shared/lib/hooks/useTheme/useTheme.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useContext, useEffect } from 'react';

import { Theme } from '@/shared/const/theme';
import { toggleFeatures } from '@/shared/lib/features';

import { toggleFeatures } from '../../features';
import { ThemeContext } from '../../context/ThemeContext';

interface UseThemeResult {
Expand All @@ -20,8 +20,6 @@ export function useTheme(): UseThemeResult {
on: () => 'redesigned',
off: () => '',
})} ${theme || Theme.LIGHT}`;

(document.childNodes[1] as HTMLElement).className = theme || Theme.LIGHT;
}, [theme]);

const toggleTheme = (saveAction: (theme: Theme) => void) => {
Expand Down

0 comments on commit 4c00445

Please sign in to comment.