webapp/src/components/NotificationsPanel/NotificationView/NotificationGroup.tsx

109 lines
3.4 KiB
TypeScript
Raw Normal View History

2023-12-20 16:54:20 +00:00
import { getPagePath, openPage } from '@nanostores/router'
import { clsx } from 'clsx'
2023-12-22 17:34:50 +00:00
import { For, Show } from 'solid-js'
2023-12-20 16:54:20 +00:00
import { useLocalize } from '../../../context/localize'
import { useNotifications } from '../../../context/notifications'
2023-12-22 17:34:50 +00:00
import { NotificationGroup as Group } from '../../../graphql/schema/notifier.gen'
2023-12-20 16:54:20 +00:00
import { useRouter, router } from '../../../stores/router'
import { GroupAvatar } from '../../_shared/GroupAvatar'
import { TimeAgo } from '../../_shared/TimeAgo'
import { ArticlePageSearchParams } from '../../Article/FullArticle'
import styles from './NotificationView.module.scss'
type NotificationGroupProps = {
2023-12-22 17:34:50 +00:00
notifications: Group[]
2023-12-20 16:54:20 +00:00
onClick: () => void
dateTimeFormat: 'ago' | 'time' | 'date'
class?: string
}
const getTitle = (title: string) => {
let shoutTitle = ''
let i = 0
const shoutTitleWords = title.split(' ')
while (shoutTitle.length <= 30 && i < shoutTitleWords.length) {
shoutTitle += shoutTitleWords[i] + ' '
i++
}
if (shoutTitle.length < title.length) {
shoutTitle = `${shoutTitle.trim()}...`
if (shoutTitle[0] === '«') {
shoutTitle += '»'
}
}
return shoutTitle
}
const reactionsCaption = (threadId: string) =>
2023-12-22 17:34:50 +00:00
threadId.includes('::') ? 'Some new replies to your comment' : 'Some new comments to your publication'
2023-12-20 16:54:20 +00:00
export const NotificationGroup = (props: NotificationGroupProps) => {
const { t, formatTime, formatDate } = useLocalize()
2023-12-22 17:45:01 +00:00
const { changeSearchParams } = useRouter<ArticlePageSearchParams>()
2023-12-20 16:54:20 +00:00
const {
2023-12-22 17:34:50 +00:00
actions: { hideNotificationsPanel, markSeenThread },
2023-12-20 16:54:20 +00:00
} = useNotifications()
const handleClick = (threadId: string) => {
props.onClick()
2023-12-22 17:34:50 +00:00
markSeenThread(threadId)
const [slug, commentId] = threadId.split('::')
openPage(router, 'article', { slug })
2023-12-22 17:45:01 +00:00
if (commentId) changeSearchParams({ commentId })
2023-12-20 16:54:20 +00:00
}
const handleLinkClick = (event: MouseEvent | TouchEvent) => {
event.stopPropagation()
hideNotificationsPanel()
}
return (
<>
2023-12-22 17:34:50 +00:00
<For each={props.notifications}>
{(n: Group) => (
2023-12-20 16:54:20 +00:00
<>
2023-12-22 17:34:50 +00:00
{t(reactionsCaption(n.id), { commentsCount: n.reactions.length })}{' '}
2023-12-20 16:54:20 +00:00
<div
2023-12-22 17:34:50 +00:00
class={clsx(styles.NotificationView, props.class, { [styles.seen]: n.seen })}
onClick={(_) => handleClick(n.id)}
2023-12-20 16:54:20 +00:00
>
<div class={styles.userpic}>
2023-12-22 17:34:50 +00:00
<GroupAvatar authors={n.authors} />
2023-12-20 16:54:20 +00:00
</div>
<div>
2023-12-22 17:34:50 +00:00
<a href={getPagePath(router, 'article', { slug: n.shout.slug })} onClick={handleLinkClick}>
{getTitle(n.shout.title)}
2023-12-20 16:54:20 +00:00
</a>{' '}
{t('from')}{' '}
<a
2023-12-22 17:34:50 +00:00
href={getPagePath(router, 'author', { slug: n.authors[0].slug })}
2023-12-20 16:54:20 +00:00
onClick={handleLinkClick}
>
2023-12-22 17:34:50 +00:00
{n.authors[0].name}
2023-12-20 16:54:20 +00:00
</a>{' '}
</div>
<div class={styles.timeContainer}>
<Show when={props.dateTimeFormat === 'ago'}>
2023-12-22 17:34:50 +00:00
<TimeAgo date={n.updated_at} />
2023-12-20 16:54:20 +00:00
</Show>
2023-12-22 17:34:50 +00:00
<Show when={props.dateTimeFormat === 'time'}>{formatTime(new Date(n.updated_at))}</Show>
2023-12-20 16:54:20 +00:00
<Show when={props.dateTimeFormat === 'date'}>
2023-12-22 17:34:50 +00:00
{formatDate(new Date(n.updated_at), { month: 'numeric', year: '2-digit' })}
2023-12-20 16:54:20 +00:00
</Show>
</div>
</div>
</>
)}
</For>
</>
)
}