diff --git a/api/resolvers/item.js b/api/resolvers/item.js index e412249d7..d0edab35d 100644 --- a/api/resolvers/item.js +++ b/api/resolvers/item.js @@ -750,6 +750,17 @@ export default { } return { id } }, + unsubscribeThread: async (parent, { id }, { me, models }) => { + if (!me) throw new GqlAuthenticationError() + await models.$executeRaw` + DELETE FROM "ThreadSubscription" ts + USING "Item" i + WHERE ts."userId" = ${me.id} + AND i.path @> (SELECT path FROM "Item" WHERE id = ${Number(id)}) + AND ts."itemId" = i.id + ` + return { id } + }, deleteItem: async (parent, { id }, { me, models }) => { const old = await models.item.findUnique({ where: { id: Number(id) } }) if (Number(old.userId) !== Number(me?.id)) { diff --git a/api/typeDefs/item.js b/api/typeDefs/item.js index 5665d565e..6bb629a2f 100644 --- a/api/typeDefs/item.js +++ b/api/typeDefs/item.js @@ -22,6 +22,7 @@ export default gql` bookmarkItem(id: ID): Item pinItem(id: ID): Item subscribeItem(id: ID): Item + unsubscribeThread(id: ID!): Item deleteItem(id: ID): Item upsertLink( id: ID, subNames: [String!], title: String!, url: String!, text: String, forward: [ItemForwardInput], diff --git a/components/notifications.js b/components/notifications.js index afeb4a0e2..1eb524c2b 100644 --- a/components/notifications.js +++ b/components/notifications.js @@ -1,6 +1,6 @@ import { useState, useEffect, useMemo, useCallback } from 'react' import { gql } from '@apollo/client' -import { useQuery } from '@apollo/client/react' +import { useMutation, useQuery } from '@apollo/client/react' import Comment, { CommentSkeleton } from './comment' import Item from './item' import ItemJob from './item-job' @@ -716,7 +716,41 @@ function JobChanged ({ n }) { } function Reply ({ n }) { - return + const toaster = useToast() + const [unsubscribed, setUnsubscribed] = useState(false) + const [unsubscribeThread] = useMutation( + gql` + mutation unsubscribeThread($id: ID!) { + unsubscribeThread(id: $id) { + id + } + } + ` + ) + return ( + <> + + {!unsubscribed && ( +
+ { + try { + await unsubscribeThread({ variables: { id: n.item.id } }) + setUnsubscribed(true) + toaster.success('unsubscribed from thread') + } catch (err) { + console.error(err) + toaster.danger('failed to unsubscribe from thread') + } + }} + > + unsubscribe from thread + +
+ )} + + ) } function FollowActivity ({ n }) {