api types; navbar style refactoring; user themes

This commit is contained in:
2020-10-11 01:30:37 +03:00
parent a6ae3fd69f
commit 069c5ac5ee
25 changed files with 274 additions and 130 deletions
+2 -1
View File
@@ -43,7 +43,8 @@
"not op_mini all"
],
"development": [
"last 1 chrome version"
"last 1 chrome version",
"last 1 firefox version"
]
}
}
+7 -7
View File
@@ -1,6 +1,6 @@
const baseUrl = process.env.NODE_ENV === "development" ? 'http://localhost:8080/v1' : 'https://api.unmei.space/v1';
const response = async (url: string, method: string, body?: string | FormData) => {
const request: ApiRequest = async (url: string, method: string, body?: string | FormData) => {
let bUrl = baseUrl;
if(baseUrl.endsWith('/')) bUrl = bUrl.slice(0, baseUrl.length-1);
if(url.startsWith('/')) url = url.slice(1, baseUrl.length);
@@ -18,17 +18,17 @@ const response = async (url: string, method: string, body?: string | FormData) =
}
if(res.status === 429) return new Promise(res => {
setTimeout(res.bind(null, response(url, method, body)), 1500);
setTimeout(res.bind(null, request(url, method, body)), 1500);
});
if(json?.error) return Promise.reject(json.error_data);
if(!res.ok) return Promise.reject(res.statusText);
return Promise.resolve(json.data);
}
const get = (url: string, data?: object) => response(url, 'GET', JSON.stringify(data));
const post = (url: string, data?: object | FormData) => response(url, 'POST', data instanceof FormData ? data : JSON.stringify(data));
const put = (url: string, data?: object) => response(url, 'PUT', JSON.stringify(data));
const del = (url: string, data?: object) => response(url, 'DELETE', JSON.stringify(data));
const get: Get = (url: string, data?: object) => request(url, 'GET', JSON.stringify(data));
const post: Post = (url: string, data?: object | FormData) => request(url, 'POST', data instanceof FormData ? data : JSON.stringify(data));
const put: Put = (url: string, data?: object) => request(url, 'PUT', JSON.stringify(data));
const del: Delete = (url: string, data?: object) => request(url, 'DELETE', JSON.stringify(data));
const TranslateStatus: { [id: string]: string } = {
planned: 'Запланировано',
@@ -39,6 +39,6 @@ const TranslateStatus: { [id: string]: string } = {
};
export const getVersion = () => get('version');
export const version = '0.10';
export const version = '0.10b';
export { get, post, put, del, TranslateStatus };
+4 -4
View File
@@ -1,6 +1,6 @@
import {post} from "./api";
export const restore = (token: string, new_password: string) => post('auth/restore', { token, new_password });
export const registerUser = (login: string, password: string, email: string, recaptcha: string) => post('auth/register', { login, password, email, recaptcha });
export const login = (login: string, password: string, recaptcha: string) => post('auth/login', { login, password, recaptcha });
export const userLogout = () => post('auth/logout');
export const restore: Restore = (token: string, new_password: string) => post('auth/restore', { token, new_password });
export const registerUser: Register = (login: string, password: string, email: string, recaptcha: string) => post('auth/register', { login, password, email, recaptcha });
export const login: Login = (login: string, password: string, recaptcha: string) => post('auth/login', { login, password, recaptcha });
export const userLogout: Logout = () => post('auth/logout');
+2 -2
View File
@@ -1,4 +1,4 @@
import {get} from "./api";
export const fetchChar = (id: number) => get(`characters/${id}`);
export const fetchCharNovels = (id: number) => get(`characters/${id}/novels`);
export const fetchChar: FetchChar = (id: number) => get(`characters/${id}`);
export const fetchCharNovels: FetchCharNovels = (id: number) => get(`characters/${id}/novels`);
+10 -9
View File
@@ -1,18 +1,19 @@
import {get, post, put} from "./api";
export const fetchUsers = () => get('users');
export const fetchUsers: FetchUsers = () => get('users');
export const fetchUser = (id: number) => get(`users/${id}`);
export const updateUser = (user: UserType) => put(`users/${user.id}`, { user })
export const fetchUser: FetchUser = (id: number) => get(`users/${id}`);
export const updateUser: UpdateUser = (user: UserType) => put(`users/${user.id}`, { user });
export const fetchCurrentUser = () => get('users/me');
export const fetchUserNovels = (id: number) => get(`users/${id}/novels`);
export const fetchCurrentUser: FetchCurrentUser = () => get('users/me');
export const fetchUserNovels: FetchUserNovels = (id: number) => get(`users/${id}/novels`);
export const activateAccount = (token: string) => post('auth/activate', { token });
export const generateActivateLink = () => post('auth/activateToken');
export const activateAccount: ActivateAccount = (token: string) => post('auth/activate', { token });
export const generateActivateLink: GenerateActivateLink = () => post('auth/activateToken');
export const fetchUserSettings = () => get('users/me/settings');
export const updateUserSettings = (use_gravatar: boolean, avatar: string) => post('users/me/settings', { use_gravatar, avatar });
export const fetchUserSettings: FetchUserSettings = () => get('users/me/settings');
export const updateUserGeneralSettings: UpdateUserGeneralSettings = (use_gravatar: boolean, avatar: string) => post('users/me/settings', { use_gravatar, avatar });
export const updateUserAppearanceSettings: UpdateUserAppearanceSettings = (theme: string) => post('users/me/settings', { theme });
export const uploadAvatar = (avatar: FormData) => post('users/me/avatar', avatar);
export const generateRestoreLink = (email: string, recaptcha: string) => post('auth/restoreToken', { email, recaptcha });
@@ -17,7 +17,7 @@ class AdminPanelUsers extends React.Component<Props, State> {
}
componentDidMount() {
fetchUsers().then(users => this.setState({ users }))
fetchUsers().then(users => this.setState({ users }));
}
render() {
@@ -46,4 +46,4 @@ export default connect(
(state: StoreState) => ({
user: state.currentUser
})
)(AdminPanelUsers);
)(AdminPanelUsers);
+9 -1
View File
@@ -41,11 +41,19 @@ class App extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
const cachedTheme = localStorage.getItem('theme');
if(cachedTheme)
document.body.setAttribute('theme', cachedTheme);
const { setUser } = this.props;
fetchCurrentUser().then((user: UserType) => {
setUser(user);
fetchUserSettings().then((settings: UserSettingsType) => {
document.body.setAttribute('theme', settings.theme);
console.log(settings.theme, cachedTheme)
if(settings.theme !== cachedTheme) {
localStorage.setItem('theme', settings.theme);
document.body.setAttribute('theme', settings.theme);
}
});
}).catch((err: ApiError) => {
if(err.code !== 3 && err.text) console.error(err.text);
+3 -2
View File
@@ -1,5 +1,5 @@
@import '../../Constants'
.Comments
margin-top: 1rem
padding: $primaryPadding
@@ -28,6 +28,7 @@
.Comments_TextArea
width: 100%
color: var(--main-color)
background-color: var(--block-color)
font-size: 1rem
padding: .25rem
@@ -43,4 +44,4 @@
border-radius: .2rem
border: none
font-size: 1rem
padding: .5rem
padding: .5rem
+17 -2
View File
@@ -10,7 +10,7 @@ $hoverColor: #f22
position: relative
width: 100%
.Header
.Navbar
color: var(--main-color)
background-color: var(--nav-bg-color)
display: flex
@@ -52,6 +52,21 @@ $hoverColor: #f22
&::before
height: 5px
&__Dropdown
cursor: pointer
&:hover>&_Menu
display: block
&_Menu
display: none
position: absolute
background-color: #fefefe
box-sizing: border-box
padding: .5rem
&_Item
margin: .2rem 0
&__User
justify-content: flex-end
@@ -90,4 +105,4 @@ $hoverColor: #f22
width: 40px
height: 40px
border-radius: 50%
margin-right: .2rem
margin-right: .2rem
+16 -19
View File
@@ -11,7 +11,7 @@ import RegisterModal from "../Modals/RegisterModal";
import LoginModal from "../Modals/LoginModal";
type Props = {
setModal: SetModalType
setModal: SetModal
logout: () => void
currentUser: UserType
};
@@ -50,48 +50,45 @@ class Navbar extends React.Component<Props, State> {
const isMinimized = window.screen.width <= 1000;
const links = (
<div className="Header__Links">
<Link to="/" className={'Header_Button'}>
<div className="Navbar__Links">
<Link to="/" className={'Navbar_Button'}>
Главная
</Link>
<Link to="/novels" className={'Header_Button'}>
<Link to="/novels" className={'Navbar_Button'}>
Новеллы
</Link>
<Link to="/users" className={'Header_Button'}>
Пользователи
</Link>
{expand && isMinimized && (
<div onClick={this.changeSize} className={'Header_Button'} style={{ position: "absolute", right: 0, margin: '.5rem' }}>X</div>
<div onClick={this.changeSize} className={'Navbar_Button'} style={{ position: "absolute", right: 0, margin: '.5rem' }}>X</div>
)}
</div>
);
return (
<nav className={`Header ${expand ? 'Expanded' : 'Minimized'}`}>
<nav className={`Navbar ${expand ? 'Expanded' : 'Minimized'}`}>
{expand || !isMinimized ? links : (
<div className="Header__Links">
<div onClick={this.changeSize} className={'Header_Button'}>
<div className="Navbar__Links">
<div onClick={this.changeSize} className={'Navbar_Button'}>
<FontAwesomeIcon icon={faBars}/>
</div>
</div>
)}
{currentUser &&
(<div className={'Header__User'}>
(<div className={'Navbar__User'}>
{currentUser.authorized ? (<>
<Link to={`/user/${currentUser.id}`} className="Header__User_Profile">
<div className={'Header__User_Avatar'} style={{ backgroundImage: `url(${currentUser.avatar}?s=40&t=${new Date().getTime()})` }}/>
<Link to={`/user/${currentUser.id}`} className="Navbar__User_Profile">
<div className={'Navbar__User_Avatar'} style={{ backgroundImage: `url(${currentUser.avatar}?s=40&t=${new Date().getTime()})` }}/>
<div>{this.props.currentUser.username}</div>
</Link>
{currentUser.group && hasAccessToAdminPanel(currentUser) && (
<Link to={'/kawaii__neko'} className={'Header_Button'}>
<Link to={'/kawaii__neko'} className={'Navbar_Button'}>
Админ-панель
</Link>
)}
<Link className="Header_Button" to={`/user/${currentUser.id}/settings`}>Настройки</Link>
<div className={'Header_Button'} onClick={this.logout}>Выйти</div>
<Link className="Navbar_Button" to={`/user/${currentUser.id}/settings`}>Настройки</Link>
<div className={'Navbar_Button'} onClick={this.logout}>Выйти</div>
</>) : (<>
<div className={'Header_Button'} onClick={() => setModal(<RegisterModal/>)}>Регистрация</div>
<div className={'Header_Button'} onClick={() => setModal(<LoginModal/>)}>Войти</div>
<div className={'Navbar_Button'} onClick={() => setModal(<RegisterModal/>)}>Регистрация</div>
<div className={'Navbar_Button'} onClick={() => setModal(<LoginModal/>)}>Войти</div>
</>)}
</div>)
}
+1 -40
View File
@@ -93,45 +93,6 @@
background-color: var(--sec-bg-color)
border-radius: $borderRadius
form
width: 100%
margin-bottom: .5rem
.Novel__Comments_BBCodes
font-size: 1.3rem
margin-bottom: .2rem
svg
cursor: pointer
svg:first-child
padding-right: .5rem
svg:last-child
padding-left: .5rem
svg:not(:first-child):not(:last-child)
padding: 0 .5rem
.Novel__Comments_TextArea
width: 100%
background-color: var(--block-color)
font-size: 1rem
padding: .25rem
border: none
border-radius: $borderRadius
box-sizing: border-box
min-height: 4rem
resize: none
margin-bottom: .5rem
.Novel__Comments_Submit
background-color: var(--block-color) !important
border-radius: $borderRadius
border: none
font-size: 1rem
padding: .5rem
.Novel__Characters
margin-top: 1rem
padding: $primaryPadding 0
@@ -169,4 +130,4 @@
height: calc(100% - 1.5rem)
background-size: cover
background-position: center
margin-bottom: .2rem
margin-bottom: .2rem
+3 -2
View File
@@ -35,6 +35,7 @@ class UserNovels extends React.Component<Props, State> {
fetchUserNovels(userId)
.then(novels => this.setState({ novels }));
fetchUser(userId)
.then(user => this.setState({ user }));
@@ -53,7 +54,7 @@ class UserNovels extends React.Component<Props, State> {
this.setState({ viewType: type });
localStorage.setItem('viewType', type);
}
render() {
const { novels, user, viewType } = this.state;
if(!novels || !user) return <Loading/>;
@@ -92,4 +93,4 @@ class UserNovels extends React.Component<Props, State> {
}
}
export default UserNovels;
export default UserNovels;
+73 -14
View File
@@ -4,8 +4,20 @@ import {connect} from "react-redux";
import NotFoundError from "../../NotFoundError";
import Button from "../../../ui/Button/Button";
import './Settings.sass';
import {fetchUserSettings, updateUserSettings, uploadAvatar} from "../../../api/users";
import {
fetchUserSettings,
updateUserAppearanceSettings,
updateUserGeneralSettings,
uploadAvatar
} from "../../../api/users";
import {setUser} from "../../../store/actions";
import Tabs from "../../../ui/Tabs/Tabs";
import TabItem from "../../../ui/Tabs/TabItem";
enum TabsNames {
General,
Appearance
}
type Props = {
match: { params: { userId: string } }
@@ -17,11 +29,15 @@ type State = {
// Avatar
useGravatar: boolean
avatar: File | null
theme: Theme
currentTab: TabsNames
}
class Settings extends React.Component<Props, State> {
state: State = {
useGravatar: false, avatar: null
useGravatar: false, avatar: null, theme: "dark",
currentTab: TabsNames.General
}
componentDidMount() {
@@ -38,7 +54,7 @@ class Settings extends React.Component<Props, State> {
saveAvatar = (event: FormEvent) => {
event.preventDefault();
const { avatar, useGravatar } = this.state;
const { avatar, useGravatar} = this.state;
const { setUser } = this.props;
if(avatar) {
@@ -46,28 +62,71 @@ class Settings extends React.Component<Props, State> {
formData.append('avatar', avatar);
uploadAvatar(formData).then(avatarUrl => {
updateUserSettings(useGravatar, avatarUrl).then(setUser)
updateUserGeneralSettings(useGravatar, avatarUrl).then(setUser)
})
} else {
updateUserSettings(useGravatar, '').then(setUser)
updateUserGeneralSettings(useGravatar, '').then(setUser)
}
}
saveTheme = (event: FormEvent) => {
event.preventDefault();
const { theme } = this.state;
updateUserAppearanceSettings(theme).then(user => {
setUser(user);
localStorage.setItem('theme', theme);
document.body.setAttribute('theme', theme);
})
}
render() {
const { currentUser, match: { params: { userId } } } = this.props;
const { useGravatar } = this.state
const { useGravatar, currentTab, theme } = this.state
if(parseInt(userId) !== currentUser.id) return <NotFoundError/>;
return (
<Group title={'Настройки'}>
<Group title={'Аватар'} className={'Settings_Avatar'}>
<form onSubmit={this.saveAvatar}>
<label>Использовать Gravatar <input type="checkbox" onChange={event => this.setState({ useGravatar: event.target.checked })} checked={useGravatar}/></label>
<label>Загрузить аватар <input type="file" onChange={this.onChangeAvatar} disabled={useGravatar}/></label>
<Button>Сохранить</Button>
</form>
</Group>
<Tabs>
<TabItem
selected={currentTab === TabsNames.General}
onClick={() => this.setState({ currentTab: TabsNames.General })}
>
Главное
</TabItem>
<TabItem
selected={currentTab === TabsNames.Appearance}
onClick={() => this.setState({ currentTab: TabsNames.Appearance })}
>
Внешний вид
</TabItem>
</Tabs>
{currentTab === TabsNames.General && (
<Group title={'Аватар'} className={'Settings_Avatar'}>
<form onSubmit={this.saveAvatar}>
<label>Использовать Gravatar <input type="checkbox" onChange={event => this.setState({ useGravatar: event.target.checked })} checked={useGravatar}/></label>
<label>Загрузить аватар <input type="file" onChange={this.onChangeAvatar} disabled={useGravatar}/></label>
<Button>Сохранить</Button>
</form>
</Group>
)}
{currentTab === TabsNames.Appearance && (
<Group title={'Тема'} className={'Settings_Avatar'}>
<form onSubmit={this.saveTheme}>
<select onChange={e => this.setState({ theme: e.target.value as Theme })} value={theme}>
<option value="dark">Dark</option>
<option value="blue">Blue</option>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="light">Light</option>
</select>
<Button>Сохранить</Button>
</form>
</Group>
)}
</Group>
);
}
@@ -80,4 +139,4 @@ export default connect(
dispatch => ({
setUser: (user: UserType) => dispatch(setUser(user))
})
)(Settings);
)(Settings);
+4 -4
View File
@@ -23,7 +23,6 @@
background-position: center
background-size: cover
background-repeat: no-repeat
border-radius: $borderRadius $borderRadius 0 0
@media (max-width: 500px)
height: 10rem !important
@@ -34,7 +33,7 @@
background-color: var(--sec-bg-color)
width: 100%
padding: 0.5rem
border-radius: 0 0 $borderRadius $borderRadius
border-radius: $borderRadius
box-sizing: border-box
&_Nick
@@ -42,6 +41,7 @@
font-weight: 600
&_Group
background-color: #0008
border-color: #eeeeee
border-width: 1px 1px 1px 4px
border-style: solid
@@ -49,7 +49,7 @@
border-radius: 4px
padding: .2rem
text-align: center
font-size: 1rem
font-size: 1.1rem
font-weight: 300
&_Avatar
@@ -142,4 +142,4 @@
&_Items
display: flex
flex-wrap: wrap
justify-content: center
justify-content: center
+34 -5
View File
@@ -7,10 +7,13 @@ import Loading from "../../ui/Loading";
import NovelItem from "../../ui/NovelItem/NovelItem";
import {connect} from "react-redux";
import Button from "../../ui/Button/Button";
import {addNotification} from "../../store/actions";
import NotificationMessage from "../../ui/Notifications/NotificationMessage";
type Props = {
match: { params: { userId: string } }
currentUser: UserType
addNotification: AddNotification
}
type State = {
@@ -38,7 +41,22 @@ class User extends React.Component<Props, State> {
}
sendActivateLink = () => {
generateActivateLink().then(console.log).catch(console.error)
generateActivateLink().then(() => {
const notification = (
<NotificationMessage level={"success"}>
Сообщение успешно отправлено!
</NotificationMessage>
);
this.props.addNotification(notification);
}).catch(err => {
const notification = (
<NotificationMessage level={"success"}>
Сообщение успешно отправлено!
</NotificationMessage>
);
this.props.addNotification(notification);
})
}
render() {
@@ -62,14 +80,22 @@ class User extends React.Component<Props, State> {
)}
<div className="User__Info" style={style}>
{user.cover && <div className="User__Info_Cover" style={{ backgroundImage: `url(${user.cover})` }}/>}
<div className={'User__Info_Main'}>
{user.cover ? (
<div className="User__Info_Cover User__Info_Main" style={{ backgroundImage: `url(${user.cover})` }}>
<div className="User__Info_Avatar" style={{ backgroundImage: `url(${user.avatar}?s=96&t=${new Date().getTime()})` }} />
<div>
<div className='User__Info_Nick'>{user.username}</div>
<div className='User__Info_Group' style={{ borderColor: user.group.color, color: user.group.color }}>{user.group.name}</div>
</div>
</div>
</div>) : (
<div className={'User__Info_Main'}>
<div className="User__Info_Avatar" style={{ backgroundImage: `url(${user.avatar}?s=96&t=${new Date().getTime()})` }} />
<div>
<div className='User__Info_Nick'>{user.username}</div>
<div className='User__Info_Group' style={{ borderColor: user.group.color, color: user.group.color }}>{user.group.name}</div>
</div>
</div>
)}
</div>
<div className="User__Statistic">
@@ -127,5 +153,8 @@ class User extends React.Component<Props, State> {
export default connect(
(state: StoreState) => ({
currentUser: state.currentUser
}),
dispatch => ({
addNotification: (notification: React.ReactNode) => dispatch(addNotification(notification))
})
)(User);
)(User);
+3 -3
View File
@@ -1,9 +1,9 @@
import {createStore} from "redux";
import index from "./reducers";
import {composeWithDevTools} from "redux-devtools-extension";
import reducers from "./reducers/reducers";
const composeEnhancers = composeWithDevTools({
trace: true
});
const store = process.env.NODE_ENV === 'development' ? createStore(index, composeEnhancers()) : createStore(index);
export default store;
const store = process.env.NODE_ENV === 'development' ? createStore(reducers, composeEnhancers()) : createStore(reducers);
export default store;
+29
View File
@@ -0,0 +1,29 @@
type ApiRequest = (url: string, method: string, body?: string | FormData) => Promise<any>;
type Get = (url: string, data?: object) => Promise<any>;
type Post = (url: string, data?: object | FormData) => Promise<any>;
type Put = (url: string, data?: object) => Promise<any>;
type Delete = (url: string, data?: object) => Promise<any>;
type FetchUsers = () => Promise<UserType[]>;
type FetchUser = (id: number) => Promise<UserType>;
type UpdateUser = (user: UserType) => Promise<UserType>;
type FetchCurrentUser = () => Promise<UserType>;
type FetchUserNovels = (id: number) => Promise<NovelType[]>;
type ActivateAccount = (token: string) => Promise<string>;
type GenerateActivateLink = () => Promise<string>;
type FetchUserSettings = () => Promise<UserSettingsType>;
type UpdateUserGeneralSettings = (use_gravatar: boolean, avatar: string) => Promise<UserType>;
type UpdateUserAppearanceSettings = (theme: string) => Promise<UserType>;
type FetchChar = (id: number) => Promise<CharacterType>;
type FetchCharNovels = (id: number) => Promise<NovelType[]>;
type Login = (login: string, password: string, recaptcha: string) => Promise<UserType>;
type Register = (login: string, password: string, email: string, recaptcha: string) => Promise<UserType>;
type Restore = (token: string, new_password: string) => Promise<string>;
type Logout = () => Promise<string>;
+11
View File
@@ -0,0 +1,11 @@
type StoreState = {
currentUser: UserType
notifications: React.ReactNode[]
modal: React.ReactNode
}
type SetUser = (user: UserType) => void
type LogoutUser = () => void
type SetModal = (modal: React.ReactNode | null) => void
type HideModal = () => void
type AddNotification = (notification: React.ReactNode) => void
+4 -10
View File
@@ -5,10 +5,12 @@ type ApiError = {
text: string
}
type DataType = NovelType | NovelType[] | CharacterType | CharacterType[] | UserType | UserType[] | UserSettingsType | UserNovelType | UserNovelType[] | UserGroupType | CommentType | CommentType[] | GenreType | GenreType[] | PostType | PostType[];
type ApiResponse = {
error: boolean
data?: any
error_data?: ApiError
error_data?: ApiError | string
data?: DataType
}
type NovelType = {
@@ -84,11 +86,3 @@ type PostType = {
author: string
author_id: number
}
type StoreState = {
currentUser: UserType
notifications: React.ReactNode[]
modal: React.ReactNode
}
type SetModalType = (modal: React.ReactNode | null) => void
+1 -1
View File
@@ -18,4 +18,4 @@
&__Content
.Comment__User_Username
font-size: 1.1rem
font-weight: 600
font-weight: 600
+13
View File
@@ -0,0 +1,13 @@
import React from "react";
interface Props extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
selected?: boolean
}
const TabItem = ({ children, selected, ...props }: Props) => (
<div className={selected ? 'TabItem Selected' : 'TabItem'} {...props}>
{children}
</div>
)
export default TabItem;
+14
View File
@@ -0,0 +1,14 @@
.Tabs
display: flex
justify-content: space-around
.TabItem
cursor: pointer
font-size: 1.2rem
color: var(--sec-color)
&:hover
color: var(--link-color)
&.Selected
color: var(--main-color)
+10
View File
@@ -0,0 +1,10 @@
import React from "react";
import './Tabs.sass';
const Tabs = ({ children }: { children: React.ReactNode[] }) => (
<div className={'Tabs'}>
{children}
</div>
)
export default Tabs;
+2 -2
View File
@@ -7,7 +7,6 @@
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
@@ -17,7 +16,8 @@
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react"
"jsx": "react",
"skipLibCheck": true
},
"include": [
"src"