webapp/src/components/Author/AuthorBadge/AuthorBadge.tsx

205 lines
7.5 KiB
TypeScript
Raw Normal View History

2024-01-25 18:19:59 +00:00
import { openPage } from '@nanostores/router'
import { clsx } from 'clsx'
2024-02-04 11:25:21 +00:00
import { Match, Show, Switch, createEffect, createMemo, createSignal, on } from 'solid-js'
2024-01-31 12:34:15 +00:00
import { useFollowing } from '../../../context/following'
import { useLocalize } from '../../../context/localize'
import { useMediaQuery } from '../../../context/mediaQuery'
import { useSession } from '../../../context/session'
2023-11-28 13:18:25 +00:00
import { Author, FollowingEntity } from '../../../graphql/schema/core.gen'
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'
import { Button } from '../../_shared/Button'
import { CheckButton } from '../../_shared/CheckButton'
import { ConditionalWrapper } from '../../_shared/ConditionalWrapper'
import { Icon } from '../../_shared/Icon'
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'
2024-03-15 12:58:22 +00:00
import { BadgeSubscribeButton } from "../../_shared/BadgeSubscribeButton";
type Props = {
author: Author
minimizeSubscribeButton?: boolean
showMessageButton?: boolean
iconButtons?: boolean
nameOnly?: boolean
inviteView?: boolean
onInvite?: (id: number) => void
selected?: boolean
}
export const AuthorBadge = (props: Props) => {
const { mediaMatches } = useMediaQuery()
2024-02-04 17:40:15 +00:00
const { author, requireAuthentication } = useSession()
2024-03-15 12:58:22 +00:00
const { follow, unfollow, subscriptions, subscribeInAction } = useFollowing()
const [isMobileView, setIsMobileView] = createSignal(false)
2024-03-15 12:58:22 +00:00
const [isSubscribed, setIsSubscribed] = createSignal<boolean>()
createEffect(() => {
if(!subscriptions || !props.author) return
const subscribed = subscriptions.authors?.some((authorEntity) => authorEntity.id === props.author?.id);
setIsSubscribed(subscribed)
})
createEffect(() => {
setIsMobileView(!mediaMatches.sm)
})
2024-01-31 12:34:15 +00:00
const { setFollowing } = useFollowing()
const { changeSearchParams } = useRouter()
2023-12-28 00:30:09 +00:00
const { t, formatDate, lang } = useLocalize()
const initChat = () => {
2024-01-31 12:34:15 +00:00
// eslint-disable-next-line solid/reactivity
requireAuthentication(() => {
2024-02-05 15:04:23 +00:00
openPage(router, 'inbox')
changeSearchParams({
initChat: props.author.id.toString(),
})
}, '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-01-31 12:34:15 +00:00
const handleFollowClick = () => {
requireAuthentication(() => {
2024-03-15 12:58:22 +00:00
isSubscribed() ? unfollow(FollowingEntity.Author, props.author.slug) : follow(FollowingEntity.Author, props.author.slug)
2024-01-31 12:34:15 +00:00
}, 'subscribe')
}
return (
<div class={clsx(styles.AuthorBadge, { [styles.nameOnly]: props.nameOnly })}>
2023-11-06 08:00:31 +00:00
<div class={styles.basicInfo}>
<Userpic
hasLink={true}
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}
/>
<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>
</Switch>
<Show when={props.author?.stat}>
<div class={styles.bio}>
<Show when={props.author?.stat.shouts > 0}>
<div>{t('PublicationsWithCount', { count: props.author.stat?.shouts ?? 0 })}</div>
</Show>
<Show when={props.author?.stat.followers > 0}>
<div>{t('FollowersWithCount', { count: props.author.stat?.followers ?? 0 })}</div>
</Show>
</div>
</Show>
2023-11-06 08:00:31 +00:00
</Show>
</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}>
<div class={styles.actions}>
2024-03-15 12:58:22 +00:00
<BadgeSubscribeButton
action={() => handleFollowClick()}
isSubscribed={isSubscribed()}
/>
{/*<Show*/}
{/* when={!props.minimizeSubscribeButton}*/}
{/* fallback={<CheckButton text={t('Follow')} checked={isSubscribed()} onClick={handleFollowClick} />}*/}
{/*>*/}
{/* <Show*/}
{/* when={isSubscribed()}*/}
{/* fallback={*/}
{/* <Button*/}
{/* variant={props.iconButtons ? 'secondary' : 'bordered'}*/}
{/* size="S"*/}
{/* value={*/}
{/* <Show when={props.iconButtons} fallback={t('Subscribe')}>*/}
{/* <Icon name="author-subscribe" class={stylesButton.icon} />*/}
{/* </Show>*/}
{/* }*/}
{/* onClick={handleFollowClick}*/}
{/* isSubscribeButton={true}*/}
{/* class={clsx(styles.actionButton, {*/}
{/* [styles.iconed]: props.iconButtons,*/}
{/* [stylesButton.subscribed]: isSubscribed(),*/}
{/* })}*/}
{/* />*/}
{/* }*/}
{/* >*/}
{/* <Button*/}
{/* variant={props.iconButtons ? 'secondary' : 'bordered'}*/}
{/* size="S"*/}
{/* 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>*/}
{/* }*/}
{/* onClick={handleFollowClick}*/}
{/* isSubscribeButton={true}*/}
{/* class={clsx(styles.actionButton, {*/}
{/* [styles.iconed]: props.iconButtons,*/}
{/* [stylesButton.subscribed]: isSubscribed(),*/}
{/* })}*/}
{/* />*/}
{/* </Show>*/}
{/*</Show>*/}
<Show when={props.showMessageButton}>
<Button
variant={props.iconButtons ? 'secondary' : 'bordered'}
size="S"
value={props.iconButtons ? <Icon name="inbox-white" /> : t('Message')}
onClick={initChat}
class={clsx(styles.actionButton, { [styles.iconed]: props.iconButtons })}
/>
</Show>
</div>
</Show>
<Show when={props.inviteView}>
<CheckButton
text={t('Invite')}
checked={props.selected}
onClick={() => props.onInvite(props.author.id)}
/>
</Show>
</div>
)
}