Skip to content
This repository has been archived by the owner on Jan 17, 2022. It is now read-only.

Add move posts modal #332

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
2 changes: 1 addition & 1 deletion src/components/comments/ViewComment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export const ViewComment: FunctionComponent<Props> = ({
</span>
}
/>
<PostDropDownMenu key={`comment-dropdown-menu-${id}`} post={struct} space={space} />
<PostDropDownMenu key={`comment-dropdown-menu-${id}`} postDetails={comment} space={space} />
</div>}
content={showEditForm
? <EditComment struct={struct} content={content as CommentContent} callback={() => setShowEditForm(false)}/>
Expand Down
26 changes: 26 additions & 0 deletions src/components/posts/MovePostLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, { useState } from 'react'
import { Post } from '@subsocial/types/substrate/interfaces'
import { MoveModal } from 'src/components/posts/modals/MoveModal'

type Props = {
post: Post
}

export const MovePostLink = ({ post }: Props) => {

const [ open, setOpen ] = useState<boolean>()
const title = 'Move post'

return <>
<a
className='DfBlackLink'
onClick={() => setOpen(true)}
title={title}
>
{title}
</a>
<MoveModal post={post} open={open} onClose={() => setOpen(false)} />
</>
}

export default MovePostLink
7 changes: 0 additions & 7 deletions src/components/posts/ShareModal/index.module.sass

This file was deleted.

128 changes: 128 additions & 0 deletions src/components/posts/modals/MoveModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React, { useState } from 'react'
import { withCalls, withMulti, spacesQueryToProp } from 'src/components/substrate'
import { Modal } from 'antd'
import Button from 'antd/lib/button'
import { withMyAccount, MyAccountProps } from 'src/components/utils/MyAccount'
import { LabeledValue } from 'antd/lib/select'
import SelectSpacePreview from 'src/components/utils/SelectSpacePreview'
import BN from 'bn.js'
import { OptionId } from '@subsocial/types/substrate/classes'
import { TxFailedCallback, TxCallback } from 'src/components/substrate/SubstrateTxButton'
import dynamic from 'next/dynamic'
import { isEmptyArray, nonEmptyArr } from '@subsocial/utils';
import { DynamicPostPreview } from 'src/components/posts/view-post/DynamicPostPreview'
import { CreateSpaceButton } from 'src/components/spaces/helpers'
import { useRouter } from 'next/router'
import { postUrl } from 'src/components/urls/subsocial'
import { Post, PostId, Space, SpaceId } from '@subsocial/types/substrate/interfaces'
import modalStyles from 'src/components/posts/modals/index.module.sass';
import NoData from 'src/components/utils/EmptyList'

const TxButton = dynamic(() => import('src/components/utils/TxButton'), { ssr: false })

type Props = MyAccountProps & {
post: Post
spaceIds?: BN[]
open: boolean
onClose: () => void
}

const InnerMoveModal = (props: Props) => {
const { open, onClose, post, post: { id: postId } } = props
let { spaceIds } = props

if (post.space_id.isSome && spaceIds) {
const postSpaceId = post.space_id.unwrap()
spaceIds = spaceIds.filter(spaceId => !spaceId.eq(postSpaceId))
}

if (!spaceIds) {
return null
}

const router = useRouter()

const [ spaceId, setSpaceId ] = useState(spaceIds[0])

const onTxFailed: TxFailedCallback = () => {
// TODO show a failure message
onClose()
}

const onTxSuccess: TxCallback = () => {
// TODO show a success message
router.push(
'/[spaceId]/posts/[postId]',
postUrl(
{ id: spaceId as SpaceId } as Space,
{ id: postId as PostId })
)
onClose()
}

const newTxParams = () => {
const spaceIdOption = new OptionId(spaceId)
return [ postId, spaceIdOption ]
}

const renderTxButton = () => nonEmptyArr(spaceIds)
? <TxButton
type='primary'
label={`Move`}
params={newTxParams}
tx={'posts.movePost'}
onFailed={onTxFailed}
onSuccess={onTxSuccess}
successMessage='Moved post to another space'
failedMessage='Failed to move post'
/>
: <CreateSpaceButton>Create one more space</CreateSpaceButton>

const renderMovePostView = () => {
if (isEmptyArray(spaceIds)) {
return <NoData description='You need to have at least one more space to move post' />
}

return <div className={modalStyles.DfPostActionModalBody}>
<span className={modalStyles.DfPostActionModalSelector}>
<SelectSpacePreview
spaceIds={spaceIds || []}
onSelect={saveSpace}
imageSize={24}
defaultValue={spaceId?.toString()}
/>
</span>

<div style={{margin: '0.75rem 0'}}>
<DynamicPostPreview id={postId} asRegularPost />
</div>
</div>
}

const saveSpace = (value: string | number | LabeledValue) => {
setSpaceId(new BN(value as string))
}

return <Modal
onCancel={onClose}
visible={open}
title={'Move post to another space'}
className={modalStyles.DfPostActionModal}
footer={
<>
<Button onClick={onClose}>Cancel</Button>
{renderTxButton()}
</>
}
>
{renderMovePostView()}
</Modal>
}

export const MoveModal = withMulti(
InnerMoveModal,
withMyAccount,
withCalls<Props>(
spacesQueryToProp(`spaceIdsByOwner`, { paramName: 'address', propName: 'spaceIds' })
)
)
3 changes: 3 additions & 0 deletions src/components/posts/modals/ShareModal/index.module.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.DfShareModalMdEditor
.CodeMirror
height: 5rem
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
import React, { useState } from 'react';
import { withCalls, withMulti, getTxParams, spacesQueryToProp } from '../../substrate';
import { withCalls, withMulti, getTxParams, spacesQueryToProp } from 'src/components/substrate';
import { Modal } from 'antd';
import Button from 'antd/lib/button';
import { withMyAccount, MyAccountProps } from '../../utils/MyAccount';
import { withMyAccount, MyAccountProps } from 'src/components/utils/MyAccount';
import { LabeledValue } from 'antd/lib/select';
import SelectSpacePreview from '../../utils/SelectSpacePreview';
import SelectSpacePreview from 'src/components/utils/SelectSpacePreview';
import BN from 'bn.js';
import { PostExtension, SharedPost, IpfsContent } from '@subsocial/types/substrate/classes';
import { useForm, Controller, ErrorMessage } from 'react-hook-form';
import { useSubsocialApi } from '../../utils/SubsocialApiContext';
import { useSubsocialApi } from 'src/components/utils/SubsocialApiContext';
import { IpfsCid } from '@subsocial/types/substrate/interfaces';
import { TxFailedCallback, TxCallback } from 'src/components/substrate/SubstrateTxButton';
import dynamic from 'next/dynamic';
import { buildSharePostValidationSchema } from '../PostValidation';
import { isEmptyArray } from '@subsocial/utils';
import DfMdEditor from '../../utils/DfMdEditor';
import { DynamicPostPreview } from '../view-post/DynamicPostPreview';
import { CreateSpaceButton } from '../../spaces/helpers';
import { buildSharePostValidationSchema } from 'src/components/posts/PostValidation';
import { isEmptyArray, nonEmptyArr } from '@subsocial/utils';
import DfMdEditor from 'src/components/utils/DfMdEditor';
import { DynamicPostPreview } from 'src/components/posts/view-post/DynamicPostPreview';
import { CreateSpaceButton } from 'src/components/spaces/helpers';
import styles from './index.module.sass'
import modalStyles from 'src/components/posts/modals/index.module.sass'
import NoData from 'src/components/utils/EmptyList';

const TxButton = dynamic(() => import('../../utils/TxButton'), { ssr: false });
const TxButton = dynamic(() => import('src/components/utils/TxButton'), { ssr: false });

type Props = MyAccountProps & {
postId: BN
Expand Down Expand Up @@ -69,8 +71,8 @@ const InnerShareModal = (props: Props) => {
return [ spaceId, extension, new IpfsContent(hash) ];
};

const renderTxButton = () =>
<TxButton
const renderTxButton = () => nonEmptyArr(spaceIds)
? <TxButton
type='primary'
label={`Create a post`}
disabled={isSubmitting}
Expand All @@ -86,38 +88,31 @@ const InnerShareModal = (props: Props) => {
successMessage='Shared to your space'
failedMessage='Failed to share'
/>
: <CreateSpaceButton>Create my first space</CreateSpaceButton>

const renderShareView = () => {
if (isEmptyArray(spaceIds)) {
return (
<CreateSpaceButton>
<a className='ui button primary'>
Create my first space
</a>
</CreateSpaceButton>
)
return <NoData description='You need to have at least one space to share post'/>
}

return <div className='DfShareModalBody'>
<span className='mr-3'>
Share the post to your space:
{' '}
return <div className={modalStyles.DfPostActionModalBody}>
<span className={modalStyles.DfPostActionModalSelector}>
<SelectSpacePreview
spaceIds={spaceIds}
spaceIds={spaceIds || []}
onSelect={saveSpace}
imageSize={24}
defaultValue={spaceId?.toString()}
/>
</span>

<form className='my-2'>
<form style={{margin: '0.75rem 0'}}>
<Controller
control={control}
as={<DfMdEditor />}
options={{ autofocus: true }}
name={Fields.body}
value={body}
className={errors[Fields.body] && 'error'}
className={`${errors[Fields.body] && 'error'} ${styles.DfShareModalMdEditor}`}
/>
<div className='DfError'>
<ErrorMessage errors={errors} name={Fields.body} />
Expand All @@ -135,7 +130,7 @@ const InnerShareModal = (props: Props) => {
onCancel={onClose}
visible={open}
title={'Share post'}
className={styles.DfShareModal}
className={modalStyles.DfPostActionModal}
footer={
<>
<Button onClick={onClose}>Cancel</Button>
Expand Down
11 changes: 11 additions & 0 deletions src/components/posts/modals/index.module.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@import 'src/styles/subsocial-vars.scss'

.DfPostActionModal
width: $max_width_content !important

.DfPostActionModalBody
\:global .DfSegment
margin: 0

.DfPostActionModalSelector
width: $max_width_content !important
10 changes: 6 additions & 4 deletions src/components/posts/share/SpaceShareLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import React, { useState } from 'react'
import { PostWithSomeDetails } from '@subsocial/types/dto';
import { PostExtension } from '@subsocial/types/substrate/classes';
import { EditOutlined } from '@ant-design/icons';
import { ShareModal } from '../ShareModal'
import { isRegularPost } from '../view-post';
import { IconWithLabel } from '../../utils';
import { ShareModal } from 'src/components/posts/modals/ShareModal'
import { isRegularPost } from 'src/components/posts/view-post';
import { IconWithLabel } from 'src/components/utils';
import { useAuth } from 'src/components/auth/AuthContext';

type Props = {
postDetails: PostWithSomeDetails
Expand All @@ -19,14 +20,15 @@ export const SpaceShareLink = ({
}
}: Props) => {

const { openSignInModal, state: { isSteps: { isSignIn } } } = useAuth()
const [ open, setOpen ] = useState<boolean>()
const postId = isRegularPost(extension as PostExtension) ? id : ext && ext.post.struct.id
const title = 'Write a post'

return <>
<a
className='DfBlackLink'
onClick={() => setOpen(true)}
onClick={() => isSignIn ? setOpen(true) : openSignInModal('AuthRequired')}
title={title}
>
<IconWithLabel icon={<EditOutlined />} label={title} />
Expand Down
2 changes: 1 addition & 1 deletion src/components/posts/view-post/PostPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const PostPage: NextPage<PostDetailsProps> = ({ postDetails: initialPost,
<HeadMeta title={title} desc={mdToText(body)} image={image} canonical={canonical} tags={tags} />
<div className='DfRow'>
<h1 className='DfPostName'>{titleMsg}</h1>
<PostDropDownMenu post={struct} space={spaceStruct} withEditButton />
<PostDropDownMenu postDetails={postDetails} space={spaceStruct} withEditButton />
</div>
<div className='DfRow'>
<PostCreator postDetails={postDetails} withSpaceName space={spaceData} />
Expand Down
3 changes: 1 addition & 2 deletions src/components/posts/view-post/ViewSharedPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import { InnerPreviewProps } from '.';
export const SharedPreview: React.FunctionComponent<InnerPreviewProps> = ({ postDetails, space, withActions, replies }) => {
const [ commentsSection, setCommentsSection ] = useState(false)

const { struct } = postDetails.post
return <>
<div className='DfRow'>
<PostCreator postDetails={postDetails} space={space} withSpaceName />
<PostDropDownMenu space={space.struct} post={struct}/>
<PostDropDownMenu space={space.struct} postDetails={postDetails}/>
</div>
<SharePostContent postDetails={postDetails} space={space} />
{withActions && <PostActionsPanel postDetails={postDetails} space={space.struct} toogleCommentSection={() => setCommentsSection(!commentsSection)} preview />}
Expand Down
11 changes: 8 additions & 3 deletions src/components/posts/view-post/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ import { postUrl, editPostUrl, HasSpaceIdOrHandle, HasPostId } from 'src/compone
import { ShareDropdown } from '../share/ShareDropdown';
import { ButtonLink } from 'src/components/utils/ButtonLink';
import { DfMd } from 'src/components/utils/DfMd';
import MovePostLink from 'src/components/posts/MovePostLink';

type DropdownProps = {
space: Space
post: Post
postDetails: PostWithSomeDetails
withEditButton?: boolean
}

Expand All @@ -57,7 +58,8 @@ const ReactionModal = ({ postId }: ReactionModalProps) => {
}

export const PostDropDownMenu: React.FunctionComponent<DropdownProps> = (props) => {
const { space, post, withEditButton = false } = props
const { space, postDetails, withEditButton = false } = props
const { post: { struct: post } } = postDetails
const isMyPost = isMyAddress(post.owner);
const postId = post.id
const postKey = `post-${postId.toString()}`
Expand All @@ -77,6 +79,9 @@ export const PostDropDownMenu: React.FunctionComponent<DropdownProps> = (props)
{isMyPost && <Menu.Item key={`hidden-${postKey}`}>
<HiddenPostButton post={post} asLink />
</Menu.Item>}
{isMyPost && !isComment(post.extension) && <Menu.Item key={`move-${postKey}`}>
<MovePostLink post={post} />
</Menu.Item>}
<Menu.Item key={`view-reaction-${postKey}`} >
<ReactionModal postId={postId} />
</Menu.Item>
Expand Down Expand Up @@ -311,7 +316,7 @@ export const InfoPostPreview: React.FunctionComponent<InfoForPostPreviewProps> =
<div className='w-100'>
<div className='DfRow'>
<PostCreator postDetails={postDetails} space={space} withSpaceName />
<PostDropDownMenu post={struct} space={space.struct} withEditButton />
<PostDropDownMenu postDetails={postDetails} space={space.struct} withEditButton />
</div>
<PostContent postDetails={postDetails} space={space.struct} />
<ViewTags tags={content?.tags} />
Expand Down
Loading