Skip to content

Commit

Permalink
🏣 Post reply in modal (Joystream#3716)
Browse files Browse the repository at this point in the history
* Queries regeneration

* New modal

* Introducing commonMocks from mocks shared throughout the tests

* Mappings changes

* UI changes for allow new logic and small cleanup

* Small fix to UI bug when query node error

* Fee validation on reply modal

* Missing modal fix

* Test fix
  • Loading branch information
WRadoslaw authored Nov 29, 2022
1 parent e67eb63 commit 5deab64
Show file tree
Hide file tree
Showing 28 changed files with 449 additions and 207 deletions.
3 changes: 3 additions & 0 deletions packages/ui/src/app/GlobalModals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { CreatePostModal, CreatePostModalCall } from '@/forum/modals/PostActionM
import { DeletePostModal, DeletePostModalCall } from '@/forum/modals/PostActionModal/DeletePostModal'
import { EditPostModal, EditPostModalCall } from '@/forum/modals/PostActionModal/EditPostModal'
import { PostHistoryModal, PostHistoryModalCall } from '@/forum/modals/PostHistoryModal'
import { PostReplyModal, PostReplyModalCall } from '@/forum/modals/PostReplyModal'
import { MemberModalCall, MemberProfile } from '@/memberships/components/MemberProfile'
import { useMyMemberships } from '@/memberships/hooks/useMyMemberships'
import { BuyMembershipModal, BuyMembershipModalCall } from '@/memberships/modals/BuyMembershipModal'
Expand Down Expand Up @@ -117,6 +118,7 @@ export type ModalNames =
| ModalName<ClaimVestingModalCall>
| ModalName<UpdateMembershipModalCall>
| ModalName<ReportContentModalCall>
| ModalName<PostReplyModalCall>

const modals: Record<ModalNames, ReactElement> = {
Member: <MemberProfile />,
Expand Down Expand Up @@ -164,6 +166,7 @@ const modals: Record<ModalNames, ReactElement> = {
ClaimVestingModal: <ClaimVestingModal />,
UpdateMembershipModal: <UpdateMembershipModal />,
ReportContentModal: <ReportContentModal />,
PostReplyModal: <PostReplyModal />,
}

const GUEST_ACCESSIBLE_MODALS: ModalNames[] = [
Expand Down
24 changes: 5 additions & 19 deletions packages/ui/src/app/pages/Forum/ForumThread.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ForumPostMetadata } from '@joystream/metadata-protobuf'
import React, { useEffect, useRef, useState } from 'react'
import { generatePath, useHistory, useParams } from 'react-router-dom'
import React, { useEffect, useRef } from 'react'
import { useHistory, useParams } from 'react-router-dom'
import styled from 'styled-components'

import { useApi } from '@/api/hooks/useApi'
Expand All @@ -25,7 +25,6 @@ import { ThreadTitle } from '@/forum/components/Thread/ThreadTitle'
import { WatchlistButton } from '@/forum/components/Thread/WatchlistButton'
import { ForumRoutes } from '@/forum/constant'
import { useForumThread } from '@/forum/hooks/useForumThread'
import { ForumPost } from '@/forum/types'
import { useMyMemberships } from '@/memberships/hooks/useMyMemberships'

import { ForumPageLayout } from './components/ForumPageLayout'
Expand All @@ -44,11 +43,6 @@ export const ForumThread = () => {
const sideNeighborRef = useRef<HTMLDivElement>(null)
const newPostRef = useRef<HTMLDivElement>(null)
const history = useHistory()
const [replyTo, setReplyTo] = useState<ForumPost | undefined>()

useEffect(() => {
replyTo && newPostRef.current?.scrollIntoView({ behavior: 'smooth', inline: 'end' })
}, [replyTo])

const isThreadActive = !!(thread && thread.status.__typename === 'ThreadStatusActive')

Expand All @@ -59,7 +53,7 @@ export const ForumThread = () => {
createType('ForumUserId', Number.parseInt(active.id)),
categoryId,
threadId,
metadataToBytes(ForumPostMetadata, { text: postText, repliesTo: replyTo ? Number(replyTo.id) : undefined }),
metadataToBytes(ForumPostMetadata, { text: postText, repliesTo: undefined }),
isEditable
)
}
Expand Down Expand Up @@ -114,16 +108,8 @@ export const ForumThread = () => {

const displayMain = () => (
<ThreadPanel ref={sideNeighborRef}>
<PostList threadId={id} isThreadActive={isThreadActive} isLoading={isLoading} replyToPost={setReplyTo} />
{thread && isThreadActive && (
<NewThreadPost
ref={newPostRef}
replyTo={replyTo}
removeReply={() => setReplyTo(undefined)}
getTransaction={getTransaction}
replyToLink={`${generatePath(ForumRoutes.thread, { id: thread.id })}?post=${replyTo?.id}`}
/>
)}
<PostList threadId={id} isThreadActive={isThreadActive} isLoading={isLoading} />
{thread && isThreadActive && <NewThreadPost ref={newPostRef} getTransaction={getTransaction} />}
</ThreadPanel>
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,26 @@
import React, { useCallback } from 'react'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { generatePath, useHistory } from 'react-router-dom'
import styled from 'styled-components'

import { TextMedium } from '@/common/components/typography'
import { PostList } from '@/forum/components/PostList/PostList'
import { ForumRoutes } from '@/forum/constant'
import { useForumThread } from '@/forum/hooks/useForumThread'
import { ForumPost } from '@/forum/types'

export interface BountyDiscussionProps {
discussionThreadId: string
}

export const BountyDiscussion = React.memo(({ discussionThreadId }: BountyDiscussionProps) => {
const { t } = useTranslation('bounty')
const { push } = useHistory()
const { isLoading, thread } = useForumThread(discussionThreadId)
const isThreadActive = !!(thread && thread.status.__typename === 'ThreadStatusActive')

const replyToPost = useCallback(
(post: ForumPost) => {
if (thread) {
return push(`${generatePath(ForumRoutes.thread, { id: thread.id })}?post=${post.id}`)
}
},
[thread]
)

return (
<Container id="bounty-discussion">
<TextMedium black bold>
{t('discussionThread.title')}
</TextMedium>
<PostList
threadId={discussionThreadId}
isLoading={isLoading}
isThreadActive={isThreadActive}
replyToPost={replyToPost}
isDiscussion
/>
<PostList threadId={discussionThreadId} isLoading={isLoading} isThreadActive={isThreadActive} isDiscussion />
</Container>
)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ interface Props {
next: ButtonState
className?: string
extraButtons?: ReactNode
extraLeftButtons?: ReactNode
}

export const ModalTransactionFooter: FC<Props> = ({
extraButtons,
extraLeftButtons,
transactionFee,
prev,
next,
Expand All @@ -34,6 +36,7 @@ export const ModalTransactionFooter: FC<Props> = ({
return (
<ModalFooter className={className} twoColumns>
<ButtonsGroup align="left">
{extraLeftButtons}
{prev && !prev.disabled && (
<ButtonGhost onClick={prev.onClick} size="medium">
<Arrow direction="left" />
Expand Down
5 changes: 1 addition & 4 deletions packages/ui/src/forum/components/PostList/PostList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,17 @@ import { AnyKeys } from '@/common/types'
import { getUrl } from '@/common/utils/getUrl'
import { ForumRoutes } from '@/forum/constant'
import { useForumThreadPosts } from '@/forum/hooks/useForumThreadPosts'
import { ForumPost } from '@/forum/types'

import { ForumPostStyles, PostListItem } from './PostListItem'

interface PostListProps {
threadId: string
isThreadActive?: boolean
isLoading?: boolean
replyToPost: (post: ForumPost) => void
isDiscussion?: boolean
}

export const PostList = ({ threadId, isThreadActive, isLoading, replyToPost, isDiscussion }: PostListProps) => {
export const PostList = ({ threadId, isThreadActive, isLoading, isDiscussion }: PostListProps) => {
const history = useHistory()
const { pathname } = useLocation()
const query = useRouteQuery()
Expand Down Expand Up @@ -61,7 +59,6 @@ export const PostList = ({ threadId, isThreadActive, isLoading, replyToPost, isD
isSelected={post.id === navigation.post}
isThreadActive={isThreadActive}
type="forum"
replyToPost={() => replyToPost({ ...post, repliesTo: undefined })}
link={getUrl({ route: ForumRoutes.thread, params: { id: threadId }, query: { post: post.id } })}
repliesToLink={`${generatePath(ForumRoutes.thread, { id: threadId })}?post=${post.repliesTo?.id}`}
isDiscussion={isDiscussion}
Expand Down
49 changes: 3 additions & 46 deletions packages/ui/src/forum/components/PostList/PostListItem.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { PostListItem } from '@/forum/components/PostList/PostListItem'
import { ForumPost } from '@/forum/types'
import { MembershipContext } from '@/memberships/providers/membership/context'
import { MockApolloProvider } from '@/mocks/components/storybook/MockApolloProvider'
import { forumPostMock } from '@/mocks/data/commonMocks'
import { getMember } from '@/mocks/helpers'

export default {
Expand Down Expand Up @@ -60,7 +61,6 @@ const Template: Story<Props> = ({ post, text, edited = -1, likes = -1, replyText
post={{ ...post, lastEditedAt, text, reaction, repliesTo }}
isThreadActive={isThreadActive}
type="forum"
replyToPost={() => true}
link="#"
repliesToLink=""
/>
Expand All @@ -80,30 +80,7 @@ consequat sunt nostrud.`,
replyText: `Amet minim mollit non deserunt ullamco est sit aliqua dolor do amet sint.
Velit officia consequat duis enim velit mollit.
Exercitation veniam consequat sunt nostrud amet.`,
post: {
id: '0',
createdAt: new Date().toISOString(),
createdAtBlock: {
number: 1000,
network: 'OLYMPIA',
timestamp: '2012-01-26T13:51:50.417-07:00',
},
author: {
id: '0',
name: 'Alice member',
rootAccount: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
controllerAccount: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
handle: 'alice',
isVerified: false,
isFoundingMember: false,
isCouncilMember: false,
roles: [],
boundAccounts: [],
inviteCount: 0,
createdAt: '',
},
status: 'PostStatusActive',
},
post: forumPostMock,
isThreadActive: true,
}

Expand All @@ -118,27 +95,7 @@ consequat sunt nostrud.`,
Velit officia consequat duis enim velit mollit.
Exercitation veniam consequat sunt nostrud amet.`,
post: {
id: '0',
createdAt: new Date().toISOString(),
createdAtBlock: {
number: 1000,
network: 'OLYMPIA',
timestamp: '2012-01-26T13:51:50.417-07:00',
},
author: {
id: '0',
name: 'Alice member',
rootAccount: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
controllerAccount: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY',
handle: 'alice',
isVerified: false,
isFoundingMember: false,
isCouncilMember: false,
roles: [],
boundAccounts: [],
inviteCount: 0,
createdAt: '',
},
...forumPostMock,
moderator: {
id: '0',
name: 'Alice member',
Expand Down
11 changes: 8 additions & 3 deletions packages/ui/src/forum/components/PostList/PostListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { useLocation } from '@/common/hooks/useLocation'
import { useModal } from '@/common/hooks/useModal'
import { relativeIfRecent } from '@/common/model/relativeIfRecent'
import { PostHistoryModalCall } from '@/forum/modals/PostHistoryModal'
import { PostReplyModalCall } from '@/forum/modals/PostReplyModal'
import { ForumPost } from '@/forum/types'
import { MemberInfo } from '@/memberships/components'
import { useMyMemberships } from '@/memberships/hooks/useMyMemberships'
Expand All @@ -37,7 +38,6 @@ interface PostListItemProps {
isThreadActive?: boolean
insertRef?: (ref: RefObject<HTMLDivElement>) => void
type: PostListItemType
replyToPost: () => void
link?: string
isDiscussion?: boolean
repliesToLink: string
Expand All @@ -52,7 +52,6 @@ export const PostListItem = ({
insertRef,
type,
link,
replyToPost,
isDiscussion,
repliesToLink,
}: PostListItemProps) => {
Expand Down Expand Up @@ -96,7 +95,13 @@ export const PostListItem = ({

const onReply = (): void => {
if (!active) showModal<SwitchMemberModalCall>({ modal: 'SwitchMember' })
return replyToPost()
showModal<PostReplyModalCall>({
modal: 'PostReplyModal',
data: {
replyTo: post,
module: type === 'forum' ? type : 'proposalsDiscussion',
},
})
}

return (
Expand Down
36 changes: 5 additions & 31 deletions packages/ui/src/forum/components/Thread/NewThreadPost.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
import { SubmittableExtrinsic } from '@polkadot/api/types'
import { ISubmittableResult } from '@polkadot/types/types'
import React, { Ref, RefObject, useCallback, useRef, useState } from 'react'
import { Link } from 'react-router-dom'

import { ButtonPrimary, ButtonsGroup } from '@/common/components/buttons'
import { ButtonsGroup } from '@/common/components/buttons'
import { TransactionButton } from '@/common/components/buttons/TransactionButton'
import { BaseCKEditor } from '@/common/components/CKEditor'
import { Checkbox, InputComponent } from '@/common/components/forms'
import { ArrowReplyIcon, CrossIcon } from '@/common/components/icons'
import { MarkdownPreview } from '@/common/components/MarkdownPreview'
import { RowGapBlock } from '@/common/components/page/PageContent'
import { Badge, TextBig } from '@/common/components/typography'
import { TextBig } from '@/common/components/typography'
import { useModal } from '@/common/hooks/useModal'
import { Reply, ReplyBadge } from '@/forum/components/PostList/PostListItem'
import { CreatePostModalCall } from '@/forum/modals/PostActionModal/CreatePostModal'
import { ForumPost } from '@/forum/types'
import { useMyMemberships } from '@/memberships/hooks/useMyMemberships'

type GetTransaction = (
Expand All @@ -24,13 +19,10 @@ type GetTransaction = (

export interface NewPostProps {
getTransaction: GetTransaction
replyTo?: ForumPost
removeReply: () => void
replyToLink: string
}

export const NewThreadPost = React.forwardRef(
({ getTransaction, replyTo, removeReply, replyToLink }: NewPostProps, ref: React.ForwardedRef<HTMLDivElement>) => {
({ getTransaction }: NewPostProps, ref: React.ForwardedRef<HTMLDivElement>) => {
const [postText, setText] = useState('')
const [isEditable, setEditable] = useState(true)
const { active } = useMyMemberships()
Expand All @@ -49,24 +41,6 @@ export const NewThreadPost = React.forwardRef(

return (
<RowGapBlock gap={8} ref={ref}>
{replyTo && (
<Reply>
<ReplyBadge>
<div>
<ArrowReplyIcon />{' '}
<Badge>
<Link to={replyToLink}>Replies to {replyTo.author.handle}</Link>
</Badge>
</div>
<div>
<ButtonPrimary size="small" square onClick={removeReply}>
<CrossIcon />
</ButtonPrimary>
</div>
</ReplyBadge>
<MarkdownPreview markdown={replyTo.text} size="s" isReply />
</Reply>
)}
<InputComponent
inputSize="auto"
message={postText === '' ? 'This field cannot be empty. Type your message here' : undefined}
Expand All @@ -82,12 +56,12 @@ export const NewThreadPost = React.forwardRef(
transaction &&
showModal<CreatePostModalCall>({
modal: 'CreatePost',
data: { module: 'proposalsDiscussion', postText, replyTo, transaction, isEditable, onSuccess },
data: { module: 'proposalsDiscussion', postText, transaction, isEditable, onSuccess },
})
}}
disabled={postText === ''}
>
{replyTo ? 'Post a reply' : 'Create post'}
Create post
</TransactionButton>
<Checkbox id="set-editable" onChange={setEditable} isChecked={isEditable}>
Keep editable
Expand Down
Loading

0 comments on commit 5deab64

Please sign in to comment.