import React, { createElement, FC, memo, useCallback, useEffect, useMemo, useState } from 'react'; import { RouteComponentProps, useHistory } from 'react-router'; import { connect } from 'react-redux'; import { canEditNode, canLikeNode, canStarNode } from '~/utils/node'; import { selectNode } from '~/redux/node/selectors'; import { Card } from '~/components/containers/Card'; import { NodePanel } from '~/components/node/NodePanel'; import { Group } from '~/components/containers/Group'; import { Padder } from '~/components/containers/Padder'; import { NodeNoComments } from '~/components/node/NodeNoComments'; import { NodeRelated } from '~/components/node/NodeRelated'; import { NodeComments } from '~/components/node/NodeComments'; import { NodeTags } from '~/components/node/NodeTags'; import { INodeComponentProps, NODE_COMPONENTS, NODE_HEADS, NODE_INLINES, } from '~/redux/node/constants'; import { selectUser } from '~/redux/auth/selectors'; import pick from 'ramda/es/pick'; import { NodeRelatedPlaceholder } from '~/components/node/NodeRelated/placeholder'; import { NodeDeletedBadge } from '~/components/node/NodeDeletedBadge'; import { NodeCommentForm } from '~/components/node/NodeCommentForm'; import { Sticky } from '~/components/containers/Sticky'; import { Footer } from '~/components/main/Footer'; import * as styles from './styles.scss'; import * as NODE_ACTIONS from '~/redux/node/actions'; import * as MODAL_ACTIONS from '~/redux/modal/actions'; import { IState } from '~/redux/store'; import { selectModal } from '~/redux/modal/selectors'; import { SidebarRouter } from '~/containers/main/SidebarRouter'; import { ITag } from '~/redux/types'; import { URLS } from '~/constants/urls'; const mapStateToProps = (state: IState) => ({ node: selectNode(state), user: selectUser(state), modal: pick(['is_shown'])(selectModal(state)), }); const mapDispatchToProps = { nodeGotoNode: NODE_ACTIONS.nodeGotoNode, nodeUpdateTags: NODE_ACTIONS.nodeUpdateTags, nodeSetCoverImage: NODE_ACTIONS.nodeSetCoverImage, nodeEdit: NODE_ACTIONS.nodeEdit, nodeLike: NODE_ACTIONS.nodeLike, nodeStar: NODE_ACTIONS.nodeStar, nodeLock: NODE_ACTIONS.nodeLock, nodeLockComment: NODE_ACTIONS.nodeLockComment, nodeEditComment: NODE_ACTIONS.nodeEditComment, nodeLoadMoreComments: NODE_ACTIONS.nodeLoadMoreComments, modalShowPhotoswipe: MODAL_ACTIONS.modalShowPhotoswipe, }; type IProps = ReturnType & typeof mapDispatchToProps & RouteComponentProps<{ id: string }> & {}; const NodeLayoutUnconnected: FC = memo( ({ match: { params: { id }, }, node: { is_loading, is_loading_comments, comments = [], current: node, related, comment_data, comment_count, }, modal: { is_shown: is_modal_shown }, user, user: { is_user }, nodeGotoNode, nodeUpdateTags, nodeEdit, nodeLike, nodeStar, nodeLock, nodeSetCoverImage, nodeLockComment, nodeEditComment, nodeLoadMoreComments, modalShowPhotoswipe, }) => { const [layout, setLayout] = useState({}); const history = useHistory(); const updateLayout = useCallback(() => setLayout({}), []); useEffect(() => { if (is_loading) return; nodeGotoNode(parseInt(id, 10), null); }, [nodeGotoNode, id]); const onTagsChange = useCallback( (tags: string[]) => { nodeUpdateTags(node.id, tags); }, [node, nodeUpdateTags] ); const onTagClick = useCallback( (tag: Partial) => { history.push(URLS.NODE_TAG_URL(node.id, encodeURIComponent(tag.title))); }, [history, node.id] ); const can_edit = useMemo(() => canEditNode(node, user), [node, user]); const can_like = useMemo(() => canLikeNode(node, user), [node, user]); const can_star = useMemo(() => canStarNode(node, user), [node, user]); const head = node && node.type && NODE_HEADS[node.type]; const block = node && node.type && NODE_COMPONENTS[node.type]; const inline = node && node.type && NODE_INLINES[node.type]; const onEdit = useCallback(() => nodeEdit(node.id), [nodeEdit, node]); const onLike = useCallback(() => nodeLike(node.id), [nodeLike, node]); const onStar = useCallback(() => nodeStar(node.id), [nodeStar, node]); const onLock = useCallback(() => nodeLock(node.id, !node.deleted_at), [nodeStar, node]); const createNodeBlock = useCallback( (block: FC) => block && createElement(block, { node, is_loading, updateLayout, layout, modalShowPhotoswipe, is_modal_shown, }), [node, is_loading, updateLayout, layout, modalShowPhotoswipe, is_modal_shown] ); useEffect(() => { if (!node.cover) return; nodeSetCoverImage(node.cover); return () => nodeSetCoverImage(null); }, [nodeSetCoverImage, node.cover]); useEffect(() => { window.scrollTo(0, 0); }, [id]); return ( <> {createNodeBlock(head)} {createNodeBlock(block)} {node.deleted_at ? ( ) : ( {inline &&
{createNodeBlock(inline)}
} {is_loading || is_loading_comments || (!comments.length && !inline) ? ( ) : ( )} {is_user && !is_loading && }
{!is_loading && ( )} {is_loading && } {!is_loading && related && related.albums && Object.keys(related.albums) .filter(album => related.albums[album].length > 0) .map(album => ( ))} {!is_loading && related && related.similar && related.similar.length > 0 && ( )}
)}