2024-01-25 18:19:59 +00:00
|
|
|
import { openPage } from '@nanostores/router'
|
2023-10-04 19:04:09 +00:00
|
|
|
import { clsx } from 'clsx'
|
2024-02-04 11:25:21 +00:00
|
|
|
import { Match, Show, Switch, createEffect, createMemo, createSignal, on } from 'solid-js'
|
2023-11-14 15:10:00 +00:00
|
|
|
|
2024-01-31 12:34:15 +00:00
|
|
|
import { useFollowing } from '../../../context/following'
|
2023-10-04 19:04:09 +00:00
|
|
|
import { useLocalize } from '../../../context/localize'
|
2023-12-29 06:39:16 +00:00
|
|
|
import { useMediaQuery } from '../../../context/mediaQuery'
|
2023-10-04 19:04:09 +00:00
|
|
|
import { useSession } from '../../../context/session'
|
2023-11-28 13:18:25 +00:00
|
|
|
import { Author, FollowingEntity } from '../../../graphql/schema/core.gen'
|
2023-11-14 15:10:00 +00:00
|
|
|
import { router, useRouter } from '../../../stores/router'
|
2023-12-31 05:01:34 +00:00
|
|
|
import { translit } from '../../../utils/ru2en'
|
2024-02-04 17:40:15 +00:00
|
|
|
import { isCyrillic } from '../../../utils/translate'
|
2023-11-14 15:10:00 +00:00
|
|
|
import { Button } from '../../_shared/Button'
|
2023-10-04 19:04:09 +00:00
|
|
|
import { CheckButton } from '../../_shared/CheckButton'
|
2024-01-25 09:57:57 +00:00
|
|
|
import { ConditionalWrapper } from '../../_shared/ConditionalWrapper'
|
2023-10-20 16:21:40 +00:00
|
|
|
import { Icon } from '../../_shared/Icon'
|
2023-11-14 15:10:00 +00:00
|
|
|
import { Userpic } from '../Userpic'
|
|
|
|
|
|
|
|
import stylesButton from '../../_shared/Button/Button.module.scss'
|
2024-02-04 11:25:21 +00:00
|
|
|
import styles from './AuthorBadge.module.scss'
|
2023-10-04 19:04:09 +00:00
|
|
|
|
2024-02-03 07:56:11 +00:00
|
|
|
type FollowedInfo = {
|
|
|
|
value?: boolean
|
|
|
|
loaded?: boolean
|
|
|
|
}
|
2023-10-04 19:04:09 +00:00
|
|
|
type Props = {
|
|
|
|
author: Author
|
|
|
|
minimizeSubscribeButton?: boolean
|
2023-10-20 16:21:40 +00:00
|
|
|
showMessageButton?: boolean
|
|
|
|
iconButtons?: boolean
|
2023-11-01 08:34:59 +00:00
|
|
|
nameOnly?: boolean
|
2024-01-25 09:57:57 +00:00
|
|
|
inviteView?: boolean
|
|
|
|
onInvite?: (id: number) => void
|
|
|
|
selected?: boolean
|
2024-02-03 07:56:11 +00:00
|
|
|
isFollowed?: FollowedInfo
|
2023-10-04 19:04:09 +00:00
|
|
|
}
|
|
|
|
export const AuthorBadge = (props: Props) => {
|
2023-12-29 06:39:16 +00:00
|
|
|
const { mediaMatches } = useMediaQuery()
|
2024-02-04 17:40:15 +00:00
|
|
|
const { author, requireAuthentication } = useSession()
|
2023-12-29 06:39:16 +00:00
|
|
|
const [isMobileView, setIsMobileView] = createSignal(false)
|
2024-02-03 07:56:11 +00:00
|
|
|
const [isFollowed, setIsFollowed] = createSignal<boolean>()
|
2023-12-29 06:39:16 +00:00
|
|
|
|
|
|
|
createEffect(() => {
|
|
|
|
setIsMobileView(!mediaMatches.sm)
|
|
|
|
})
|
|
|
|
|
2024-01-31 12:34:15 +00:00
|
|
|
const { setFollowing } = useFollowing()
|
2023-12-20 08:07:57 +00:00
|
|
|
const { changeSearchParams } = useRouter()
|
2023-12-28 00:30:09 +00:00
|
|
|
const { t, formatDate, lang } = useLocalize()
|
2023-10-04 19:04:09 +00:00
|
|
|
|
2023-10-20 16:21:40 +00:00
|
|
|
const initChat = () => {
|
2024-01-31 12:34:15 +00:00
|
|
|
// eslint-disable-next-line solid/reactivity
|
2023-10-20 16:21:40 +00:00
|
|
|
requireAuthentication(() => {
|
|
|
|
openPage(router, `inbox`)
|
2023-12-20 08:07:57 +00:00
|
|
|
changeSearchParams({
|
2023-11-14 15:10:00 +00:00
|
|
|
initChat: props.author.id.toString(),
|
2023-10-20 16:21:40 +00:00
|
|
|
})
|
|
|
|
}, 'discussions')
|
|
|
|
}
|
2023-11-02 22:02:11 +00:00
|
|
|
|
2023-12-28 01:22:04 +00:00
|
|
|
const name = createMemo(() => {
|
|
|
|
if (lang() !== 'ru' && isCyrillic(props.author.name)) {
|
|
|
|
if (props.author.name === 'Дискурс') {
|
|
|
|
return 'Discours'
|
|
|
|
}
|
|
|
|
|
|
|
|
return translit(props.author.name)
|
|
|
|
}
|
|
|
|
|
|
|
|
return props.author.name
|
|
|
|
})
|
2023-12-28 00:30:09 +00:00
|
|
|
|
2024-02-03 07:56:11 +00:00
|
|
|
createEffect(
|
|
|
|
on(
|
|
|
|
() => props.isFollowed,
|
|
|
|
() => {
|
|
|
|
setIsFollowed(props.isFollowed.value)
|
|
|
|
},
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
2024-01-31 12:34:15 +00:00
|
|
|
const handleFollowClick = () => {
|
2024-02-03 07:56:11 +00:00
|
|
|
const value = !isFollowed()
|
2024-01-31 12:34:15 +00:00
|
|
|
requireAuthentication(() => {
|
2024-02-03 07:56:11 +00:00
|
|
|
setIsFollowed(value)
|
2024-01-31 12:34:15 +00:00
|
|
|
setFollowing(FollowingEntity.Author, props.author.slug, value)
|
|
|
|
}, 'subscribe')
|
|
|
|
}
|
|
|
|
|
2023-10-04 19:04:09 +00:00
|
|
|
return (
|
2023-11-01 08:34:59 +00:00
|
|
|
<div class={clsx(styles.AuthorBadge, { [styles.nameOnly]: props.nameOnly })}>
|
2023-11-06 08:00:31 +00:00
|
|
|
<div class={styles.basicInfo}>
|
|
|
|
<Userpic
|
|
|
|
hasLink={true}
|
2023-12-29 06:39:16 +00:00
|
|
|
size={isMobileView() ? 'M' : 'L'}
|
2023-12-28 00:30:09 +00:00
|
|
|
name={name()}
|
2023-11-28 13:18:25 +00:00
|
|
|
userpic={props.author.pic}
|
2023-11-06 08:00:31 +00:00
|
|
|
slug={props.author.slug}
|
|
|
|
/>
|
2024-01-25 09:57:57 +00:00
|
|
|
<ConditionalWrapper
|
|
|
|
condition={!props.inviteView}
|
|
|
|
wrapper={(children) => (
|
|
|
|
<a href={`/author/${props.author.slug}`} class={styles.info}>
|
|
|
|
{children}
|
|
|
|
</a>
|
|
|
|
)}
|
|
|
|
>
|
2023-11-06 08:00:31 +00:00
|
|
|
<div class={styles.name}>
|
2023-12-28 00:30:09 +00:00
|
|
|
<span>{name()}</span>
|
2023-11-06 08:00:31 +00:00
|
|
|
</div>
|
|
|
|
<Show when={!props.nameOnly}>
|
|
|
|
<Switch
|
|
|
|
fallback={
|
|
|
|
<div class={styles.bio}>
|
2023-11-28 13:18:25 +00:00
|
|
|
{t('Registered since {date}', {
|
|
|
|
date: formatDate(new Date(props.author.created_at * 1000)),
|
|
|
|
})}
|
2023-11-06 08:00:31 +00:00
|
|
|
</div>
|
|
|
|
}
|
|
|
|
>
|
|
|
|
<Match when={props.author.bio}>
|
|
|
|
<div class={clsx('text-truncate', styles.bio)} innerHTML={props.author.bio} />
|
|
|
|
</Match>
|
|
|
|
<Match when={props.author?.stat && props.author?.stat.shouts > 0}>
|
|
|
|
<div class={styles.bio}>
|
|
|
|
{t('PublicationsWithCount', { count: props.author.stat?.shouts ?? 0 })}
|
|
|
|
</div>
|
|
|
|
</Match>
|
|
|
|
</Switch>
|
|
|
|
</Show>
|
2024-01-25 09:57:57 +00:00
|
|
|
</ConditionalWrapper>
|
2023-11-06 08:00:31 +00:00
|
|
|
</div>
|
2023-12-13 23:56:44 +00:00
|
|
|
<Show when={props.author.slug !== author()?.slug && !props.nameOnly}>
|
2023-10-04 19:04:09 +00:00
|
|
|
<div class={styles.actions}>
|
|
|
|
<Show
|
|
|
|
when={!props.minimizeSubscribeButton}
|
2024-02-03 07:56:11 +00:00
|
|
|
fallback={<CheckButton text={t('Follow')} checked={isFollowed()} onClick={handleFollowClick} />}
|
2023-10-04 19:04:09 +00:00
|
|
|
>
|
|
|
|
<Show
|
2024-02-03 07:56:11 +00:00
|
|
|
when={isFollowed()}
|
2023-10-04 19:04:09 +00:00
|
|
|
fallback={
|
|
|
|
<Button
|
2023-10-20 16:21:40 +00:00
|
|
|
variant={props.iconButtons ? 'secondary' : 'bordered'}
|
2023-12-29 06:39:16 +00:00
|
|
|
size="S"
|
2023-11-14 10:45:44 +00:00
|
|
|
value={
|
2024-01-31 12:34:15 +00:00
|
|
|
<Show when={props.iconButtons} fallback={t('Subscribe')}>
|
2023-11-14 10:45:44 +00:00
|
|
|
<Icon name="author-subscribe" class={stylesButton.icon} />
|
|
|
|
</Show>
|
|
|
|
}
|
2024-01-31 12:34:15 +00:00
|
|
|
onClick={handleFollowClick}
|
2023-11-08 20:42:13 +00:00
|
|
|
isSubscribeButton={true}
|
2023-11-08 20:52:56 +00:00
|
|
|
class={clsx(styles.actionButton, {
|
|
|
|
[styles.iconed]: props.iconButtons,
|
2024-02-03 07:56:11 +00:00
|
|
|
[stylesButton.subscribed]: isFollowed(),
|
2023-11-08 20:52:56 +00:00
|
|
|
})}
|
2023-10-04 19:04:09 +00:00
|
|
|
/>
|
|
|
|
}
|
|
|
|
>
|
|
|
|
<Button
|
2023-10-20 16:21:40 +00:00
|
|
|
variant={props.iconButtons ? 'secondary' : 'bordered'}
|
2023-12-29 06:39:16 +00:00
|
|
|
size="S"
|
2023-11-14 07:47:22 +00:00
|
|
|
value={
|
|
|
|
<Show
|
|
|
|
when={props.iconButtons}
|
|
|
|
fallback={
|
|
|
|
<>
|
|
|
|
<span class={styles.actionButtonLabel}>{t('Following')}</span>
|
|
|
|
<span class={styles.actionButtonLabelHovered}>{t('Unfollow')}</span>
|
|
|
|
</>
|
|
|
|
}
|
|
|
|
>
|
|
|
|
<Icon name="author-unsubscribe" class={stylesButton.icon} />
|
|
|
|
</Show>
|
|
|
|
}
|
2024-01-31 12:34:15 +00:00
|
|
|
onClick={handleFollowClick}
|
2023-11-08 20:42:13 +00:00
|
|
|
isSubscribeButton={true}
|
2023-11-08 20:52:56 +00:00
|
|
|
class={clsx(styles.actionButton, {
|
|
|
|
[styles.iconed]: props.iconButtons,
|
2024-02-03 07:56:11 +00:00
|
|
|
[stylesButton.subscribed]: isFollowed(),
|
2023-11-08 20:52:56 +00:00
|
|
|
})}
|
2023-10-04 19:04:09 +00:00
|
|
|
/>
|
|
|
|
</Show>
|
|
|
|
</Show>
|
2023-10-20 16:21:40 +00:00
|
|
|
<Show when={props.showMessageButton}>
|
|
|
|
<Button
|
|
|
|
variant={props.iconButtons ? 'secondary' : 'bordered'}
|
2023-12-29 06:39:16 +00:00
|
|
|
size="S"
|
2023-10-20 16:21:40 +00:00
|
|
|
value={props.iconButtons ? <Icon name="inbox-white" /> : t('Message')}
|
|
|
|
onClick={initChat}
|
|
|
|
class={clsx(styles.actionButton, { [styles.iconed]: props.iconButtons })}
|
|
|
|
/>
|
|
|
|
</Show>
|
2023-10-04 19:04:09 +00:00
|
|
|
</div>
|
|
|
|
</Show>
|
2024-01-25 09:57:57 +00:00
|
|
|
<Show when={props.inviteView}>
|
|
|
|
<CheckButton
|
|
|
|
text={t('Invite')}
|
|
|
|
checked={props.selected}
|
|
|
|
onClick={() => props.onInvite(props.author.id)}
|
|
|
|
/>
|
|
|
|
</Show>
|
2023-10-04 19:04:09 +00:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|