Refactor useActorStatus, add disablement and appeal dialog
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
import {useCallback, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {type AppBskyActorDefs, ToolsOzoneReportDefs} from '@atproto/api'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useMutation} from '@tanstack/react-query'
|
||||
|
||||
import {BLUESKY_MOD_SERVICE_HEADERS} from '#/lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {useAgent} from '#/state/session'
|
||||
import {atoms as a, web} from '#/alf'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
export function GoLiveDisabledDialog({
|
||||
control,
|
||||
status,
|
||||
}: {
|
||||
control: Dialog.DialogControlProps
|
||||
status: AppBskyActorDefs.StatusView
|
||||
}) {
|
||||
return (
|
||||
<Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
|
||||
<Dialog.Handle />
|
||||
<DialogInner control={control} status={status} />
|
||||
</Dialog.Outer>
|
||||
)
|
||||
}
|
||||
|
||||
export function DialogInner({
|
||||
control,
|
||||
status,
|
||||
}: {
|
||||
control: Dialog.DialogControlProps
|
||||
status: AppBskyActorDefs.StatusView
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const agent = useAgent()
|
||||
const [details, setDetails] = useState('')
|
||||
|
||||
const {mutate, isPending} = useMutation({
|
||||
mutationFn: async () => {
|
||||
if (!agent.session?.did) {
|
||||
throw new Error('Not logged in')
|
||||
}
|
||||
|
||||
if (__DEV__) {
|
||||
logger.info('Submitting go live appeal', {
|
||||
details,
|
||||
})
|
||||
} else {
|
||||
await agent.createModerationReport(
|
||||
{
|
||||
reasonType: ToolsOzoneReportDefs.REASONAPPEAL,
|
||||
subject: {
|
||||
$type: 'com.atproto.repo.strongRef',
|
||||
uri: status.uri!,
|
||||
cid: status.cid!,
|
||||
},
|
||||
reason: details,
|
||||
},
|
||||
{
|
||||
encoding: 'application/json',
|
||||
headers: BLUESKY_MOD_SERVICE_HEADERS,
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
Toast.show(_(msg`Failed to submit appeal, please try again.`), {
|
||||
type: 'error',
|
||||
})
|
||||
},
|
||||
onSuccess: () => {
|
||||
control.close()
|
||||
Toast.show(_(msg({message: 'Appeal submitted', context: 'toast'})), {
|
||||
type: 'success',
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
const onSubmit = useCallback(() => mutate(), [mutate])
|
||||
|
||||
return (
|
||||
<Dialog.ScrollableInner
|
||||
label={_(msg`Appeal livestream suspension`)}
|
||||
style={[web({maxWidth: 400})]}>
|
||||
<View style={[a.gap_lg]}>
|
||||
<View style={[a.gap_md]}>
|
||||
<Text
|
||||
style={[
|
||||
a.flex_1,
|
||||
a.text_2xl,
|
||||
a.font_semi_bold,
|
||||
a.leading_snug,
|
||||
a.pr_4xl,
|
||||
]}>
|
||||
<Trans>Going live is currently disabled for your account</Trans>
|
||||
</Text>
|
||||
<Text style={[a.text_md, a.leading_snug]}>
|
||||
<Trans>
|
||||
You are currently blocked from using the Go Live feature. To
|
||||
appeal this moderation decision, please submit the form below.
|
||||
</Trans>
|
||||
</Text>
|
||||
<Text style={[a.text_md, a.leading_snug]}>
|
||||
<Trans>
|
||||
This appeal will be sent to Bluesky's moderation service.
|
||||
</Trans>
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={[a.gap_md]}>
|
||||
<Dialog.Input
|
||||
label={_(msg`Text input field`)}
|
||||
placeholder={_(
|
||||
msg`Please explain why you think your Go Live access was incorrectly disabled.`,
|
||||
)}
|
||||
value={details}
|
||||
onChangeText={setDetails}
|
||||
autoFocus={true}
|
||||
numberOfLines={3}
|
||||
multiline
|
||||
maxLength={300}
|
||||
/>
|
||||
<Button
|
||||
testID="submitBtn"
|
||||
variant="solid"
|
||||
color="primary"
|
||||
size="large"
|
||||
onPress={onSubmit}
|
||||
label={_(msg`Submit`)}>
|
||||
<ButtonText>{_(msg`Submit`)}</ButtonText>
|
||||
{isPending && <ButtonIcon icon={Loader} />}
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
<Dialog.Close />
|
||||
</Dialog.ScrollableInner>
|
||||
)
|
||||
}
|
||||
+21
-8
@@ -19,15 +19,27 @@ export function useActorStatus(actor?: bsky.profile.AnyProfileView) {
|
||||
return useMemo(() => {
|
||||
tick! // revalidate every minute
|
||||
|
||||
if (
|
||||
shadowed &&
|
||||
'status' in shadowed &&
|
||||
shadowed.status &&
|
||||
validateStatus(shadowed.did, shadowed.status, config) &&
|
||||
isStatusStillActive(shadowed.status.expiresAt)
|
||||
) {
|
||||
if (shadowed && 'status' in shadowed && shadowed.status) {
|
||||
const isValid = validateStatus(shadowed.did, shadowed.status, config)
|
||||
const isDisabled = shadowed.status.isDisabled || false
|
||||
const isActive = isStatusStillActive(shadowed.status.expiresAt)
|
||||
if (isValid && !isDisabled && isActive) {
|
||||
return {
|
||||
uri: shadowed.status.uri,
|
||||
cid: shadowed.status.cid,
|
||||
isDisabled: false,
|
||||
isActive: true,
|
||||
status: 'app.bsky.actor.status#live',
|
||||
embed: shadowed.status.embed as $Typed<AppBskyEmbedExternal.View>, // temp_isStatusValid asserts this
|
||||
expiresAt: shadowed.status.expiresAt!, // isStatusStillActive asserts this
|
||||
record: shadowed.status.record,
|
||||
} satisfies AppBskyActorDefs.StatusView
|
||||
}
|
||||
return {
|
||||
isActive: true,
|
||||
uri: shadowed.status.uri,
|
||||
cid: shadowed.status.cid,
|
||||
isDisabled,
|
||||
isActive: false,
|
||||
status: 'app.bsky.actor.status#live',
|
||||
embed: shadowed.status.embed as $Typed<AppBskyEmbedExternal.View>, // temp_isStatusValid asserts this
|
||||
expiresAt: shadowed.status.expiresAt!, // isStatusStillActive asserts this
|
||||
@@ -36,6 +48,7 @@ export function useActorStatus(actor?: bsky.profile.AnyProfileView) {
|
||||
} else {
|
||||
return {
|
||||
status: '',
|
||||
isDisabled: false,
|
||||
isActive: false,
|
||||
record: {},
|
||||
} satisfies AppBskyActorDefs.StatusView
|
||||
|
||||
@@ -49,6 +49,7 @@ import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/
|
||||
import {StarterPack} from '#/components/icons/StarterPack'
|
||||
import {EditLiveDialog} from '#/components/live/EditLiveDialog'
|
||||
import {GoLiveDialog} from '#/components/live/GoLiveDialog'
|
||||
import {GoLiveDisabledDialog} from '#/components/live/GoLiveDisabledDialog'
|
||||
import * as Menu from '#/components/Menu'
|
||||
import {
|
||||
ReportDialog,
|
||||
@@ -79,6 +80,7 @@ let ProfileMenu = ({
|
||||
const [devModeEnabled] = useDevMode()
|
||||
const verification = useFullVerificationState({profile})
|
||||
const canGoLive = useCanGoLive(currentAccount?.did)
|
||||
const status = useActorStatus(profile)
|
||||
|
||||
const [queueMute, queueUnmute] = useProfileMuteMutationQueue(profile)
|
||||
const [queueBlock, queueUnblock] = useProfileBlockMutationQueue(profile)
|
||||
@@ -90,6 +92,7 @@ let ProfileMenu = ({
|
||||
const blockPromptControl = Prompt.usePromptControl()
|
||||
const loggedOutWarningPromptControl = Prompt.usePromptControl()
|
||||
const goLiveDialogControl = useDialogControl()
|
||||
const goLiveDisabledDialogControl = useDialogControl()
|
||||
const addToStarterPacksDialogControl = useDialogControl()
|
||||
|
||||
const showLoggedOutWarning = React.useMemo(() => {
|
||||
@@ -220,8 +223,6 @@ let ProfileMenu = ({
|
||||
return v.issuer === currentAccount?.did
|
||||
}) ?? []
|
||||
|
||||
const status = useActorStatus(profile)
|
||||
|
||||
return (
|
||||
<EventStopper onKeyDown={false}>
|
||||
<Menu.Root>
|
||||
@@ -330,13 +331,21 @@ let ProfileMenu = ({
|
||||
<Menu.Item
|
||||
testID="profileHeaderDropdownListAddRemoveBtn"
|
||||
label={
|
||||
status.isActive
|
||||
? _(msg`Edit live status`)
|
||||
: _(msg`Go live`)
|
||||
status.isDisabled
|
||||
? _(msg`Go live is disabled`)
|
||||
: status.isActive
|
||||
? _(msg`Edit live status`)
|
||||
: _(msg`Go live`)
|
||||
}
|
||||
onPress={goLiveDialogControl.open}>
|
||||
onPress={
|
||||
status.isDisabled
|
||||
? goLiveDisabledDialogControl.open
|
||||
: goLiveDialogControl.open
|
||||
}>
|
||||
<Menu.ItemText>
|
||||
{status.isActive ? (
|
||||
{status.isDisabled ? (
|
||||
<Trans>Go live is disabled</Trans>
|
||||
) : status.isActive ? (
|
||||
<Trans>Edit live status</Trans>
|
||||
) : (
|
||||
<Trans>Go live</Trans>
|
||||
@@ -517,7 +526,12 @@ let ProfileMenu = ({
|
||||
verifications={currentAccountVerifications}
|
||||
/>
|
||||
|
||||
{status.isActive ? (
|
||||
{status.isDisabled ? (
|
||||
<GoLiveDisabledDialog
|
||||
control={goLiveDisabledDialogControl}
|
||||
status={status}
|
||||
/>
|
||||
) : status.isActive ? (
|
||||
<EditLiveDialog
|
||||
control={goLiveDialogControl}
|
||||
status={status}
|
||||
|
||||
Reference in New Issue
Block a user