webapp/src/components/Article/Comment.tsx

267 lines
8.5 KiB
TypeScript
Raw Normal View History

import { Show, createMemo, createSignal, For, lazy, Suspense } from 'solid-js'
2022-09-09 11:53:35 +00:00
import { clsx } from 'clsx'
import { getPagePath } from '@nanostores/router'
2022-10-07 11:02:34 +00:00
import MD from './MD'
import { AuthorCard } from '../Author/AuthorCard'
2022-11-27 17:02:04 +00:00
import Userpic from '../Author/Userpic'
import { CommentRatingControl } from './CommentRatingControl'
import { CommentDate } from './CommentDate'
import { ShowIfAuthenticated } from '../_shared/ShowIfAuthenticated'
import { Icon } from '../_shared/Icon'
import { useSession } from '../../context/session'
import { useLocalize } from '../../context/localize'
2023-02-17 09:21:02 +00:00
import { useReactions } from '../../context/reactions'
import { useSnackbar } from '../../context/snackbar'
import { useConfirm } from '../../context/confirm'
2023-08-07 09:02:58 +00:00
import { Author, Reaction, ReactionKind } from '../../graphql/types.gen'
import { router } from '../../stores/router'
import styles from './Comment.module.scss'
2023-03-06 14:06:48 +00:00
const SimplifiedEditor = lazy(() => import('../Editor/SimplifiedEditor'))
2022-09-09 11:53:35 +00:00
type Props = {
comment: Reaction
2022-09-09 11:53:35 +00:00
compact?: boolean
isArticleAuthor?: boolean
2023-02-17 09:21:02 +00:00
sortedComments?: Reaction[]
2023-03-06 14:06:48 +00:00
lastSeen?: Date
class?: string
showArticleLink?: boolean
}
2023-01-04 13:26:18 +00:00
export const Comment = (props: Props) => {
2023-02-17 09:21:02 +00:00
const { t } = useLocalize()
2022-11-26 21:27:54 +00:00
const [isReplyVisible, setIsReplyVisible] = createSignal(false)
const [loading, setLoading] = createSignal<boolean>(false)
2023-02-07 12:48:45 +00:00
const [editMode, setEditMode] = createSignal<boolean>(false)
const { session } = useSession()
2023-02-17 09:21:02 +00:00
const {
actions: { createReaction, deleteReaction, updateReaction }
} = useReactions()
const {
actions: { showConfirm }
} = useConfirm()
2023-02-17 09:21:02 +00:00
const {
actions: { showSnackbar }
} = useSnackbar()
2023-03-06 14:06:48 +00:00
const isCommentAuthor = createMemo(() => props.comment.createdBy?.slug === session()?.user?.slug)
2022-11-26 21:27:54 +00:00
2022-09-09 11:53:35 +00:00
const comment = createMemo(() => props.comment)
2022-11-26 01:46:34 +00:00
const body = createMemo(() => (comment().body || '').trim())
const remove = async () => {
2022-09-09 11:53:35 +00:00
if (comment()?.id) {
try {
const isConfirmed = await showConfirm()
if (isConfirmed) {
await deleteReaction(comment().id)
await showSnackbar({ body: t('Comment successfully deleted') })
}
} catch (error) {
console.error('[deleteReaction]', error)
}
}
}
const handleCreate = async (value) => {
try {
setLoading(true)
2023-02-17 09:21:02 +00:00
await createReaction({
kind: ReactionKind.Comment,
replyTo: props.comment.id,
body: value,
shout: props.comment.shout.id
})
setIsReplyVisible(false)
setLoading(false)
} catch (error) {
console.error('[handleCreate reaction]:', error)
2022-09-09 11:53:35 +00:00
}
}
2023-02-07 12:48:45 +00:00
const toggleEditMode = () => {
setEditMode((oldEditMode) => !oldEditMode)
}
const handleUpdate = async (value) => {
setLoading(true)
try {
await updateReaction(props.comment.id, {
kind: ReactionKind.Comment,
body: value,
shout: props.comment.shout.id
})
setEditMode(false)
setLoading(false)
} catch (error) {
console.error('[handleCreate reaction]:', error)
}
}
2022-09-09 11:53:35 +00:00
2023-03-06 14:06:48 +00:00
const createdAt = new Date(comment()?.createdAt)
2023-04-17 10:31:20 +00:00
2022-09-09 11:53:35 +00:00
return (
<li
id={`comment_${comment().id}`}
2023-05-17 21:42:42 +00:00
class={clsx(styles.comment, props.class, {
[styles.isNew]: !isCommentAuthor() && createdAt > props.lastSeen
})}
>
2022-09-09 11:53:35 +00:00
<Show when={!!body()}>
2022-11-26 21:27:54 +00:00
<div class={styles.commentContent}>
2022-09-09 11:53:35 +00:00
<Show
when={!props.compact}
fallback={
2022-11-27 17:02:04 +00:00
<div>
2023-02-17 09:21:02 +00:00
<Userpic
user={comment().createdBy as Author}
isBig={false}
class={clsx({
[styles.compactUserpic]: props.compact
})}
/>
<small>
2022-11-27 17:02:04 +00:00
<a href={`#comment-${comment()?.id}`}>{comment()?.shout.title || ''}</a>
</small>
2022-09-09 11:53:35 +00:00
</div>
}
>
2022-11-26 21:27:54 +00:00
<div class={styles.commentDetails}>
<div class={styles.commentAuthor}>
2022-09-09 11:53:35 +00:00
<AuthorCard
author={comment()?.createdBy as Author}
hideDescription={true}
hideFollow={true}
2022-11-26 21:27:54 +00:00
isComments={true}
hasLink={true}
2022-09-09 11:53:35 +00:00
/>
</div>
<Show when={props.isArticleAuthor}>
<div class={styles.articleAuthor}>{t('Author')}</div>
</Show>
<Show when={props.showArticleLink}>
<div class={styles.articleLink}>
<Icon name="arrow-right" class={styles.articleLinkIcon} />
<a
href={`${getPagePath(router, 'article', { slug: comment().shout.slug })}?commentId=${
comment().id
}`}
>
{comment().shout.title}
</a>
</div>
</Show>
<CommentDate comment={comment()} isShort={true} />
2023-03-09 12:34:08 +00:00
<CommentRatingControl comment={comment()} />
2022-09-09 11:53:35 +00:00
</div>
</Show>
2023-02-07 12:48:45 +00:00
<div class={styles.commentBody} id={'comment-' + (comment().id || '')}>
<Show when={editMode()} fallback={<MD body={body()} />}>
2023-02-11 09:32:52 +00:00
<Suspense fallback={<p>{t('Loading')}</p>}>
<SimplifiedEditor
initialContent={comment().body}
submitButtonText={t('Save')}
quoteEnabled={true}
imageEnabled={true}
placeholder={t('Write a comment...')}
onSubmit={(value) => handleUpdate(value)}
submitByShiftEnter={true}
/>
2023-02-07 12:48:45 +00:00
</Suspense>
</Show>
2022-09-09 11:53:35 +00:00
</div>
<Show when={!props.compact}>
2022-11-26 21:27:54 +00:00
<div class={styles.commentControls}>
2023-02-17 09:21:02 +00:00
<ShowIfAuthenticated>
<button
disabled={loading()}
onClick={() => setIsReplyVisible(!isReplyVisible())}
class={clsx(styles.commentControl, styles.commentControlReply)}
>
<Icon name="reply" class={styles.icon} />
{loading() ? t('Loading') : t('Reply')}
</button>
</ShowIfAuthenticated>
2023-03-06 14:06:48 +00:00
<Show when={isCommentAuthor()}>
2023-02-07 12:48:45 +00:00
<button
class={clsx(styles.commentControl, styles.commentControlEdit)}
onClick={toggleEditMode}
>
<Icon name="edit" class={styles.icon} />
{t('Edit')}
</button>
2022-11-26 21:27:54 +00:00
<button
class={clsx(styles.commentControl, styles.commentControlDelete)}
onClick={() => remove()}
>
<Icon name="delete" class={styles.icon} />
2022-09-09 11:53:35 +00:00
{t('Delete')}
</button>
</Show>
{/*<SharePopup*/}
{/* title={'artile.title'}*/}
{/* description={getDescription(body())}*/}
{/* containerCssClass={stylesHeader.control}*/}
{/* trigger={*/}
{/* <button class={clsx(styles.commentControl, styles.commentControlShare)}>*/}
{/* <Icon name="share" class={styles.icon} />*/}
{/* {t('Share')}*/}
{/* </button>*/}
{/* }*/}
{/*/>*/}
2022-11-26 21:27:54 +00:00
2022-09-09 11:53:35 +00:00
{/*<button*/}
2022-11-26 21:27:54 +00:00
{/* class={clsx(styles.commentControl, styles.commentControlComplain)}*/}
2022-09-09 11:53:35 +00:00
{/* onClick={() => showModal('reportComment')}*/}
{/*>*/}
{/* {t('Report')}*/}
{/*</button>*/}
</div>
2022-11-26 21:27:54 +00:00
<Show when={isReplyVisible()}>
2023-02-07 12:48:45 +00:00
<Suspense fallback={<p>{t('Loading')}</p>}>
<SimplifiedEditor
quoteEnabled={true}
imageEnabled={true}
placeholder={t('Write a comment...')}
2023-04-17 10:31:20 +00:00
onSubmit={(value) => handleCreate(value)}
submitByShiftEnter={true}
2023-04-17 10:31:20 +00:00
/>
2023-02-07 12:48:45 +00:00
</Suspense>
2022-11-26 21:27:54 +00:00
</Show>
2022-09-09 11:53:35 +00:00
</Show>
</div>
</Show>
2023-02-17 09:21:02 +00:00
<Show when={props.sortedComments}>
<ul>
2023-02-17 09:21:02 +00:00
<For each={props.sortedComments.filter((r) => r.replyTo === props.comment.id)}>
{(c) => (
<Comment
2023-02-17 09:21:02 +00:00
sortedComments={props.sortedComments}
isArticleAuthor={props.isArticleAuthor}
2023-02-17 09:21:02 +00:00
comment={c}
2023-03-06 14:06:48 +00:00
lastSeen={props.lastSeen}
/>
)}
</For>
</ul>
</Show>
</li>
2022-09-09 11:53:35 +00:00
)
}