Skip to content

Commit 87b6571

Browse files
committed
Add Territory Sub management tab in Subscriptions
1 parent 00f0e97 commit 87b6571

File tree

7 files changed

+138
-20
lines changed

7 files changed

+138
-20
lines changed

api/resolvers/sub.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,33 @@ export default {
170170
cursor: subs.length === limit ? nextCursorEncoded(decodedCursor, limit) : null,
171171
subs
172172
}
173+
},
174+
mySubscribedSubs: async (parent, { cursor }, { models, me }) => {
175+
if (!me) {
176+
throw new GqlAuthenticationError()
177+
}
178+
179+
const decodedCursor = decodeCursor(cursor)
180+
const subs = await models.$queryRawUnsafe(`
181+
SELECT "Sub".*,
182+
EXISTS (
183+
SELECT 1 FROM "MuteSub"
184+
WHERE "MuteSub"."userId" = $1 AND "MuteSub"."subName" = "Sub".name
185+
) AS "meMuteSub",
186+
TRUE as "meSubscription"
187+
FROM "SubSubscription"
188+
JOIN "Sub" ON "SubSubscription"."subName" = "Sub".name
189+
WHERE "SubSubscription"."userId" = $1
190+
AND "Sub".status <> 'STOPPED'
191+
ORDER BY "Sub".name ASC
192+
OFFSET $2
193+
LIMIT $3
194+
`, me.id, decodedCursor.offset, LIMIT)
195+
196+
return {
197+
cursor: subs.length === LIMIT ? nextCursorEncoded(decodedCursor, LIMIT) : null,
198+
subs
199+
}
173200
}
174201
},
175202
Mutation: {

api/typeDefs/sub.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export default gql`
77
subs: [Sub!]!
88
topSubs(cursor: String, when: String, from: String, to: String, by: String, limit: Limit): Subs
99
userSubs(name: String!, cursor: String, when: String, from: String, to: String, by: String, limit: Limit): Subs
10+
mySubscribedSubs(cursor: String): Subs
1011
subSuggestions(q: String!, limit: Limit): [Sub!]!
1112
}
1213

components/territory-header.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { createContext, useContext } from 'react'
12
import { Badge, Button, CardFooter, Dropdown } from 'react-bootstrap'
23
import { AccordianCard } from './accordian-item'
34
import TerritoryPaymentDue, { TerritoryBillingLine } from './territory-payment-due'
@@ -13,6 +14,16 @@ import { useToast } from './toast'
1314
import ActionDropdown from './action-dropdown'
1415
import { TerritoryTransferDropdownItem } from './territory-transfer'
1516

17+
const SubscribeTerritoryContext = createContext({ refetchQueries: [] })
18+
19+
export const SubscribeTerritoryContextProvider = ({ children, value }) => (
20+
<SubscribeTerritoryContext.Provider value={value}>
21+
{children}
22+
</SubscribeTerritoryContext.Provider>
23+
)
24+
25+
export const useSubscribeTerritoryContext = () => useContext(SubscribeTerritoryContext)
26+
1627
export function TerritoryDetails ({ sub, children }) {
1728
return (
1829
<AccordianCard
@@ -149,12 +160,15 @@ export default function TerritoryHeader ({ sub }) {
149160

150161
export function MuteSubDropdownItem ({ item, sub }) {
151162
const toaster = useToast()
163+
const { refetchQueries } = useSubscribeTerritoryContext()
152164

153165
const [toggleMuteSub] = useMutation(
154166
gql`
155167
mutation toggleMuteSub($name: String!) {
156168
toggleMuteSub(name: $name)
157169
}`, {
170+
refetchQueries,
171+
awaitRefetchQueries: true,
158172
update (cache, { data: { toggleMuteSub } }) {
159173
cache.modify({
160174
id: `Sub:{"name":"${sub.name}"}`,
@@ -213,11 +227,14 @@ export function PinSubDropdownItem ({ item: { id, position } }) {
213227

214228
export function ToggleSubSubscriptionDropdownItem ({ sub: { name, meSubscription } }) {
215229
const toaster = useToast()
230+
const { refetchQueries } = useSubscribeTerritoryContext()
216231
const [toggleSubSubscription] = useMutation(
217232
gql`
218233
mutation toggleSubSubscription($name: String!) {
219234
toggleSubSubscription(name: $name)
220235
}`, {
236+
refetchQueries,
237+
awaitRefetchQueries: true,
221238
update (cache, { data: { toggleSubSubscription } }) {
222239
cache.modify({
223240
id: `Sub:{"name":"${name}"}`,

components/territory-list.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import { useQuery } from '@apollo/client'
66
import MoreFooter from './more-footer'
77
import { useData } from './use-data'
88
import Info from './info'
9-
import { TerritoryInfo } from './territory-header'
9+
import ActionDropdown from './action-dropdown'
10+
import { TerritoryInfo, ToggleSubSubscriptionDropdownItem, MuteSubDropdownItem } from './territory-header'
1011

1112
// all of this nonsense is to show the stat we are sorting by first
1213
const Revenue = ({ sub }) => (sub.optional.revenue !== null && <span>{abbrNum(sub.optional.revenue)} revenue</span>)
@@ -35,16 +36,16 @@ function separate (arr, separator) {
3536
return arr.flatMap((x, i) => i < arr.length - 1 ? [x, separator] : [x])
3637
}
3738

38-
export default function TerritoryList ({ ssrData, query, variables, destructureData, rank }) {
39+
export default function TerritoryList ({ ssrData, query, variables, destructureData, rank, statCompsProp }) {
3940
const { data, fetchMore } = useQuery(query, { variables })
4041
const dat = useData(data, ssrData)
41-
const [statComps, setStatComps] = useState(separate(STAT_COMPONENTS, Separator))
42+
const [statComps, setStatComps] = useState(separate(statCompsProp || STAT_COMPONENTS, Separator))
4243

4344
useEffect(() => {
4445
// shift the stat we are sorting by to the front
45-
const comps = [...STAT_COMPONENTS]
46+
const comps = [...statComps]
4647
setStatComps(separate([...comps.splice(STAT_POS[variables?.by || 0], 1), ...comps], Separator))
47-
}, [variables?.by])
48+
}, [variables?.by], statComps)
4849

4950
const { subs, cursor } = useMemo(() => {
5051
if (!dat) return {}
@@ -77,6 +78,10 @@ export default function TerritoryList ({ ssrData, query, variables, destructureD
7778
{sub.name}
7879
</Link>
7980
<Info className='d-flex'><TerritoryInfo sub={sub} /></Info>
81+
<ActionDropdown>
82+
<ToggleSubSubscriptionDropdownItem sub={sub} />
83+
<MuteSubDropdownItem sub={sub} />
84+
</ActionDropdown>
8085
</div>
8186
<div className={styles.other}>
8287
{statComps.map((Comp, i) => <Comp key={i} sub={sub} />)}

fragments/subs.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,15 @@ export const TOP_SUBS = gql`
149149
}
150150
}
151151
`
152+
153+
export const MY_SUBSCRIBED_SUBS = gql`
154+
${SUB_FULL_FIELDS}
155+
query MySubscribedSubs($cursor: String) {
156+
mySubscribedSubs(cursor: $cursor) {
157+
subs {
158+
...SubFullFields
159+
}
160+
cursor
161+
}
162+
}
163+
`

fragments/users.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,3 +390,28 @@ export const USER_STATS = gql`
390390
}
391391
}
392392
}`
393+
394+
export const MY_SUBSCRIPTIONS = gql`
395+
${STREAK_FIELDS}
396+
${SUB_FULL_FIELDS}
397+
query MySubscriptions($cursor: String) {
398+
mySubscribedUsers(cursor: $cursor) {
399+
users {
400+
id
401+
name
402+
photoId
403+
meSubscriptionPosts
404+
meSubscriptionComments
405+
meMute
406+
...StreakFields
407+
}
408+
cursor
409+
}
410+
mySubscribedSubs(cursor: $cursor) {
411+
subs {
412+
...SubFullFields
413+
}
414+
cursor
415+
}
416+
}
417+
`

pages/settings/subscriptions/index.js

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,61 @@
1-
import { useMemo } from 'react'
1+
import { useMemo, useState } from 'react'
22
import { getGetServerSideProps } from '@/api/ssrApollo'
33
import Layout from '@/components/layout'
4+
import { Select } from '@/components/form'
45
import UserList from '@/components/user-list'
5-
import { MY_SUBSCRIBED_USERS } from '@/fragments/users'
6+
import TerritoryList from '@/components/territory-list'
7+
import { MY_SUBSCRIPTIONS } from '@/fragments/users'
68
import { SettingsHeader } from '../index'
79
import { SubscribeUserContextProvider } from '@/components/subscribeUser'
10+
import { SubscribeTerritoryContextProvider } from '@/components/territory-header'
811

9-
export const getServerSideProps = getGetServerSideProps({ query: MY_SUBSCRIBED_USERS, authRequired: true })
12+
export const getServerSideProps = getGetServerSideProps({
13+
query: MY_SUBSCRIPTIONS,
14+
authRequired: true
15+
})
1016

1117
export default function MySubscribedUsers ({ ssrData }) {
12-
const subscribeUserContextValue = useMemo(() => ({ refetchQueries: ['MySubscribedUsers'] }), [])
18+
const [view, setView] = useState('stackers')
19+
const subscribeContextValue = useMemo(() => ({ refetchQueries: ['MySubscriptions'] }), [])
20+
1321
return (
1422
<Layout>
1523
<div className='pb-3 w-100 mt-2'>
1624
<SettingsHeader />
17-
<div className='mb-4 text-muted'>These here are stackers you've hitched your wagon to, pardner.</div>
18-
<SubscribeUserContextProvider value={subscribeUserContextValue}>
19-
<UserList
20-
ssrData={ssrData} query={MY_SUBSCRIBED_USERS}
21-
destructureData={data => data.mySubscribedUsers}
22-
variables={{}}
23-
rank
24-
nymActionDropdown
25-
statCompsProp={[]}
26-
/>
27-
</SubscribeUserContextProvider>
25+
<Select
26+
name='subscriptionType'
27+
size='sm'
28+
noForm
29+
items={['stackers', 'territories']}
30+
value={view}
31+
onChange={(_, e) => setView(e.target.value)}
32+
/>
33+
{view === 'stackers'
34+
? (
35+
<SubscribeUserContextProvider value={subscribeContextValue}>
36+
<UserList
37+
ssrData={ssrData}
38+
query={MY_SUBSCRIPTIONS}
39+
destructureData={data => data.mySubscribedUsers}
40+
variables={{}}
41+
rank
42+
nymActionDropdown
43+
statCompsProp={[]}
44+
/>
45+
</SubscribeUserContextProvider>
46+
)
47+
: (
48+
<SubscribeTerritoryContextProvider value={subscribeContextValue}>
49+
<TerritoryList
50+
ssrData={ssrData}
51+
query={MY_SUBSCRIPTIONS}
52+
variables={{}}
53+
destructureData={data => data.mySubscribedSubs}
54+
rank
55+
statCompsProp={[]}
56+
/>
57+
</SubscribeTerritoryContextProvider>
58+
)}
2859
</div>
2960
</Layout>
3061
)

0 commit comments

Comments
 (0)