finish editing
This commit is contained in:
@@ -116,11 +116,11 @@ function reducer(state: State, action: Action): State {
|
|||||||
// TODO supply the initial state to this component
|
// TODO supply the initial state to this component
|
||||||
export function Provider({
|
export function Provider({
|
||||||
starterPack,
|
starterPack,
|
||||||
profiles,
|
listItems,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
starterPack?: AppBskyGraphDefs.StarterPackView
|
starterPack?: AppBskyGraphDefs.StarterPackView
|
||||||
profiles?: AppBskyActorDefs.ProfileViewBasic[]
|
listItems?: AppBskyGraphDefs.ListItemView[]
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
}) {
|
}) {
|
||||||
const createInitialState = (): State => {
|
const createInitialState = (): State => {
|
||||||
@@ -130,7 +130,7 @@ export function Provider({
|
|||||||
currentStep: 'Details',
|
currentStep: 'Details',
|
||||||
name: starterPack.record.name,
|
name: starterPack.record.name,
|
||||||
description: starterPack.record.description,
|
description: starterPack.record.description,
|
||||||
profiles: profiles ?? [],
|
profiles: listItems?.map(i => i.subject) ?? [],
|
||||||
feeds: starterPack.feeds ?? [],
|
feeds: starterPack.feeds ?? [],
|
||||||
processing: false,
|
processing: false,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,35 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {Keyboard, TouchableOpacity, View} from 'react-native'
|
import {Keyboard, TouchableOpacity, View} from 'react-native'
|
||||||
import {KeyboardAwareScrollView} from 'react-native-keyboard-controller'
|
import {KeyboardAwareScrollView} from 'react-native-keyboard-controller'
|
||||||
import {AppBskyActorDefs, AtUri} from '@atproto/api'
|
import {
|
||||||
|
AppBskyActorDefs,
|
||||||
|
AppBskyGraphDefs,
|
||||||
|
AppBskyGraphStarterpack,
|
||||||
|
AtUri,
|
||||||
|
} from '@atproto/api'
|
||||||
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 {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {msg, Plural, Trans} from '@lingui/macro'
|
import {msg, Plural, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useFocusEffect, useNavigation} from '@react-navigation/native'
|
import {useFocusEffect, useNavigation} from '@react-navigation/native'
|
||||||
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||||
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {HITSLOP_10} from 'lib/constants'
|
import {HITSLOP_10} from 'lib/constants'
|
||||||
import {CommonNavigatorParams, NavigationProp} from 'lib/routes/types'
|
import {CommonNavigatorParams, NavigationProp} from 'lib/routes/types'
|
||||||
import {enforceLen} from 'lib/strings/helpers'
|
import {enforceLen} from 'lib/strings/helpers'
|
||||||
import {isAndroid, isNative, isWeb} from 'platform/detection'
|
import {isAndroid, isNative, isWeb} from 'platform/detection'
|
||||||
import {useListMembersQuery} from 'state/queries/list-members'
|
import {invalidateActorStarterPacksQuery} from 'state/queries/actor-starter-packs'
|
||||||
|
import {
|
||||||
|
invalidateListMembersQuery,
|
||||||
|
useListMembersQuery,
|
||||||
|
} from 'state/queries/list-members'
|
||||||
import {useProfileQuery} from 'state/queries/profile'
|
import {useProfileQuery} from 'state/queries/profile'
|
||||||
import {useResolveDidQuery} from 'state/queries/resolve-uri'
|
import {useResolveDidQuery} from 'state/queries/resolve-uri'
|
||||||
import {useStarterPackQuery} from 'state/queries/useStarterPackQuery'
|
import {
|
||||||
|
invalidateStarterPack,
|
||||||
|
useStarterPackQuery,
|
||||||
|
} from 'state/queries/useStarterPackQuery'
|
||||||
import {useAgent, useSession} from 'state/session'
|
import {useAgent, useSession} from 'state/session'
|
||||||
import {useSetMinimalShellMode} from 'state/shell'
|
import {useSetMinimalShellMode} from 'state/shell'
|
||||||
import {UserAvatar} from 'view/com/util/UserAvatar'
|
import {UserAvatar} from 'view/com/util/UserAvatar'
|
||||||
@@ -61,9 +74,13 @@ export function Wizard({
|
|||||||
isLoading: isLoadingProfiles,
|
isLoading: isLoadingProfiles,
|
||||||
isError: isErrorProfiles,
|
isError: isErrorProfiles,
|
||||||
} = useListMembersQuery(listUri, 51) // 51 because we also include the current user
|
} = useListMembersQuery(listUri, 51) // 51 because we also include the current user
|
||||||
const profiles = profilesData?.pages.flatMap(p => p.items.map(i => i.subject))
|
const listItems = profilesData?.pages.flatMap(p => p.items)
|
||||||
|
|
||||||
if (name && rkey && (!starterPack || (starterPack && listUri && !profiles))) {
|
if (
|
||||||
|
name &&
|
||||||
|
rkey &&
|
||||||
|
(!starterPack || (starterPack && listUri && !listItems))
|
||||||
|
) {
|
||||||
return (
|
return (
|
||||||
<ListMaybePlaceholder
|
<ListMaybePlaceholder
|
||||||
isLoading={isLoadingDid || isLoadingStarterPack || isLoadingProfiles}
|
isLoading={isLoadingDid || isLoadingStarterPack || isLoadingProfiles}
|
||||||
@@ -74,16 +91,39 @@ export function Wizard({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Provider starterPack={starterPack} profiles={profiles}>
|
<Provider starterPack={starterPack} listItems={listItems}>
|
||||||
<WizardInner />
|
<WizardInner
|
||||||
|
did={did}
|
||||||
|
rkey={rkey}
|
||||||
|
createdAt={
|
||||||
|
AppBskyGraphStarterpack.isRecord(starterPack?.record)
|
||||||
|
? starterPack.record.createdAt
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
listItems={listItems}
|
||||||
|
listUri={listUri}
|
||||||
|
/>
|
||||||
</Provider>
|
</Provider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function WizardInner() {
|
function WizardInner({
|
||||||
|
did,
|
||||||
|
rkey,
|
||||||
|
createdAt: initialCreatedAt,
|
||||||
|
listUri: initialListUri,
|
||||||
|
listItems: initialListItems,
|
||||||
|
}: {
|
||||||
|
did?: string
|
||||||
|
rkey?: string
|
||||||
|
createdAt?: string
|
||||||
|
listUri?: string
|
||||||
|
listItems?: AppBskyGraphDefs.ListItemView[]
|
||||||
|
}) {
|
||||||
const navigation = useNavigation<NavigationProp>()
|
const navigation = useNavigation<NavigationProp>()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
|
const queryClient = useQueryClient()
|
||||||
const [state, dispatch] = useWizardState()
|
const [state, dispatch] = useWizardState()
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
@@ -131,63 +171,163 @@ function WizardInner() {
|
|||||||
|
|
||||||
const uiStrings = wizardUiStrings[state.currentStep]
|
const uiStrings = wizardUiStrings[state.currentStep]
|
||||||
|
|
||||||
|
const createList = async (): Promise<
|
||||||
|
{uri: string; cid: string} | undefined
|
||||||
|
> => {
|
||||||
|
if (state.profiles.length === 0) return
|
||||||
|
|
||||||
|
const list = await agent.app.bsky.graph.list.create(
|
||||||
|
{repo: currentAccount?.did},
|
||||||
|
{
|
||||||
|
name: state.name ?? '',
|
||||||
|
description: state.description ?? '',
|
||||||
|
descriptionFacets: [],
|
||||||
|
avatar: undefined,
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
purpose: 'app.bsky.graph.defs#referencelist',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if (!list) throw new Error('List creation failed')
|
||||||
|
await agent.com.atproto.repo.applyWrites({
|
||||||
|
repo: currentAccount!.did,
|
||||||
|
writes: state.profiles.map(p => ({
|
||||||
|
$type: 'com.atproto.repo.applyWrites#create',
|
||||||
|
collection: 'app.bsky.graph.listitem',
|
||||||
|
value: {
|
||||||
|
$type: 'app.bsky.graph.listitem',
|
||||||
|
subject: p.did,
|
||||||
|
list: list?.uri,
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
dispatch({type: 'SetProcessing', processing: true})
|
dispatch({type: 'SetProcessing', processing: true})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const list = await agent.app.bsky.graph.list.create(
|
if (did && rkey) {
|
||||||
{repo: currentAccount?.did},
|
// Editing an existing starter pack
|
||||||
{
|
let list: {uri: string; cid: string} | undefined = initialListUri
|
||||||
name: state.name ?? '',
|
? {uri: initialListUri, cid: ''}
|
||||||
description: state.description ?? '',
|
: undefined
|
||||||
descriptionFacets: [],
|
if (initialListUri) {
|
||||||
avatar: undefined,
|
const removedItems = initialListItems?.filter(
|
||||||
createdAt: new Date().toISOString(),
|
i => !state.profiles.find(p => p.did === i.subject.did),
|
||||||
purpose: 'app.bsky.graph.defs#referencelist',
|
)
|
||||||
},
|
if (removedItems && removedItems.length > 0) {
|
||||||
)
|
await agent.com.atproto.repo.applyWrites({
|
||||||
|
repo: currentAccount!.did,
|
||||||
|
writes: removedItems.map(i => ({
|
||||||
|
$type: 'com.atproto.repo.applyWrites#delete',
|
||||||
|
collection: 'app.bsky.graph.listitem',
|
||||||
|
rkey: new AtUri(i.uri).rkey,
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
await agent.com.atproto.repo.applyWrites({
|
const addedProfiles = state.profiles.filter(
|
||||||
repo: currentAccount!.did,
|
p => !initialListItems?.find(i => i.subject.did === p.did),
|
||||||
writes: state.profiles.map(p => ({
|
)
|
||||||
$type: 'com.atproto.repo.applyWrites#create',
|
|
||||||
collection: 'app.bsky.graph.listitem',
|
if (addedProfiles.length > 0) {
|
||||||
value: {
|
await agent.com.atproto.repo.applyWrites({
|
||||||
$type: 'app.bsky.graph.listitem',
|
repo: currentAccount!.did,
|
||||||
subject: p.did,
|
writes: addedProfiles.map(p => ({
|
||||||
list: list.uri,
|
$type: 'com.atproto.repo.applyWrites#create',
|
||||||
|
collection: 'app.bsky.graph.listitem',
|
||||||
|
value: {
|
||||||
|
$type: 'app.bsky.graph.listitem',
|
||||||
|
subject: p.did,
|
||||||
|
list: list?.uri,
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
list = await createList()
|
||||||
|
}
|
||||||
|
|
||||||
|
await agent.com.atproto.repo.putRecord({
|
||||||
|
repo: currentAccount!.did,
|
||||||
|
collection: 'app.bsky.graph.starterpack',
|
||||||
|
rkey,
|
||||||
|
record: {
|
||||||
|
name: state.name ?? '',
|
||||||
|
description: state.description ?? '',
|
||||||
|
descriptionFacets: [],
|
||||||
|
list: list?.uri,
|
||||||
|
feeds: state.feeds.map(f => ({
|
||||||
|
uri: f.uri,
|
||||||
|
})),
|
||||||
|
createdAt: initialCreatedAt,
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (initialListUri) {
|
||||||
|
await invalidateListMembersQuery({queryClient, uri: initialListUri})
|
||||||
|
}
|
||||||
|
await invalidateActorStarterPacksQuery({
|
||||||
|
queryClient,
|
||||||
|
did,
|
||||||
|
})
|
||||||
|
await invalidateStarterPack({
|
||||||
|
queryClient,
|
||||||
|
did,
|
||||||
|
rkey,
|
||||||
|
})
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (navigation.canGoBack()) {
|
||||||
|
navigation.goBack()
|
||||||
|
} else {
|
||||||
|
navigation.replace('StarterPack', {
|
||||||
|
name: currentAccount!.handle,
|
||||||
|
rkey,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
dispatch({type: 'SetProcessing', processing: false})
|
||||||
|
}, 1000)
|
||||||
|
} else {
|
||||||
|
// Creating a new starter pack
|
||||||
|
const list = await createList()
|
||||||
|
const res = await agent.app.bsky.graph.starterpack.create(
|
||||||
|
{
|
||||||
|
repo: currentAccount!.did,
|
||||||
|
validate: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: state.name ?? '',
|
||||||
|
description: state.description ?? '',
|
||||||
|
descriptionFacets: [],
|
||||||
|
list: list?.uri,
|
||||||
|
feeds: state.feeds.map(f => ({
|
||||||
|
uri: f.uri,
|
||||||
|
})),
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
},
|
},
|
||||||
})),
|
)
|
||||||
})
|
|
||||||
|
|
||||||
const res = await agent.app.bsky.graph.starterpack.create(
|
const newRkey = new AtUri(res.uri).rkey
|
||||||
{
|
|
||||||
repo: currentAccount!.did,
|
|
||||||
validate: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: state.name ?? '',
|
|
||||||
description: state.description ?? '',
|
|
||||||
descriptionFacets: [],
|
|
||||||
list: list.uri,
|
|
||||||
feeds: state.feeds.map(f => ({
|
|
||||||
uri: f.uri,
|
|
||||||
})),
|
|
||||||
createdAt: new Date().toISOString(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
const rkey = new AtUri(res.uri).rkey
|
// TODO hack?
|
||||||
|
setTimeout(() => {
|
||||||
// TODO hack?
|
navigation.replace('StarterPack', {
|
||||||
setTimeout(() => {
|
name: currentAccount!.handle,
|
||||||
navigation.replace('StarterPack', {name: currentAccount!.handle, rkey})
|
rkey: newRkey,
|
||||||
dispatch({type: 'SetProcessing', processing: false})
|
})
|
||||||
}, 1000)
|
dispatch({type: 'SetProcessing', processing: false})
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// TODO handle the error here
|
// TODO handle the error here
|
||||||
dispatch({type: 'SetProcessing', processing: false})
|
dispatch({type: 'SetProcessing', processing: false})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
import {AppBskyGraphGetActorStarterPacks} from '@atproto/api'
|
import {AppBskyGraphGetActorStarterPacks} from '@atproto/api'
|
||||||
import {InfiniteData, QueryKey, useInfiniteQuery} from '@tanstack/react-query'
|
import {
|
||||||
|
InfiniteData,
|
||||||
|
QueryClient,
|
||||||
|
QueryKey,
|
||||||
|
useInfiniteQuery,
|
||||||
|
} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {STALE} from 'state/queries/index'
|
|
||||||
import {useAgent} from 'state/session'
|
import {useAgent} from 'state/session'
|
||||||
|
|
||||||
const RQKEY_ROOT = 'actor-starter-packs'
|
const RQKEY_ROOT = 'actor-starter-packs'
|
||||||
|
const RQKEY = (did?: string) => [RQKEY_ROOT, did]
|
||||||
|
|
||||||
export function useActorStarterPacksQuery({did}: {did?: string}) {
|
export function useActorStarterPacksQuery({did}: {did?: string}) {
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
@@ -16,7 +21,7 @@ export function useActorStarterPacksQuery({did}: {did?: string}) {
|
|||||||
QueryKey,
|
QueryKey,
|
||||||
string | undefined
|
string | undefined
|
||||||
>({
|
>({
|
||||||
queryKey: [RQKEY_ROOT, did],
|
queryKey: RQKEY(did),
|
||||||
queryFn: async ({pageParam}: {pageParam?: string}) => {
|
queryFn: async ({pageParam}: {pageParam?: string}) => {
|
||||||
const res = await agent.app.bsky.graph.getActorStarterPacks({
|
const res = await agent.app.bsky.graph.getActorStarterPacks({
|
||||||
actor: did!,
|
actor: did!,
|
||||||
@@ -28,6 +33,15 @@ export function useActorStarterPacksQuery({did}: {did?: string}) {
|
|||||||
enabled: Boolean(did),
|
enabled: Boolean(did),
|
||||||
initialPageParam: undefined,
|
initialPageParam: undefined,
|
||||||
getNextPageParam: lastPage => lastPage.cursor,
|
getNextPageParam: lastPage => lastPage.cursor,
|
||||||
staleTime: STALE.MINUTES.ONE,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function invalidateActorStarterPacksQuery({
|
||||||
|
queryClient,
|
||||||
|
did,
|
||||||
|
}: {
|
||||||
|
queryClient: QueryClient
|
||||||
|
did: string
|
||||||
|
}) {
|
||||||
|
await queryClient.invalidateQueries({queryKey: RQKEY(did)})
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,6 +40,16 @@ export function useListMembersQuery(uri?: string, limit: number = PAGE_SIZE) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function invalidateListMembersQuery({
|
||||||
|
queryClient,
|
||||||
|
uri,
|
||||||
|
}: {
|
||||||
|
queryClient: QueryClient
|
||||||
|
uri: string
|
||||||
|
}) {
|
||||||
|
await queryClient.invalidateQueries({queryKey: RQKEY(uri)})
|
||||||
|
}
|
||||||
|
|
||||||
export function* findAllProfilesInQueryData(
|
export function* findAllProfilesInQueryData(
|
||||||
queryClient: QueryClient,
|
queryClient: QueryClient,
|
||||||
did: string,
|
did: string,
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import {StarterPackView} from '@atproto/api/dist/client/types/app/bsky/graph/defs'
|
import {StarterPackView} from '@atproto/api/dist/client/types/app/bsky/graph/defs'
|
||||||
import {useMutation, useQuery} from '@tanstack/react-query'
|
import {QueryClient, useMutation, useQuery} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {STALE} from 'state/queries/index'
|
|
||||||
import {useAgent, useSession} from 'state/session'
|
import {useAgent, useSession} from 'state/session'
|
||||||
|
|
||||||
const RQKEY_ROOT = 'starter-pack'
|
const RQKEY_ROOT = 'starter-pack'
|
||||||
|
const RQKEY = (did?: string, rkey?: string) => [RQKEY_ROOT, did, rkey]
|
||||||
|
|
||||||
export function useStarterPackQuery({
|
export function useStarterPackQuery({
|
||||||
did,
|
did,
|
||||||
@@ -17,7 +17,7 @@ export function useStarterPackQuery({
|
|||||||
const uri = `at://${did}/app.bsky.graph.starterpack/${rkey}`
|
const uri = `at://${did}/app.bsky.graph.starterpack/${rkey}`
|
||||||
|
|
||||||
return useQuery<StarterPackView>({
|
return useQuery<StarterPackView>({
|
||||||
queryKey: [RQKEY_ROOT, did, rkey],
|
queryKey: RQKEY(did, rkey),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const res = await agent.app.bsky.graph.getStarterPack({
|
const res = await agent.app.bsky.graph.getStarterPack({
|
||||||
starterPack: uri,
|
starterPack: uri,
|
||||||
@@ -25,7 +25,6 @@ export function useStarterPackQuery({
|
|||||||
return res.data.starterPack
|
return res.data.starterPack
|
||||||
},
|
},
|
||||||
enabled: Boolean(did) && Boolean(rkey),
|
enabled: Boolean(did) && Boolean(rkey),
|
||||||
staleTime: STALE.MINUTES.FIVE,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,13 +39,32 @@ export function useDeleteStarterPackMutation({
|
|||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: async (rkey: string) => {
|
mutationFn: async (rkey: string, listRkey?: string) => {
|
||||||
await agent.app.bsky.graph.starterpack.delete({
|
await agent.app.bsky.graph.starterpack.delete({
|
||||||
repo: currentAccount!.did,
|
repo: currentAccount!.did,
|
||||||
rkey,
|
rkey,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (listRkey) {
|
||||||
|
await agent.app.bsky.graph.list.delete({
|
||||||
|
repo: currentAccount!.did,
|
||||||
|
rkey: listRkey,
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onError,
|
onError,
|
||||||
onSuccess,
|
onSuccess,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function invalidateStarterPack({
|
||||||
|
queryClient,
|
||||||
|
did,
|
||||||
|
rkey,
|
||||||
|
}: {
|
||||||
|
queryClient: QueryClient
|
||||||
|
did: string
|
||||||
|
rkey: string
|
||||||
|
}) {
|
||||||
|
await queryClient.invalidateQueries({queryKey: RQKEY(did, rkey)})
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user