Composer - replace threadgate modal with alf dialog (#4329)
* replace threadgate modal with alf dialog * add accessibility to selectable * add aria * hide spinner once fetched * add `hasOpenDialogs` value to context * remove state * Rm loading state * Update the threadgate dialog button theming * Factor out the threadgate editor and add editing to post views * Mark messages for localization * Use colors from mute dialog * Remove unnecessary effect * Reset state on dialog dismiss * Clearer CTA * Fix bugs * Scope keyboard fix * Rm getAreDialogsActive (no longer needed) --------- Co-authored-by: Dan Abramov <dan.abramov@gmail.com> Co-authored-by: Paul Frazee <pfrazee@gmail.com>
This commit is contained in:
@@ -17,7 +17,6 @@ import {HITSLOP_10} from '#/lib/constants'
|
||||
import {makeListLink, makeProfileLink} from '#/lib/routes/links'
|
||||
import {logger} from '#/logger'
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {useModalControls} from '#/state/modals'
|
||||
import {RQKEY_ROOT as POST_THREAD_RQKEY_ROOT} from '#/state/queries/post-thread'
|
||||
import {
|
||||
ThreadgateSetting,
|
||||
@@ -34,6 +33,7 @@ import {Earth_Stroke2_Corner0_Rounded as Earth} from '#/components/icons/Globe'
|
||||
import {Group3_Stroke2_Corner0_Rounded as Group} from '#/components/icons/Group'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {TextLink} from '../view/com/util/Link'
|
||||
import {ThreadgateEditorDialog} from './dialogs/ThreadgateEditor'
|
||||
import {PencilLine_Stroke2_Corner0_Rounded as PencilLine} from './icons/Pencil'
|
||||
|
||||
interface WhoCanReplyProps {
|
||||
@@ -46,7 +46,15 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
const infoDialogControl = useDialogControl()
|
||||
const {settings, isRootPost, onPressEdit} = useWhoCanReply(post)
|
||||
const editDialogControl = useDialogControl()
|
||||
const agent = useAgent()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const settings = React.useMemo(
|
||||
() => threadgateViewToSettings(post.threadgate),
|
||||
[post],
|
||||
)
|
||||
const isRootPost = !('reply' in post.record)
|
||||
|
||||
if (!isRootPost) {
|
||||
return null
|
||||
@@ -63,6 +71,55 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
|
||||
? _(msg`Replies disabled`)
|
||||
: _(msg`Some people can reply`)
|
||||
|
||||
const onPressEdit = () => {
|
||||
if (isNative && Keyboard.isVisible()) {
|
||||
Keyboard.dismiss()
|
||||
}
|
||||
if (isThreadAuthor) {
|
||||
editDialogControl.open()
|
||||
} else {
|
||||
infoDialogControl.open()
|
||||
}
|
||||
}
|
||||
|
||||
const onEditConfirm = async (newSettings: ThreadgateSetting[]) => {
|
||||
if (JSON.stringify(settings) === JSON.stringify(newSettings)) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
if (newSettings.length) {
|
||||
await createThreadgate(agent, post.uri, newSettings)
|
||||
} else {
|
||||
await agent.api.com.atproto.repo.deleteRecord({
|
||||
repo: agent.session!.did,
|
||||
collection: 'app.bsky.feed.threadgate',
|
||||
rkey: new AtUri(post.uri).rkey,
|
||||
})
|
||||
}
|
||||
await whenAppViewReady(agent, post.uri, res => {
|
||||
const thread = res.data.thread
|
||||
if (AppBskyFeedDefs.isThreadViewPost(thread)) {
|
||||
const fetchedSettings = threadgateViewToSettings(
|
||||
thread.post.threadgate,
|
||||
)
|
||||
return JSON.stringify(fetchedSettings) === JSON.stringify(newSettings)
|
||||
}
|
||||
return false
|
||||
})
|
||||
Toast.show(_(msg`Thread settings updated`))
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [POST_THREAD_RQKEY_ROOT],
|
||||
})
|
||||
} catch (err) {
|
||||
Toast.show(
|
||||
_(
|
||||
msg`There was an issue. Please check your internet connection and try again.`,
|
||||
),
|
||||
)
|
||||
logger.error('Failed to edit threadgate', {message: err})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
@@ -93,7 +150,18 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
|
||||
</View>
|
||||
)}
|
||||
</Button>
|
||||
<WhoCanReplyDialog control={infoDialogControl} post={post} />
|
||||
<WhoCanReplyDialog
|
||||
control={infoDialogControl}
|
||||
post={post}
|
||||
settings={settings}
|
||||
/>
|
||||
{isThreadAuthor && (
|
||||
<ThreadgateEditorDialog
|
||||
control={editDialogControl}
|
||||
threadgate={settings}
|
||||
onConfirm={onEditConfirm}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -113,24 +181,31 @@ function Icon({
|
||||
return <IconComponent fill={color} width={width} />
|
||||
}
|
||||
|
||||
export function WhoCanReplyDialog({
|
||||
function WhoCanReplyDialog({
|
||||
control,
|
||||
post,
|
||||
settings,
|
||||
}: {
|
||||
control: Dialog.DialogControlProps
|
||||
post: AppBskyFeedDefs.PostView
|
||||
settings: ThreadgateSetting[]
|
||||
}) {
|
||||
return (
|
||||
<Dialog.Outer control={control}>
|
||||
<Dialog.Handle />
|
||||
<WhoCanReplyDialogInner post={post} />
|
||||
<WhoCanReplyDialogInner post={post} settings={settings} />
|
||||
</Dialog.Outer>
|
||||
)
|
||||
}
|
||||
|
||||
function WhoCanReplyDialogInner({post}: {post: AppBskyFeedDefs.PostView}) {
|
||||
function WhoCanReplyDialogInner({
|
||||
post,
|
||||
settings,
|
||||
}: {
|
||||
post: AppBskyFeedDefs.PostView
|
||||
settings: ThreadgateSetting[]
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const {settings} = useWhoCanReply(post)
|
||||
return (
|
||||
<Dialog.ScrollableInner
|
||||
label={_(msg`Who can reply dialog`)}
|
||||
@@ -245,67 +320,6 @@ function Separator({i, length}: {i: number; length: number}) {
|
||||
return <>, </>
|
||||
}
|
||||
|
||||
function useWhoCanReply(post: AppBskyFeedDefs.PostView) {
|
||||
const agent = useAgent()
|
||||
const queryClient = useQueryClient()
|
||||
const {openModal} = useModalControls()
|
||||
|
||||
const settings = React.useMemo(
|
||||
() => threadgateViewToSettings(post.threadgate),
|
||||
[post],
|
||||
)
|
||||
const isRootPost = !('reply' in post.record)
|
||||
|
||||
const onPressEdit = () => {
|
||||
if (isNative && Keyboard.isVisible()) {
|
||||
Keyboard.dismiss()
|
||||
}
|
||||
openModal({
|
||||
name: 'threadgate',
|
||||
settings,
|
||||
async onConfirm(newSettings: ThreadgateSetting[]) {
|
||||
if (JSON.stringify(settings) === JSON.stringify(newSettings)) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
if (newSettings.length) {
|
||||
await createThreadgate(agent, post.uri, newSettings)
|
||||
} else {
|
||||
await agent.api.com.atproto.repo.deleteRecord({
|
||||
repo: agent.session!.did,
|
||||
collection: 'app.bsky.feed.threadgate',
|
||||
rkey: new AtUri(post.uri).rkey,
|
||||
})
|
||||
}
|
||||
await whenAppViewReady(agent, post.uri, res => {
|
||||
const thread = res.data.thread
|
||||
if (AppBskyFeedDefs.isThreadViewPost(thread)) {
|
||||
const fetchedSettings = threadgateViewToSettings(
|
||||
thread.post.threadgate,
|
||||
)
|
||||
return (
|
||||
JSON.stringify(fetchedSettings) === JSON.stringify(newSettings)
|
||||
)
|
||||
}
|
||||
return false
|
||||
})
|
||||
Toast.show('Thread settings updated')
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [POST_THREAD_RQKEY_ROOT],
|
||||
})
|
||||
} catch (err) {
|
||||
Toast.show(
|
||||
'There was an issue. Please check your internet connection and try again.',
|
||||
)
|
||||
logger.error('Failed to edit threadgate', {message: err})
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return {settings, isRootPost, onPressEdit}
|
||||
}
|
||||
|
||||
async function whenAppViewReady(
|
||||
agent: BskyAgent,
|
||||
uri: string,
|
||||
|
||||
Reference in New Issue
Block a user