Address starter pack opt-out review feedback
This commit is contained in:
@@ -703,6 +703,7 @@ export type Events = {
|
||||
}
|
||||
'starterPack:removeUser': {
|
||||
starterPack?: string
|
||||
context?: 'opt-out'
|
||||
}
|
||||
'starterPack:share': {
|
||||
starterPack: string
|
||||
|
||||
@@ -22,6 +22,7 @@ import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {Default as ProfileCard} from '#/components/ProfileCard'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE, IS_WEB} from '#/env'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
@@ -159,9 +160,14 @@ function OptedOutControls({
|
||||
canRemove: boolean
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const ax = useAnalytics()
|
||||
const [isRemoved, setIsRemoved] = useState(false)
|
||||
const {mutate: removeMembership, isPending} = useListMembershipRemoveMutation(
|
||||
{
|
||||
onSuccess: () => Toast.show(_(msg`Removed from starter pack`)),
|
||||
onSuccess: () => {
|
||||
setIsRemoved(true)
|
||||
Toast.show(_(msg`Removed from starter pack`))
|
||||
},
|
||||
onError: error =>
|
||||
Toast.show(cleanError(error), {
|
||||
type: 'error',
|
||||
@@ -169,6 +175,8 @@ function OptedOutControls({
|
||||
},
|
||||
)
|
||||
|
||||
if (isRemoved) return null
|
||||
|
||||
return (
|
||||
<Admonition.Outer type="info" style={[a.mt_sm]}>
|
||||
<Admonition.Row style={[a.align_center]}>
|
||||
@@ -183,13 +191,14 @@ function OptedOutControls({
|
||||
label={_(msg`Remove user from starter pack`)}
|
||||
color="secondary"
|
||||
disabled={isPending}
|
||||
onPress={() =>
|
||||
onPress={() => {
|
||||
ax.metric('starterPack:removeUser', {context: 'opt-out'})
|
||||
removeMembership({
|
||||
listUri,
|
||||
actorDid: item.subject.did,
|
||||
membershipUri: item.uri,
|
||||
})
|
||||
}>
|
||||
}}>
|
||||
{isPending ? (
|
||||
<ButtonIcon icon={Loader} />
|
||||
) : (
|
||||
|
||||
@@ -36,6 +36,7 @@ function WizardListCard({
|
||||
avatar,
|
||||
included,
|
||||
disabled,
|
||||
subjectOptedOut,
|
||||
moderationUi,
|
||||
}: {
|
||||
type: 'user' | 'algo'
|
||||
@@ -48,6 +49,7 @@ function WizardListCard({
|
||||
avatar?: string
|
||||
included?: boolean
|
||||
disabled?: boolean
|
||||
subjectOptedOut?: boolean
|
||||
moderationUi: ModerationUI
|
||||
}) {
|
||||
const t = useTheme()
|
||||
@@ -97,6 +99,11 @@ function WizardListCard({
|
||||
numberOfLines={1}>
|
||||
{subtitle}
|
||||
</Text>
|
||||
{subjectOptedOut ? (
|
||||
<Text style={[a.text_sm, t.atoms.text_contrast_medium]}>
|
||||
<Trans>Opted out</Trans>
|
||||
</Text>
|
||||
) : null}
|
||||
</View>
|
||||
{btnType === 'checkbox' ? (
|
||||
<Checkbox />
|
||||
@@ -123,12 +130,14 @@ export function WizardProfileCard({
|
||||
dispatch,
|
||||
profile,
|
||||
moderationOpts,
|
||||
subjectOptedOut = false,
|
||||
}: {
|
||||
btnType: 'checkbox' | 'remove'
|
||||
state: WizardState
|
||||
dispatch: (action: WizardAction) => void
|
||||
profile: bsky.profile.AnyProfileView
|
||||
moderationOpts: ModerationOpts
|
||||
subjectOptedOut?: boolean
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
const {currentAccount} = useSession()
|
||||
@@ -138,7 +147,9 @@ export function WizardProfileCard({
|
||||
const isTarget = profile.did === targetProfileDid
|
||||
const included = isTarget || state.profiles.some(p => p.did === profile.did)
|
||||
const disabled =
|
||||
isTarget || (!included && state.profiles.length >= STARTER_PACK_MAX_SIZE)
|
||||
subjectOptedOut ||
|
||||
isTarget ||
|
||||
(!included && state.profiles.length >= STARTER_PACK_MAX_SIZE)
|
||||
const moderationUi = moderateProfile(profile, moderationOpts).ui('avatar')
|
||||
const displayName = profile.displayName
|
||||
? sanitizeDisplayName(profile.displayName)
|
||||
@@ -169,6 +180,7 @@ export function WizardProfileCard({
|
||||
avatar={profile.avatar}
|
||||
included={included}
|
||||
disabled={disabled}
|
||||
subjectOptedOut={subjectOptedOut}
|
||||
moderationUi={moderationUi}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -557,6 +557,11 @@ function OverflowMenu({
|
||||
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', {
|
||||
|
||||
@@ -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