mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-25 21:06:42 +07:00
messages form
This commit is contained in:
parent
98c66dec8c
commit
371f47f866
7 changed files with 98 additions and 16 deletions
|
@ -1,14 +1,14 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import * as styles from './styles.scss';
|
import * as styles from './styles.scss';
|
||||||
import { Icon } from '../Icon';
|
|
||||||
import { describeArc } from '~/utils/dom';
|
import { describeArc } from '~/utils/dom';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
size?: number;
|
size?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LoaderCircle: FC<IProps> = ({ size = 24 }) => (
|
export const LoaderCircle: FC<IProps> = ({ size = 24 }) => (
|
||||||
<div className={styles.wrap}>
|
<div className={classNames(styles.wrap, 'loader-circle')}>
|
||||||
<svg className={styles.icon} width={size} height={size}>
|
<svg className={styles.icon} width={size} height={size}>
|
||||||
<path d={describeArc(size / 2, size / 2, size / 2, 0, 90)} />
|
<path d={describeArc(size / 2, size / 2, size / 2, 0, 90)} />
|
||||||
<path d={describeArc(size / 2, size / 2, size / 2, 180, 270)} />
|
<path d={describeArc(size / 2, size / 2, size / 2, 180, 270)} />
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { FC, useState, useCallback } from 'react';
|
import React, { FC, useState, useCallback, KeyboardEventHandler } from 'react';
|
||||||
import styles from './styles.scss';
|
import styles from './styles.scss';
|
||||||
import { Textarea } from '~/components/input/Textarea';
|
import { Textarea } from '~/components/input/Textarea';
|
||||||
import { Filler } from '~/components/containers/Filler';
|
import { Filler } from '~/components/containers/Filler';
|
||||||
|
@ -21,7 +21,7 @@ const mapDispatchToProps = {
|
||||||
type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
|
type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
|
||||||
|
|
||||||
const MessageFormUnconnected: FC<IProps> = ({
|
const MessageFormUnconnected: FC<IProps> = ({
|
||||||
profile: { is_sending_messages, messages_error },
|
profile: { is_sending_messages, is_loading_messages, messages_error },
|
||||||
authSendMessage,
|
authSendMessage,
|
||||||
}) => {
|
}) => {
|
||||||
const [text, setText] = useState('');
|
const [text, setText] = useState('');
|
||||||
|
@ -34,14 +34,35 @@ const MessageFormUnconnected: FC<IProps> = ({
|
||||||
authSendMessage({ text }, onSuccess);
|
authSendMessage({ text }, onSuccess);
|
||||||
}, [authSendMessage, text, onSuccess]);
|
}, [authSendMessage, text, onSuccess]);
|
||||||
|
|
||||||
|
const onKeyDown = useCallback<KeyboardEventHandler<HTMLTextAreaElement>>(
|
||||||
|
({ ctrlKey, key }) => {
|
||||||
|
if (!!ctrlKey && key === 'Enter') onSubmit();
|
||||||
|
},
|
||||||
|
[onSubmit]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrap}>
|
<div className={styles.wrap}>
|
||||||
{messages_error && <div className={styles.error}>{ERROR_LITERAL[messages_error]}</div>}
|
{messages_error && <div className={styles.error}>{ERROR_LITERAL[messages_error]}</div>}
|
||||||
|
{is_loading_messages && !messages_error && (
|
||||||
|
<Group className={styles.loader} horizontal>
|
||||||
|
<LoaderCircle size={20} />
|
||||||
|
<div>Обновляем</div>
|
||||||
|
</Group>
|
||||||
|
)}
|
||||||
<Group className={styles.content}>
|
<Group className={styles.content}>
|
||||||
<Textarea value={text} handler={setText} minRows={1} maxRows={4} seamless />
|
<Textarea
|
||||||
|
value={text}
|
||||||
|
handler={setText}
|
||||||
|
minRows={1}
|
||||||
|
maxRows={4}
|
||||||
|
seamless
|
||||||
|
onKeyDown={onKeyDown}
|
||||||
|
disabled={is_sending_messages}
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
|
||||||
<div className={styles.buttons}>
|
<Group className={styles.buttons} horizontal>
|
||||||
<Filler />
|
<Filler />
|
||||||
|
|
||||||
{is_sending_messages && <LoaderCircle size={20} />}
|
{is_sending_messages && <LoaderCircle size={20} />}
|
||||||
|
@ -55,7 +76,7 @@ const MessageFormUnconnected: FC<IProps> = ({
|
||||||
>
|
>
|
||||||
Сказать
|
Сказать
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,10 +2,11 @@
|
||||||
@include outer_shadow();
|
@include outer_shadow();
|
||||||
padding: $gap;
|
padding: $gap;
|
||||||
background: $content_bg;
|
background: $content_bg;
|
||||||
position: relative;
|
// position: relative;
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
// margin-bottom: 40px;
|
// margin-bottom: 40px;
|
||||||
|
padding-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +22,12 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
padding: 0 $gap / 2 $gap / 2 $gap / 2;
|
padding: 0 $gap / 2 $gap / 2 $gap / 2;
|
||||||
|
|
||||||
|
:global(.loader-circle) {
|
||||||
|
svg {
|
||||||
|
fill: $wisegreen;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
.error {
|
||||||
|
@ -35,3 +42,19 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-radius: 0 0 $radius $radius;
|
border-radius: 0 0 $radius $radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loader {
|
||||||
|
position: absolute;
|
||||||
|
right: 50%;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 2;
|
||||||
|
padding: $gap;
|
||||||
|
text-transform: uppercase;
|
||||||
|
background: $wisegreen;
|
||||||
|
border-radius: $radius;
|
||||||
|
transform: translate(50%, -10px);
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
15
src/containers/profile/ProfileLoader/index.tsx
Normal file
15
src/containers/profile/ProfileLoader/index.tsx
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import React, { FC } from 'react';
|
||||||
|
import styles from './styles.scss';
|
||||||
|
import { LoaderCircle } from '~/components/input/LoaderCircle';
|
||||||
|
|
||||||
|
interface IProps {}
|
||||||
|
|
||||||
|
const ProfileLoader: FC<IProps> = ({}) => {
|
||||||
|
return (
|
||||||
|
<div className={styles.loader}>
|
||||||
|
<LoaderCircle size={40} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { ProfileLoader };
|
6
src/containers/profile/ProfileLoader/styles.scss
Normal file
6
src/containers/profile/ProfileLoader/styles.scss
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
.loader {
|
||||||
|
min-height: 33vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import * as AUTH_ACTIONS from '~/redux/auth/actions';
|
||||||
import { Message } from '~/components/profile/Message';
|
import { Message } from '~/components/profile/Message';
|
||||||
import { Group } from '~/components/containers/Group';
|
import { Group } from '~/components/containers/Group';
|
||||||
import pick from 'ramda/es/pick';
|
import pick from 'ramda/es/pick';
|
||||||
|
import { NodeNoComments } from '~/components/node/NodeNoComments';
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
profile: selectAuthProfile(state),
|
profile: selectAuthProfile(state),
|
||||||
|
@ -25,6 +26,9 @@ const ProfileMessagesUnconnected: FC<IProps> = ({ profile, user: { id }, authGet
|
||||||
authGetMessages(profile.user.username);
|
authGetMessages(profile.user.username);
|
||||||
}, [profile.user]);
|
}, [profile.user]);
|
||||||
|
|
||||||
|
if (!profile.messages.length || profile.is_loading)
|
||||||
|
return <NodeNoComments is_loading={profile.is_loading_messages || profile.is_loading} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Group className={styles.messages}>
|
<Group className={styles.messages}>
|
||||||
{profile.messages
|
{profile.messages
|
||||||
|
|
|
@ -114,19 +114,32 @@ function* openProfile({ username }: ReturnType<typeof authOpenProfile>) {
|
||||||
return yield put(modalSetShown(false));
|
return yield put(modalSetShown(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
yield put(authSetProfile({ is_loading: false, user }));
|
yield put(authSetProfile({ is_loading: false, user, messages: [] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
function* getMessages({ username }: ReturnType<typeof authGetMessages>) {
|
function* getMessages({ username }: ReturnType<typeof authGetMessages>) {
|
||||||
yield put(modalShowDialog(DIALOGS.PROFILE));
|
// yield put(modalShowDialog(DIALOGS.PROFILE));
|
||||||
yield put(authSetProfile({ is_loading_messages: true }));
|
const { messages } = yield select(selectAuthProfile);
|
||||||
|
|
||||||
|
yield put(
|
||||||
|
authSetProfile({
|
||||||
|
is_loading_messages: true,
|
||||||
|
messages:
|
||||||
|
messages &&
|
||||||
|
messages.length > 0 &&
|
||||||
|
(messages[0].to.username === username || messages[0].from.username === username)
|
||||||
|
? messages
|
||||||
|
: [],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
error,
|
error,
|
||||||
data: { messages },
|
data,
|
||||||
|
// data: { messages },
|
||||||
} = yield call(reqWrapper, apiAuthGetUserMessages, { username });
|
} = yield call(reqWrapper, apiAuthGetUserMessages, { username });
|
||||||
|
|
||||||
if (error || !messages) {
|
if (error || !data.messages) {
|
||||||
return yield put(
|
return yield put(
|
||||||
authSetProfile({
|
authSetProfile({
|
||||||
is_loading_messages: false,
|
is_loading_messages: false,
|
||||||
|
@ -135,7 +148,7 @@ function* getMessages({ username }: ReturnType<typeof authGetMessages>) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
yield put(authSetProfile({ is_loading_messages: false, messages }));
|
yield put(authSetProfile({ is_loading_messages: false, messages: data.messages }));
|
||||||
}
|
}
|
||||||
|
|
||||||
function* sendMessage({ message, onSuccess }: ReturnType<typeof authSendMessage>) {
|
function* sendMessage({ message, onSuccess }: ReturnType<typeof authSendMessage>) {
|
||||||
|
@ -169,7 +182,7 @@ function* sendMessage({ message, onSuccess }: ReturnType<typeof authSendMessage>
|
||||||
yield put(
|
yield put(
|
||||||
authSetProfile({
|
authSetProfile({
|
||||||
is_sending_messages: false,
|
is_sending_messages: false,
|
||||||
messages: [message, ...messages],
|
messages: [data.message, ...messages],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue