Mute Management Settings Page (#1034)

* first pass of a mute mgmt page, ported from subscription mgmt page pr

* adjust error message for mutes

* muted users -> muted stackers

* fix typo in component name
This commit is contained in:
SatsAllDay 2024-04-08 10:13:56 -04:00 committed by GitHub
parent 91a0d1ccd7
commit e6b825dafe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 108 additions and 1 deletions

View File

@ -161,6 +161,26 @@ export default {
users
}
},
myMutedUsers: async (parent, { cursor }, { models, me }) => {
if (!me) {
throw new GraphQLError('You must be logged in to view muted users', { extensions: { code: 'UNAUTHENTICATED' } })
}
const decodedCursor = decodeCursor(cursor)
const users = await models.$queryRaw`
SELECT users.*
FROM "Mute"
JOIN users ON "Mute"."mutedId" = users.id
WHERE "Mute"."muterId" = ${me.id}
OFFSET ${decodedCursor.offset}
LIMIT ${LIMIT}
`
return {
cursor: users.length === LIMIT ? nextCursorEncoded(decodedCursor) : null,
users
}
},
topCowboys: async (parent, { cursor }, { models, me }) => {
const decodedCursor = decodeCursor(cursor)
const range = whenRange('forever')

View File

@ -13,6 +13,7 @@ export default gql`
userSuggestions(q: String, limit: Limit): [User!]!
hasNewNotes: Boolean!
mySubscribedUsers(cursor: String): Users!
myMutedUsers(cursor: String): Users!
}
type UsersNullable {

View File

@ -1,10 +1,26 @@
import { createContext, useContext } from 'react'
import { useMutation } from '@apollo/client'
import { gql } from 'graphql-tag'
import Dropdown from 'react-bootstrap/Dropdown'
import { useToast } from './toast'
const MuteUserContext = createContext(() => ({
refetchQueries: []
}))
export const MuteUserContextProvider = ({ children, value }) => {
return (
<MuteUserContext.Provider value={value}>
{children}
</MuteUserContext.Provider>
)
}
export const useMuteUserContext = () => useContext(MuteUserContext)
export default function MuteDropdownItem ({ user: { name, id, meMute } }) {
const toaster = useToast()
const { refetchQueries } = useMuteUserContext()
const [toggleMute] = useMutation(
gql`
mutation toggleMute($id: ID!) {
@ -12,6 +28,7 @@ export default function MuteDropdownItem ({ user: { name, id, meMute } }) {
meMute
}
}`, {
refetchQueries,
update (cache, { data: { toggleMute } }) {
cache.modify({
id: `User:${id}`,

View File

@ -226,6 +226,26 @@ export const MY_SUBSCRIBED_USERS = gql`
}
`
export const MY_MUTED_USERS = gql`
query MyMutedUsers($cursor: String) {
myMutedUsers(cursor: $cursor) {
users {
id
name
photoId
meSubscriptionPosts
meSubscriptionComments
meMute
optional {
streak
}
}
cursor
}
}
`
export const TOP_USERS = gql`
query TopUsers($cursor: String, $when: String, $from: String, $to: String, $by: String, ) {
topUsers(cursor: $cursor, when: $when, from: $from, to: $to, by: $by) {

View File

@ -99,6 +99,19 @@ function getClient (uri) {
}
}
},
myMutedUsers: {
keyArgs: false,
merge (existing, incoming) {
if (isFirstPage(incoming.cursor, existing?.users)) {
return incoming
}
return {
cursor: incoming.cursor,
users: [...(existing?.users || []), ...incoming.users]
}
}
},
userSuggestions: {
keyArgs: ['q', 'limit'],
merge (existing, incoming) {

View File

@ -41,7 +41,7 @@ function bech32encode (hexString) {
export function SettingsHeader () {
const router = useRouter()
const pathParts = router.asPath.split('/').filter(segment => !!segment)
const activeKey = pathParts.length === 1 ? 'general' : 'subscriptions'
const activeKey = pathParts[1] ?? 'general'
return (
<>
<h2 className='mb-2 text-start'>settings</h2>
@ -59,6 +59,11 @@ export function SettingsHeader () {
<Nav.Link eventKey='subscriptions'>subscriptions</Nav.Link>
</Link>
</Nav.Item>
<Nav.Item>
<Link href='/settings/mutes' passHref legacyBehavior>
<Nav.Link eventKey='mutes'>muted stackers</Nav.Link>
</Link>
</Nav.Item>
</Nav>
</>
)

View File

@ -0,0 +1,31 @@
import { useMemo } from 'react'
import { getGetServerSideProps } from '@/api/ssrApollo'
import Layout from '@/components/layout'
import UserList from '@/components/user-list'
import { MY_MUTED_USERS } from '@/fragments/users'
import { SettingsHeader } from '../index'
import { MuteUserContextProvider } from '@/components/mute'
export const getServerSideProps = getGetServerSideProps({ query: MY_MUTED_USERS, authRequired: true })
export default function MyMutedUsers ({ ssrData }) {
const muteUserContextValue = useMemo(() => ({ refetchQueries: ['MyMutedUsers'] }), [])
return (
<Layout>
<div className='pb-3 w-100 mt-2'>
<SettingsHeader />
<div className='mb-4 text-muted'>Well now, reckon these here are the folks you've gone and silenced.</div>
<MuteUserContextProvider value={muteUserContextValue}>
<UserList
ssrData={ssrData} query={MY_MUTED_USERS}
destructureData={data => data.myMutedUsers}
variables={{}}
rank
nymActionDropdown
statCompsProp={[]}
/>
</MuteUserContextProvider>
</div>
</Layout>
)
}