mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-25 12:56:41 +07:00
added message editing button
This commit is contained in:
parent
a0d18076ad
commit
4c4a33a819
5 changed files with 67 additions and 28 deletions
|
@ -42,6 +42,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
z-index: 6;
|
z-index: 6;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
animation: appear 0.25s forwards;
|
animation: appear 0.25s forwards;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,45 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC, useCallback } from 'react';
|
||||||
import { IMessage } from '~/redux/types';
|
import { IMessage } from '~/redux/types';
|
||||||
import styles from './styles.scss';
|
import styles from './styles.scss';
|
||||||
import { formatText, getURL, getPrettyDate } from '~/utils/dom';
|
import { formatText, getURL, getPrettyDate } from '~/utils/dom';
|
||||||
import { PRESETS } from '~/constants/urls';
|
import { PRESETS } from '~/constants/urls';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Group } from '~/components/containers/Group';
|
import { Group } from '~/components/containers/Group';
|
||||||
|
import { CommentMenu } from '~/components/node/CommentMenu';
|
||||||
|
import { MessageForm } from '~/components/profile/MessageForm';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
message: IMessage;
|
message: IMessage;
|
||||||
incoming: boolean;
|
incoming: boolean;
|
||||||
|
onEdit: (id: number) => void;
|
||||||
|
onDelete: (id: number) => void;
|
||||||
|
isEditing: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Message: FC<IProps> = ({ message, incoming }) => (
|
const Message: FC<IProps> = ({ message, incoming, onEdit, onDelete, isEditing }) => {
|
||||||
<div className={classNames(styles.message, { [styles.incoming]: incoming })}>
|
const onEditClicked = useCallback(() => onEdit(message.id), [message.id]);
|
||||||
<Group className={styles.text} dangerouslySetInnerHTML={{ __html: formatText(message.text) }} />
|
const onDeleteClicked = useCallback(() => onDelete(message.id), [message.id]);
|
||||||
|
|
||||||
<div
|
return (
|
||||||
className={styles.avatar}
|
<div className={classNames(styles.message, { [styles.incoming]: incoming })}>
|
||||||
style={{ backgroundImage: `url("${getURL(message.from.photo, PRESETS.avatar)}")` }}
|
{isEditing ? (
|
||||||
/>
|
<div className={styles.form}>
|
||||||
|
<MessageForm id={message.id} text={message.text} />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className={styles.text}>
|
||||||
|
{!incoming && <CommentMenu onEdit={onEditClicked} onDelete={onDeleteClicked} />}
|
||||||
|
<Group dangerouslySetInnerHTML={{ __html: formatText(message.text) }} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className={styles.stamp}>{getPrettyDate(message.created_at)}</div>
|
<div
|
||||||
</div>
|
className={styles.avatar}
|
||||||
);
|
style={{ backgroundImage: `url("${getURL(message.from.photo, PRESETS.avatar)}")` }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className={styles.stamp}>{getPrettyDate(message.created_at)}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
export { Message };
|
export { Message };
|
||||||
|
|
|
@ -57,7 +57,6 @@ $outgoing_color: $comment_bg;
|
||||||
|
|
||||||
background: 50% 50% no-repeat;
|
background: 50% 50% no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
// display: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
|
@ -65,8 +64,17 @@ $outgoing_color: $comment_bg;
|
||||||
background: $outgoing_color;
|
background: $outgoing_color;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
width: 90%;
|
width: 100%;
|
||||||
border-radius: $radius $radius 0 $radius;
|
border-radius: $radius $radius 0 $radius;
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: $radius $radius 0 $radius;
|
||||||
|
background: $outgoing_color;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stamp {
|
.stamp {
|
||||||
|
|
|
@ -18,21 +18,27 @@ const mapDispatchToProps = {
|
||||||
authSendMessage: AUTH_ACTIONS.authSendMessage,
|
authSendMessage: AUTH_ACTIONS.authSendMessage,
|
||||||
};
|
};
|
||||||
|
|
||||||
type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
|
type IProps = ReturnType<typeof mapStateToProps> &
|
||||||
|
typeof mapDispatchToProps & {
|
||||||
|
id?: number;
|
||||||
|
text?: string;
|
||||||
|
};
|
||||||
|
|
||||||
const MessageFormUnconnected: FC<IProps> = ({
|
const MessageFormUnconnected: FC<IProps> = ({
|
||||||
|
id = 0,
|
||||||
|
text: initialText = '',
|
||||||
profile: { is_sending_messages, is_loading_messages, messages_error },
|
profile: { is_sending_messages, is_loading_messages, messages_error },
|
||||||
authSendMessage,
|
authSendMessage,
|
||||||
}) => {
|
}) => {
|
||||||
const [text, setText] = useState('');
|
const [text, setText] = useState(initialText);
|
||||||
|
|
||||||
const onSuccess = useCallback(() => {
|
const onSuccess = useCallback(() => {
|
||||||
setText('');
|
setText('');
|
||||||
}, [setText]);
|
}, [setText]);
|
||||||
|
|
||||||
const onSubmit = useCallback(() => {
|
const onSubmit = useCallback(() => {
|
||||||
authSendMessage({ text }, onSuccess);
|
authSendMessage({ text, id }, onSuccess);
|
||||||
}, [authSendMessage, text, onSuccess]);
|
}, [authSendMessage, text, id, onSuccess]);
|
||||||
|
|
||||||
const onKeyDown = useCallback<KeyboardEventHandler<HTMLTextAreaElement>>(
|
const onKeyDown = useCallback<KeyboardEventHandler<HTMLTextAreaElement>>(
|
||||||
({ ctrlKey, key }) => {
|
({ ctrlKey, key }) => {
|
||||||
|
@ -82,9 +88,6 @@ const MessageFormUnconnected: FC<IProps> = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const MessageForm = connect(
|
const MessageForm = connect(mapStateToProps, mapDispatchToProps)(MessageFormUnconnected);
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(MessageFormUnconnected);
|
|
||||||
|
|
||||||
export { MessageForm };
|
export { MessageForm };
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { FC, useEffect } from 'react';
|
import React, { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectAuthProfile, selectAuth, selectAuthUser } from '~/redux/auth/selectors';
|
import { selectAuthProfile, selectAuthUser } from '~/redux/auth/selectors';
|
||||||
import styles from './styles.scss';
|
import styles from './styles.scss';
|
||||||
import * as AUTH_ACTIONS from '~/redux/auth/actions';
|
import * as AUTH_ACTIONS from '~/redux/auth/actions';
|
||||||
import { Message } from '~/components/profile/Message';
|
import { Message } from '~/components/profile/Message';
|
||||||
|
@ -20,6 +20,11 @@ const mapDispatchToProps = {
|
||||||
type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
|
type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
|
||||||
|
|
||||||
const ProfileMessagesUnconnected: FC<IProps> = ({ profile, user: { id }, authGetMessages }) => {
|
const ProfileMessagesUnconnected: FC<IProps> = ({ profile, user: { id }, authGetMessages }) => {
|
||||||
|
const [editingMessageId, setEditingMessageId] = useState(0);
|
||||||
|
|
||||||
|
const onEditMessage = useCallback((id: number) => setEditingMessageId(id), [setEditingMessageId]);
|
||||||
|
const onDeleteMessage = useCallback((id: number) => console.log({ id }), []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (profile.is_loading || !profile.user || !profile.user.username) return;
|
if (profile.is_loading || !profile.user || !profile.user.username) return;
|
||||||
|
|
||||||
|
@ -45,7 +50,14 @@ const ProfileMessagesUnconnected: FC<IProps> = ({ profile, user: { id }, authGet
|
||||||
.map((
|
.map((
|
||||||
message // TODO: show files / memo
|
message // TODO: show files / memo
|
||||||
) => (
|
) => (
|
||||||
<Message message={message} incoming={id !== message.from.id} key={message.id} />
|
<Message
|
||||||
|
message={message}
|
||||||
|
incoming={id !== message.from.id}
|
||||||
|
key={message.id}
|
||||||
|
onEdit={onEditMessage}
|
||||||
|
onDelete={onDeleteMessage}
|
||||||
|
isEditing={editingMessageId === message.id}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{!profile.is_loading_messages && profile.messages.length > 0 && (
|
{!profile.is_loading_messages && profile.messages.length > 0 && (
|
||||||
|
@ -55,9 +67,6 @@ const ProfileMessagesUnconnected: FC<IProps> = ({ profile, user: { id }, authGet
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ProfileMessages = connect(
|
const ProfileMessages = connect(mapStateToProps, mapDispatchToProps)(ProfileMessagesUnconnected);
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(ProfileMessagesUnconnected);
|
|
||||||
|
|
||||||
export { ProfileMessages };
|
export { ProfileMessages };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue