diff --git a/src/screens/StarterPack/StarterPackScreen.tsx b/src/screens/StarterPack/StarterPackScreen.tsx index c8e524c7c1..5158996750 100644 --- a/src/screens/StarterPack/StarterPackScreen.tsx +++ b/src/screens/StarterPack/StarterPackScreen.tsx @@ -1,5 +1,5 @@ import React from 'react' -import {Pressable, View} from 'react-native' +import {View} from 'react-native' import {AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {msg, Trans} from '@lingui/macro' @@ -8,6 +8,7 @@ import {useNavigation} from '@react-navigation/native' import {NativeStackScreenProps} from '@react-navigation/native-stack' import {useQueryClient} from '@tanstack/react-query' +import {useDeleteStarterPackMutation} from '#/state/queries/starter-packs' import {HITSLOP_20} from 'lib/constants' import {makeProfileLink, makeStarterPackLink} from 'lib/routes/links' import {CommonNavigatorParams, NavigationProp} from 'lib/routes/types' @@ -23,25 +24,31 @@ import {PagerWithHeader} from 'view/com/pager/PagerWithHeader' import {ProfileSubpageHeader} from 'view/com/profile/ProfileSubpageHeader' import {CenteredView} from 'view/com/util/Views' import {bulkWriteFollows} from '#/screens/Onboarding/util' -import {atoms as a, useTheme} from '#/alf' -import {Button, ButtonText} from '#/components/Button' -import {DialogControlProps, useDialogControl} from '#/components/Dialog' +import {atoms as a, useBreakpoints, useTheme} from '#/alf' +import {Button, ButtonIcon, ButtonText} from '#/components/Button' +import {useDialogControl} from '#/components/Dialog' import {ArrowOutOfBox_Stroke2_Corner0_Rounded as ArrowOutOfBox} from '#/components/icons/ArrowOutOfBox' import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' import {DotGrid_Stroke2_Corner0_Rounded as Ellipsis} from '#/components/icons/DotGrid' +import {Pencil_Stroke2_Corner0_Rounded as Pencil} from '#/components/icons/Pencil' import {QrCode_Stroke2_Corner0_Rounded as QrCode} from '#/components/icons/QrCode' +import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash' import {ListMaybePlaceholder} from '#/components/Lists' import {Loader} from '#/components/Loader' import * as Menu from '#/components/Menu' +import * as Prompt from '#/components/Prompt' import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog' import {FeedsList} from '#/components/StarterPack/Main/FeedsList' import {ProfilesList} from '#/components/StarterPack/Main/ProfilesList' import {QrCodeDialog} from '#/components/StarterPack/QrCodeDialog' import {Text} from '#/components/Typography' -export function StarterPackScreen({ - route, -}: NativeStackScreenProps) { +type StarterPackScreeProps = NativeStackScreenProps< + CommonNavigatorParams, + 'StarterPack' +> + +export function StarterPackScreen({route}: StarterPackScreeProps) { const {_} = useLingui() const {name, rkey} = route.params @@ -83,7 +90,7 @@ export function StarterPackScreen({ items={tabs} isHeaderReady={true} renderHeader={() => ( -
+
)}> {starterPack.list != null ? ({headerHeight, scrollElRef}) => ( @@ -117,12 +124,10 @@ export function StarterPackScreen({ function Header({ starterPack, - name, - rkey, + routeParams, }: { starterPack: AppBskyGraphDefs.StarterPackView - name: string - rkey: string + routeParams: StarterPackScreeProps['route']['params'] }) { const {_} = useLingui() const t = useTheme() @@ -130,8 +135,6 @@ function Header({ const {currentAccount} = useSession() const agent = useAgent() const queryClient = useQueryClient() - const qrCodeDialogControl = useDialogControl() - const reportDialogControl = useReportDialogControl() const [isProcessing, setIsProcessing] = React.useState(false) @@ -191,7 +194,9 @@ function Header({ variant="solid" color="secondary" size="small" - onPress={() => navigation.navigate('StarterPackEdit', {rkey})}> + onPress={() => + navigation.navigate('StarterPackEdit', {rkey: routeParams.rkey}) + }> Edit @@ -210,13 +215,7 @@ function Header({ )} - + {record.description || joinedAllTimeCount >= 25 ? ( @@ -244,6 +243,136 @@ function Header({ ) : null} ) : null} + + ) +} + +function OverflowMenu({ + starterPack, + routeParams, +}: { + starterPack: AppBskyGraphDefs.StarterPackView + routeParams: StarterPackScreeProps['route']['params'] +}) { + const {_} = useLingui() + const {gtMobile} = useBreakpoints() + const {currentAccount} = useSession() + const qrCodeDialogControl = useDialogControl() + const reportDialogControl = useReportDialogControl() + const deleteDialogControl = useDialogControl() + const navigation = useNavigation() + const { + mutateAsync: deleteStarterPack, + isPending: isDeletePending, + error: deleteError, + } = useDeleteStarterPackMutation() + + const isOwn = starterPack.creator.did === currentAccount?.did + + const onDeleteStarterPack = async () => { + await deleteStarterPack({ + rkey: routeParams.rkey, + // TODO need to fix types + listUri: starterPack.list!.uri, + }) + + logEvent('starterPack:delete', {}) + + deleteDialogControl.close(() => { + navigation.popToTop() + }) + } + + return ( + <> + + + {({props}) => ( + + )} + + + {isOwn ? ( + <> + { + navigation.navigate('StarterPackEdit', { + rkey: routeParams.rkey, + }) + }}> + + Edit + + + + { + deleteDialogControl.open() + }}> + + Delete + + + + + ) : ( + <> + + { + logEvent('starterPack:share', { + starterPack: starterPack.uri, + shareType: 'link', + }) + shareUrl( + makeStarterPackLink(routeParams.name, routeParams.rkey), + ) + }}> + + Share link + + + + + + Create QR code + + + + + + + + Report starter pack + + + + + )} + + + + + + + Delete starter pack? + + + Are you sure you want delete this starter pack? + + + + + + + {deleteError && ( + + {deleteError.toString()} + + )} + ) } - -function Dropdown({ - name, - rkey, - starterPack, - qrCodeDialogControl, - reportDialogControl, -}: { - name: string - rkey: string - starterPack: AppBskyGraphDefs.StarterPackView - qrCodeDialogControl: DialogControlProps - reportDialogControl: DialogControlProps -}) { - const {_} = useLingui() - const t = useTheme() - const {currentAccount} = useSession() - - const isOwn = starterPack.creator.did === currentAccount?.did - - return ( - - - {({props, state}) => ( - <> - {isOwn ? ( - - - Share - - - ) : ( - - - - )} - - )} - - - - { - logEvent('starterPack:share', { - starterPack: starterPack.uri, - shareType: 'link', - }) - shareUrl(makeStarterPackLink(name, rkey)) - }}> - - Share link - - - - - - Create QR code - - - - - {!isOwn && ( - - - Report starter pack - - - - )} - - - ) -} diff --git a/src/state/queries/starter-packs.ts b/src/state/queries/starter-packs.ts new file mode 100644 index 0000000000..02fa94099b --- /dev/null +++ b/src/state/queries/starter-packs.ts @@ -0,0 +1,42 @@ +import {AtUri} from '@atproto/api' +import {useMutation, useQueryClient} from '@tanstack/react-query' + +import {useAgent} from '#/state/session' +import {invalidateActorStarterPacksQuery} from 'state/queries/actor-starter-packs' +import {invalidateListMembersQuery} from 'state/queries/list-members' +import {invalidateStarterPack} from 'state/queries/useStarterPackQuery' + +export function useDeleteStarterPackMutation() { + const agent = useAgent() + const queryClient = useQueryClient() + + return useMutation({ + mutationFn: async ({listUri, rkey}: {listUri: string; rkey: string}) => { + if (!agent.session) { + throw new Error(`Requires logged in user`) + } + + // TODO parallel? + await agent.app.bsky.graph.list.delete({ + repo: agent.session.did, + rkey: new AtUri(listUri).rkey, + }) + await agent.app.bsky.graph.starterpack.delete({ + repo: agent.session.did, + rkey, + }) + }, + onSuccess: async (_, {listUri, rkey}) => { + await invalidateListMembersQuery({queryClient, uri: listUri}) + await invalidateActorStarterPacksQuery({ + queryClient, + did: agent.session!.did, + }) + await invalidateStarterPack({ + queryClient, + did: agent.session!.did, + rkey, + }) + }, + }) +}