2023-11-14 15:10:00 +00:00
|
|
|
import type { ArticlePageSearchParams } from '../../Article/FullArticle'
|
|
|
|
|
|
|
|
import { getPagePath, openPage } from '@nanostores/router'
|
|
|
|
import { clsx } from 'clsx'
|
2023-10-14 11:39:24 +00:00
|
|
|
import { createMemo, createSignal, onMount, Show } from 'solid-js'
|
2023-11-14 15:10:00 +00:00
|
|
|
|
|
|
|
import { useLocalize } from '../../../context/localize'
|
|
|
|
import { useNotifications } from '../../../context/notifications'
|
2023-11-28 13:18:25 +00:00
|
|
|
import { Notification } from '../../../graphql/schema/notifier.gen'
|
2023-10-16 17:24:33 +00:00
|
|
|
import { router, useRouter } from '../../../stores/router'
|
2023-11-14 15:10:00 +00:00
|
|
|
import { GroupAvatar } from '../../_shared/GroupAvatar'
|
2023-10-18 10:56:41 +00:00
|
|
|
import { TimeAgo } from '../../_shared/TimeAgo'
|
|
|
|
import styles from './NotificationView.module.scss'
|
2023-11-28 13:18:25 +00:00
|
|
|
import { apiClient } from '../../../graphql/client/core'
|
|
|
|
import { Reaction, Shout } from '../../../graphql/schema/core.gen'
|
2023-10-14 11:39:24 +00:00
|
|
|
|
|
|
|
type Props = {
|
|
|
|
notification: Notification
|
|
|
|
onClick: () => void
|
2023-10-18 10:56:41 +00:00
|
|
|
dateTimeFormat: 'ago' | 'time' | 'date'
|
2023-10-14 11:39:24 +00:00
|
|
|
class?: string
|
|
|
|
}
|
|
|
|
|
|
|
|
export const NotificationView = (props: Props) => {
|
|
|
|
const {
|
2023-11-14 15:10:00 +00:00
|
|
|
actions: { markNotificationAsRead, hideNotificationsPanel },
|
2023-10-14 11:39:24 +00:00
|
|
|
} = useNotifications()
|
|
|
|
|
2023-10-16 17:24:33 +00:00
|
|
|
const { changeSearchParam } = useRouter<ArticlePageSearchParams>()
|
|
|
|
|
2023-10-18 10:56:41 +00:00
|
|
|
const { t, formatDate, formatTime } = useLocalize()
|
2023-10-14 11:39:24 +00:00
|
|
|
|
2023-11-28 13:18:25 +00:00
|
|
|
const [data, setData] = createSignal<Reaction>(null) // NOTE: supports only SSMessage.entity == "reaction"
|
2023-10-14 11:39:24 +00:00
|
|
|
|
|
|
|
onMount(() => {
|
2023-11-28 13:18:25 +00:00
|
|
|
setTimeout(() => setData(JSON.parse(props.notification.payload)))
|
2023-10-14 11:39:24 +00:00
|
|
|
})
|
|
|
|
|
2023-11-28 13:18:25 +00:00
|
|
|
const lastUser = createMemo(() => data().created_by)
|
2023-10-14 11:39:24 +00:00
|
|
|
|
2023-10-16 17:24:33 +00:00
|
|
|
const handleLinkClick = (event: MouseEvent) => {
|
|
|
|
event.stopPropagation()
|
|
|
|
hideNotificationsPanel()
|
|
|
|
}
|
|
|
|
|
2023-10-14 11:39:24 +00:00
|
|
|
const content = createMemo(() => {
|
|
|
|
if (!data()) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
|
|
|
let shoutTitle = ''
|
|
|
|
let i = 0
|
|
|
|
const shoutTitleWords = data().shout.title.split(' ')
|
|
|
|
|
|
|
|
while (shoutTitle.length <= 30 && i < shoutTitleWords.length) {
|
|
|
|
shoutTitle += shoutTitleWords[i] + ' '
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shoutTitle.length < data().shout.title.length) {
|
2023-10-16 17:24:33 +00:00
|
|
|
shoutTitle = `${shoutTitle.trim()}...`
|
|
|
|
|
|
|
|
if (shoutTitle[0] === '«') {
|
|
|
|
shoutTitle += '»'
|
|
|
|
}
|
2023-10-14 11:39:24 +00:00
|
|
|
}
|
|
|
|
|
2023-11-28 13:18:25 +00:00
|
|
|
switch (props.notification.action) {
|
|
|
|
case 'create': {
|
|
|
|
if (data()?.reply_to) {
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
{t('NotificationNewReplyText1', {
|
|
|
|
commentsCount: 0, // FIXME: props.notification.occurrences,
|
|
|
|
})}{' '}
|
|
|
|
<a
|
|
|
|
href={getPagePath(router, 'article', { slug: data().shout.slug })}
|
|
|
|
onClick={handleLinkClick}
|
|
|
|
>
|
|
|
|
{shoutTitle}
|
|
|
|
</a>{' '}
|
|
|
|
{t('NotificationNewReplyText2')}{' '}
|
|
|
|
<a href={getPagePath(router, 'author', { slug: lastUser().slug })} onClick={handleLinkClick}>
|
|
|
|
{lastUser().name}
|
|
|
|
</a>{' '}
|
|
|
|
{t('NotificationNewReplyText3', {
|
|
|
|
restUsersCount: 0, // FIXME: data().users.length - 1,
|
|
|
|
})}
|
|
|
|
</>
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
{t('NotificationNewCommentText1', {
|
|
|
|
commentsCount: 0, // FIXME: props.notification.occurrences,
|
|
|
|
})}{' '}
|
|
|
|
<a
|
|
|
|
href={getPagePath(router, 'article', { slug: data().shout.slug })}
|
|
|
|
onClick={handleLinkClick}
|
|
|
|
>
|
|
|
|
{shoutTitle}
|
|
|
|
</a>{' '}
|
|
|
|
{t('NotificationNewCommentText2')}{' '}
|
|
|
|
<a href={getPagePath(router, 'author', { slug: lastUser().slug })} onClick={handleLinkClick}>
|
|
|
|
{lastUser().name}
|
|
|
|
</a>{' '}
|
|
|
|
{t('NotificationNewCommentText3', {
|
|
|
|
restUsersCount: 0, // FIXME: data().users.length - 1,
|
|
|
|
})}
|
|
|
|
</>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case 'update': {
|
|
|
|
}
|
|
|
|
case 'delete': {
|
2023-10-14 11:39:24 +00:00
|
|
|
}
|
2023-11-28 13:18:25 +00:00
|
|
|
case 'follow': {
|
2023-10-14 11:39:24 +00:00
|
|
|
}
|
2023-11-28 13:18:25 +00:00
|
|
|
case 'unfollow': {
|
|
|
|
}
|
|
|
|
case 'invited': {
|
|
|
|
// TODO: invited for collaborative authoring
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return <></>
|
2023-10-14 11:39:24 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
const handleClick = () => {
|
2023-10-16 17:24:33 +00:00
|
|
|
props.onClick()
|
|
|
|
|
2023-10-14 11:39:24 +00:00
|
|
|
if (!props.notification.seen) {
|
|
|
|
markNotificationAsRead(props.notification)
|
|
|
|
}
|
|
|
|
|
|
|
|
openPage(router, 'article', { slug: data().shout.slug })
|
2023-11-28 13:18:25 +00:00
|
|
|
// FIXME:
|
|
|
|
// if (data().reactionIds) {
|
|
|
|
// changeSearchParam({ commentId: data().reactionIds[0].toString() })
|
|
|
|
// }
|
2023-10-14 11:39:24 +00:00
|
|
|
}
|
|
|
|
|
2023-10-18 10:56:41 +00:00
|
|
|
const formattedDateTime = createMemo(() => {
|
|
|
|
switch (props.dateTimeFormat) {
|
|
|
|
case 'ago': {
|
2023-11-28 13:18:25 +00:00
|
|
|
return <TimeAgo date={props.notification.created_at} />
|
2023-10-18 10:56:41 +00:00
|
|
|
}
|
|
|
|
case 'time': {
|
2023-11-28 13:18:25 +00:00
|
|
|
return formatTime(new Date(props.notification.created_at))
|
2023-10-18 10:56:41 +00:00
|
|
|
}
|
|
|
|
case 'date': {
|
2023-11-28 13:18:25 +00:00
|
|
|
return formatDate(new Date(props.notification.created_at), { month: 'numeric', year: '2-digit' })
|
2023-10-18 10:56:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2023-10-14 11:39:24 +00:00
|
|
|
return (
|
|
|
|
<Show when={data()}>
|
|
|
|
<div
|
|
|
|
class={clsx(styles.NotificationView, props.class, {
|
2023-11-14 15:10:00 +00:00
|
|
|
[styles.seen]: props.notification.seen,
|
2023-10-14 11:39:24 +00:00
|
|
|
})}
|
|
|
|
onClick={handleClick}
|
|
|
|
>
|
2023-10-20 16:21:40 +00:00
|
|
|
<div class={styles.userpic}>
|
2023-11-28 13:18:25 +00:00
|
|
|
<GroupAvatar authors={[] /*d FIXME: data().users */} />
|
2023-10-20 16:21:40 +00:00
|
|
|
</div>
|
2023-10-14 11:39:24 +00:00
|
|
|
<div>{content()}</div>
|
2023-10-18 10:56:41 +00:00
|
|
|
<div class={styles.timeContainer}>{formattedDateTime()}</div>
|
2023-10-14 11:39:24 +00:00
|
|
|
</div>
|
|
|
|
</Show>
|
|
|
|
)
|
|
|
|
}
|