2023-03-03 18:26:26 +00:00
|
|
|
import { clsx } from 'clsx'
|
2023-07-09 18:38:31 +00:00
|
|
|
import { createMemo, Show } from 'solid-js'
|
2023-03-04 17:26:28 +00:00
|
|
|
import { ReactionKind, Shout } from '../../graphql/types.gen'
|
2023-03-03 18:26:26 +00:00
|
|
|
import { loadShout } from '../../stores/zine/articles'
|
|
|
|
import { useSession } from '../../context/session'
|
|
|
|
import { useReactions } from '../../context/reactions'
|
|
|
|
import { Popup } from '../_shared/Popup'
|
2023-03-09 23:56:19 +00:00
|
|
|
import { VotersList } from '../_shared/VotersList'
|
2023-03-09 23:39:07 +00:00
|
|
|
import { useLocalize } from '../../context/localize'
|
2023-07-09 18:34:59 +00:00
|
|
|
import { Icon } from '../_shared/Icon'
|
2023-07-18 11:26:32 +00:00
|
|
|
import styles from './ShoutRatingControl.module.scss'
|
2023-03-03 18:26:26 +00:00
|
|
|
|
|
|
|
interface ShoutRatingControlProps {
|
|
|
|
shout: Shout
|
|
|
|
class?: string
|
|
|
|
}
|
|
|
|
|
|
|
|
export const ShoutRatingControl = (props: ShoutRatingControlProps) => {
|
2023-03-09 23:39:07 +00:00
|
|
|
const { t } = useLocalize()
|
2023-06-14 17:19:30 +00:00
|
|
|
const {
|
|
|
|
user,
|
|
|
|
actions: { requireAuthentication }
|
|
|
|
} = useSession()
|
2023-03-03 18:26:26 +00:00
|
|
|
|
|
|
|
const {
|
|
|
|
reactionEntities,
|
|
|
|
actions: { createReaction, deleteReaction, loadReactionsBy }
|
|
|
|
} = useReactions()
|
|
|
|
|
|
|
|
const checkReaction = (reactionKind: ReactionKind) =>
|
|
|
|
Object.values(reactionEntities).some(
|
|
|
|
(r) =>
|
|
|
|
r.kind === reactionKind &&
|
2023-03-29 08:51:27 +00:00
|
|
|
r.createdBy.slug === user()?.slug &&
|
2023-03-03 18:26:26 +00:00
|
|
|
r.shout.id === props.shout.id &&
|
|
|
|
!r.replyTo
|
|
|
|
)
|
|
|
|
|
|
|
|
const isUpvoted = createMemo(() => checkReaction(ReactionKind.Like))
|
|
|
|
|
|
|
|
const isDownvoted = createMemo(() => checkReaction(ReactionKind.Dislike))
|
|
|
|
|
|
|
|
const shoutRatingReactions = createMemo(() =>
|
|
|
|
Object.values(reactionEntities).filter(
|
2023-03-08 16:35:13 +00:00
|
|
|
(r) =>
|
|
|
|
[ReactionKind.Like, ReactionKind.Dislike].includes(r.kind) &&
|
|
|
|
r.shout.id === props.shout.id &&
|
|
|
|
!r.replyTo
|
2023-03-03 18:26:26 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
const deleteShoutReaction = async (reactionKind: ReactionKind) => {
|
|
|
|
const reactionToDelete = Object.values(reactionEntities).find(
|
|
|
|
(r) =>
|
|
|
|
r.kind === reactionKind &&
|
2023-03-29 08:51:27 +00:00
|
|
|
r.createdBy.slug === user()?.slug &&
|
2023-03-03 18:26:26 +00:00
|
|
|
r.shout.id === props.shout.id &&
|
|
|
|
!r.replyTo
|
|
|
|
)
|
|
|
|
return deleteReaction(reactionToDelete.id)
|
|
|
|
}
|
|
|
|
|
|
|
|
const handleRatingChange = async (isUpvote: boolean) => {
|
2023-06-14 17:19:30 +00:00
|
|
|
requireAuthentication(async () => {
|
|
|
|
if (isUpvoted()) {
|
|
|
|
await deleteShoutReaction(ReactionKind.Like)
|
|
|
|
} else if (isDownvoted()) {
|
|
|
|
await deleteShoutReaction(ReactionKind.Dislike)
|
|
|
|
} else {
|
|
|
|
await createReaction({
|
|
|
|
kind: isUpvote ? ReactionKind.Like : ReactionKind.Dislike,
|
|
|
|
shout: props.shout.id
|
|
|
|
})
|
|
|
|
}
|
2023-03-03 18:26:26 +00:00
|
|
|
|
2023-06-14 17:19:30 +00:00
|
|
|
loadShout(props.shout.slug)
|
|
|
|
loadReactionsBy({
|
|
|
|
by: { shout: props.shout.slug }
|
|
|
|
})
|
|
|
|
}, 'vote')
|
2023-03-03 18:26:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
2023-07-09 18:34:59 +00:00
|
|
|
<div class={clsx(styles.rating, props.class)}>
|
2023-07-18 11:26:32 +00:00
|
|
|
<button onClick={() => handleRatingChange(false)}>
|
2023-07-09 18:34:59 +00:00
|
|
|
<Show when={!isDownvoted()}>
|
|
|
|
<Icon name="rating-control-less" />
|
|
|
|
</Show>
|
|
|
|
<Show when={isDownvoted()}>
|
|
|
|
<Icon name="rating-control-checked" />
|
|
|
|
</Show>
|
2023-03-03 18:26:26 +00:00
|
|
|
</button>
|
|
|
|
|
|
|
|
<Popup trigger={<span class={styles.ratingValue}>{props.shout.stat.rating}</span>} variant="tiny">
|
2023-03-09 23:39:07 +00:00
|
|
|
<VotersList
|
|
|
|
reactions={shoutRatingReactions()}
|
|
|
|
fallbackMessage={t('This post has not been rated yet')}
|
|
|
|
/>
|
2023-03-03 18:26:26 +00:00
|
|
|
</Popup>
|
|
|
|
|
2023-07-18 11:26:32 +00:00
|
|
|
<button onClick={() => handleRatingChange(true)}>
|
2023-07-09 18:34:59 +00:00
|
|
|
<Show when={!isUpvoted()}>
|
|
|
|
<Icon name="rating-control-more" />
|
|
|
|
</Show>
|
|
|
|
<Show when={isUpvoted()}>
|
|
|
|
<Icon name="rating-control-checked" />
|
|
|
|
</Show>
|
2023-03-03 18:26:26 +00:00
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|