From 3f3c1516c8f4579c910d746d8c50e3e9eb07a022 Mon Sep 17 00:00:00 2001
From: Fedor Katurov <gotham48@gmail.com>
Date: Tue, 8 Sep 2020 13:27:00 +0700
Subject: [PATCH] fixed message delete appearance

---
 src/components/profile/Message/index.tsx      | 44 +++++++++++++++++--
 src/components/profile/Message/styles.scss    | 12 +++++
 src/constants/errors.ts                       |  2 +
 .../profile/ProfileMessages/index.tsx         |  6 ++-
 src/redux/messages/actions.ts                 |  3 +-
 src/redux/messages/api.ts                     |  7 ++-
 src/redux/messages/sagas.ts                   |  3 +-
 7 files changed, 69 insertions(+), 8 deletions(-)

diff --git a/src/components/profile/Message/index.tsx b/src/components/profile/Message/index.tsx
index b1415fa7..c543f264 100644
--- a/src/components/profile/Message/index.tsx
+++ b/src/components/profile/Message/index.tsx
@@ -1,25 +1,61 @@
 import React, { FC, useCallback } from 'react';
 import { IMessage } from '~/redux/types';
 import styles from './styles.scss';
-import { formatText, getURL, getPrettyDate } from '~/utils/dom';
+import { formatText, getPrettyDate, getURL } from '~/utils/dom';
 import { PRESETS } from '~/constants/urls';
 import classNames from 'classnames';
 import { Group } from '~/components/containers/Group';
 import { CommentMenu } from '~/components/node/CommentMenu';
 import { MessageForm } from '~/components/profile/MessageForm';
+import { Filler } from '~/components/containers/Filler';
+import { Button } from '~/components/input/Button';
 
 interface IProps {
   message: IMessage;
   incoming: boolean;
   onEdit: (id: number) => void;
   onDelete: (id: number) => void;
+  onRestore: (id: number) => void;
   onCancelEdit: () => void;
   isEditing: boolean;
 }
 
