From 9db25afb2806dff5c44d99ed0b9c2832b7c074a1 Mon Sep 17 00:00:00 2001 From: Fedor Katurov Date: Mon, 9 Nov 2020 17:55:00 +0700 Subject: [PATCH] refactored comment form --- .../{node => comment}/Comment/index.tsx | 8 +- .../Comment/styles.module.scss | 0 .../CommentContent/index.tsx | 0 .../CommentContent/styles.module.scss | 0 .../{node => comment}/CommentForm/index.tsx | 146 +++--------------- .../CommentForm/styles.module.scss | 0 .../comment/CommentFormAttaches/index.tsx | 133 ++++++++++++++++ .../comment/CommentFormButtons/index.tsx | 36 +++++ .../{node => comment}/CommentMenu/index.tsx | 0 .../CommentMenu/styles.module.scss | 0 src/components/editors/AudioGrid/index.tsx | 10 +- src/components/editors/ImageGrid/index.tsx | 10 +- .../editors/SortableAudioGrid/index.tsx | 11 +- .../editors/SortableImageGrid/index.tsx | 6 +- src/components/media/AudioPlayer/index.tsx | 17 +- src/components/node/NodeCommentForm/index.tsx | 2 +- src/components/node/NodeComments/index.tsx | 2 +- src/components/profile/Message/index.tsx | 2 +- .../profile/ProfileLayout/index.tsx | 5 +- 19 files changed, 235 insertions(+), 153 deletions(-) rename src/components/{node => comment}/Comment/index.tsx (88%) rename src/components/{node => comment}/Comment/styles.module.scss (100%) rename src/components/{node => comment}/CommentContent/index.tsx (100%) rename src/components/{node => comment}/CommentContent/styles.module.scss (100%) rename src/components/{node => comment}/CommentForm/index.tsx (65%) rename src/components/{node => comment}/CommentForm/styles.module.scss (100%) create mode 100644 src/components/comment/CommentFormAttaches/index.tsx create mode 100644 src/components/comment/CommentFormButtons/index.tsx rename src/components/{node => comment}/CommentMenu/index.tsx (100%) rename src/components/{node => comment}/CommentMenu/styles.module.scss (100%) diff --git a/src/components/node/Comment/index.tsx b/src/components/comment/Comment/index.tsx similarity index 88% rename from src/components/node/Comment/index.tsx rename to src/components/comment/Comment/index.tsx index 839748b1..5f194158 100644 --- a/src/components/node/Comment/index.tsx +++ b/src/components/comment/Comment/index.tsx @@ -1,12 +1,12 @@ import React, { FC, HTMLAttributes, memo } from 'react'; import { CommentWrapper } from '~/components/containers/CommentWrapper'; -import { ICommentGroup, IComment } from '~/redux/types'; -import { CommentContent } from '~/components/node/CommentContent'; +import { ICommentGroup } from '~/redux/types'; +import { CommentContent } from '~/components/comment/CommentContent'; import styles from './styles.module.scss'; -import { nodeLockComment, nodeEditComment } from '~/redux/node/actions'; +import { nodeEditComment, nodeLockComment } from '~/redux/node/actions'; import { INodeState } from '~/redux/node/reducer'; import { CommentForm } from '../CommentForm'; -import { CommendDeleted } from '../CommendDeleted'; +import { CommendDeleted } from '../../node/CommendDeleted'; import * as MODAL_ACTIONS from '~/redux/modal/actions'; type IProps = HTMLAttributes & { diff --git a/src/components/node/Comment/styles.module.scss b/src/components/comment/Comment/styles.module.scss similarity index 100% rename from src/components/node/Comment/styles.module.scss rename to src/components/comment/Comment/styles.module.scss diff --git a/src/components/node/CommentContent/index.tsx b/src/components/comment/CommentContent/index.tsx similarity index 100% rename from src/components/node/CommentContent/index.tsx rename to src/components/comment/CommentContent/index.tsx diff --git a/src/components/node/CommentContent/styles.module.scss b/src/components/comment/CommentContent/styles.module.scss similarity index 100% rename from src/components/node/CommentContent/styles.module.scss rename to src/components/comment/CommentContent/styles.module.scss diff --git a/src/components/node/CommentForm/index.tsx b/src/components/comment/CommentForm/index.tsx similarity index 65% rename from src/components/node/CommentForm/index.tsx rename to src/components/comment/CommentForm/index.tsx index 3481b9b5..1463f757 100644 --- a/src/components/node/CommentForm/index.tsx +++ b/src/components/comment/CommentForm/index.tsx @@ -4,7 +4,7 @@ import styles from './styles.module.scss'; import { Filler } from '~/components/containers/Filler'; import { Button } from '~/components/input/Button'; import assocPath from 'ramda/es/assocPath'; -import { IFile, IFileWithUUID, InputHandler } from '~/redux/types'; +import { IComment, IFile, IFileWithUUID, InputHandler } from '~/redux/types'; import { connect } from 'react-redux'; import * as NODE_ACTIONS from '~/redux/node/actions'; import { selectNode } from '~/redux/node/selectors'; @@ -23,6 +23,8 @@ import { SortEnd } from 'react-sortable-hoc'; import { SortableAudioGrid } from '~/components/editors/SortableAudioGrid'; import { getRandomPhrase } from '~/constants/phrases'; import { ERROR_LITERAL } from '~/constants/errors'; +import { CommentFormAttaches } from '~/components/comment/CommentFormAttaches'; +import { CommentFormButtons } from '~/components/comment/CommentFormButtons'; const mapStateToProps = (state: IState) => ({ node: selectNode(state), @@ -53,13 +55,9 @@ const CommentFormUnconnected: FC = memo( uploadUploadFiles, nodeCancelCommentEdit, }) => { - const onInputChange = useCallback( - event => { - event.preventDefault(); - - if (!event.target.files || !event.target.files.length) return; - - const items: IFileWithUUID[] = Array.from(event.target.files).map( + const onUpload = useCallback( + (files: File[]) => { + const items: IFileWithUUID[] = files.map( (file: File): IFileWithUUID => ({ file, temp_id: uuid(), @@ -109,7 +107,7 @@ const CommentFormUnconnected: FC = memo( } }, [statuses, files]); - const comment = comment_data[id]; + const comment = useMemo(() => comment_data[id], [comment_data, id]); const is_uploading_files = useMemo(() => comment.temp_ids.length > 0, [comment.temp_ids]); @@ -156,88 +154,12 @@ const CommentFormUnconnected: FC = memo( [statuses, comment.temp_ids] ); - const onFileDrop = useCallback( - (fileId: IFile['id']) => { - nodeSetCommentData( - id, - assocPath( - ['files'], - comment.files.filter(file => file.id != fileId), - comment_data[id] - ) - ); - }, - [comment_data, id, nodeSetCommentData] - ); - - const onTitleChange = useCallback( - (fileId: IFile['id'], title: IFile['metadata']['title']) => { - nodeSetCommentData( - id, - assocPath( - ['files'], - comment.files.map(file => - file.id === fileId ? { ...file, metadata: { ...file.metadata, title } } : file - ), - comment_data[id] - ) - ); - }, - [comment_data, id, nodeSetCommentData] - ); - - const onImageMove = useCallback( - ({ oldIndex, newIndex }: SortEnd) => { - nodeSetCommentData( - id, - assocPath( - ['files'], - [ - ...audios, - ...(moveArrItem( - oldIndex, - newIndex, - images.filter(file => !!file) - ) as IFile[]), - ], - comment_data[id] - ) - ); - }, - [images, audios, comment_data, nodeSetCommentData] - ); - - const onAudioMove = useCallback( - ({ oldIndex, newIndex }: SortEnd) => { - nodeSetCommentData( - id, - assocPath( - ['files'], - [ - ...images, - ...(moveArrItem( - oldIndex, - newIndex, - audios.filter(file => !!file) - ) as IFile[]), - ], - comment_data[id] - ) - ); - }, - [images, audios, comment_data, nodeSetCommentData] - ); - const onCancelEdit = useCallback(() => { nodeCancelCommentEdit(id); }, [nodeCancelCommentEdit, comment.id]); const placeholder = getRandomPhrase('SIMPLE'); - const hasImageAttaches = images.length > 0 || locked_images.length > 0; - const hasAudioAttaches = audios.length > 0 || locked_audios.length > 0; - const hasAttaches = hasImageAttaches || hasAudioAttaches; - const clearError = useCallback(() => nodeSetCommentData(id, { error: '' }), [ id, nodeSetCommentData, @@ -247,6 +169,13 @@ const CommentFormUnconnected: FC = memo( if (comment.error) clearError(); }, [comment.files, comment.text]); + const setData = useCallback( + (data: Partial) => { + nodeSetCommentData(id, data); + }, + [nodeSetCommentData, id] + ); + return (
@@ -266,46 +195,17 @@ const CommentFormUnconnected: FC = memo( )}
- {hasAttaches && ( -
- {hasImageAttaches && ( - - )} - - {hasAudioAttaches && ( - - )} -
- )} + - - - - - + diff --git a/src/components/node/CommentForm/styles.module.scss b/src/components/comment/CommentForm/styles.module.scss similarity index 100% rename from src/components/node/CommentForm/styles.module.scss rename to src/components/comment/CommentForm/styles.module.scss diff --git a/src/components/comment/CommentFormAttaches/index.tsx b/src/components/comment/CommentFormAttaches/index.tsx new file mode 100644 index 00000000..d3408b18 --- /dev/null +++ b/src/components/comment/CommentFormAttaches/index.tsx @@ -0,0 +1,133 @@ +import React, { FC, useCallback } from 'react'; +import styles from '~/components/comment/CommentForm/styles.module.scss'; +import { SortableImageGrid } from '~/components/editors/SortableImageGrid'; +import { SortableAudioGrid } from '~/components/editors/SortableAudioGrid'; +import { IComment, IFile } from '~/redux/types'; +import { IUploadStatus } from '~/redux/uploads/reducer'; +import { SortEnd } from 'react-sortable-hoc'; +import assocPath from 'ramda/es/assocPath'; +import { moveArrItem } from '~/utils/fn'; + +interface IProps { + images: IFile[]; + audios: IFile[]; + locked_images: IUploadStatus[]; + locked_audios: IUploadStatus[]; + comment: IComment; + setComment: (data: IComment) => void; +} + +const CommentFormAttaches: FC = ({ + images, + audios, + locked_images, + locked_audios, + comment, + setComment, +}) => { + const hasImageAttaches = images.length > 0 || locked_images.length > 0; + const hasAudioAttaches = audios.length > 0 || locked_audios.length > 0; + const hasAttaches = hasImageAttaches || hasAudioAttaches; + + const onImageMove = useCallback( + ({ oldIndex, newIndex }: SortEnd) => { + setComment( + assocPath( + ['files'], + [ + ...audios, + ...(moveArrItem( + oldIndex, + newIndex, + images.filter(file => !!file) + ) as IFile[]), + ], + comment + ) + ); + }, + [images, audios, comment, setComment] + ); + + const onFileDelete = useCallback( + (fileId: IFile['id']) => { + setComment( + assocPath( + ['files'], + comment.files.filter(file => file.id != fileId), + comment + ) + ); + }, + [setComment, comment] + ); + + const onTitleChange = useCallback( + (fileId: IFile['id'], title: IFile['metadata']['title']) => { + setComment( + assocPath( + ['files'], + comment.files.map(file => + file.id === fileId ? { ...file, metadata: { ...file.metadata, title } } : file + ), + comment + ) + ); + }, + [comment, setComment] + ); + + const onAudioMove = useCallback( + ({ oldIndex, newIndex }: SortEnd) => { + setComment( + assocPath( + ['files'], + [ + ...images, + ...(moveArrItem( + oldIndex, + newIndex, + audios.filter(file => !!file) + ) as IFile[]), + ], + comment + ) + ); + }, + [images, audios, comment, setComment] + ); + + return ( + hasAttaches && ( +
+ {hasImageAttaches && ( + + )} + + {hasAudioAttaches && ( + + )} +
+ ) + ); +}; + +export { CommentFormAttaches }; diff --git a/src/components/comment/CommentFormButtons/index.tsx b/src/components/comment/CommentFormButtons/index.tsx new file mode 100644 index 00000000..44761ac7 --- /dev/null +++ b/src/components/comment/CommentFormButtons/index.tsx @@ -0,0 +1,36 @@ +import React, { FC, useCallback } from 'react'; +import { ButtonGroup } from '~/components/input/ButtonGroup'; +import { Button } from '~/components/input/Button'; + +interface IProps { + onUpload: (files: File[]) => void; +} + +const CommentFormButtons: FC = ({ onUpload }) => { + const onInputChange = useCallback( + event => { + event.preventDefault(); + + const files: File[] = Array.from(event.target?.files); + + if (!files || !files.length) return; + + onUpload(files); + }, + [onUpload] + ); + + return ( + + + + + + ); +}; + +export { CommentFormButtons }; diff --git a/src/components/node/CommentMenu/index.tsx b/src/components/comment/CommentMenu/index.tsx similarity index 100% rename from src/components/node/CommentMenu/index.tsx rename to src/components/comment/CommentMenu/index.tsx diff --git a/src/components/node/CommentMenu/styles.module.scss b/src/components/comment/CommentMenu/styles.module.scss similarity index 100% rename from src/components/node/CommentMenu/styles.module.scss rename to src/components/comment/CommentMenu/styles.module.scss diff --git a/src/components/editors/AudioGrid/index.tsx b/src/components/editors/AudioGrid/index.tsx index 7f2451a2..1640754f 100644 --- a/src/components/editors/AudioGrid/index.tsx +++ b/src/components/editors/AudioGrid/index.tsx @@ -16,7 +16,13 @@ interface IProps { const AudioGrid: FC = ({ files, setFiles, locked }) => { const onMove = useCallback( ({ oldIndex, newIndex }: SortEnd) => { - setFiles(moveArrItem(oldIndex, newIndex, files.filter(file => !!file)) as IFile[]); + setFiles( + moveArrItem( + oldIndex, + newIndex, + files.filter(file => !!file) + ) as IFile[] + ); }, [setFiles, files] ); @@ -41,7 +47,7 @@ const AudioGrid: FC = ({ files, setFiles, locked }) => { return ( = ({ files, setFiles, locked }) => { const onMove = useCallback( ({ oldIndex, newIndex }: SortEnd) => { - setFiles(moveArrItem(oldIndex, newIndex, files.filter(file => !!file)) as IFile[]); + setFiles( + moveArrItem( + oldIndex, + newIndex, + files.filter(file => !!file) + ) as IFile[] + ); }, [setFiles, files] ); @@ -29,7 +35,7 @@ const ImageGrid: FC = ({ files, setFiles, locked }) => { return ( void; + onDelete: (file_id: IFile['id']) => void; onTitleChange: (file_id: IFile['id'], title: IFile['metadata']['title']) => void; }) => { console.log(locked); @@ -27,7 +27,12 @@ const SortableAudioGrid = SortableContainer( .filter(file => file && file.id) .map((file, index) => ( - + ))} diff --git a/src/components/editors/SortableImageGrid/index.tsx b/src/components/editors/SortableImageGrid/index.tsx index edfc4ea7..4c40d94e 100644 --- a/src/components/editors/SortableImageGrid/index.tsx +++ b/src/components/editors/SortableImageGrid/index.tsx @@ -12,12 +12,12 @@ const SortableImageGrid = SortableContainer( ({ items, locked, - onDrop, + onDelete, size = 200, }: { items: IFile[]; locked: IUploadStatus[]; - onDrop: (file_id: IFile['id']) => void; + onDelete: (file_id: IFile['id']) => void; size?: number; }) => (
file && file.id) .map((file, index) => ( - + ))} diff --git a/src/components/media/AudioPlayer/index.tsx b/src/components/media/AudioPlayer/index.tsx index 6e698639..d5942f2f 100644 --- a/src/components/media/AudioPlayer/index.tsx +++ b/src/components/media/AudioPlayer/index.tsx @@ -25,14 +25,14 @@ type Props = ReturnType & typeof mapDispatchToProps & { file: IFile; isEditing?: boolean; - onDrop?: (id: IFile['id']) => void; + onDelete?: (id: IFile['id']) => void; onTitleChange?: (file_id: IFile['id'], title: IFile['metadata']['title']) => void; }; const AudioPlayerUnconnected = memo( ({ file, - onDrop, + onDelete, isEditing, onTitleChange, player: { file: current, status }, @@ -78,10 +78,10 @@ const AudioPlayerUnconnected = memo( ); const onDropClick = useCallback(() => { - if (!onDrop) return; + if (!onDelete) return; - onDrop(file.id); - }, [file, onDrop]); + onDelete(file.id); + }, [file, onDelete]); const title = useMemo( () => @@ -111,7 +111,7 @@ const AudioPlayerUnconnected = memo( return (
- {onDrop && ( + {onDelete && (
@@ -149,7 +149,4 @@ const AudioPlayerUnconnected = memo( } ); -export const AudioPlayer = connect( - mapStateToProps, - mapDispatchToProps -)(AudioPlayerUnconnected); +export const AudioPlayer = connect(mapStateToProps, mapDispatchToProps)(AudioPlayerUnconnected); diff --git a/src/components/node/NodeCommentForm/index.tsx b/src/components/node/NodeCommentForm/index.tsx index b72c663b..16d96f17 100644 --- a/src/components/node/NodeCommentForm/index.tsx +++ b/src/components/node/NodeCommentForm/index.tsx @@ -13,7 +13,7 @@ import * as UPLOAD_ACTIONS from '~/redux/uploads/actions'; import { selectUploads } from '~/redux/uploads/selectors'; import { IState } from '~/redux/store'; import { selectUser, selectAuthUser } from '~/redux/auth/selectors'; -import { CommentForm } from '../CommentForm'; +import { CommentForm } from '../../comment/CommentForm'; const mapStateToProps = state => ({ user: selectAuthUser(state), diff --git a/src/components/node/NodeComments/index.tsx b/src/components/node/NodeComments/index.tsx index 4cc1e3d3..205a0e4f 100644 --- a/src/components/node/NodeComments/index.tsx +++ b/src/components/node/NodeComments/index.tsx @@ -1,5 +1,5 @@ import React, { FC, useMemo, memo } from 'react'; -import { Comment } from '../Comment'; +import { Comment } from '../../comment/Comment'; import { Filler } from '~/components/containers/Filler'; import styles from './styles.module.scss'; diff --git a/src/components/profile/Message/index.tsx b/src/components/profile/Message/index.tsx index 373159a4..83b9a7be 100644 --- a/src/components/profile/Message/index.tsx +++ b/src/components/profile/Message/index.tsx @@ -5,7 +5,7 @@ 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 { CommentMenu } from '~/components/comment/CommentMenu'; import { MessageForm } from '~/components/profile/MessageForm'; import { Filler } from '~/components/containers/Filler'; import { Button } from '~/components/input/Button'; diff --git a/src/containers/profile/ProfileLayout/index.tsx b/src/containers/profile/ProfileLayout/index.tsx index c95bacba..5c9c25a5 100644 --- a/src/containers/profile/ProfileLayout/index.tsx +++ b/src/containers/profile/ProfileLayout/index.tsx @@ -1,10 +1,9 @@ import React, { FC, useEffect, useState } from 'react'; -import { useRouteMatch, withRouter, RouteComponentProps } from 'react-router'; +import { RouteComponentProps, useRouteMatch, withRouter } from 'react-router'; import styles from './styles.module.scss'; import { NodeNoComments } from '~/components/node/NodeNoComments'; import { Grid } from '~/components/containers/Grid'; -import { CommentForm } from '~/components/node/CommentForm'; -import { ProfileInfo } from '../ProfileInfo'; +import { CommentForm } from '~/components/comment/CommentForm'; import * as NODE_ACTIONS from '~/redux/node/actions'; import { connect } from 'react-redux'; import { IUser } from '~/redux/auth/types';