Change size (#4957)
parent
6616a6467e
commit
61f0be705d
|
@ -9,14 +9,15 @@ import {
|
||||||
import {InfiniteData, UseInfiniteQueryResult} from '@tanstack/react-query'
|
import {InfiniteData, UseInfiniteQueryResult} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {useBottomBarOffset} from 'lib/hooks/useBottomBarOffset'
|
import {useBottomBarOffset} from 'lib/hooks/useBottomBarOffset'
|
||||||
|
import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
|
||||||
import {isBlockedOrBlocking} from 'lib/moderation/blocked-and-muted'
|
import {isBlockedOrBlocking} from 'lib/moderation/blocked-and-muted'
|
||||||
import {isNative, isWeb} from 'platform/detection'
|
import {isNative, isWeb} from 'platform/detection'
|
||||||
import {useListMembersQuery} from 'state/queries/list-members'
|
import {useAllListMembersQuery} from 'state/queries/list-members'
|
||||||
import {useSession} from 'state/session'
|
import {useSession} from 'state/session'
|
||||||
import {List, ListRef} from 'view/com/util/List'
|
import {List, ListRef} from 'view/com/util/List'
|
||||||
import {SectionRef} from '#/screens/Profile/Sections/types'
|
import {SectionRef} from '#/screens/Profile/Sections/types'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {ListMaybePlaceholder} from '#/components/Lists'
|
import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
|
||||||
import {Default as ProfileCard} from '#/components/ProfileCard'
|
import {Default as ProfileCard} from '#/components/ProfileCard'
|
||||||
|
|
||||||
function keyExtractor(item: AppBskyActorDefs.ProfileViewBasic, index: number) {
|
function keyExtractor(item: AppBskyActorDefs.ProfileViewBasic, index: number) {
|
||||||
|
@ -39,17 +40,20 @@ export const ProfilesList = React.forwardRef<SectionRef, ProfilesListProps>(
|
||||||
ref,
|
ref,
|
||||||
) {
|
) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const [initialHeaderHeight] = React.useState(headerHeight)
|
const bottomBarOffset = useBottomBarOffset(200)
|
||||||
const bottomBarOffset = useBottomBarOffset(20)
|
const initialNumToRender = useInitialNumToRender()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const {data, refetch, isError} = useListMembersQuery(listUri, 50)
|
const {data, refetch, isError} = useAllListMembersQuery(listUri)
|
||||||
|
|
||||||
const [isPTRing, setIsPTRing] = React.useState(false)
|
const [isPTRing, setIsPTRing] = React.useState(false)
|
||||||
|
|
||||||
// The server returns these sorted by descending creation date, so we want to invert
|
// The server returns these sorted by descending creation date, so we want to invert
|
||||||
const profiles = data?.pages
|
|
||||||
.flatMap(p => p.items.map(i => i.subject))
|
const profiles = data
|
||||||
.filter(p => !isBlockedOrBlocking(p) && !p.associated?.labeler)
|
?.filter(
|
||||||
|
p => !isBlockedOrBlocking(p.subject) && !p.subject.associated?.labeler,
|
||||||
|
)
|
||||||
|
.map(p => p.subject)
|
||||||
.reverse()
|
.reverse()
|
||||||
const isOwn = new AtUri(listUri).host === currentAccount?.did
|
const isOwn = new AtUri(listUri).host === currentAccount?.did
|
||||||
|
|
||||||
|
@ -99,7 +103,11 @@ export const ProfilesList = React.forwardRef<SectionRef, ProfilesListProps>(
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return (
|
return (
|
||||||
<View style={{marginTop: headerHeight, marginBottom: bottomBarOffset}}>
|
<View
|
||||||
|
style={[
|
||||||
|
a.h_full_vh,
|
||||||
|
{marginTop: headerHeight, marginBottom: bottomBarOffset},
|
||||||
|
]}>
|
||||||
<ListMaybePlaceholder
|
<ListMaybePlaceholder
|
||||||
isLoading={true}
|
isLoading={true}
|
||||||
isError={isError}
|
isError={isError}
|
||||||
|
@ -118,10 +126,13 @@ export const ProfilesList = React.forwardRef<SectionRef, ProfilesListProps>(
|
||||||
ref={scrollElRef}
|
ref={scrollElRef}
|
||||||
headerOffset={headerHeight}
|
headerOffset={headerHeight}
|
||||||
ListFooterComponent={
|
ListFooterComponent={
|
||||||
<View style={[{height: initialHeaderHeight + bottomBarOffset}]} />
|
<ListFooter
|
||||||
|
style={{paddingBottom: bottomBarOffset, borderTopWidth: 0}}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
desktopFixedHeight
|
desktopFixedHeight
|
||||||
|
initialNumToRender={initialNumToRender}
|
||||||
refreshing={isPTRing}
|
refreshing={isPTRing}
|
||||||
onRefresh={async () => {
|
onRefresh={async () => {
|
||||||
setIsPTRing(true)
|
setIsPTRing(true)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {BottomSheetFlatListMethods} from '@discord/bottom-sheet'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
|
||||||
import {isWeb} from 'platform/detection'
|
import {isWeb} from 'platform/detection'
|
||||||
import {useSession} from 'state/session'
|
import {useSession} from 'state/session'
|
||||||
import {WizardAction, WizardState} from '#/screens/StarterPack/Wizard/State'
|
import {WizardAction, WizardState} from '#/screens/StarterPack/Wizard/State'
|
||||||
|
@ -42,6 +43,7 @@ export function WizardEditListDialog({
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
|
const initialNumToRender = useInitialNumToRender()
|
||||||
|
|
||||||
const listRef = useRef<BottomSheetFlatListMethods>(null)
|
const listRef = useRef<BottomSheetFlatListMethods>(null)
|
||||||
|
|
||||||
|
@ -148,6 +150,7 @@ export function WizardEditListDialog({
|
||||||
webInnerStyle={[a.py_0, {maxWidth: 500, minWidth: 200}]}
|
webInnerStyle={[a.py_0, {maxWidth: 500, minWidth: 200}]}
|
||||||
keyboardDismissMode="on-drag"
|
keyboardDismissMode="on-drag"
|
||||||
removeClippedSubviews={true}
|
removeClippedSubviews={true}
|
||||||
|
initialNumToRender={initialNumToRender}
|
||||||
/>
|
/>
|
||||||
</Dialog.Outer>
|
</Dialog.Outer>
|
||||||
)
|
)
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {GeneratorView} from '@atproto/api/dist/client/types/app/bsky/feed/defs'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {DISCOVER_FEED_URI} from 'lib/constants'
|
import {DISCOVER_FEED_URI, STARTER_PACK_MAX_SIZE} from 'lib/constants'
|
||||||
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||||
import {sanitizeHandle} from 'lib/strings/handles'
|
import {sanitizeHandle} from 'lib/strings/handles'
|
||||||
import {useSession} from 'state/session'
|
import {useSession} from 'state/session'
|
||||||
|
@ -130,7 +130,8 @@ export function WizardProfileCard({
|
||||||
|
|
||||||
const isMe = profile.did === currentAccount?.did
|
const isMe = profile.did === currentAccount?.did
|
||||||
const included = isMe || state.profiles.some(p => p.did === profile.did)
|
const included = isMe || state.profiles.some(p => p.did === profile.did)
|
||||||
const disabled = isMe || (!included && state.profiles.length >= 49)
|
const disabled =
|
||||||
|
isMe || (!included && state.profiles.length >= STARTER_PACK_MAX_SIZE - 1)
|
||||||
const moderationUi = moderateProfile(profile, moderationOpts).ui('avatar')
|
const moderationUi = moderateProfile(profile, moderationOpts).ui('avatar')
|
||||||
const displayName = profile.displayName
|
const displayName = profile.displayName
|
||||||
? sanitizeDisplayName(profile.displayName)
|
? sanitizeDisplayName(profile.displayName)
|
||||||
|
|
|
@ -12,6 +12,7 @@ export const HELP_DESK_URL = `https://blueskyweb.zendesk.com/hc/${HELP_DESK_LANG
|
||||||
export const EMBED_SERVICE = 'https://embed.bsky.app'
|
export const EMBED_SERVICE = 'https://embed.bsky.app'
|
||||||
export const EMBED_SCRIPT = `${EMBED_SERVICE}/static/embed.js`
|
export const EMBED_SCRIPT = `${EMBED_SERVICE}/static/embed.js`
|
||||||
export const BSKY_DOWNLOAD_URL = 'https://bsky.app/download'
|
export const BSKY_DOWNLOAD_URL = 'https://bsky.app/download'
|
||||||
|
export const STARTER_PACK_MAX_SIZE = 150
|
||||||
|
|
||||||
// HACK
|
// HACK
|
||||||
// Yes, this is exactly what it looks like. It's a hard-coded constant
|
// Yes, this is exactly what it looks like. It's a hard-coded constant
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {useProgressGuideControls} from '#/state/shell/progress-guide'
|
||||||
import {uploadBlob} from 'lib/api'
|
import {uploadBlob} from 'lib/api'
|
||||||
import {useRequestNotificationsPermission} from 'lib/notifications/notifications'
|
import {useRequestNotificationsPermission} from 'lib/notifications/notifications'
|
||||||
import {useSetHasCheckedForStarterPack} from 'state/preferences/used-starter-packs'
|
import {useSetHasCheckedForStarterPack} from 'state/preferences/used-starter-packs'
|
||||||
|
import {getAllListMembers} from 'state/queries/list-members'
|
||||||
import {
|
import {
|
||||||
useActiveStarterPack,
|
useActiveStarterPack,
|
||||||
useSetActiveStarterPack,
|
useSetActiveStarterPack,
|
||||||
|
@ -73,18 +74,20 @@ export function StepFinished() {
|
||||||
starterPack: activeStarterPack.uri,
|
starterPack: activeStarterPack.uri,
|
||||||
})
|
})
|
||||||
starterPack = spRes.data.starterPack
|
starterPack = spRes.data.starterPack
|
||||||
|
|
||||||
if (starterPack.list) {
|
|
||||||
const listRes = await agent.app.bsky.graph.getList({
|
|
||||||
list: starterPack.list.uri,
|
|
||||||
limit: 50,
|
|
||||||
})
|
|
||||||
listItems = listRes.data.items
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('Failed to fetch starter pack', {safeMessage: e})
|
logger.error('Failed to fetch starter pack', {safeMessage: e})
|
||||||
// don't tell the user, just get them through onboarding.
|
// don't tell the user, just get them through onboarding.
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
if (starterPack?.list) {
|
||||||
|
listItems = await getAllListMembers(agent, starterPack.list.uri)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('Failed to fetch starter pack list items', {
|
||||||
|
safeMessage: e,
|
||||||
|
})
|
||||||
|
// don't tell the user, just get them through onboarding.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {
|
||||||
BskyAgent,
|
BskyAgent,
|
||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
import {TID} from '@atproto/common-web'
|
import {TID} from '@atproto/common-web'
|
||||||
|
import chunk from 'lodash.chunk'
|
||||||
|
|
||||||
import {until} from '#/lib/async/until'
|
import {until} from '#/lib/async/until'
|
||||||
|
|
||||||
|
@ -29,10 +30,13 @@ export async function bulkWriteFollows(agent: BskyAgent, dids: string[]) {
|
||||||
value: r,
|
value: r,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
const chunks = chunk(followWrites, 50)
|
||||||
|
for (const chunk of chunks) {
|
||||||
await agent.com.atproto.repo.applyWrites({
|
await agent.com.atproto.repo.applyWrites({
|
||||||
repo: session.did,
|
repo: session.did,
|
||||||
writes: followWrites,
|
writes: chunk,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
await whenFollowsIndexed(agent, session.did, res => !!res.data.follows.length)
|
await whenFollowsIndexed(agent, session.did, res => !!res.data.follows.length)
|
||||||
|
|
||||||
const followUris = new Map()
|
const followUris = new Map()
|
||||||
|
|
|
@ -32,6 +32,7 @@ import {getStarterPackOgCard} from 'lib/strings/starter-pack'
|
||||||
import {isWeb} from 'platform/detection'
|
import {isWeb} from 'platform/detection'
|
||||||
import {updateProfileShadow} from 'state/cache/profile-shadow'
|
import {updateProfileShadow} from 'state/cache/profile-shadow'
|
||||||
import {useModerationOpts} from 'state/preferences/moderation-opts'
|
import {useModerationOpts} from 'state/preferences/moderation-opts'
|
||||||
|
import {getAllListMembers} from 'state/queries/list-members'
|
||||||
import {useResolvedStarterPackShortLink} from 'state/queries/resolve-short-link'
|
import {useResolvedStarterPackShortLink} from 'state/queries/resolve-short-link'
|
||||||
import {useResolveDidQuery} from 'state/queries/resolve-uri'
|
import {useResolveDidQuery} from 'state/queries/resolve-uri'
|
||||||
import {useShortenLink} from 'state/queries/shorten-link'
|
import {useShortenLink} from 'state/queries/shorten-link'
|
||||||
|
@ -327,11 +328,19 @@ function Header({
|
||||||
|
|
||||||
setIsProcessing(true)
|
setIsProcessing(true)
|
||||||
|
|
||||||
|
let listItems: AppBskyGraphDefs.ListItemView[] = []
|
||||||
try {
|
try {
|
||||||
const list = await agent.app.bsky.graph.getList({
|
listItems = await getAllListMembers(agent, starterPack.list.uri)
|
||||||
list: starterPack.list.uri,
|
} catch (e) {
|
||||||
|
setIsProcessing(false)
|
||||||
|
Toast.show(_(msg`An error occurred while trying to follow all`), 'xmark')
|
||||||
|
logger.error('Failed to get list members for starter pack', {
|
||||||
|
safeMessage: e,
|
||||||
})
|
})
|
||||||
const dids = list.data.items
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const dids = listItems
|
||||||
.filter(
|
.filter(
|
||||||
li =>
|
li =>
|
||||||
li.subject.did !== currentAccount?.did &&
|
li.subject.did !== currentAccount?.did &&
|
||||||
|
@ -341,8 +350,16 @@ function Header({
|
||||||
)
|
)
|
||||||
.map(li => li.subject.did)
|
.map(li => li.subject.did)
|
||||||
|
|
||||||
const followUris = await bulkWriteFollows(agent, dids)
|
let followUris: Map<string, string>
|
||||||
|
try {
|
||||||
|
followUris = await bulkWriteFollows(agent, dids)
|
||||||
|
} catch (e) {
|
||||||
|
setIsProcessing(false)
|
||||||
|
Toast.show(_(msg`An error occurred while trying to follow all`), 'xmark')
|
||||||
|
logger.error('Failed to follow all accounts', {safeMessage: e})
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsProcessing(false)
|
||||||
batchedUpdates(() => {
|
batchedUpdates(() => {
|
||||||
for (let did of dids) {
|
for (let did of dids) {
|
||||||
updateProfileShadow(queryClient, did, {
|
updateProfileShadow(queryClient, did, {
|
||||||
|
@ -350,19 +367,13 @@ function Header({
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
Toast.show(_(msg`All accounts have been followed!`))
|
||||||
|
captureAction(ProgressGuideAction.Follow, dids.length)
|
||||||
logEvent('starterPack:followAll', {
|
logEvent('starterPack:followAll', {
|
||||||
logContext: 'StarterPackProfilesList',
|
logContext: 'StarterPackProfilesList',
|
||||||
starterPack: starterPack.uri,
|
starterPack: starterPack.uri,
|
||||||
count: dids.length,
|
count: dids.length,
|
||||||
})
|
})
|
||||||
captureAction(ProgressGuideAction.Follow, dids.length)
|
|
||||||
Toast.show(_(msg`All accounts have been followed!`))
|
|
||||||
} catch (e) {
|
|
||||||
Toast.show(_(msg`An error occurred while trying to follow all`), 'xmark')
|
|
||||||
} finally {
|
|
||||||
setIsProcessing(false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!AppBskyGraphStarterpack.isRecord(record)) {
|
if (!AppBskyGraphStarterpack.isRecord(record)) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
import {GeneratorView} from '@atproto/api/dist/client/types/app/bsky/feed/defs'
|
import {GeneratorView} from '@atproto/api/dist/client/types/app/bsky/feed/defs'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
|
|
||||||
|
import {STARTER_PACK_MAX_SIZE} from 'lib/constants'
|
||||||
import {useSession} from 'state/session'
|
import {useSession} from 'state/session'
|
||||||
import * as Toast from '#/view/com/util/Toast'
|
import * as Toast from '#/view/com/util/Toast'
|
||||||
|
|
||||||
|
@ -73,9 +74,10 @@ function reducer(state: State, action: Action): State {
|
||||||
updatedState = {...state, description: action.description}
|
updatedState = {...state, description: action.description}
|
||||||
break
|
break
|
||||||
case 'AddProfile':
|
case 'AddProfile':
|
||||||
if (state.profiles.length >= 51) {
|
if (state.profiles.length > STARTER_PACK_MAX_SIZE) {
|
||||||
Toast.show(
|
Toast.show(
|
||||||
msg`You may only add up to 50 profiles`.message ?? '',
|
msg`You may only add up to ${STARTER_PACK_MAX_SIZE} profiles`
|
||||||
|
.message ?? '',
|
||||||
'info',
|
'info',
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -91,8 +93,8 @@ function reducer(state: State, action: Action): State {
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'AddFeed':
|
case 'AddFeed':
|
||||||
if (state.feeds.length >= 50) {
|
if (state.feeds.length >= 3) {
|
||||||
Toast.show(msg`You may only add up to 50 feeds`.message ?? '', 'info')
|
Toast.show(msg`You may only add up to 3 feeds`.message ?? '', 'info')
|
||||||
} else {
|
} else {
|
||||||
updatedState = {...state, feeds: [...state.feeds, action.feed]}
|
updatedState = {...state, feeds: [...state.feeds, action.feed]}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import {useFocusEffect, useNavigation} from '@react-navigation/native'
|
||||||
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {HITSLOP_10} from 'lib/constants'
|
import {HITSLOP_10, STARTER_PACK_MAX_SIZE} from 'lib/constants'
|
||||||
import {createSanitizedDisplayName} from 'lib/moderation/create-sanitized-display-name'
|
import {createSanitizedDisplayName} from 'lib/moderation/create-sanitized-display-name'
|
||||||
import {CommonNavigatorParams, NavigationProp} from 'lib/routes/types'
|
import {CommonNavigatorParams, NavigationProp} from 'lib/routes/types'
|
||||||
import {logEvent} from 'lib/statsig/statsig'
|
import {logEvent} from 'lib/statsig/statsig'
|
||||||
|
@ -33,7 +33,7 @@ import {
|
||||||
} from 'lib/strings/starter-pack'
|
} from 'lib/strings/starter-pack'
|
||||||
import {isAndroid, isNative, isWeb} from 'platform/detection'
|
import {isAndroid, isNative, isWeb} from 'platform/detection'
|
||||||
import {useModerationOpts} from 'state/preferences/moderation-opts'
|
import {useModerationOpts} from 'state/preferences/moderation-opts'
|
||||||
import {useListMembersQuery} from 'state/queries/list-members'
|
import {useAllListMembersQuery} from 'state/queries/list-members'
|
||||||
import {useProfileQuery} from 'state/queries/profile'
|
import {useProfileQuery} from 'state/queries/profile'
|
||||||
import {
|
import {
|
||||||
useCreateStarterPackMutation,
|
useCreateStarterPackMutation,
|
||||||
|
@ -78,11 +78,10 @@ export function Wizard({
|
||||||
const listUri = starterPack?.list?.uri
|
const listUri = starterPack?.list?.uri
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: profilesData,
|
data: listItems,
|
||||||
isLoading: isLoadingProfiles,
|
isLoading: isLoadingProfiles,
|
||||||
isError: isErrorProfiles,
|
isError: isErrorProfiles,
|
||||||
} = useListMembersQuery(listUri, 50)
|
} = useAllListMembersQuery(listUri)
|
||||||
const listItems = profilesData?.pages.flatMap(p => p.items)
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: profile,
|
data: profile,
|
||||||
|
@ -428,7 +427,8 @@ function Footer({
|
||||||
{items.length > minimumItems && (
|
{items.length > minimumItems && (
|
||||||
<View style={[a.absolute, {right: 14, top: 31}]}>
|
<View style={[a.absolute, {right: 14, top: 31}]}>
|
||||||
<Text style={[a.font_bold]}>
|
<Text style={[a.font_bold]}>
|
||||||
{items.length}/{state.currentStep === 'Profiles' ? 50 : 3}
|
{items.length}/
|
||||||
|
{state.currentStep === 'Profiles' ? STARTER_PACK_MAX_SIZE : 3}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
import {AppBskyActorDefs, AppBskyGraphGetList} from '@atproto/api'
|
import {
|
||||||
|
AppBskyActorDefs,
|
||||||
|
AppBskyGraphDefs,
|
||||||
|
AppBskyGraphGetList,
|
||||||
|
BskyAgent,
|
||||||
|
} from '@atproto/api'
|
||||||
import {
|
import {
|
||||||
InfiniteData,
|
InfiniteData,
|
||||||
QueryClient,
|
QueryClient,
|
||||||
QueryKey,
|
QueryKey,
|
||||||
useInfiniteQuery,
|
useInfiniteQuery,
|
||||||
|
useQuery,
|
||||||
} from '@tanstack/react-query'
|
} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
|
@ -14,6 +20,7 @@ type RQPageParam = string | undefined
|
||||||
|
|
||||||
const RQKEY_ROOT = 'list-members'
|
const RQKEY_ROOT = 'list-members'
|
||||||
export const RQKEY = (uri: string) => [RQKEY_ROOT, uri]
|
export const RQKEY = (uri: string) => [RQKEY_ROOT, uri]
|
||||||
|
export const RQKEY_ALL = (uri: string) => [RQKEY_ROOT, uri, 'all']
|
||||||
|
|
||||||
export function useListMembersQuery(uri?: string, limit: number = PAGE_SIZE) {
|
export function useListMembersQuery(uri?: string, limit: number = PAGE_SIZE) {
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
|
@ -40,6 +47,38 @@ export function useListMembersQuery(uri?: string, limit: number = PAGE_SIZE) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useAllListMembersQuery(uri?: string) {
|
||||||
|
const agent = useAgent()
|
||||||
|
return useQuery({
|
||||||
|
staleTime: STALE.MINUTES.ONE,
|
||||||
|
queryKey: RQKEY_ALL(uri ?? ''),
|
||||||
|
queryFn: async () => {
|
||||||
|
return getAllListMembers(agent, uri!)
|
||||||
|
},
|
||||||
|
enabled: Boolean(uri),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getAllListMembers(agent: BskyAgent, uri: string) {
|
||||||
|
let hasMore = true
|
||||||
|
let cursor: string | undefined
|
||||||
|
const listItems: AppBskyGraphDefs.ListItemView[] = []
|
||||||
|
// We want to cap this at 6 pages, just for anything weird happening with the api
|
||||||
|
let i = 0
|
||||||
|
while (hasMore && i < 6) {
|
||||||
|
const res = await agent.app.bsky.graph.getList({
|
||||||
|
list: uri,
|
||||||
|
limit: 50,
|
||||||
|
cursor,
|
||||||
|
})
|
||||||
|
listItems.push(...res.data.items)
|
||||||
|
hasMore = Boolean(res.data.cursor)
|
||||||
|
cursor = res.data.cursor
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
return listItems
|
||||||
|
}
|
||||||
|
|
||||||
export async function invalidateListMembersQuery({
|
export async function invalidateListMembersQuery({
|
||||||
queryClient,
|
queryClient,
|
||||||
uri,
|
uri,
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
useQuery,
|
useQuery,
|
||||||
useQueryClient,
|
useQueryClient,
|
||||||
} from '@tanstack/react-query'
|
} from '@tanstack/react-query'
|
||||||
|
import chunk from 'lodash.chunk'
|
||||||
|
|
||||||
import {until} from 'lib/async/until'
|
import {until} from 'lib/async/until'
|
||||||
import {createStarterPackList} from 'lib/generate-starterpack'
|
import {createStarterPackList} from 'lib/generate-starterpack'
|
||||||
|
@ -200,26 +201,29 @@ export function useEditStarterPackMutation({
|
||||||
i.subject.did !== agent.session?.did &&
|
i.subject.did !== agent.session?.did &&
|
||||||
!profiles.find(p => p.did === i.subject.did && p.did),
|
!profiles.find(p => p.did === i.subject.did && p.did),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (removedItems.length !== 0) {
|
if (removedItems.length !== 0) {
|
||||||
|
const chunks = chunk(removedItems, 50)
|
||||||
|
for (const chunk of chunks) {
|
||||||
await agent.com.atproto.repo.applyWrites({
|
await agent.com.atproto.repo.applyWrites({
|
||||||
repo: agent.session!.did,
|
repo: agent.session!.did,
|
||||||
writes: removedItems.map(i => ({
|
writes: chunk.map(i => ({
|
||||||
$type: 'com.atproto.repo.applyWrites#delete',
|
$type: 'com.atproto.repo.applyWrites#delete',
|
||||||
collection: 'app.bsky.graph.listitem',
|
collection: 'app.bsky.graph.listitem',
|
||||||
rkey: new AtUri(i.uri).rkey,
|
rkey: new AtUri(i.uri).rkey,
|
||||||
})),
|
})),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const addedProfiles = profiles.filter(
|
const addedProfiles = profiles.filter(
|
||||||
p => !currentListItems.find(i => i.subject.did === p.did),
|
p => !currentListItems.find(i => i.subject.did === p.did),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (addedProfiles.length > 0) {
|
if (addedProfiles.length > 0) {
|
||||||
|
const chunks = chunk(addedProfiles, 50)
|
||||||
|
for (const chunk of chunks) {
|
||||||
await agent.com.atproto.repo.applyWrites({
|
await agent.com.atproto.repo.applyWrites({
|
||||||
repo: agent.session!.did,
|
repo: agent.session!.did,
|
||||||
writes: addedProfiles.map(p => ({
|
writes: chunk.map(p => ({
|
||||||
$type: 'com.atproto.repo.applyWrites#create',
|
$type: 'com.atproto.repo.applyWrites#create',
|
||||||
collection: 'app.bsky.graph.listitem',
|
collection: 'app.bsky.graph.listitem',
|
||||||
value: {
|
value: {
|
||||||
|
@ -231,6 +235,7 @@ export function useEditStarterPackMutation({
|
||||||
})),
|
})),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const rkey = parseStarterPackUri(currentStarterPack.uri)!.rkey
|
const rkey = parseStarterPackUri(currentStarterPack.uri)!.rkey
|
||||||
await agent.com.atproto.repo.putRecord({
|
await agent.com.atproto.repo.putRecord({
|
||||||
|
|
Loading…
Reference in New Issue