1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-25 21:06:42 +07:00

fixed cyclic dependencies for dialogs

This commit is contained in:
Fedor Katurov 2019-11-25 15:02:32 +07:00
parent d7ed0cbe54
commit c0c832d158
19 changed files with 399 additions and 263 deletions

View file

@ -4,8 +4,9 @@ import { connect } from 'react-redux';
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
import { ImageGrid } from '../ImageGrid';
import { AudioGrid } from '../AudioGrid';
import * as UPLOAD_ACTIONS from '~/redux/uploads/actions';
import { selectUploads } from '~/redux/uploads/selectors';
import * as UPLOAD_ACTIONS from '~/redux/uploads/actions';
import * as styles from './styles.scss';
const mapStateToProps = selectUploads;

View file

@ -1,11 +1,12 @@
import React, { FC, useCallback } from 'react';
import { SortEnd } from 'react-sortable-hoc';
import * as styles from './styles.scss';
import { IFile } from '~/redux/types';
import { IUploadStatus } from '~/redux/uploads/reducer';
import { moveArrItem } from '~/utils/fn';
import { SortableAudioGrid } from '~/components/editors/SortableAudioGrid';
import * as styles from './styles.scss';
interface IProps {
files: IFile[];
setFiles: (val: IFile[]) => void;

30
src/constants/dialogs.ts Normal file
View file

@ -0,0 +1,30 @@
import { NODE_TYPES } from '~/redux/node/constants';
import { EditorDialogImage } from '~/containers/editors/EditorDialogImage';
import { EditorDialogText } from '~/containers/editors/EditorDialogText';
import { EditorDialogVideo } from '~/containers/editors/EditorDialogVideo';
import { EditorDialogAudio } from '~/containers/editors/EditorDialogAudio';
import { LoginDialog } from '~/containers/dialogs/LoginDialog';
import { LoadingDialog } from '~/containers/dialogs/LoadingDialog';
import { TestDialog } from '~/containers/dialogs/TestDialog';
import { ProfileDialog } from '~/containers/dialogs/ProfileDialog';
import { RestoreRequestDialog } from '~/containers/dialogs/RestoreRequestDialog';
import { DIALOGS } from '~/redux/modal/constants';
export const DIALOG_CONTENT = {
[DIALOGS.EDITOR_IMAGE]: EditorDialogImage,
[DIALOGS.EDITOR_TEXT]: EditorDialogText,
[DIALOGS.EDITOR_VIDEO]: EditorDialogVideo,
[DIALOGS.EDITOR_AUDIO]: EditorDialogAudio,
[DIALOGS.LOGIN]: LoginDialog,
[DIALOGS.LOADING]: LoadingDialog,
[DIALOGS.TEST]: TestDialog,
[DIALOGS.PROFILE]: ProfileDialog,
[DIALOGS.RESTORE_REQUEST]: RestoreRequestDialog,
};
export const NODE_EDITOR_DIALOGS = {
[NODE_TYPES.IMAGE]: DIALOGS.EDITOR_IMAGE,
[NODE_TYPES.TEXT]: DIALOGS.EDITOR_TEXT,
[NODE_TYPES.VIDEO]: DIALOGS.EDITOR_VIDEO,
[NODE_TYPES.AUDIO]: DIALOGS.EDITOR_AUDIO,
};

View file

@ -1,35 +1,37 @@
export const ERRORS = {
NOT_AN_EMAIL: "Not_An_Email",
TOO_SHIRT: "Is_Too_Shirt",
EMPTY_RESPONSE: "Empty_Response",
NO_COMMENTS: "No_Comments",
FILES_REQUIRED: "Files_Required",
TEXT_REQUIRED: "Text_Required",
UNKNOWN_NODE_TYPE: "Unknown_Node_Type",
URL_INVALID: "Url_Invalid",
FILES_AUDIO_REQUIRED: "Files_Audio_Required",
NOT_ENOUGH_RIGHTS: "Not_Enough_Rights",
INCORRECT_DATA: "Incorrect_Data",
IMAGE_CONVERSION_FAILED: "Image_Conversion_Failed",
USER_NOT_FOUND: "User_Not_found",
USER_EXIST: "User_Exist",
INCORRECT_PASSWORD: "Incorrect_Password"
NOT_AN_EMAIL: 'Not_An_Email',
TOO_SHIRT: 'Is_Too_Shirt',
EMPTY_RESPONSE: 'Empty_Response',
NO_COMMENTS: 'No_Comments',
FILES_REQUIRED: 'Files_Required',
TEXT_REQUIRED: 'Text_Required',
UNKNOWN_NODE_TYPE: 'Unknown_Node_Type',
URL_INVALID: 'Url_Invalid',
FILES_AUDIO_REQUIRED: 'Files_Audio_Required',
NOT_ENOUGH_RIGHTS: 'Not_Enough_Rights',
INCORRECT_DATA: 'Incorrect_Data',
IMAGE_CONVERSION_FAILED: 'Image_Conversion_Failed',
USER_NOT_FOUND: 'User_Not_found',
USER_EXIST: 'User_Exist',
INCORRECT_PASSWORD: 'Incorrect_Password',
CODE_IS_INVALID: 'Code_Is_Invalid',
};
export const ERROR_LITERAL = {
[ERRORS.NOT_AN_EMAIL]: "Введите правильный e-mail",
[ERRORS.TOO_SHIRT]: "Слишком короткий",
[ERRORS.NO_COMMENTS]: "Комментариев пока нет",
[ERRORS.EMPTY_RESPONSE]: "Пустой ответ сервера",
[ERRORS.FILES_REQUIRED]: "Добавьте файлы",
[ERRORS.TEXT_REQUIRED]: "Нужно немного текста",
[ERRORS.UNKNOWN_NODE_TYPE]: "Неизвестный тип поста",
[ERRORS.URL_INVALID]: "Неизвестный адрес",
[ERRORS.FILES_AUDIO_REQUIRED]: "Нужна хотя бы одна песня",
[ERRORS.NOT_ENOUGH_RIGHTS]: "У вас недостаточно прав",
[ERRORS.INCORRECT_DATA]: "Недопустимые данные",
[ERRORS.IMAGE_CONVERSION_FAILED]: "Не удалось изменить изображение",
[ERRORS.USER_NOT_FOUND]: "Пользователь не найден",
[ERRORS.USER_EXIST]: "Такой пользователь уже существует",
[ERRORS.INCORRECT_PASSWORD]: "Неправильный пароль"
[ERRORS.NOT_AN_EMAIL]: 'Введите правильный e-mail',
[ERRORS.TOO_SHIRT]: 'Слишком короткий',
[ERRORS.NO_COMMENTS]: 'Комментариев пока нет',
[ERRORS.EMPTY_RESPONSE]: 'Пустой ответ сервера',
[ERRORS.FILES_REQUIRED]: 'Добавьте файлы',
[ERRORS.TEXT_REQUIRED]: 'Нужно немного текста',
[ERRORS.UNKNOWN_NODE_TYPE]: 'Неизвестный тип поста',
[ERRORS.URL_INVALID]: 'Неизвестный адрес',
[ERRORS.FILES_AUDIO_REQUIRED]: 'Нужна хотя бы одна песня',
[ERRORS.NOT_ENOUGH_RIGHTS]: 'У вас недостаточно прав',
[ERRORS.INCORRECT_DATA]: 'Недопустимые данные',
[ERRORS.IMAGE_CONVERSION_FAILED]: 'Не удалось изменить изображение',
[ERRORS.USER_NOT_FOUND]: 'Пользователь не найден',
[ERRORS.USER_EXIST]: 'Такой пользователь уже существует',
[ERRORS.INCORRECT_PASSWORD]: 'Неправильный пароль',
[ERRORS.CODE_IS_INVALID]: 'Код не существует или устарел',
};

View file

@ -1,37 +1,43 @@
import React, { FC, FormEvent, useCallback, useEffect, useState } from "react";
import { connect } from "react-redux";
import { ScrollDialog } from "../ScrollDialog";
import { IDialogProps } from "~/redux/modal/constants";
import { useCloseOnEscape } from "~/utils/hooks";
import { Group } from "~/components/containers/Group";
import { InputText } from "~/components/input/InputText";
import { Button } from "~/components/input/Button";
import { Padder } from "~/components/containers/Padder";
import * as styles from "./styles.scss";
import { selectAuthLogin } from "~/redux/auth/selectors";
import * as ACTIONS from "~/redux/auth/actions";
import { API } from "~/constants/api";
import { BetterScrollDialog } from "../BetterScrollDialog";
import React, { FC, FormEvent, useCallback, useEffect, useState, useMemo } from 'react';
import { connect } from 'react-redux';
import { IDialogProps } from '~/redux/modal/constants';
import { DIALOGS } from '~/redux/modal/constants';
import { useCloseOnEscape } from '~/utils/hooks';
import { Group } from '~/components/containers/Group';
import { InputText } from '~/components/input/InputText';
import { Button } from '~/components/input/Button';
import { Padder } from '~/components/containers/Padder';
import { selectAuthLogin } from '~/redux/auth/selectors';
import { API } from '~/constants/api';
import { BetterScrollDialog } from '../BetterScrollDialog';
import * as styles from './styles.scss';
import * as ACTIONS from '~/redux/auth/actions';
import * as MODAL_ACTIONS from '~/redux/modal/actions';
const mapStateToProps = selectAuthLogin;
const mapDispatchToProps = {
userSendLoginRequest: ACTIONS.userSendLoginRequest,
userSetLoginError: ACTIONS.userSetLoginError
userSetLoginError: ACTIONS.userSetLoginError,
modalShowDialog: MODAL_ACTIONS.modalShowDialog,
};
type IProps = ReturnType<typeof mapStateToProps> &
typeof mapDispatchToProps &
IDialogProps & {};
type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & IDialogProps & {};
console.log('initial', MODAL_ACTIONS);
const LoginDialogUnconnected: FC<IProps> = ({
onRequestClose,
error,
userSendLoginRequest,
userSetLoginError
userSetLoginError,
modalShowDialog,
}) => {
const [username, setUserName] = useState("");
const [password, setPassword] = useState("");
console.log({ modalShowDialog, MODAL_ACTIONS });
const [username, setUserName] = useState('');
const [password, setPassword] = useState('');
const onSubmit = useCallback(
(event: FormEvent) => {
@ -41,61 +47,60 @@ const LoginDialogUnconnected: FC<IProps> = ({
[userSendLoginRequest, username, password]
);
const onRestoreRequest = useCallback(
event => {
console.log('a', { MODAL_ACTIONS, modalShowDialog, userSetLoginError });
event.preventDefault();
modalShowDialog(DIALOGS.RESTORE_REQUEST);
},
[modalShowDialog, userSetLoginError]
);
const onSocialLogin = useCallback(() => {
window.open(API.USER.VKONTAKTE_LOGIN, "", "width=600,height=400");
window.open(API.USER.VKONTAKTE_LOGIN, '', 'width=600,height=400');
}, []);
useEffect(() => {
if (error) userSetLoginError(null);
}, [username, password]);
const buttons = (
<Group horizontal className={styles.footer}>
<Button stretchy>
<span>Войти</span>
</Button>
</Group>
const buttons = useMemo(
() => (
<Group className={styles.footer}>
<Button
className={styles.secondary_button}
iconLeft="vk"
type="button"
onClick={onSocialLogin}
>
<span>Вконтакте</span>
</Button>
<Button>
<span>Войти</span>
</Button>
</Group>
),
[onSocialLogin]
);
useCloseOnEscape(onRequestClose);
return (
<form onSubmit={onSubmit}>
<BetterScrollDialog
width={260}
error={error}
onClose={onRequestClose}
footer={buttons}
>
<BetterScrollDialog width={260} error={error} onClose={onRequestClose} footer={buttons}>
<Padder>
<div className={styles.wrap}>
<Group>
<h2>РЕШИТЕЛЬНО ВОЙТИ</h2>
<InputText
title="Логин"
handler={setUserName}
value={username}
autoFocus
/>
<InputText title="Логин" handler={setUserName} value={username} autoFocus />
<InputText
title="Пароль"
handler={setPassword}
value={password}
type="password"
/>
<InputText title="Пароль" handler={setPassword} value={password} type="password" />
<Group className={styles.buttons}>
<Button
className={styles.vk}
iconLeft="vk"
type="button"
onClick={onSocialLogin}
>
<span>Вконтакте</span>
</Button>
</Group>
<Button className={styles.forgot_button} type="button" onClick={onRestoreRequest}>
Вспомнить пароль
</Button>
</Group>
</div>
</Padder>

View file

@ -1,4 +1,5 @@
$vk_color: darken(desaturate($blue, 100%), 30%);
$secondary_color: darken(desaturate($blue, 100%), 30%);
$vk_color: $secondary_color;
.wrap {
display: flex;
@ -15,7 +16,7 @@ $vk_color: darken(desaturate($blue, 100%), 30%);
}
}
.vk {
.secondary_button {
background: $content_bg;
box-shadow: inset $vk_color 0 0 0 2px;
color: $vk_color;
@ -23,11 +24,15 @@ $vk_color: darken(desaturate($blue, 100%), 30%);
svg {
fill: $vk_color;
margin-right: $gap;
// width: 24px;
// height: 24px;
}
}
.forgot_button {
background: $content_bg;
box-shadow: none;
color: $secondary_color;
}
.buttons {
margin: $gap * 2 0 0 0 !important;
padding: $gap * 2 0 0 0;
@ -41,3 +46,12 @@ $vk_color: darken(desaturate($blue, 100%), 30%);
// text-align: left;
}
}
.links {
font: $font_14_regular;
text-align: center;
a {
color: lighten($content_bg, 40%);
}
}

View file

@ -4,7 +4,7 @@ import ReactDOM from 'react-dom';
import * as styles from './styles.scss';
import { IState } from '~/redux/store';
import * as ACTIONS from '~/redux/modal/actions';
import { DIALOG_CONTENT } from '~/redux/modal/constants';
import { DIALOG_CONTENT } from '~/constants/dialogs';
const mapStateToProps = ({ modal }: IState) => ({ ...modal });
const mapDispatchToProps = {

View file

@ -0,0 +1,41 @@
import React, { FC, useState, useMemo, useCallback } from 'react';
import { IDialogProps } from '~/redux/types';
import { connect } from 'react-redux';
import { BetterScrollDialog } from '../BetterScrollDialog';
import { Group } from '~/components/containers/Group';
import { InputText } from '~/components/input/InputText';
import { Button } from '~/components/input/Button';
const mapStateToProps = () => ({});
const mapDispatchToProps = {};
type IProps = IDialogProps & ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
const RestoreRequestDialogUnconnected: FC<IProps> = ({}) => {
const [field, setField] = useState();
const onSubmit = useCallback(event => {
event.preventDefault();
}, []);
const buttons = useMemo(() => <Button>Восстановить</Button>, []);
return (
<form onSubmit={onSubmit}>
<BetterScrollDialog footer={buttons}>
<Group>
<InputText title="Имя или email" value={field} handler={setField} />
<div>Введите имя пользователя или адрес почты. Мы пришлем ссылку для сброса пароля.</div>
</Group>
</BetterScrollDialog>
</form>
);
};
const RestoreRequestDialog = connect(
mapStateToProps,
mapDispatchToProps
)(RestoreRequestDialogUnconnected);
export { RestoreRequestDialog };

View file

@ -34,6 +34,7 @@ const INITIAL_STATE: IAuthState = {
restore: {
code: '',
user: null,
is_loading: false,
is_succesfull: false,
errors: {},

View file

@ -1,17 +1,5 @@
import {
call,
put,
takeEvery,
takeLatest,
select,
delay
} from "redux-saga/effects";
import {
AUTH_USER_ACTIONS,
EMPTY_USER,
USER_ERRORS,
USER_ROLES
} from "~/redux/auth/constants";
import { call, put, takeEvery, takeLatest, select, delay } from 'redux-saga/effects';
import { AUTH_USER_ACTIONS, EMPTY_USER, USER_ERRORS, USER_ROLES } from '~/redux/auth/constants';
import {
authSetToken,
userSetLoginError,
@ -25,8 +13,10 @@ import {
authSetUpdates,
authLoggedIn,
authSetLastSeenMessages,
authPatchUser
} from "~/redux/auth/actions";
authPatchUser,
authRestorePassword,
authSetRestore,
} from '~/redux/auth/actions';
import {
apiUserLogin,
apiAuthGetUser,
@ -34,31 +24,19 @@ import {
apiAuthGetUserMessages,
apiAuthSendMessage,
apiAuthGetUpdates,
apiUpdateUser
} from "~/redux/auth/api";
import { modalSetShown, modalShowDialog } from "~/redux/modal/actions";
import {
selectToken,
selectAuthProfile,
selectAuthUser,
selectAuthUpdates
} from "./selectors";
import {
IResultWithStatus,
INotification,
IMessageNotification
} from "../types";
import { IUser, IAuthState } from "./types";
import { REHYDRATE, RehydrateAction } from "redux-persist";
import { selectModal } from "../modal/selectors";
import { IModalState } from "../modal/reducer";
import { DIALOGS } from "../modal/constants";
import { ERRORS } from "~/constants/errors";
apiUpdateUser,
} from '~/redux/auth/api';
import { modalSetShown, modalShowDialog } from '~/redux/modal/actions';
import { selectToken, selectAuthProfile, selectAuthUser, selectAuthUpdates } from './selectors';
import { IResultWithStatus, INotification, IMessageNotification } from '../types';
import { IUser, IAuthState } from './types';
import { REHYDRATE, RehydrateAction } from 'redux-persist';
import { selectModal } from '~/redux/modal/selectors';
import { IModalState } from '~/redux/modal/reducer';
import { DIALOGS } from '~/redux/modal/constants';
import { ERRORS } from '~/constants/errors';
export function* reqWrapper(
requestAction,
props = {}
): ReturnType<typeof requestAction> {
export function* reqWrapper(requestAction, props = {}): ReturnType<typeof requestAction> {
const access = yield select(selectToken);
const result = yield call(requestAction, { access, ...props });
@ -70,22 +48,16 @@ export function* reqWrapper(
return result;
}
function* sendLoginRequestSaga({
username,
password
}: ReturnType<typeof userSendLoginRequest>) {
function* sendLoginRequestSaga({ username, password }: ReturnType<typeof userSendLoginRequest>) {
if (!username || !password) return;
const {
error,
data: { token, user }
}: IResultWithStatus<{ token: string; user: IUser }> = yield call(
apiUserLogin,
{
username,
password
}
);
data: { token, user },
}: IResultWithStatus<{ token: string; user: IUser }> = yield call(apiUserLogin, {
username,
password,
});
if (error) {
yield put(userSetLoginError(error));
@ -101,17 +73,14 @@ function* sendLoginRequestSaga({
function* refreshUser() {
const {
error,
data: { user }
}: IResultWithStatus<{ user: IUser }> = yield call(
reqWrapper,
apiAuthGetUser
);
data: { user },
}: IResultWithStatus<{ user: IUser }> = yield call(reqWrapper, apiAuthGetUser);
if (error) {
yield put(
authSetUser({
...EMPTY_USER,
is_user: false
is_user: false,
})
);
@ -122,7 +91,7 @@ function* refreshUser() {
}
function* checkUserSaga({ key }: RehydrateAction) {
if (key !== "auth") return;
if (key !== 'auth') return;
yield call(refreshUser);
// yield put(authOpenProfile("gvorcek", "settings"));
}
@ -142,21 +111,18 @@ function* logoutSaga() {
yield put(
authSetUpdates({
last: null,
notifications: []
notifications: [],
})
);
}
function* openProfile({
username,
tab = "profile"
}: ReturnType<typeof authOpenProfile>) {
function* openProfile({ username, tab = 'profile' }: ReturnType<typeof authOpenProfile>) {
yield put(modalShowDialog(DIALOGS.PROFILE));
yield put(authSetProfile({ is_loading: true, tab }));
const {
error,
data: { user }
data: { user },
} = yield call(reqWrapper, apiAuthGetUserProfile, { username });
if (error || !user) {
@ -176,16 +142,15 @@ function* getMessages({ username }: ReturnType<typeof authGetMessages>) {
messages:
messages &&
messages.length > 0 &&
(messages[0].to.username === username ||
messages[0].from.username === username)
(messages[0].to.username === username || messages[0].from.username === username)
? messages
: []
: [],
})
);
const {
error,
data
data,
// data: { messages },
} = yield call(reqWrapper, apiAuthGetUserMessages, { username });
@ -193,21 +158,19 @@ function* getMessages({ username }: ReturnType<typeof authGetMessages>) {
return yield put(
authSetProfile({
is_loading_messages: false,
messages_error: ERRORS.EMPTY_RESPONSE
messages_error: ERRORS.EMPTY_RESPONSE,
})
);
}
yield put(
authSetProfile({ is_loading_messages: false, messages: data.messages })
);
yield put(authSetProfile({ is_loading_messages: false, messages: data.messages }));
const { notifications } = yield select(selectAuthUpdates);
// clear viewed message from notifcation list
const filtered = notifications.filter(
notification =>
notification.type !== "message" ||
notification.type !== 'message' ||
(notification as IMessageNotification).content.from.username !== username
);
@ -216,23 +179,18 @@ function* getMessages({ username }: ReturnType<typeof authGetMessages>) {
}
}
function* sendMessage({
message,
onSuccess
}: ReturnType<typeof authSendMessage>) {
function* sendMessage({ message, onSuccess }: ReturnType<typeof authSendMessage>) {
const {
user: { username }
user: { username },
} = yield select(selectAuthProfile);
if (!username) return;
yield put(
authSetProfile({ is_sending_messages: true, messages_error: null })
);
yield put(authSetProfile({ is_sending_messages: true, messages_error: null }));
const { error, data } = yield call(reqWrapper, apiAuthSendMessage, {
username,
message
message,
});
console.log({ error, data });
@ -241,7 +199,7 @@ function* sendMessage({
return yield put(
authSetProfile({
is_sending_messages: false,
messages_error: error || ERRORS.EMPTY_RESPONSE
messages_error: error || ERRORS.EMPTY_RESPONSE,
})
);
}
@ -255,7 +213,7 @@ function* sendMessage({
yield put(
authSetProfile({
is_sending_messages: false,
messages: [data.message, ...messages]
messages: [data.message, ...messages],
})
);
@ -265,35 +223,28 @@ function* sendMessage({
function* getUpdates() {
const user = yield select(selectAuthUser);
if (!user || !user.is_user || user.role === USER_ROLES.GUEST || !user.id)
return;
if (!user || !user.is_user || user.role === USER_ROLES.GUEST || !user.id) return;
const modal: IModalState = yield select(selectModal);
const profile: IAuthState["profile"] = yield select(selectAuthProfile);
const { last }: IAuthState["updates"] = yield select(selectAuthUpdates);
const profile: IAuthState['profile'] = yield select(selectAuthProfile);
const { last }: IAuthState['updates'] = yield select(selectAuthUpdates);
const exclude_dialogs =
modal.is_shown && modal.dialog === DIALOGS.PROFILE && profile.user.id
? profile.user.id
: null;
modal.is_shown && modal.dialog === DIALOGS.PROFILE && profile.user.id ? profile.user.id : null;
const {
error,
data
}: IResultWithStatus<{ notifications: INotification[] }> = yield call(
const { error, data }: IResultWithStatus<{ notifications: INotification[] }> = yield call(
reqWrapper,
apiAuthGetUpdates,
{ exclude_dialogs, last: last || user.last_seen_messages }
);
if (error || !data || !data.notifications || !data.notifications.length)
return;
if (error || !data || !data.notifications || !data.notifications.length) return;
const { notifications } = data;
yield put(
authSetUpdates({
last: notifications[0].created_at,
notifications
notifications,
})
);
}
@ -305,9 +256,7 @@ function* startPollingSaga() {
}
}
function* setLastSeenMessages({
last_seen_messages
}: ReturnType<typeof authSetLastSeenMessages>) {
function* setLastSeenMessages({ last_seen_messages }: ReturnType<typeof authSetLastSeenMessages>) {
if (!Date.parse(last_seen_messages)) return;
yield call(reqWrapper, apiUpdateUser, { user: { last_seen_messages } });
@ -323,7 +272,19 @@ function* patchUser({ user }: ReturnType<typeof authPatchUser>) {
}
yield put(authSetUser({ ...me, ...data.user }));
yield put(authSetProfile({ user: { ...me, ...data.user }, tab: "profile" }));
yield put(authSetProfile({ user: { ...me, ...data.user }, tab: 'profile' }));
}
function* restorePassword({ code }: ReturnType<typeof authRestorePassword>) {
if (!code && !code.length) {
return yield put(
authSetRestore({
errors: { code: ERRORS.CODE_IS_INVALID },
is_loading: false,
})
);
}
console.log({ code });
}
function* authSaga() {
@ -336,11 +297,9 @@ function* authSaga() {
yield takeLatest(AUTH_USER_ACTIONS.OPEN_PROFILE, openProfile);
yield takeLatest(AUTH_USER_ACTIONS.GET_MESSAGES, getMessages);
yield takeLatest(AUTH_USER_ACTIONS.SEND_MESSAGE, sendMessage);
yield takeLatest(
AUTH_USER_ACTIONS.SET_LAST_SEEN_MESSAGES,
setLastSeenMessages
);
yield takeLatest(AUTH_USER_ACTIONS.SET_LAST_SEEN_MESSAGES, setLastSeenMessages);
yield takeLatest(AUTH_USER_ACTIONS.PATCH_USER, patchUser);
yield takeLatest(AUTH_USER_ACTIONS.RESTORE_PASSWORD, restorePassword);
}
export default authSaga;

View file

@ -52,6 +52,7 @@ export type IAuthState = Readonly<{
restore: {
code: string;
user: Pick<IUser, 'username' | 'photo'>;
is_loading: boolean;
is_succesfull: boolean;
errors: Record<string, string>;

View file

@ -8,12 +8,7 @@ import { EditorDialogAudio } from '~/containers/editors/EditorDialogAudio';
import { NODE_TYPES } from '../node/constants';
import { TestDialog } from '~/containers/dialogs/TestDialog';
import { ProfileDialog } from '~/containers/dialogs/ProfileDialog';
export const MODAL_ACTIONS = {
SET_SHOWN: 'MODAL.SET_SHOWN',
SET_DIALOG: 'SET_DIALOG',
SHOW_DIALOG: 'SHOW_DIALOG',
};
import { RestoreRequestDialog } from '~/containers/dialogs/RestoreRequestDialog';
export const DIALOGS = {
EDITOR_IMAGE: 'EDITOR_IMAGE',
@ -23,25 +18,14 @@ export const DIALOGS = {
LOGIN: 'LOGIN',
LOADING: 'LOADING',
PROFILE: 'PROFILE',
RESTORE_REQUEST: 'RESTORE_REQUEST',
TEST: 'TEST',
};
export const DIALOG_CONTENT = {
[DIALOGS.EDITOR_IMAGE]: EditorDialogImage,
[DIALOGS.EDITOR_TEXT]: EditorDialogText,
[DIALOGS.EDITOR_VIDEO]: EditorDialogVideo,
[DIALOGS.EDITOR_AUDIO]: EditorDialogAudio,
[DIALOGS.LOGIN]: LoginDialog,
[DIALOGS.LOADING]: LoadingDialog,
[DIALOGS.TEST]: TestDialog,
[DIALOGS.PROFILE]: ProfileDialog,
};
export const NODE_EDITOR_DIALOGS = {
[NODE_TYPES.IMAGE]: DIALOGS.EDITOR_IMAGE,
[NODE_TYPES.TEXT]: DIALOGS.EDITOR_TEXT,
[NODE_TYPES.VIDEO]: DIALOGS.EDITOR_VIDEO,
[NODE_TYPES.AUDIO]: DIALOGS.EDITOR_AUDIO,
export const MODAL_ACTIONS = {
SET_SHOWN: 'MODAL.SET_SHOWN',
SET_DIALOG: 'SET_DIALOG',
SHOW_DIALOG: 'SHOW_DIALOG',
};
export interface IDialogProps {

View file

@ -40,7 +40,8 @@ import { selectFlowNodes, selectFlow } from '../flow/selectors';
import { URLS } from '~/constants/urls';
import { selectNode } from './selectors';
import { IResultWithStatus, INode } from '../types';
import { NODE_EDITOR_DIALOGS, DIALOGS } from '../modal/constants';
import { NODE_EDITOR_DIALOGS } from '~/constants/dialogs';
import { DIALOGS } from '~/redux/modal/constants';
import { INodeState } from './reducer';
import { IFlowState } from '../flow/reducer';

View file

@ -1,7 +1,7 @@
import { DetailedHTMLProps, InputHTMLAttributes } from "react";
import { DIALOGS } from "~/redux/modal/constants";
import { ERRORS } from "~/constants/errors";
import { IUser } from "./auth/types";
import { DetailedHTMLProps, InputHTMLAttributes } from 'react';
import { DIALOGS } from '~/redux/modal/constants';
import { ERRORS } from '~/constants/errors';
import { IUser } from './auth/types';
export interface ITag {
id: number;
@ -55,7 +55,7 @@ export interface IResultWithStatus<T> {
export type UUID = string;
export type IUploadType = "image" | "text" | "audio" | "video" | "other";
export type IUploadType = 'image' | 'text' | 'audio' | 'video' | 'other';
export interface IFile {
id?: number;
@ -96,12 +96,12 @@ export interface IFileWithUUID {
}
export interface IBlockText {
type: "text";
type: 'text';
text: string;
}
export interface IBlockEmbed {
type: "video";
type: 'video';
url: string;
}
@ -124,7 +124,7 @@ export interface INode {
is_heroic?: boolean;
flow: {
display: "single" | "vertical" | "horizontal" | "quadro";
display: 'single' | 'vertical' | 'horizontal' | 'quadro';
show_description: boolean;
};
@ -147,7 +147,7 @@ export interface IComment {
update_at?: string;
}
export type IMessage = Omit<IComment, "user" | "node"> & {
export type IMessage = Omit<IComment, 'user' | 'node'> & {
from: IUser;
to: IUser;
};
@ -155,7 +155,7 @@ export type IMessage = Omit<IComment, "user" | "node"> & {
export interface ICommentGroup {
user: IUser;
comments: IComment[];
ids: IComment["id"][];
ids: IComment['id'][];
}
export type IUploadProgressHandler = (progress: ProgressEvent) => void;
@ -164,25 +164,25 @@ export type IValidationErrors = Record<string, IError>;
export type InputHandler<T = string> = (val: T) => void;
export const NOTIFICATION_TYPES = {
message: "message",
comment: "comment",
node: "node"
message: 'message',
comment: 'comment',
node: 'node',
};
export type IMessageNotification = {
type: typeof NOTIFICATION_TYPES["message"];
type: typeof NOTIFICATION_TYPES['message'];
content: Partial<IMessage>;
created_at: string;
};
export type ICommentNotification = {
type: typeof NOTIFICATION_TYPES["comment"];
type: typeof NOTIFICATION_TYPES['comment'];
content: Partial<IComment>;
created_at: string;
};
export type INodeNotification = {
type: typeof NOTIFICATION_TYPES["node"];
type: typeof NOTIFICATION_TYPES['node'];
content: Partial<INode>;
created_at: string;
};

View file

@ -12,6 +12,9 @@ $grass: #41800d;
$wisegreen: #007962;
// $wisegreen: #006868;
$primary: $red;
$secondary: $wisegreen;
$red_gradient: linear-gradient(165deg, $orange -50%, $red 150%);
$blue_gradient: linear-gradient(170deg, $green, $dark_blue);
$green_gradient: linear-gradient(

View file

@ -96,6 +96,11 @@ body {
font-weight: bold;
}
a {
color: $primary;
text-decoration: underline;
}
::-webkit-scrollbar {
width: 18px;
height: 18px;