-const Message: FC<IProps> = ({ message, incoming, onEdit, onDelete, isEditing, onCancelEdit }) => {
-  const onEditClicked = useCallback(() => onEdit(message.id), [message.id]);
-  const onDeleteClicked = useCallback(() => onDelete(message.id), [message.id]);
+const Message: FC<IProps> = ({
+  message,
+  incoming,
+  onEdit,
+  onDelete,
+  isEditing,
+  onCancelEdit,
+  onRestore,
+}) => {
+  const onEditClicked = useCallback(() => onEdit(message.id), [onEdit, message.id]);
+  const onDeleteClicked = useCallback(() => onDelete(message.id), [onDelete, message.id]);
+  const onRestoreClicked = useCallback(() => onRestore(message.id), [onRestore, message.id]);
+
+  if (message.deleted_at) {
+    return (
+      <div className={classNames(styles.message)}>
+        <Group className={styles.deleted} horizontal>
+          <Filler>Сообщение удалено</Filler>
+          <Button
+            size="mini"
+            onClick={onRestoreClicked}
+            color="link"
+            iconLeft="restore"
+            className={styles.restore}
+          >
+            Восстановить
+          </Button>
+        </Group>
+
+        <div
+          className={styles.avatar}
+          style={{ backgroundImage: `url("${getURL(message.from.photo, PRESETS.avatar)}")` }}
+        />
+      </div>
+    );
+  }
 
   return (
     <div className={classNames(styles.message, { [styles.incoming]: incoming })}>
diff --git a/src/components/profile/Message/styles.scss b/src/components/profile/Message/styles.scss
index 19b11bb2..1f20ef35 100644
--- a/src/components/profile/Message/styles.scss
+++ b/src/components/profile/Message/styles.scss
@@ -87,3 +87,15 @@ $outgoing_color: $comment_bg;
   padding: 2px $gap;
   border-radius: $radius;
 }
+
+.restore {
+  color: $red;
+  fill: $red;
+}
+
+.deleted {
+  background: mix($red, $content_bg, 50%);
+  border-radius: $radius $radius $radius 0;
+  padding: $gap / 2;
+  z-index: 2;
+}
diff --git a/src/constants/errors.ts b/src/constants/errors.ts
index 70dd4a27..1aac68d2 100644
--- a/src/constants/errors.ts
+++ b/src/constants/errors.ts
@@ -40,6 +40,7 @@ export const ERRORS = {
   CANT_SAVE_USER: 'CantSaveUser',
   CANT_DELETE_COMMENT: 'CantDeleteComment',
   CANT_RESTORE_COMMENT: 'CantRestoreComment',
+  MESSAGE_NOT_FOUND: 'MessageNotFound',
 };
 
 export const ERROR_LITERAL = {
@@ -85,4 +86,5 @@ export const ERROR_LITERAL = {
   [ERRORS.CANT_SAVE_USER]: 'Не удалось сохранить пользователя',
   [ERRORS.CANT_DELETE_COMMENT]: 'Не удалось удалить комментарий',
   [ERRORS.CANT_RESTORE_COMMENT]: 'Не удалось восстановить комментарий',
+  [ERRORS.MESSAGE_NOT_FOUND]: 'Сообщение не найдено',
 };
diff --git a/src/containers/profile/ProfileMessages/index.tsx b/src/containers/profile/ProfileMessages/index.tsx
index b91bc89b..7700f048 100644
--- a/src/containers/profile/ProfileMessages/index.tsx
+++ b/src/containers/profile/ProfileMessages/index.tsx
@@ -33,7 +33,10 @@ const ProfileMessagesUnconnected: FC<IProps> = ({
 
   const onEditMessage = useCallback((id: number) => setEditingMessageId(id), [setEditingMessageId]);
   const onCancelEdit = useCallback(() => setEditingMessageId(0), [setEditingMessageId]);
-  const onDeleteMessage = useCallback((id: number) => messagesDeleteMessage(id), [
+  const onDeleteMessage = useCallback((id: number) => messagesDeleteMessage(id, true), [
+    messagesDeleteMessage,
+  ]);
+  const onRestoreMessage = useCallback((id: number) => messagesDeleteMessage(id, false), [
     messagesDeleteMessage,
   ]);
 
@@ -70,6 +73,7 @@ const ProfileMessagesUnconnected: FC<IProps> = ({
             onDelete={onDeleteMessage}
             isEditing={editingMessageId === message.id}
             onCancelEdit={onCancelEdit}
+            onRestore={onRestoreMessage}
           />
         ))}
 
diff --git a/src/redux/messages/actions.ts b/src/redux/messages/actions.ts
index 1679d571..ce563b68 100644
--- a/src/redux/messages/actions.ts
+++ b/src/redux/messages/actions.ts
@@ -13,9 +13,10 @@ export const messagesSendMessage = (message: Partial<IMessage>, onSuccess) => ({
   onSuccess,
 });
 
-export const messagesDeleteMessage = (id: IMessage['id']) => ({
+export const messagesDeleteMessage = (id: IMessage['id'], is_locked: boolean) => ({
   type: MESSAGES_ACTIONS.DELETE_MESSAGE,
   id,
+  is_locked,
 });
 
 export const messagesSet = (messages: Partial<IMessagesState>) => ({
diff --git a/src/redux/messages/api.ts b/src/redux/messages/api.ts
index a5252022..d485d2f4 100644
--- a/src/redux/messages/api.ts
+++ b/src/redux/messages/api.ts
@@ -25,12 +25,17 @@ export const apiMessagesDeleteMessage = ({
   access,
   username,
   id,
+  is_locked,
 }: {
   access: string;
   username: string;
   id: number;
+  is_locked: boolean;
 }): Promise<IResultWithStatus<{ message: IMessage }>> =>
   api
-    .delete(API.USER.MESSAGE_DELETE(username, id), configWithToken(access))
+    .delete(
+      API.USER.MESSAGE_DELETE(username, id),
+      configWithToken(access, { params: { is_locked } })
+    )
     .then(resultMiddleware)
     .catch(errorMiddleware);
diff --git a/src/redux/messages/sagas.ts b/src/redux/messages/sagas.ts
index f59b6e66..c2609a28 100644
--- a/src/redux/messages/sagas.ts
+++ b/src/redux/messages/sagas.ts
@@ -120,7 +120,7 @@ function* sendMessage({ message, onSuccess }: ReturnType<typeof messagesSendMess
   onSuccess();
 }
 
-function* deleteMessage({ id }: ReturnType<typeof messagesDeleteMessage>) {
+function* deleteMessage({ id, is_locked }: ReturnType<typeof messagesDeleteMessage>) {
   const username: ReturnType<typeof selectAuthProfileUsername> = yield select(
     selectAuthProfileUsername
   );
@@ -135,6 +135,7 @@ function* deleteMessage({ id }: ReturnType<typeof messagesDeleteMessage>) {
     {
       username,
       id,
+      is_locked,
     }
   );