2022-11-26 21:27:54 +00:00
|
|
|
import styles from './Comment.module.scss'
|
2022-11-14 17:41:05 +00:00
|
|
|
import { Icon } from '../_shared/Icon'
|
2022-09-09 11:53:35 +00:00
|
|
|
import { AuthorCard } from '../Author/Card'
|
2023-02-07 12:48:45 +00:00
|
|
|
import { Show, createMemo, createSignal, For, lazy, Suspense } from 'solid-js'
|
2022-09-09 11:53:35 +00:00
|
|
|
import { clsx } from 'clsx'
|
2023-01-20 04:40:55 +00:00
|
|
|
import type { Author, Reaction } from '../../graphql/types.gen'
|
2022-09-09 11:53:35 +00:00
|
|
|
import { t } from '../../utils/intl'
|
2023-02-07 12:48:45 +00:00
|
|
|
import { createReaction, deleteReaction, updateReaction } from '../../stores/zine/reactions'
|
2022-10-07 11:02:34 +00:00
|
|
|
import MD from './MD'
|
2022-11-26 21:27:54 +00:00
|
|
|
import { formatDate } from '../../utils'
|
2022-11-27 17:02:04 +00:00
|
|
|
import Userpic from '../Author/Userpic'
|
2023-01-20 04:40:55 +00:00
|
|
|
import { useSession } from '../../context/session'
|
|
|
|
import { ReactionKind } from '../../graphql/types.gen'
|
2023-02-07 12:48:45 +00:00
|
|
|
const CommentEditor = lazy(() => import('../_shared/CommentEditor'))
|
2022-09-09 11:53:35 +00:00
|
|
|
|
2023-01-20 04:40:55 +00:00
|
|
|
type Props = {
|
|
|
|
comment: Reaction
|
2022-09-09 11:53:35 +00:00
|
|
|
compact?: boolean
|
2023-01-20 04:40:55 +00:00
|
|
|
reactions?: Reaction[]
|
2023-01-26 06:59:43 +00:00
|
|
|
isArticleAuthor?: boolean
|
2023-01-20 04:40:55 +00:00
|
|
|
}
|
|
|
|
|
2023-01-04 13:26:18 +00:00
|
|
|
export const Comment = (props: Props) => {
|
2022-11-26 21:27:54 +00:00
|
|
|
const [isReplyVisible, setIsReplyVisible] = createSignal(false)
|
2023-01-26 06:59:43 +00:00
|
|
|
const [loading, setLoading] = createSignal<boolean>(false)
|
2023-02-07 12:48:45 +00:00
|
|
|
const [editMode, setEditMode] = createSignal<boolean>(false)
|
2023-01-20 04:40:55 +00:00
|
|
|
const { session } = useSession()
|
|
|
|
|
|
|
|
const canEdit = 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())
|
2023-01-20 04:40:55 +00:00
|
|
|
const remove = async () => {
|
2022-09-09 11:53:35 +00:00
|
|
|
if (comment()?.id) {
|
2023-01-20 04:40:55 +00:00
|
|
|
try {
|
|
|
|
await deleteReaction(comment().id)
|
|
|
|
} catch (error) {
|
|
|
|
console.error('[deleteReaction]', error)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const handleCreate = async (value) => {
|
|
|
|
try {
|
|
|
|
setLoading(true)
|
|
|
|
await createReaction(
|
|
|
|
{
|
|
|
|
kind: ReactionKind.Comment,
|
|
|
|
replyTo: props.comment.id,
|
|
|
|
body: value,
|
|
|
|
shout: props.comment.shout.id
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: session().user.name,
|
|
|
|
userpic: session().user.userpic,
|
|
|
|
slug: session().user.slug
|
|
|
|
}
|
|
|
|
)
|
|
|
|
setIsReplyVisible(false)
|
|
|
|
setLoading(false)
|
|
|
|
} catch (error) {
|
|
|
|
console.error('[handleCreate reaction]:', error)
|
2022-09-09 11:53:35 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-26 06:59:43 +00:00
|
|
|
|
2023-02-07 12:48:45 +00:00
|
|
|
const formattedDate = (date) =>
|
|
|
|
createMemo(() => formatDate(new Date(date), { hour: 'numeric', minute: 'numeric' }))
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
return (
|
2023-01-20 04:40:55 +00:00
|
|
|
<li class={styles.comment}>
|
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>
|
|
|
|
<Userpic user={comment().createdBy as Author} isBig={false} isAuthorsList={false} />
|
|
|
|
<small class={styles.commentArticle}>
|
|
|
|
<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>
|
|
|
|
|
2023-01-26 06:59:43 +00:00
|
|
|
<Show when={props.isArticleAuthor}>
|
|
|
|
<div class={styles.articleAuthor}>{t('Author')}</div>
|
|
|
|
</Show>
|
|
|
|
|
2023-02-07 12:48:45 +00:00
|
|
|
<div class={styles.commentDates}>
|
|
|
|
<div class={styles.date}>{formattedDate(comment()?.createdAt)}</div>
|
|
|
|
<Show when={comment()?.updatedAt}>
|
|
|
|
<div class={styles.date}>
|
|
|
|
<Icon name="edit" class={styles.icon} />
|
|
|
|
{t('Edited')} {formattedDate(comment()?.updatedAt)}
|
|
|
|
</div>
|
|
|
|
</Show>
|
|
|
|
</div>
|
2022-11-26 21:27:54 +00:00
|
|
|
<div
|
|
|
|
class={styles.commentRating}
|
|
|
|
classList={{
|
|
|
|
[styles.commentRatingPositive]: comment().stat?.rating > 0,
|
|
|
|
[styles.commentRatingNegative]: comment().stat?.rating < 0
|
|
|
|
}}
|
|
|
|
>
|
2022-12-07 20:10:26 +00:00
|
|
|
<button class={clsx(styles.commentRatingControl, styles.commentRatingControlUp)} />
|
2022-11-26 21:27:54 +00:00
|
|
|
<div class={styles.commentRatingValue}>{comment().stat?.rating || 0}</div>
|
2022-12-07 20:10:26 +00:00
|
|
|
<button class={clsx(styles.commentRatingControl, styles.commentRatingControlDown)} />
|
2022-11-26 21:27:54 +00:00
|
|
|
</div>
|
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>}>
|
2023-02-07 12:48:45 +00:00
|
|
|
<CommentEditor initialContent={body()} onSubmit={(value) => handleUpdate(value)} />
|
|
|
|
</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}>
|
|
|
|
<button
|
2023-01-20 04:40:55 +00:00
|
|
|
disabled={loading()}
|
2022-11-26 21:27:54 +00:00
|
|
|
onClick={() => setIsReplyVisible(!isReplyVisible())}
|
2023-01-20 04:40:55 +00:00
|
|
|
class={clsx(styles.commentControl, styles.commentControlReply)}
|
2022-11-26 21:27:54 +00:00
|
|
|
>
|
|
|
|
<Icon name="reply" class={styles.icon} />
|
2023-01-20 04:40:55 +00:00
|
|
|
{loading() ? t('Loading') : t('Reply')}
|
2022-09-09 11:53:35 +00:00
|
|
|
</button>
|
|
|
|
|
2023-01-20 04:40:55 +00:00
|
|
|
<Show when={canEdit()}>
|
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>
|
|
|
|
|
2023-01-30 10:39:36 +00:00
|
|
|
{/*<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>}>
|
|
|
|
<CommentEditor placeholder={''} onSubmit={(value) => handleCreate(value)} />
|
|
|
|
</Suspense>
|
2022-11-26 21:27:54 +00:00
|
|
|
</Show>
|
2022-09-09 11:53:35 +00:00
|
|
|
</Show>
|
|
|
|
</div>
|
|
|
|
</Show>
|
2023-01-20 04:40:55 +00:00
|
|
|
<Show when={props.reactions}>
|
|
|
|
<ul>
|
|
|
|
<For each={props.reactions.filter((r) => r.replyTo === props.comment.id)}>
|
2023-01-26 06:59:43 +00:00
|
|
|
{(reaction) => (
|
|
|
|
<Comment
|
|
|
|
isArticleAuthor={props.isArticleAuthor}
|
|
|
|
reactions={props.reactions}
|
|
|
|
comment={reaction}
|
|
|
|
/>
|
|
|
|
)}
|
2023-01-20 04:40:55 +00:00
|
|
|
</For>
|
|
|
|
</ul>
|
|
|
|
</Show>
|
|
|
|
</li>
|
2022-09-09 11:53:35 +00:00
|
|
|
)
|
|
|
|
}
|
2023-01-20 04:40:55 +00:00
|
|
|
|
|
|
|
export default Comment
|