Merge pull request #409 from Discours/feature/editor-buttons

canEdit-fix
This commit is contained in:
Tony 2024-02-19 14:30:21 +03:00 committed by GitHub
commit cbfe03c04e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 43 additions and 30 deletions

View File

@ -38,12 +38,17 @@ export const Comment = (props: Props) => {
const [loading, setLoading] = createSignal(false) const [loading, setLoading] = createSignal(false)
const [editMode, setEditMode] = createSignal(false) const [editMode, setEditMode] = createSignal(false)
const [clearEditor, setClearEditor] = createSignal(false) const [clearEditor, setClearEditor] = createSignal(false)
const { author } = useSession() const { author, session } = useSession()
const { createReaction, deleteReaction, updateReaction } = useReactions() const { createReaction, deleteReaction, updateReaction } = useReactions()
const { showConfirm } = useConfirm() const { showConfirm } = useConfirm()
const { showSnackbar } = useSnackbar() const { showSnackbar } = useSnackbar()
const isCommentAuthor = createMemo(() => props.comment.created_by?.slug === author()?.slug) const canEdit = createMemo(
() =>
Boolean(author()?.id) &&
(props.comment?.created_by?.id === author().id || session()?.user?.roles.includes('editor')),
)
const comment = createMemo(() => props.comment) const comment = createMemo(() => props.comment)
const body = createMemo(() => (comment().body || '').trim()) const body = createMemo(() => (comment().body || '').trim())
@ -93,7 +98,8 @@ export const Comment = (props: Props) => {
const handleUpdate = async (value) => { const handleUpdate = async (value) => {
setLoading(true) setLoading(true)
try { try {
await updateReaction(props.comment.id, { await updateReaction({
id: props.comment.id,
kind: ReactionKind.Comment, kind: ReactionKind.Comment,
body: value, body: value,
shout: props.comment.shout.id, shout: props.comment.shout.id,
@ -108,9 +114,7 @@ export const Comment = (props: Props) => {
return ( return (
<li <li
id={`comment_${comment().id}`} id={`comment_${comment().id}`}
class={clsx(styles.comment, props.class, { class={clsx(styles.comment, props.class, { [styles.isNew]: comment()?.created_at > props.lastSeen })}
[styles.isNew]: !isCommentAuthor() && comment()?.created_at > props.lastSeen,
})}
> >
<Show when={!!body()}> <Show when={!!body()}>
<div class={styles.commentContent}> <div class={styles.commentContent}>
@ -189,7 +193,7 @@ export const Comment = (props: Props) => {
{loading() ? t('Loading') : t('Reply')} {loading() ? t('Loading') : t('Reply')}
</button> </button>
</ShowIfAuthenticated> </ShowIfAuthenticated>
<Show when={isCommentAuthor()}> <Show when={canEdit()}>
<button <button
class={clsx(styles.commentControl, styles.commentControlEdit)} class={clsx(styles.commentControl, styles.commentControlEdit)}
onClick={toggleEditMode} onClick={toggleEditMode}

View File

@ -75,10 +75,17 @@ export const FullArticle = (props: Props) => {
const [isReactionsLoaded, setIsReactionsLoaded] = createSignal(false) const [isReactionsLoaded, setIsReactionsLoaded] = createSignal(false)
const [isActionPopupActive, setIsActionPopupActive] = createSignal(false) const [isActionPopupActive, setIsActionPopupActive] = createSignal(false)
const { t, formatDate, lang } = useLocalize() const { t, formatDate, lang } = useLocalize()
const { author, isAuthenticated, requireAuthentication } = useSession() const { author, session, isAuthenticated, requireAuthentication } = useSession()
const formattedDate = createMemo(() => formatDate(new Date(props.article.published_at * 1000))) const formattedDate = createMemo(() => formatDate(new Date(props.article.published_at * 1000)))
const canEdit = () => props.article.authors?.some((a) => Boolean(a) && a?.slug === author()?.slug)
const canEdit = createMemo(
() =>
Boolean(author()?.id) &&
(props.article?.authors?.some((a) => Boolean(a) && a?.id === author().id) ||
props.article?.created_by?.id === author().id ||
session()?.user?.roles.includes('editor')),
)
const mainTopic = createMemo(() => { const mainTopic = createMemo(() => {
const mainTopicSlug = props.article.topics.length > 0 ? props.article.main_topic : null const mainTopicSlug = props.article.topics.length > 0 ? props.article.main_topic : null
@ -544,7 +551,7 @@ export const FullArticle = (props: Props) => {
</Show> </Show>
<FeedArticlePopup <FeedArticlePopup
isOwner={canEdit()} canEdit={canEdit()}
containerCssClass={clsx(stylesHeader.control, styles.articlePopupOpener)} containerCssClass={clsx(stylesHeader.control, styles.articlePopupOpener)}
onShareClick={() => showModal('share')} onShareClick={() => showModal('share')}
onInviteClick={() => showModal('inviteMembers')} onInviteClick={() => showModal('inviteMembers')}

View File

@ -106,7 +106,7 @@ const LAYOUT_ASPECT = {
export const ArticleCard = (props: ArticleCardProps) => { export const ArticleCard = (props: ArticleCardProps) => {
const { t, lang, formatDate } = useLocalize() const { t, lang, formatDate } = useLocalize()
const { author } = useSession() const { author, session } = useSession()
const { changeSearchParams } = useRouter() const { changeSearchParams } = useRouter()
const [isActionPopupActive, setIsActionPopupActive] = createSignal(false) const [isActionPopupActive, setIsActionPopupActive] = createSignal(false)
const [isCoverImageLoadError, setIsCoverImageLoadError] = createSignal(false) const [isCoverImageLoadError, setIsCoverImageLoadError] = createSignal(false)
@ -120,9 +120,13 @@ export const ArticleCard = (props: ArticleCardProps) => {
props.article.published_at ? formatDate(new Date(props.article.published_at * 1000)) : '', props.article.published_at ? formatDate(new Date(props.article.published_at * 1000)) : '',
) )
const canEdit = () => const canEdit = createMemo(
props.article.authors?.some((a) => a && a?.slug === author()?.slug) || () =>
props.article.created_by?.id === author()?.id Boolean(author()?.id) &&
(props.article?.authors?.some((a) => Boolean(a) && a?.id === author().id) ||
props.article?.created_by?.id === author().id ||
session()?.user?.roles.includes('editor')),
)
const scrollToComments = (event) => { const scrollToComments = (event) => {
event.preventDefault() event.preventDefault()
@ -365,7 +369,7 @@ export const ArticleCard = (props: ArticleCardProps) => {
<div class={styles.shoutCardDetailsItem}> <div class={styles.shoutCardDetailsItem}>
<FeedArticlePopup <FeedArticlePopup
isOwner={canEdit()} canEdit={canEdit()}
containerCssClass={stylesHeader.control} containerCssClass={stylesHeader.control}
onShareClick={() => props.onShare(props.article)} onShareClick={() => props.onShare(props.article)}
onInviteClick={props.onInvite} onInviteClick={props.onInvite}

View File

@ -10,7 +10,7 @@ import { SoonChip } from '../../_shared/SoonChip'
import styles from './FeedArticlePopup.module.scss' import styles from './FeedArticlePopup.module.scss'
type Props = { type Props = {
isOwner: boolean canEdit: boolean
onInviteClick: () => void onInviteClick: () => void
onShareClick: () => void onShareClick: () => void
} & Omit<PopupProps, 'children'> } & Omit<PopupProps, 'children'>
@ -41,7 +41,7 @@ export const FeedArticlePopup = (props: Props) => {
{t('Share')} {t('Share')}
</button> </button>
</li> </li>
<Show when={!props.isOwner}> <Show when={!props.canEdit}>
<li> <li>
<button <button
class={styles.action} class={styles.action}
@ -67,7 +67,7 @@ export const FeedArticlePopup = (props: Props) => {
{t('Invite experts')} {t('Invite experts')}
</button> </button>
</li> </li>
<Show when={!props.isOwner}> <Show when={!props.canEdit}>
<li> <li>
<button class={clsx(styles.action, styles.soon)} role="button"> <button class={clsx(styles.action, styles.soon)} role="button">
{t('Subscribe to comments')} <SoonChip /> {t('Subscribe to comments')} <SoonChip />
@ -79,7 +79,7 @@ export const FeedArticlePopup = (props: Props) => {
{t('Add to bookmarks')} <SoonChip /> {t('Add to bookmarks')} <SoonChip />
</button> </button>
</li> </li>
{/*<Show when={!props.isOwner}>*/} {/*<Show when={!props.canEdit}>*/}
{/* <li>*/} {/* <li>*/}
{/* <button*/} {/* <button*/}
{/* class={styles.action}*/} {/* class={styles.action}*/}

View File

@ -18,7 +18,7 @@ type ReactionsContextType = {
offset?: number offset?: number
}) => Promise<Reaction[]> }) => Promise<Reaction[]>
createReaction: (reaction: ReactionInput) => Promise<void> createReaction: (reaction: ReactionInput) => Promise<void>
updateReaction: (id: number, reaction: ReactionInput) => Promise<void> updateReaction: (reaction: ReactionInput) => Promise<void>
deleteReaction: (id: number) => Promise<void> deleteReaction: (id: number) => Promise<void>
} }
@ -88,8 +88,8 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
} }
} }
const updateReaction = async (id: number, input: ReactionInput): Promise<void> => { const updateReaction = async (input: ReactionInput): Promise<void> => {
const reaction = await apiClient.updateReaction(id, input) const reaction = await apiClient.updateReaction(input)
setReactionEntities(reaction.id, reaction) setReactionEntities(reaction.id, reaction)
} }

View File

@ -178,15 +178,13 @@ export const apiClient = {
console.debug('[graphql.client.core] createReaction:', response) console.debug('[graphql.client.core] createReaction:', response)
return response.data.create_reaction.reaction return response.data.create_reaction.reaction
}, },
destroyReaction: async (id: number) => { destroyReaction: async (reaction_id: number) => {
const response = await apiClient.private.mutation(reactionDestroy, { id: id }).toPromise() const response = await apiClient.private.mutation(reactionDestroy, { reaction_id }).toPromise()
console.debug('[graphql.client.core] destroyReaction:', response) console.debug('[graphql.client.core] destroyReaction:', response)
return response.data.delete_reaction.reaction return response.data.delete_reaction.reaction
}, },
updateReaction: async (id: number, input: ReactionInput) => { updateReaction: async (reaction: ReactionInput) => {
const response = await apiClient.private const response = await apiClient.private.mutation(reactionUpdate, { reaction }).toPromise()
.mutation(reactionUpdate, { id: id, reaction: input })
.toPromise()
console.debug('[graphql.client.core] updateReaction:', response) console.debug('[graphql.client.core] updateReaction:', response)
return response.data.update_reaction.reaction return response.data.update_reaction.reaction
}, },

View File

@ -1,8 +1,8 @@
import { gql } from '@urql/core' import { gql } from '@urql/core'
export default gql` export default gql`
mutation UpdateReactionMutation($id: Int!, $reaction: ReactionInput!) { mutation UpdateReactionMutation($reaction: ReactionInput!) {
update_reaction(id: $id, reaction: $reaction) { update_reaction(reaction: $reaction) {
error error
reaction { reaction {
id id