Add starter pack reference-list opt-out UI (#11578)
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
||||
useListBlockMutation,
|
||||
useListDeleteMutation,
|
||||
useListMuteMutation,
|
||||
useReferenceListOptOutMutation,
|
||||
} from '#/state/queries/list'
|
||||
import {useRemoveFeedMutation} from '#/state/queries/preferences'
|
||||
import {useSession} from '#/state/session'
|
||||
@@ -51,6 +52,7 @@ export function MoreOptionsMenu({
|
||||
const editListDialogControl = useDialogControl()
|
||||
const deleteListPromptControl = useDialogControl()
|
||||
const reportDialogControl = useReportDialogControl()
|
||||
const optOutDialogControl = useDialogControl()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
|
||||
const {mutateAsync: removeSavedFeed} = useRemoveFeedMutation()
|
||||
@@ -60,10 +62,36 @@ export function MoreOptionsMenu({
|
||||
|
||||
const isCurateList = list.purpose === app.bsky.graph.defs.curatelist.value
|
||||
const isModList = list.purpose === app.bsky.graph.defs.modlist.value
|
||||
const isReferenceList =
|
||||
list.purpose === app.bsky.graph.defs.referencelist.value
|
||||
const isBlocking = !!list.viewer?.blocked
|
||||
const isMuting = !!list.viewer?.muted
|
||||
const isPinned = Boolean(savedFeedConfig?.pinned)
|
||||
const isOwner = currentAccount?.did === list.creator.did
|
||||
const referenceListOptOut = list.viewer?.referenceListOptOut
|
||||
const {mutate: setReferenceListOptOut, isPending: isOptOutPending} =
|
||||
useReferenceListOptOutMutation({
|
||||
list,
|
||||
onSuccess: action => {
|
||||
ax.metric('starterPack:optOut', {
|
||||
starterPack: list.uri,
|
||||
action,
|
||||
})
|
||||
Toast.show(
|
||||
action === 'optOut'
|
||||
? _(msg`Opted out of starter pack`)
|
||||
: _(msg`Opt-out undone`),
|
||||
)
|
||||
},
|
||||
onError: error => {
|
||||
logger.error('Failed to update starter pack opt-out', {
|
||||
safeMessage: error,
|
||||
})
|
||||
Toast.show(_(msg`Failed to update starter pack opt-out`), {
|
||||
type: 'error',
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
const onPressShare = () => {
|
||||
const {rkey} = new AtUri(list.uri)
|
||||
@@ -206,16 +234,41 @@ export function MoreOptionsMenu({
|
||||
</Menu.Item>
|
||||
</Menu.Group>
|
||||
) : (
|
||||
<Menu.Group>
|
||||
<Menu.Item
|
||||
label={_(msg`Report list`)}
|
||||
onPress={reportDialogControl.open}>
|
||||
<Menu.ItemText>
|
||||
<Trans>Report list</Trans>
|
||||
</Menu.ItemText>
|
||||
<Menu.ItemIcon position="right" icon={WarningIcon} />
|
||||
</Menu.Item>
|
||||
</Menu.Group>
|
||||
<>
|
||||
<Menu.Group>
|
||||
<Menu.Item
|
||||
label={_(msg`Report list`)}
|
||||
onPress={reportDialogControl.open}>
|
||||
<Menu.ItemText>
|
||||
<Trans>Report list</Trans>
|
||||
</Menu.ItemText>
|
||||
<Menu.ItemIcon position="right" icon={WarningIcon} />
|
||||
</Menu.Item>
|
||||
</Menu.Group>
|
||||
{isReferenceList ? (
|
||||
<>
|
||||
<Menu.Divider />
|
||||
<Menu.Group>
|
||||
<Menu.Item
|
||||
label={
|
||||
referenceListOptOut
|
||||
? _(msg`Undo opt-out from starter pack`)
|
||||
: _(msg`Opt out of starter pack`)
|
||||
}
|
||||
disabled={isOptOutPending}
|
||||
onPress={optOutDialogControl.open}>
|
||||
<Menu.ItemText>
|
||||
{referenceListOptOut ? (
|
||||
<Trans>Undo opt-out</Trans>
|
||||
) : (
|
||||
<Trans>Opt out of starter pack</Trans>
|
||||
)}
|
||||
</Menu.ItemText>
|
||||
</Menu.Item>
|
||||
</Menu.Group>
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
|
||||
{isModList && isPinned && (
|
||||
@@ -277,6 +330,46 @@ export function MoreOptionsMenu({
|
||||
confirmButtonColor="negative"
|
||||
/>
|
||||
|
||||
{isReferenceList ? (
|
||||
<Prompt.Outer control={optOutDialogControl}>
|
||||
<Prompt.TitleText>
|
||||
{referenceListOptOut ? (
|
||||
<Trans>Undo opt-out?</Trans>
|
||||
) : (
|
||||
<Trans>Opt out of this starter pack?</Trans>
|
||||
)}
|
||||
</Prompt.TitleText>
|
||||
<Prompt.DescriptionText>
|
||||
{referenceListOptOut ? (
|
||||
<Trans>
|
||||
You will be eligible to appear in this starter pack again.
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans>
|
||||
You will no longer appear in this starter pack. The creator will
|
||||
be able to see that you've opted out and remove you if they
|
||||
wish.
|
||||
</Trans>
|
||||
)}
|
||||
</Prompt.DescriptionText>
|
||||
<Prompt.Actions>
|
||||
<Prompt.Action
|
||||
cta={
|
||||
referenceListOptOut
|
||||
? _(msg`Undo opt-out`)
|
||||
: _(msg`Opt out of starter pack`)
|
||||
}
|
||||
color={referenceListOptOut ? 'primary' : 'negative'}
|
||||
disabled={isOptOutPending}
|
||||
onPress={() => {
|
||||
setReferenceListOptOut({referenceListOptOut})
|
||||
}}
|
||||
/>
|
||||
<Prompt.Cancel />
|
||||
</Prompt.Actions>
|
||||
</Prompt.Outer>
|
||||
) : null}
|
||||
|
||||
<ReportDialog
|
||||
control={reportDialogControl}
|
||||
subject={{
|
||||
|
||||
@@ -30,6 +30,7 @@ import {useResolveDidQuery} from '#/state/queries/resolve-uri'
|
||||
import {useShortenLink} from '#/state/queries/shorten-link'
|
||||
import {
|
||||
useDeleteStarterPackMutation,
|
||||
useReferenceListOptOutMutation,
|
||||
useStarterPackQuery,
|
||||
} from '#/state/queries/starter-packs'
|
||||
import {useAppviewClient, usePdsClient, useSession} from '#/state/session'
|
||||
@@ -523,6 +524,7 @@ function OverflowMenu({
|
||||
const reportDialogControl = useReportDialogControl()
|
||||
const deleteDialogControl = useDialogControl()
|
||||
const convertToListDialogControl = useDialogControl()
|
||||
const optOutDialogControl = useDialogControl()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
|
||||
const {
|
||||
@@ -546,6 +548,30 @@ function OverflowMenu({
|
||||
})
|
||||
|
||||
const isOwn = starterPack.creator.did === currentAccount?.did
|
||||
const referenceListOptOut = starterPack.list?.viewer?.referenceListOptOut
|
||||
const {mutate: setReferenceListOptOut, isPending: isOptOutPending} =
|
||||
useReferenceListOptOutMutation({
|
||||
starterPack,
|
||||
onSuccess: action => {
|
||||
ax.metric('starterPack:optOut', {
|
||||
starterPack: starterPack.uri,
|
||||
action,
|
||||
})
|
||||
Toast.show(
|
||||
action === 'optOut'
|
||||
? _(msg`Opted out of starter pack`)
|
||||
: _(msg`Opt-out undone`),
|
||||
)
|
||||
},
|
||||
onError: error => {
|
||||
logger.error('Failed to update starter pack opt-out', {
|
||||
safeMessage: error,
|
||||
})
|
||||
Toast.show(_(msg`Failed to update starter pack opt-out`), {
|
||||
type: 'error',
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
const onDeleteStarterPack = async () => {
|
||||
if (!starterPack.list) {
|
||||
@@ -650,6 +676,24 @@ function OverflowMenu({
|
||||
</Menu.ItemText>
|
||||
<Menu.ItemIcon icon={CircleInfo} position="right" />
|
||||
</Menu.Item>
|
||||
{starterPack.list ? (
|
||||
<Menu.Item
|
||||
label={
|
||||
referenceListOptOut
|
||||
? _(msg`Undo opt-out from starter pack`)
|
||||
: _(msg`Opt out of starter pack`)
|
||||
}
|
||||
disabled={isOptOutPending}
|
||||
onPress={() => optOutDialogControl.open()}>
|
||||
<Menu.ItemText>
|
||||
{referenceListOptOut ? (
|
||||
<Trans>Undo opt-out</Trans>
|
||||
) : (
|
||||
<Trans>Opt out of starter pack</Trans>
|
||||
)}
|
||||
</Menu.ItemText>
|
||||
</Menu.Item>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</Menu.Outer>
|
||||
@@ -709,6 +753,58 @@ function OverflowMenu({
|
||||
</Prompt.Actions>
|
||||
</Prompt.Outer>
|
||||
|
||||
{starterPack.list ? (
|
||||
<Prompt.Outer control={optOutDialogControl}>
|
||||
<Prompt.TitleText>
|
||||
{referenceListOptOut ? (
|
||||
<Trans>Undo opt-out?</Trans>
|
||||
) : (
|
||||
<Trans>Opt out of this starter pack?</Trans>
|
||||
)}
|
||||
</Prompt.TitleText>
|
||||
<Prompt.DescriptionText>
|
||||
{referenceListOptOut ? (
|
||||
<Trans>
|
||||
You will be eligible to appear in this starter pack again.
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans>
|
||||
You will no longer appear in this starter pack. The creator will
|
||||
be able to see that you've opted out and remove you if they
|
||||
wish.
|
||||
</Trans>
|
||||
)}
|
||||
</Prompt.DescriptionText>
|
||||
<Prompt.Actions>
|
||||
<Button
|
||||
variant="solid"
|
||||
color={referenceListOptOut ? 'primary' : 'negative'}
|
||||
size="large"
|
||||
label={
|
||||
referenceListOptOut
|
||||
? _(msg`Undo opt-out`)
|
||||
: _(msg`Opt out of starter pack`)
|
||||
}
|
||||
disabled={isOptOutPending}
|
||||
onPress={() => {
|
||||
optOutDialogControl.close(() => {
|
||||
setReferenceListOptOut({referenceListOptOut})
|
||||
})
|
||||
}}>
|
||||
<ButtonText>
|
||||
{referenceListOptOut ? (
|
||||
<Trans>Undo opt-out</Trans>
|
||||
) : (
|
||||
<Trans>Opt out</Trans>
|
||||
)}
|
||||
</ButtonText>
|
||||
{isOptOutPending && <ButtonIcon icon={Loader} />}
|
||||
</Button>
|
||||
<Prompt.Cancel />
|
||||
</Prompt.Actions>
|
||||
</Prompt.Outer>
|
||||
) : null}
|
||||
|
||||
<CreateListFromStarterPackDialog
|
||||
control={convertToListDialogControl}
|
||||
starterPack={starterPack}
|
||||
|
||||
@@ -138,7 +138,8 @@ export function Provider({
|
||||
currentStep: 'Details',
|
||||
name: starterPack.record.name,
|
||||
description: starterPack.record.description,
|
||||
profiles: listItems?.map(i => i.subject) ?? [],
|
||||
profiles:
|
||||
listItems?.filter(i => !i.subjectOptedOut).map(i => i.subject) ?? [],
|
||||
feeds: starterPack.feeds ?? [],
|
||||
processing: false,
|
||||
transitionDirection: 'Forward',
|
||||
|
||||
@@ -24,8 +24,10 @@ function keyExtractor(item: bsky.profile.AnyProfileView) {
|
||||
|
||||
export function StepProfiles({
|
||||
moderationOpts,
|
||||
optedOutDids,
|
||||
}: {
|
||||
moderationOpts: ModerationOpts
|
||||
optedOutDids: Set<string>
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const [state, dispatch] = useWizardState()
|
||||
@@ -59,6 +61,7 @@ export function StepProfiles({
|
||||
state={state}
|
||||
dispatch={dispatch}
|
||||
moderationOpts={moderationOpts}
|
||||
subjectOptedOut={optedOutDids.has(item.did)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -341,7 +341,16 @@ function WizardInner({
|
||||
{state.currentStep === 'Details' ? (
|
||||
<StepDetails />
|
||||
) : state.currentStep === 'Profiles' ? (
|
||||
<StepProfiles moderationOpts={moderationOpts} />
|
||||
<StepProfiles
|
||||
moderationOpts={moderationOpts}
|
||||
optedOutDids={
|
||||
new Set(
|
||||
currentListItems
|
||||
?.filter(item => item.subjectOptedOut)
|
||||
.map(item => item.subject.did),
|
||||
)
|
||||
}
|
||||
/>
|
||||
) : state.currentStep === 'Feeds' ? (
|
||||
<StepFeeds moderationOpts={moderationOpts} />
|
||||
) : null}
|
||||
|
||||
Reference in New Issue
Block a user