finished types; novel improvement; fixed navbar for mobile
This commit is contained in:
Generated
+9
-9
@@ -3944,9 +3944,9 @@
|
||||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001146",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001146.tgz",
|
||||
"integrity": "sha512-VAy5RHDfTJhpxnDdp2n40GPPLp3KqNrXz1QqFv4J64HvArKs8nuNMOWkB3ICOaBTU/Aj4rYAo/ytdQDDFF/Pug==",
|
||||
"version": "1.0.30001147",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001147.tgz",
|
||||
"integrity": "sha512-CPyN875geYk46eIqPl5jlmotCr5YZC2KxIVfb4z0FrNfLxPM+MyodWD2irJGDG8vUUE1fmg3De9vt8uaC6Nf6w==",
|
||||
"dev": true
|
||||
},
|
||||
"capture-exit": {
|
||||
@@ -4791,9 +4791,9 @@
|
||||
}
|
||||
},
|
||||
"css-what": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.1.tgz",
|
||||
"integrity": "sha512-wHOppVDKl4vTAOWzJt5Ek37Sgd9qq1Bmj/T1OjvicWbU5W7ru7Pqbn0Jdqii3Drx/h+dixHKXNhZYx7blthL7g==",
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
|
||||
"integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==",
|
||||
"dev": true
|
||||
},
|
||||
"cssdb": {
|
||||
@@ -13914,9 +13914,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "6.12.5",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz",
|
||||
"integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==",
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
|
||||
+26
-9
@@ -1,6 +1,6 @@
|
||||
const baseUrl = process.env.NODE_ENV === "development" ? 'http://192.168.0.103:8080/v1' : 'https://api.unmei.space/v1';
|
||||
const baseUrl = process.env.NODE_ENV === "development" ? 'http://localhost:8080/v1' : 'https://api.unmei.space/v1';
|
||||
|
||||
const request: ApiRequest = async (url: string, method: string, body?: string | FormData) => {
|
||||
async function request<T>(url: string, method: string, body?: string | FormData): Promise<T> {
|
||||
let bUrl = baseUrl;
|
||||
if(baseUrl.endsWith('/')) bUrl = bUrl.slice(0, baseUrl.length-1);
|
||||
if(url.startsWith('/')) url = url.slice(1, baseUrl.length);
|
||||
@@ -10,7 +10,7 @@ const request: ApiRequest = async (url: string, method: string, body?: string |
|
||||
credentials: "include"
|
||||
});
|
||||
|
||||
let json: ApiResponse;
|
||||
let json: ApiResponse<T>;
|
||||
try {
|
||||
json = await res.json();
|
||||
} catch (e) {
|
||||
@@ -22,13 +22,22 @@ const request: ApiRequest = async (url: string, method: string, body?: string |
|
||||
});
|
||||
if(json?.error) return Promise.reject(json.error_data);
|
||||
if(!res.ok) return Promise.reject(res.statusText);
|
||||
if(!json.data) return Promise.reject(null);
|
||||
return Promise.resolve(json.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));
|
||||
function get<T>(url: string, data?: object): Promise<T> {
|
||||
return request<T>(url, 'GET', JSON.stringify(data));
|
||||
}
|
||||
function post<T>(url: string, data?: object | FormData): Promise<T> {
|
||||
return request(url, 'POST', data instanceof FormData ? data : JSON.stringify(data));
|
||||
}
|
||||
function put<T>(url: string, data?: object): Promise<T> {
|
||||
return request<T>(url, 'PUT', JSON.stringify(data));
|
||||
}
|
||||
function del<T>(url: string, data?: object): Promise<T> {
|
||||
return request<T>(url, 'DELETE', JSON.stringify(data));
|
||||
}
|
||||
|
||||
const TranslateStatus: { [id: string]: string } = {
|
||||
planned: 'Запланировано',
|
||||
@@ -38,7 +47,15 @@ const TranslateStatus: { [id: string]: string } = {
|
||||
deferred: 'Отложено'
|
||||
};
|
||||
|
||||
export const getVersion = () => get('version');
|
||||
const TranslatePlatform: { [id: string]: string } = {
|
||||
win: 'Windows'
|
||||
};
|
||||
|
||||
const TranslateExitStatus: { [id: string]: string } = {
|
||||
came_out: 'Вышла'
|
||||
}
|
||||
|
||||
export const getVersion = () => get<VersionResponse>('version');
|
||||
export const version = '0.10b';
|
||||
|
||||
export { get, post, put, del, TranslateStatus };
|
||||
export { get, post, put, del, TranslateStatus, TranslatePlatform, TranslateExitStatus };
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
import {post} from "./api";
|
||||
|
||||
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');
|
||||
export const restore = (token: string, new_password: string) => post<string>('auth/restore', { token, new_password });
|
||||
export const registerUser = (login: string, password: string, email: string, recaptcha: string) => post<UserType>('auth/register', { login, password, email, recaptcha });
|
||||
export const login = (login: string, password: string, recaptcha: string) => post<UserType>('auth/login', { login, password, recaptcha });
|
||||
export const userLogout = () => post<string>('auth/logout');
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {get} from "./api";
|
||||
|
||||
export const fetchChar: FetchChar = (id: number) => get(`characters/${id}`);
|
||||
export const fetchCharNovels: FetchCharNovels = (id: number) => get(`characters/${id}/novels`);
|
||||
export const fetchChar = (id: number) => get<CharacterType>(`characters/${id}`);
|
||||
export const fetchCharNovels = (id: number) => get<NovelType[]>(`characters/${id}/novels`);
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
import {del, get, put} from './api';
|
||||
|
||||
export const fetchNews = () => get('news');
|
||||
export const fetchNews = () => get<PostType[]>('news');
|
||||
|
||||
export const fetchPost = (id: number) => get(`news/${id}`);
|
||||
export const updatePost = (post: PostType) => put(`news/${post.id}`, post);
|
||||
export const deletePost = (id: number) => del(`news/${id}`);
|
||||
export const fetchPost = (id: number) => get<PostType>(`news/${id}`);
|
||||
export const updatePost = (post: PostType) => put<PostType>(`news/${post.id}`, post);
|
||||
export const deletePost = (id: number) => del(`news/${id}`);
|
||||
|
||||
+12
-12
@@ -1,20 +1,20 @@
|
||||
import { get, post, put, del } from "./api";
|
||||
|
||||
|
||||
export const fetchNovels = (orderBy?: string) => get(orderBy ? `novels?sort=${orderBy}` : 'novels');
|
||||
export const createNovel = (novel: NovelType) => post('novels', { ...novel });
|
||||
export const fetchNovels = (orderBy?: string) => get<NovelType[]>(orderBy ? `novels?sort=${orderBy}` : 'novels');
|
||||
export const createNovel = (novel: NovelType) => post<NovelType>('novels', { ...novel });
|
||||
|
||||
export const fetchNovel = (id: number) => get(`novels/${id}`);
|
||||
export const updateNovel = (id: number, novel: NovelType) => put(`novels/${id}`, { ...novel });
|
||||
export const fetchNovel = (id: number) => get<NovelType>(`novels/${id}`);
|
||||
export const updateNovel = (id: number, novel: NovelType) => put<NovelType>(`novels/${id}`, { ...novel });
|
||||
|
||||
export const fetchNovelCharacters = (id: number) => get(`novels/${id}/characters`);
|
||||
export const fetchNovelCharacters = (id: number) => get<CharacterType[]>(`novels/${id}/characters`);
|
||||
|
||||
export const fetchNovelGenres = (id: number) => get(`novels/${id}/genres`);
|
||||
export const fetchNovelGenres = (id: number) => get<GenreType[]>(`novels/${id}/genres`);
|
||||
|
||||
export const fetchNovelComments = (id: number, offset=0, count=5) => get(`novels/${id}/comments?offset=${offset}&count=${count}`);
|
||||
export const postNovelComment = (id: number, text: string) => post(`novels/${id}/comments`, { text });
|
||||
export const fetchNovelComments = (id: number, offset=0, count=5) => get<CommentsResponse>(`novels/${id}/comments?offset=${offset}&count=${count}`);
|
||||
export const postNovelComment = (id: number, text: string) => post<CommentType>(`novels/${id}/comments`, { text });
|
||||
|
||||
export const fetchUserNovel = (userId: number, novelId: number) => get(`users/${userId}/novels/${novelId}`);
|
||||
export const createUserNovel = (userId: number, novelId: number, status='planned') => post(`users/${userId}/novels`, { novel_id: Number(novelId), status });
|
||||
export const updateUserNovel = (userId: number, novelId: number, data: { mark?: number; status?: string }) => put(`users/${userId}/novels/${novelId}`, data);
|
||||
export const deleteUserNovel = (userId: number, novelId: number) => del(`users/${userId}/novels/${novelId}`);
|
||||
export const fetchUserNovel = (userId: number, novelId: number) => get<UserNovelType>(`users/${userId}/novels/${novelId}`);
|
||||
export const createUserNovel = (userId: number, novelId: number, status='planned') => post<UserNovelType>(`users/${userId}/novels`, { novel_id: Number(novelId), status });
|
||||
export const updateUserNovel = (userId: number, novelId: number, data: { mark?: number; status?: string }) => put<UserNovelType>(`users/${userId}/novels/${novelId}`, data);
|
||||
export const deleteUserNovel = (userId: number, novelId: number) => del(`users/${userId}/novels/${novelId}`);
|
||||
|
||||
+11
-11
@@ -1,19 +1,19 @@
|
||||
import {get, post, put} from "./api";
|
||||
|
||||
export const fetchUsers: FetchUsers = () => get('users');
|
||||
export const fetchUsers = () => get<UserType[]>('users');
|
||||
|
||||
export const fetchUser: FetchUser = (id: number) => get(`users/${id}`);
|
||||
export const updateUser: UpdateUser = (user: UserType) => put(`users/${user.id}`, { user });
|
||||
export const fetchUser = (id: number) => get<UserType>(`users/${id}`);
|
||||
export const updateUser = (user: UserType) => put<UserType>(`users/${user.id}`, { user });
|
||||
|
||||
export const fetchCurrentUser: FetchCurrentUser = () => get('users/me');
|
||||
export const fetchUserNovels: FetchUserNovels = (id: number) => get(`users/${id}/novels`);
|
||||
export const fetchCurrentUser = () => get<UserType>('users/me');
|
||||
export const fetchUserNovels = (id: number) => get<NovelType[]>(`users/${id}/novels`);
|
||||
|
||||
export const activateAccount: ActivateAccount = (token: string) => post('auth/activate', { token });
|
||||
export const generateActivateLink: GenerateActivateLink = () => post('auth/activateToken');
|
||||
export const activateAccount = (token: string) => post<string>('auth/activate', { token });
|
||||
export const generateActivateLink = () => post<string>('auth/activateToken');
|
||||
|
||||
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 fetchUserSettings = () => get<UserSettingsType>('users/me/settings');
|
||||
export const updateUserGeneralSettings = (use_gravatar: boolean, avatar: string) => post<UserType>('users/me/settings', { use_gravatar, avatar });
|
||||
export const updateUserAppearanceSettings = (theme: string) => post<UserType>('users/me/settings', { theme });
|
||||
export const uploadAvatar = (avatar: FormData) => post<string>('users/me/avatar', avatar);
|
||||
|
||||
export const generateRestoreLink = (email: string, recaptcha: string) => post('auth/restoreToken', { email, recaptcha });
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
// @ts-ignore
|
||||
import Loader from 'react-loader-spinner';
|
||||
import Popout from "../../ui/Modal/Popout";
|
||||
|
||||
const LoadingModal = () => (
|
||||
<Popout>
|
||||
<Loader color='#aaa' type='Rings'/>
|
||||
</Popout>
|
||||
);
|
||||
|
||||
export default LoadingModal;
|
||||
@@ -56,17 +56,25 @@ $hoverColor: #f22
|
||||
cursor: pointer
|
||||
|
||||
&:hover>&_Menu
|
||||
display: block
|
||||
display: flex
|
||||
flex-direction: column
|
||||
|
||||
&_Menu
|
||||
display: none
|
||||
position: absolute
|
||||
background-color: #fefefe
|
||||
background-color: var(--nav-bg-color)
|
||||
box-sizing: border-box
|
||||
padding: .5rem
|
||||
max-width: 250px
|
||||
right: 0
|
||||
|
||||
&_Item
|
||||
margin: .2rem 0
|
||||
color: var(--main-color)
|
||||
|
||||
&:hover
|
||||
color: var(--link-color)
|
||||
|
||||
&__User
|
||||
justify-content: flex-end
|
||||
|
||||
|
||||
+33
-14
@@ -12,7 +12,7 @@ import LoginModal from "../Modals/LoginModal";
|
||||
|
||||
type Props = {
|
||||
setModal: SetModal
|
||||
logout: () => void
|
||||
logout: LogoutUser
|
||||
currentUser: UserType
|
||||
};
|
||||
|
||||
@@ -63,6 +63,37 @@ class Navbar extends React.Component<Props, State> {
|
||||
</div>
|
||||
);
|
||||
|
||||
const user = isMinimized ? (
|
||||
<div className={'Navbar__Dropdown'}>
|
||||
<div className="Navbar__Dropdown_Button 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>
|
||||
</div>
|
||||
<div className="Navbar__Dropdown_Menu">
|
||||
<Link to={`/user/${currentUser.id}`} className="Navbar__Dropdown_Item">Профиль</Link>
|
||||
{currentUser.group && hasAccessToAdminPanel(currentUser) && (
|
||||
<Link to={'/kawaii__neko'} className={'Navbar__Dropdown_Item'}>
|
||||
Админ-панель
|
||||
</Link>
|
||||
)}
|
||||
<Link className="Navbar__Dropdown_Item" to={`/user/${currentUser.id}/settings`}>Настройки</Link>
|
||||
<div className="Navbar__Dropdown_Item" onClick={this.logout}>Выход</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (<>
|
||||
<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={'Navbar_Button'}>
|
||||
Админ-панель
|
||||
</Link>
|
||||
)}
|
||||
<Link className="Navbar_Button" to={`/user/${currentUser.id}/settings`}>Настройки</Link>
|
||||
<div className={'Navbar_Button'} onClick={this.logout}>Выйти</div>
|
||||
</>)
|
||||
|
||||
return (
|
||||
<nav className={`Navbar ${expand ? 'Expanded' : 'Minimized'}`}>
|
||||
{expand || !isMinimized ? links : (
|
||||
@@ -74,19 +105,7 @@ class Navbar extends React.Component<Props, State> {
|
||||
)}
|
||||
{currentUser &&
|
||||
(<div className={'Navbar__User'}>
|
||||
{currentUser.authorized ? (<>
|
||||
<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={'Navbar_Button'}>
|
||||
Админ-панель
|
||||
</Link>
|
||||
)}
|
||||
<Link className="Navbar_Button" to={`/user/${currentUser.id}/settings`}>Настройки</Link>
|
||||
<div className={'Navbar_Button'} onClick={this.logout}>Выйти</div>
|
||||
</>) : (<>
|
||||
{currentUser.authorized ? user : (<>
|
||||
<div className={'Navbar_Button'} onClick={() => setModal(<RegisterModal/>)}>Регистрация</div>
|
||||
<div className={'Navbar_Button'} onClick={() => setModal(<LoginModal/>)}>Войти</div>
|
||||
</>)}
|
||||
|
||||
+41
-11
@@ -13,11 +13,15 @@ import {
|
||||
} from "../../api/novels";
|
||||
import {Link} from "react-router-dom";
|
||||
import Loading from "../../ui/Loading";
|
||||
import { TranslateStatus } from "../../api/api";
|
||||
import {TranslateExitStatus, TranslatePlatform, TranslateStatus} from "../../api/api";
|
||||
import Comments from "../Comments/Comments";
|
||||
import {hideModal, setModal} from "../../store/actions";
|
||||
import LoadingModal from "../Modals/LoadingModal";
|
||||
|
||||
type Props = {
|
||||
currentUser: UserType
|
||||
setModal: SetModal
|
||||
hideModal: HideModal
|
||||
match: { params: { novelId: number } }
|
||||
};
|
||||
|
||||
@@ -43,25 +47,30 @@ class Novel extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
updateNovelStatus = (status: string) => {
|
||||
const { match: { params } , currentUser } = this.props;
|
||||
const { match: { params } , currentUser, setModal, hideModal } = this.props;
|
||||
const { userData } = this.state;
|
||||
|
||||
setModal(<LoadingModal/>);
|
||||
if(userData) {
|
||||
updateUserNovel(currentUser.id, params.novelId, { status }).then(r => {
|
||||
this.setState({ userData: r, statusExpanded: false })
|
||||
this.setState({ userData: r, statusExpanded: false });
|
||||
hideModal();
|
||||
}).catch(console.error);
|
||||
} else {
|
||||
createUserNovel(currentUser.id, params.novelId, status).then(r => {
|
||||
this.setState({ userData: r, statusExpanded: false })
|
||||
this.setState({ userData: r, statusExpanded: false });
|
||||
hideModal();
|
||||
}).catch(console.error);
|
||||
}
|
||||
};
|
||||
|
||||
deleteNovelStatus = () => {
|
||||
const { match: { params } , currentUser } = this.props;
|
||||
const { match: { params } , currentUser, setModal, hideModal } = this.props;
|
||||
|
||||
deleteUserNovel(currentUser.id, params.novelId).then(() => {
|
||||
setModal(<LoadingModal/>);
|
||||
deleteUserNovel(currentUser.id, params.novelId).then(() => {
|
||||
this.setState({ userData: null, statusExpanded: false });
|
||||
hideModal();
|
||||
});
|
||||
};
|
||||
|
||||
@@ -113,7 +122,7 @@ class Novel extends React.Component<Props, State> {
|
||||
}).catch((err: ApiError) => {
|
||||
this.setState({ errorCode: err.code });
|
||||
});
|
||||
|
||||
|
||||
if(currentUser.authorized)
|
||||
fetchUserNovel(currentUser.id, params.novelId).then((userData: UserNovelType) => {
|
||||
this.setState({ userData });
|
||||
@@ -123,15 +132,26 @@ class Novel extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
updateNovelMark = (mark: number) => {
|
||||
const { match: { params }, currentUser } = this.props;
|
||||
const { match: { params }, currentUser, hideModal, setModal } = this.props;
|
||||
const { userData } = this.state;
|
||||
|
||||
if(userData?.mark === mark) return;
|
||||
setModal(<LoadingModal/>);
|
||||
updateUserNovel(currentUser.id, params.novelId, { mark }).then(res => {
|
||||
userData!!.mark = mark;
|
||||
this.setState({ userData })
|
||||
this.setState({ userData: res });
|
||||
hideModal();
|
||||
});
|
||||
}
|
||||
|
||||
countNovelDuration = (t: number) => {
|
||||
const h = Math.round(t / 60);
|
||||
const m = t - (t*60);
|
||||
|
||||
if(h === 0) return `${m} мин`;
|
||||
else return `${h} ч`;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { errorCode, novel, comments, characters, genres, userData, statusExpanded, hasMoreComments } = this.state;
|
||||
const { currentUser } = this.props;
|
||||
@@ -193,6 +213,12 @@ class Novel extends React.Component<Props, State> {
|
||||
<div>
|
||||
<strong>Год выхода</strong>: {novel.release_date.toLocaleDateString()}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Статус</strong>: {TranslateExitStatus[novel.exit_status]}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Продолжительность</strong>: {this.countNovelDuration(novel.duration)}
|
||||
</div>
|
||||
<div className="Novel__Info_Rating"><strong>Ср. оценка</strong>: {novel.rating.toFixed(2)}</div>
|
||||
<pre className={'Novel__Info_Description'}>{novel.description}</pre>
|
||||
</div>
|
||||
@@ -215,7 +241,11 @@ class Novel extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
export default connect(
|
||||
(state: any) => ({
|
||||
(state: StoreState) => ({
|
||||
currentUser: state.currentUser
|
||||
}),
|
||||
dispatch => ({
|
||||
setModal: (modal: React.ReactNode | null) => dispatch(setModal(modal)),
|
||||
hideModal: () => dispatch(hideModal())
|
||||
})
|
||||
)(Novel);
|
||||
)(Novel);
|
||||
|
||||
@@ -18,4 +18,4 @@ export default (state=initialState, action: Action) => {
|
||||
}
|
||||
default: return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+7
-28
@@ -1,29 +1,8 @@
|
||||
type ApiRequest = (url: string, method: string, body?: string | FormData) => Promise<any>;
|
||||
type VersionResponse = {
|
||||
version: string
|
||||
}
|
||||
|
||||
|
||||
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>;
|
||||
type CommentsResponse = {
|
||||
comments: CommentType[]
|
||||
count: number
|
||||
}
|
||||
|
||||
Vendored
+7
-4
@@ -1,16 +1,16 @@
|
||||
type Theme = 'dark' | 'blue' | 'red' | 'green' | 'light'
|
||||
type ExitStatus = 'came_out'
|
||||
type NovelPlatform = 'win'
|
||||
|
||||
type ApiError = {
|
||||
code: number
|
||||
text: string
|
||||
}
|
||||
|
||||
type DataType = NovelType | NovelType[] | CharacterType | CharacterType[] | UserType | UserType[] | UserSettingsType | UserNovelType | UserNovelType[] | UserGroupType | CommentType | CommentType[] | GenreType | GenreType[] | PostType | PostType[];
|
||||
|
||||
type ApiResponse = {
|
||||
type ApiResponse<T> = {
|
||||
error: boolean
|
||||
error_data?: ApiError | string
|
||||
data?: DataType
|
||||
data?: T
|
||||
}
|
||||
|
||||
type NovelType = {
|
||||
@@ -22,6 +22,9 @@ type NovelType = {
|
||||
status: string
|
||||
rating: number
|
||||
release_date: Date
|
||||
exit_status: ExitStatus
|
||||
duration: number
|
||||
platform: NovelPlatform
|
||||
}
|
||||
|
||||
type CharacterType = {
|
||||
|
||||
+2
-2
@@ -4,8 +4,8 @@ import Loader from 'react-loader-spinner'
|
||||
|
||||
const Loading: React.FC = () => (
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Loader color='#aaa' type='Rings' style={{ height: '100%' }} />
|
||||
<Loader color='#aaa' type='Rings'/>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Loading;
|
||||
export default Loading;
|
||||
|
||||
@@ -5,7 +5,7 @@ import {setModal} from "../../store/actions";
|
||||
|
||||
type Props = {
|
||||
setModal: (modal: React.ReactNode | null) => void
|
||||
children: any
|
||||
children: React.ReactChild | React.ReactChild[]
|
||||
className?: string
|
||||
title?: string
|
||||
}
|
||||
@@ -63,4 +63,4 @@ export default connect(null,
|
||||
dispatch(setModal(modal))
|
||||
}
|
||||
})
|
||||
)(Modal);
|
||||
)(Modal);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import React from "react";
|
||||
import './Modal.sass';
|
||||
|
||||
type Props = {
|
||||
children: React.ReactChild | React.ReactChild[]
|
||||
}
|
||||
|
||||
const Popout = ({ children }: Props) => (
|
||||
<div className="Modal__Overlay">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Popout;
|
||||
Reference in New Issue
Block a user