diff --git a/src/components/Article/Comment.module.scss b/src/components/Article/Comment.module.scss index 61e01bb9..1ea32cec 100644 --- a/src/components/Article/Comment.module.scss +++ b/src/components/Article/Comment.module.scss @@ -201,39 +201,6 @@ margin-bottom: 1.2rem; } -.commentRating { - align-items: center; - display: flex; - font-weight: bold; -} - -.commentRatingValue { - padding: 0 0.3em; -} - -.commentRatingPositive { - color: #2bb452; -} - -.commentRatingNegative { - color: #d00820; -} - -.commentRatingControl { - border-left: 6px solid transparent; - border-right: 6px solid transparent; - height: 0; - width: 0; -} - -.commentRatingControlUp { - border-bottom: 8px solid rgb(0 0 0 / 40%); -} - -.commentRatingControlDown { - border-top: 8px solid rgb(0 0 0 / 40%); -} - .compactUserpic { height: 28px; width: 28px; diff --git a/src/components/Article/Comment.tsx b/src/components/Article/Comment.tsx index 152b0945..21942340 100644 --- a/src/components/Article/Comment.tsx +++ b/src/components/Article/Comment.tsx @@ -13,7 +13,7 @@ import { useReactions } from '../../context/reactions' import { useSnackbar } from '../../context/snackbar' import { ShowIfAuthenticated } from '../_shared/ShowIfAuthenticated' import { useLocalize } from '../../context/localize' -import Cookie from 'js-cookie' +import { CommentRatingControl } from './CommentRatingControl' const CommentEditor = lazy(() => import('../_shared/CommentEditor')) @@ -140,17 +140,7 @@ export const Comment = (props: Props) => { -
0, - [styles.commentRatingNegative]: comment().stat.rating < 0 - }} - > -
+
diff --git a/src/components/Article/CommentRatingControl.module.scss b/src/components/Article/CommentRatingControl.module.scss new file mode 100644 index 00000000..f1f8cbfa --- /dev/null +++ b/src/components/Article/CommentRatingControl.module.scss @@ -0,0 +1,45 @@ +.commentRating { + align-items: center; + display: flex; + font-weight: bold; + + .commentRatingValue { + padding: 0 0.3em; + margin: 0 0.6rem; + font-size: 1.2rem; + cursor: pointer; + transition: opacity 0.3s ease-in-out; + &:hover { + opacity: 0.5; + } + } + + .commentRatingPositive { + color: #2bb452; + } + + .commentRatingNegative { + color: #d00820; + } + + .commentRatingControl { + border-left: 6px solid transparent; + border-right: 6px solid transparent; + height: 0; + width: 0; + } + + .commentRatingControlUp { + border-bottom: 8px solid rgb(0 0 0 / 40%); + &.voted { + border-bottom-color: #2bb452; + } + } + + .commentRatingControlDown { + border-top: 8px solid rgb(0 0 0 / 40%); + &.voted { + border-top-color: #d00820; + } + } +} diff --git a/src/components/Article/CommentRatingControl.tsx b/src/components/Article/CommentRatingControl.tsx new file mode 100644 index 00000000..69598129 --- /dev/null +++ b/src/components/Article/CommentRatingControl.tsx @@ -0,0 +1,125 @@ +import { clsx } from 'clsx' +import styles from './CommentRatingControl.module.scss' +import type { Reaction } from '../../graphql/types.gen' +import { ReactionKind } from '../../graphql/types.gen' +import { useSession } from '../../context/session' +import { useReactions } from '../../context/reactions' +import { createMemo, For } from 'solid-js' +import { loadShout } from '../../stores/zine/articles' +import { Popup } from '../_shared/Popup' +import { useLocalize } from '../../context/localize' +import { useSnackbar } from '../../context/snackbar' + +type Props = { + comment: Reaction +} + +export const CommentRatingControl = (props: Props) => { + const { t } = useLocalize() + const { userSlug } = useSession() + const { + actions: { showSnackbar } + } = useSnackbar() + const { + reactionEntities, + actions: { createReaction, deleteReaction, loadReactionsBy } + } = useReactions() + + const checkReaction = (reactionKind: ReactionKind) => + Object.values(reactionEntities).some( + (r) => + r.kind === reactionKind && + r.createdBy.slug === userSlug() && + r.shout.id === props.comment.shout.id && + r.replyTo === props.comment.id + ) + const isUpvoted = createMemo(() => checkReaction(ReactionKind.Like)) + const isDownvoted = createMemo(() => checkReaction(ReactionKind.Dislike)) + const canVote = createMemo(() => userSlug() !== props.comment.createdBy.slug) + + const shoutRatingReactions = createMemo(() => + Object.values(reactionEntities).filter( + (r) => + [ReactionKind.Like, ReactionKind.Dislike].includes(r.kind) && + r.shout.id === props.comment.shout.id && + r.replyTo === props.comment.id + ) + ) + const deleteCommentReaction = async (reactionKind: ReactionKind) => { + const reactionToDelete = Object.values(reactionEntities).find( + (r) => + r.kind === reactionKind && + r.createdBy.slug === userSlug() && + r.shout.id === props.comment.shout.id && + r.replyTo === props.comment.id + ) + return deleteReaction(reactionToDelete.id) + } + + const handleRatingChange = async (isUpvote: boolean) => { + try { + if (isUpvoted()) { + await deleteCommentReaction(ReactionKind.Like) + } else if (isDownvoted()) { + await deleteCommentReaction(ReactionKind.Dislike) + } else { + await createReaction({ + kind: isUpvote ? ReactionKind.Like : ReactionKind.Dislike, + shout: props.comment.shout.id, + replyTo: props.comment.id + }) + } + } catch (e) { + showSnackbar({ type: 'error', body: t('Error') }) + } + + await loadShout(props.comment.shout.slug) + await loadReactionsBy({ + by: { shout: props.comment.shout.slug } + }) + } + + return ( +
+
+ } + variant="tiny" + > + + +
+ ) +} diff --git a/src/pages/profile/profileSettings.page.tsx b/src/pages/profile/profileSettings.page.tsx index cbbf1c9e..70d6ce71 100644 --- a/src/pages/profile/profileSettings.page.tsx +++ b/src/pages/profile/profileSettings.page.tsx @@ -6,7 +6,6 @@ import { clsx } from 'clsx' import styles from './Settings.module.scss' import { useProfileForm } from '../../context/profile' import validateUrl from '../../utils/validateUrl' - import { createFileUploader, UploadFile } from '@solid-primitives/upload' import { Loading } from '../../components/_shared/Loading' import { useSession } from '../../context/session' diff --git a/src/utils/clone.ts b/src/utils/clone.ts new file mode 100644 index 00000000..1f224f77 --- /dev/null +++ b/src/utils/clone.ts @@ -0,0 +1,3 @@ +// debug nested objects console.log('message', clone(obj)) + +export const clone = (obj: T): T => JSON.parse(JSON.stringify(obj))