v1.1.2; bugfixes; admin panel improvement; small folder re-struct

This commit is contained in:
2021-02-20 15:15:39 +03:00
parent fa13227e0b
commit ecf88a8608
35 changed files with 4222 additions and 2881 deletions
+16 -17
View File
@@ -1,13 +1,12 @@
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
"@fortawesome/fontawesome-svg-core": "1.2.32",
"@fortawesome/free-brands-svg-icons": "5.15.1",
"@fortawesome/free-solid-svg-icons": "5.15.1",
"@fortawesome/react-fontawesome": "0.1.13",
"@sentry/react": "5.28.0",
"@fortawesome/fontawesome-svg-core": "1.2.34",
"@fortawesome/free-brands-svg-icons": "5.15.2",
"@fortawesome/free-solid-svg-icons": "5.15.2",
"@fortawesome/react-fontawesome": "0.1.14",
"@sentry/react": "6.2.0",
"bbcode-to-react": "0.2.9",
"eruda": "2.4.1",
"eruda-dom": "2.0.0",
@@ -15,23 +14,23 @@
"eruda-memory": "2.0.0",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-loader-spinner": "3.1.14",
"react-loader-spinner": "4.0.0",
"react-redux": "7.2.2",
"react-router-dom": "5.2.0",
"react-snowfall": "^1.0.2",
"react-snowfall": "1.0.2",
"redux": "4.0.5"
},
"devDependencies": {
"@types/node": "14.14.9",
"@types/react": "17.0.0",
"@types/react-dom": "17.0.0",
"@types/react-redux": "7.1.11",
"@types/react-router-dom": "5.1.6",
"@types/react-transition-group": "4.4.0",
"react-scripts": "3.4.4",
"@types/node": "14.14.31",
"@types/react": "17.0.2",
"@types/react-dom": "17.0.1",
"@types/react-redux": "7.1.16",
"@types/react-router-dom": "5.1.7",
"@types/react-transition-group": "4.4.1",
"react-scripts": "4.0.2",
"redux-devtools-extension": "2.13.8",
"sass": "1.29.0",
"typescript": "4.1.2"
"sass": "1.32.8",
"typescript": "4.1.5"
},
"scripts": {
"start": "react-scripts start",
+13
View File
@@ -1,5 +1,11 @@
const baseUrl = process.env.NODE_ENV === "development" ? 'http://localhost:8080/v1' : 'https://api.unmei.space/v1';
// function loadRequestFromCache<T>(url: string): T | null {
// let cached = sessionStorage.getItem(url);
// if(!cached) return null;
// return JSON.parse(cached) as T;
// }
async function request<T>(url: string, method: string, body?: string | FormData): Promise<T> {
let bUrl = baseUrl;
if(baseUrl.endsWith('/'))
@@ -7,6 +13,12 @@ async function request<T>(url: string, method: string, body?: string | FormData)
if(url.startsWith('/'))
url = url.slice(1, baseUrl.length);
// const cached = method.toLowerCase() === 'get' ? loadRequestFromCache<T>(url) : null;
// if(cached) {
// console.debug(`${baseUrl}/${url} loaded from session cache!`);
// return Promise.resolve(cached);
// }
const res = await fetch(`${bUrl}/${url}`, {
method, body,
credentials: "include",
@@ -28,6 +40,7 @@ async function request<T>(url: string, method: string, body?: string | FormData)
if(json?.error) return Promise.reject(json.error_data);
if(!res.ok) return Promise.reject(res.statusText);
if(!json.data) return Promise.reject(null);
sessionStorage.setItem(url, JSON.stringify(json.data));
return Promise.resolve(json.data);
}
+2 -1
View File
@@ -1,6 +1,7 @@
import { del, get, put } from './api';
import { del, get, post, put } from './api';
export const fetchNews = () => get<PostType[]>('news');
export const createPost = (p: PostType) => post<PostType>('news', p);
export const fetchPost = (id: number) => get<PostType>(`news/${id}`);
export const updatePost = (post: PostType) => put<PostType>(`news/${post.id}`, post);
@@ -6,8 +6,8 @@ import { Link } from "react-router-dom";
import { hasAccessToAdminPanel } from "../../utils";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faBars } from '@fortawesome/free-solid-svg-icons';
import RegisterModal from "../Modals/RegisterModal";
import LoginModal from "../Modals/LoginModal";
import RegisterModal from "../../pages/Modals/RegisterModal";
import LoginModal from "../../pages/Modals/LoginModal";
import { logout } from "../../store/ducks/currentUser";
import { setModal } from "../../store/ducks/modal";
+1 -1
View File
@@ -2,7 +2,7 @@ import React from "react";
import { activateAccount } from "../api/users";
import { connect } from "react-redux";
import errors from "../api/errors";
import Loading from "../ui/Loading";
import Loading from "../components/Loading";
import { addNotification } from "../store/ducks/notifications";
type Props = {
+21 -31
View File
@@ -1,51 +1,28 @@
import { connect } from "react-redux";
import React from "react";
import NotFoundError from "../NotFoundError";
import NotFoundError from "../../components/NotFoundError";
import { hasAccessToAdminPanel } from "../../utils";
import './AdminPanel.sass';
import { Link } from "react-router-dom";
import AdminPanelUsers from "./Users/AdminPanelUsers";
import AdminPanelNovels from "./Novels/AdminPanelNovels";
import ModifyUser from "./Users/ModifyUser";
import { Link, Route, Switch } from "react-router-dom";
import APNews from "./News/APNews";
import APModifyPost from "./News/APModifyPost";
import APAddPost from "./News/APAddPost";
import APNovels from "./Novels/APNovels";
import APUsers from "./Users/APUsers";
import APModifyUser from "./Users/APModifyUser";
type Props = {
user: UserType
match: { path: string }
location: { pathname: string }
}
type State = {}
class AdminPanel extends React.Component<Props, State> {
render() {
const { user, match: { path }, location: { pathname } } = this.props;
const { user, match: { path } } = this.props;
if(!user || !user.group) return <NotFoundError/>;
if(!hasAccessToAdminPanel(user)) return <NotFoundError/>;
const subPath = pathname.slice(path.length + 1);
let component;
switch(subPath) {
case 'users':
component = <AdminPanelUsers path={`${path}/${subPath}`}/>;
break;
case 'novels':
component = <AdminPanelNovels/>;
break;
case 'news':
component = <APNews path={`${path}/${subPath}`}/>;
break;
default: {
const users = /users\/(\d+)/;
const news = /news\/(\d+)/;
const userMatch = subPath.match(users);
const newsMatch = subPath.match(news);
if(userMatch) component = <ModifyUser userId={parseInt(userMatch[1])}/>;
if(newsMatch) component = <APModifyPost postId={parseInt(newsMatch[1])}/>;
}
}
return (
<div className={'AdminPanel'}>
@@ -57,7 +34,20 @@ class AdminPanel extends React.Component<Props, State> {
<Link to={`${path}/novels`}>Новелы</Link>
<Link to={`${path}/news`}>Новости</Link>
</div>
{component}
<Switch>
<Route exact path={`${path}/news`} component={APNews}/>
<Route exact path={`${path}/news/new`} component={APAddPost}/>
<Route exact path={`${path}/news/:id`} component={APModifyPost}/>
<Route exact path={`${path}/novels`} component={APNovels}/>
<Route exact path={`${path}/novels/new`} component={NotFoundError}/>
<Route exact path={`${path}/novels/:id`} component={NotFoundError}/>
<Route exact path={`${path}/users`} component={APUsers}/>
<Route exact path={`${path}/users/new`} component={NotFoundError}/>
<Route exact path={`${path}/users/:id`} component={APModifyUser}/>
</Switch>
</div>
);
}
+122
View File
@@ -0,0 +1,122 @@
import React, { ChangeEvent, FormEvent } from "react";
import Group from "../../../ui/Group/Group";
import { createPost } from "../../../api/news";
import './APNews.sass';
import '../../../ui/TextField/TextField.sass'
import Input from "../../../ui/Input/Input";
import Button from "../../../ui/Button/Button";
import BBEditor from "../../../ui/BBEditor/BBEditor";
// @ts-ignore
import parser from 'bbcode-to-react';
import Title from "../../../ui/Title/Title";
import { connect } from "react-redux";
import NotificationMessage from "../../../ui/Notifications/NotificationMessage";
import { setModal } from "../../../store/ducks/modal";
import { addNotification } from "../../../store/ducks/notifications";
type Props = {
match: { path: string }
history: { push: (path: string) => void }
setPopout: (modal: React.ReactNode | null) => void
addNotification: (notification: React.ReactNode) => void
};
type State = {
post: PostType
title: string
previewShort: string
previewFull: string
};
class APModifyPost extends React.Component<Props, State> {
state: State = {
post: {} as PostType, title: '',
previewShort: '', previewFull: ''
}
private shortPost = React.createRef<HTMLTextAreaElement>();
private fullPost = React.createRef<HTMLTextAreaElement>();
savePost = async(event: FormEvent) => {
event.preventDefault();
const { post } = this.state;
if(!this.shortPost.current || !this.fullPost.current)
return;
post.short_post = this.shortPost.current.value;
post.full_post = this.fullPost.current.value;
const { addNotification } = this.props;
createPost(post).then(createdPost => {
const notification = (
<NotificationMessage level={"success"}>
Успешно создана новость с ID {createdPost.id}!
</NotificationMessage>
);
addNotification(notification);
const path = this.props.match.path.split('/');
this.props.history.push(`/${path[1]}/${path[2]}`);
});
}
previewShort = () => {
if(!this.shortPost.current) return;
this.setState({ previewShort: parser.toReact(this.shortPost.current.value) })
}
previewFull = () => {
if(!this.fullPost.current) return;
this.setState({ previewFull: parser.toReact(this.fullPost.current.value) })
}
changeTitle = (event: ChangeEvent<HTMLInputElement>) => {
const { post } = this.state;
post.title = event.target.value;
document.title = event.target.value || 'Unmei';
this.setState({ post });
}
render() {
const { post, title, previewShort, previewFull } = this.state;
return (
<Group title={title}>
<form onSubmit={this.savePost} className={'APPost'}>
<Input type="text" placeholder={'Заголовок'} value={post.title ?? ''} onChange={this.changeTitle}/>
<div className={'APPost__Short'}>
<Title>Короткая новость</Title>
<BBEditor inputRef={this.shortPost} placeholder={'Короткая новость'}/>
{previewShort.length > 0 && (<>
<Title>Предпросмотр</Title>
<div className={'APPost__Short_Preview TextField'}>{previewShort}</div>
</>)}
<Button type={"button"} onClick={this.previewShort}>Предпросмотр</Button>
</div>
<div className={'APPost__Full'}>
<Title>Полная новость</Title>
<BBEditor inputRef={this.fullPost} placeholder={'Полная новость'}/>
{previewFull.length > 0 && (<>
<Title>Предпросмотр</Title>
<div className={'APPost__Full_Preview TextField'}>{previewFull}</div>
</>)}
<Button type={"button"} onClick={this.previewFull}>Предпросмотр</Button>
</div>
<div>
<Button style={{ marginRight: '1rem' }}>Сохранить</Button>
</div>
</form>
</Group>
)
}
}
export default connect(null,
dispatch => ({
setPopout: (modal: React.ReactNode | null) => dispatch(setModal(modal)),
addNotification: (notification: React.ReactNode) => dispatch(addNotification(notification))
})
)(APModifyPost);
+18 -10
View File
@@ -1,9 +1,8 @@
import React, { ChangeEvent, FormEvent } from "react";
import Group from "../../../ui/Group/Group";
import NotFoundError from "../../NotFoundError";
import NotFoundError from "../../../components/NotFoundError";
import { deletePost, fetchPost, updatePost } from "../../../api/news";
import './APNews.sass';
import '../../../ui/TextField/TextField.sass'
import Input from "../../../ui/Input/Input";
import Button from "../../../ui/Button/Button";
import BBEditor from "../../../ui/BBEditor/BBEditor";
@@ -17,7 +16,8 @@ import { setModal } from "../../../store/ducks/modal";
import { addNotification } from "../../../store/ducks/notifications";
type Props = {
postId: number
match: { params: { id: number }, path: string }
history: { push: (path: string) => void }
setPopout: (modal: React.ReactNode | null) => void
addNotification: (notification: React.ReactNode) => void
};
@@ -39,8 +39,9 @@ class APModifyPost extends React.Component<Props, State> {
private fullPost = React.createRef<HTMLTextAreaElement>();
componentDidMount() {
const { postId } = this.props;
fetchPost(postId).then((post: PostType) => {
const { match } = this.props;
fetchPost(match.params.id).then((post: PostType) => {
this.setState({ post, title: post.title });
});
}
@@ -61,7 +62,7 @@ class APModifyPost extends React.Component<Props, State> {
<NotificationMessage level={"success"}>
Успешно!
</NotificationMessage>
)
);
addNotification(notification)
});
}
@@ -88,14 +89,21 @@ class APModifyPost extends React.Component<Props, State> {
const post = this.state.post;
if(!post) return;
post.title = event.target.value;
document.title = event.target.value || 'Unmei';
this.setState({ post });
}
deletePost = () => {
const { postId, setPopout } = this.props;
deletePost = async (postId: number) => {
await deletePost(postId);
const path = this.props.match.path.split('/')
this.props.history.push(`/${path[1]}/${path[2]}`);
}
_deletePost = () => {
const { match: { params: { id} }, setPopout } = this.props;
const popout = (
<ConfirmPopout onConfirm={() => deletePost(postId)}>
<ConfirmPopout onConfirm={() => this.deletePost(id)}>
Вы уверены?
</ConfirmPopout>
);
@@ -135,7 +143,7 @@ class APModifyPost extends React.Component<Props, State> {
<div>
<Button style={{ marginRight: '1rem' }}>Сохранить</Button>
<Button type={"button"} style={{ color: 'var(--error-bg-color)' }}
onClick={this.deletePost}>Удалить</Button>
onClick={this._deletePost}>Удалить</Button>
</div>
</form>
</Group>
+4 -2
View File
@@ -5,7 +5,7 @@ import { Link } from "react-router-dom";
import Button from "../../../ui/Button/Button";
type Props = {
path: string
match: { path: string }
};
type State = {
@@ -23,11 +23,13 @@ class APNews extends React.Component<Props, State> {
render() {
const { news } = this.state;
const { path } = this.props;
const { match: { path } } = this.props;
return (
<Group title={'Новости'}>
<Link to={`${path}/new`}>
<Button>Добавить новость</Button>
</Link>
{news.map(post => (
<Link to={`${path}/${post.id}`} key={post.id}>
<div style={{ display: "flex" }}>
@@ -5,7 +5,7 @@ type Props = {};
type State = {};
class AdminPanelNovels extends React.Component<Props, State> {
class APNovels extends React.Component<Props, State> {
render() {
return (
<div>Novels</div>
@@ -17,4 +17,4 @@ export default connect(
(state: StoreState) => ({
user: state.currentUser
})
)(AdminPanelNovels);
)(APNovels);
@@ -1,14 +1,14 @@
import React, { ChangeEvent, FormEvent } from "react";
import { connect } from "react-redux";
import { fetchUser, updateUser } from "../../../api/users";
import Loading from "../../../ui/Loading";
import Loading from "../../../components/Loading";
import './APUser.sass';
import NotificationMessage from "../../../ui/Notifications/NotificationMessage";
import Button from "../../../ui/Button/Button";
import { addNotification } from "../../../store/ducks/notifications";
type Props = {
userId: number
match: { params: { id: number } }
addNotification: (notification: React.ReactNode) => void
};
@@ -17,14 +17,14 @@ type State = {
username: string
};
class ModifyUser extends React.Component<Props, State> {
class APModifyUser extends React.Component<Props, State> {
state: State = {
user: null, username: ''
}
componentDidMount() {
const { userId } = this.props;
fetchUser(userId).then((user: UserType) => {
const { match: { params: { id } } } = this.props;
fetchUser(id).then((user: UserType) => {
this.setState({ user, username: user.username });
document.title = `${user.username} / Админ-панель`;
})
@@ -95,4 +95,4 @@ export default connect(
dispatch(addNotification(notification))
}
})
)(ModifyUser);
)(APModifyUser);
+1 -1
View File
@@ -24,4 +24,4 @@
width: 100%
&[type='checkbox']
width: 0
width: 16px
+47
View File
@@ -0,0 +1,47 @@
import React from "react";
import { connect } from "react-redux";
import { fetchUsers } from "../../../api/users";
import { Link } from "react-router-dom";
import Group from "../../../ui/Group/Group";
type Props = {
match: { path: string }
};
type State = {
users: UserType[]
};
class APUsers extends React.Component<Props, State> {
state: State = {
users: []
}
componentDidMount() {
fetchUsers().then(users => this.setState({ users }));
}
render() {
const { users } = this.state;
const { match: { path } } = this.props;
return (
<Group title={'Пользователи'}>
{users.sort((a, b) => a.id - b.id).map(user => (
<Link to={`${path}/${user.id}`} key={user.id}>
<div style={{ display: "flex" }}>
<div style={{ marginRight: '.5rem', fontWeight: 600 }}>{user.id}</div>
<div>{user.username}</div>
</div>
</Link>
))}
</Group>
)
}
}
export default connect(
(state: StoreState) => ({
user: state.currentUser
})
)(APUsers);
@@ -1,49 +0,0 @@
import React from "react";
import { connect } from "react-redux";
import { fetchUsers } from "../../../api/users";
import { Link } from "react-router-dom";
type Props = {
path: string
};
type State = {
users: UserType[]
};
class AdminPanelUsers extends React.Component<Props, State> {
state: State = {
users: []
}
componentDidMount() {
fetchUsers().then(users => this.setState({ users }));
}
render() {
const { users } = this.state;
const { path } = this.props;
return (
<div>
<div style={{ textAlign: "center", fontWeight: 600, fontSize: '1.5rem' }}>Пользователи</div>
<div>
{users.sort((a, b) => a.id - b.id).map(user => (
<Link to={`${path}/${user.id}`} key={user.id}>
<div style={{ display: "flex" }}>
<div style={{ marginRight: '.5rem', fontWeight: 600 }}>{user.id}</div>
<div>{user.username}</div>
</div>
</Link>
))}
</div>
</div>
)
}
}
export default connect(
(state: StoreState) => ({
user: state.currentUser
})
)(AdminPanelUsers);
+3 -3
View File
@@ -1,17 +1,17 @@
import React from 'react';
import { Route, Switch } from "react-router-dom";
import './App.sass';
import Navbar from "../Navbar/Navbar";
import Navbar from "../../components/Navbar/Navbar";
import Novel from "../Novel/Novel";
import User from "../User/User";
import Main from "../Main/Main"
import NotFoundError from "../NotFoundError";
import NotFoundError from "../../components/NotFoundError";
import { fetchCurrentUser, fetchUserSettings } from "../../api/users";
import { connect } from "react-redux";
import Character from "../Character/Character";
import SpoilerTag from "../../ui/Spoiler/SpoilerTag";
import Novels from "../Novels/Novels";
import Footer from '../Footer/Footer';
import Footer from '../../components/Footer/Footer';
import UserNovels from '../User/Novels/UserNovels';
import ColorTag from "../../ui/Tags/ColorTag";
import ActivateAccount from "../ActivateAccount";
+2 -2
View File
@@ -4,8 +4,8 @@ import './Character.sass'
// @ts-ignore
import parser from 'bbcode-to-react';
import NovelItem from "../../ui/NovelItem/NovelItem";
import Loading from "../../ui/Loading";
import NotFoundError from "../NotFoundError";
import Loading from "../../components/Loading";
import NotFoundError from "../../components/NotFoundError";
type Props = {
match: { params: { charId: number } }
+1 -1
View File
@@ -1,6 +1,6 @@
import React from "react";
import { getClub } from "../../api/clubs";
import Loading from "../../ui/Loading";
import Loading from "../../components/Loading";
import Group from "../../ui/Group/Group";
type Props = {
+9 -8
View File
@@ -10,7 +10,7 @@ import {
} from "@fortawesome/free-solid-svg-icons";
import Comment from '../../ui/Comment/Comment';
import './Comments.sass';
import Loading from "../../ui/Loading";
import Loading from "../../components/Loading";
import { fetchUser } from "../../api/users";
import { connect } from "react-redux";
import NotificationMessage from "../../ui/Notifications/NotificationMessage";
@@ -71,9 +71,8 @@ class Comments extends React.Component<Props, State> {
componentDidUpdate(prevProps: Readonly<Props>) {
const { comments } = this.props;
const { comments: prevComments } = prevProps;
if(prevComments.length !== comments.length) {
if(prevProps.comments.length !== comments.length) {
let { users } = this.state;
comments.forEach(async comment => {
@@ -89,7 +88,8 @@ class Comments extends React.Component<Props, State> {
render() {
const { user, comments, hasMore, loadMore } = this.props;
const { users, commentText } = this.state;
if(!user) return <Loading/>;
if(!user)
return <Loading/>;
return (
<div className="Comments">
@@ -120,12 +120,13 @@ class Comments extends React.Component<Props, State> {
{hasMore && <Button onClick={loadMore}>Загрузить ещё</Button>}
</div>
</form>}
{!comments && (
{comments.length === 0 && (
<Loading/>
)}
{comments && comments.length > 0 ? (
comments.map(comment => <Comment text={comment.text} key={comment.id}
user={users.get(comment.user_id)}/>)
{comments.length > 0 ? (
comments.map(comment => (
<Comment text={comment.text} key={comment.id} user={users.get(comment.user_id)}/>
))
) : (
'Никто не оставил комментарий к этой новелле... :c'
)}
+1 -1
View File
@@ -1,6 +1,6 @@
import React from "react";
import { fetchNews } from "../../api/news";
import Loading from "../../ui/Loading";
import Loading from "../../components/Loading";
import { Link } from "react-router-dom";
import NewsPost from "../../ui/NewsPost/NewsPost";
+1 -1
View File
@@ -1,5 +1,5 @@
import React from "react";
import Loading from "../../ui/Loading";
import Loading from "../../components/Loading";
import { fetchNews } from "../../api/news";
import NewsPost from "../../ui/NewsPost/NewsPost";
import { Link } from "react-router-dom";
+2 -2
View File
@@ -1,7 +1,7 @@
import React from "react";
import { fetchPost } from "../../api/news";
import Loading from "../../ui/Loading";
import NotFoundError from "../NotFoundError";
import Loading from "../../components/Loading";
import NotFoundError from "../../components/NotFoundError";
import './Post.sass'
import { Link } from "react-router-dom";
// @ts-ignore
+2 -2
View File
@@ -1,6 +1,6 @@
import React from "react";
import './Novel.sass'
import NotFoundError from "../NotFoundError";
import NotFoundError from "../../components/NotFoundError";
import { connect } from "react-redux";
import {
createUserNovel,
@@ -14,7 +14,7 @@ import {
updateUserNovel
} from "../../api/novels";
import { Link } from "react-router-dom";
import Loading from "../../ui/Loading";
import Loading from "../../components/Loading";
import { TranslateExitStatus, TranslatePlatform, TranslateStatus } from "../../api/api";
import Comments from "../Comments/Comments";
import LoadingModal from "../Modals/LoadingModal";
+1 -1
View File
@@ -2,7 +2,7 @@ import './Novels.sass'
import React from "react";
import { fetchNovels } from "../../api/novels";
import NovelItem from '../../ui/NovelItem/NovelItem';
import Loading from "../../ui/Loading";
import Loading from "../../components/Loading";
type State = {
novels: NovelType[] | null
+1 -1
View File
@@ -1,7 +1,7 @@
import React from 'react';
import './UserNovels.sass';
import { fetchUser, fetchUserNovels } from '../../../api/users';
import Loading from '../../../ui/Loading';
import Loading from '../../../components/Loading';
import NovelItem from '../../../ui/NovelItem/NovelItem';
import { capitalize, generateClassName, getRandomInt } from "../../../utils";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+1 -1
View File
@@ -1,7 +1,7 @@
import React from "react";
import Group from "../../../ui/Group/Group";
import { connect } from "react-redux";
import NotFoundError from "../../NotFoundError";
import NotFoundError from "../../../components/NotFoundError";
import './Settings.sass';
import Tabs from "../../../ui/Tabs/Tabs";
import TabItem from "../../../ui/Tabs/TabItem";
+2 -2
View File
@@ -1,9 +1,9 @@
import React, { CSSProperties } from "react";
import { fetchUser, fetchUserNovels, generateActivateLink } from "../../api/users";
import './User.sass'
import NotFoundError from "../NotFoundError";
import NotFoundError from "../../components/NotFoundError";
import { Link } from "react-router-dom";
import Loading from "../../ui/Loading";
import Loading from "../../components/Loading";
import NovelItem from "../../ui/NovelItem/NovelItem";
import { connect } from "react-redux";
import Button from "../../ui/Button/Button";
+1 -1
View File
@@ -1,6 +1,6 @@
import React from "react";
import { fetchUsers } from "../../api/users";
import Loading from "../../ui/Loading";
import Loading from "../../components/Loading";
import './Users.sass';
import { Link } from "react-router-dom";
+1 -1
View File
@@ -3,7 +3,7 @@ import './Comment.sass'
import { Link } from "react-router-dom";
// @ts-ignore
import parser from 'bbcode-to-react';
import Loading from "../Loading";
import Loading from "../../components/Loading";
type Props = {
user: UserType | undefined
+3 -2
View File
@@ -16,8 +16,9 @@
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react",
"skipLibCheck": true
"jsx": "react-jsx",
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true
},
"include": [
"src"
+3716 -2510
View File
File diff suppressed because it is too large Load Diff