From 29aaf09a8b8b199b249cef9123673022fde11c4f Mon Sep 17 00:00:00 2001
From: Samuel Newman <mozzius@protonmail.com>
Date: Mon, 24 Jun 2024 23:15:11 +0100
Subject: 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>
---
 src/components/WhoCanReply.tsx | 150 ++++++++++++++++++++++-------------------
 1 file changed, 82 insertions(+), 68 deletions(-)

(limited to 'src/components/WhoCanReply.tsx')

diff --git a/src/components/WhoCanReply.tsx b/src/components/WhoCanReply.tsx
index cd171a0a4..a73aae850 100644
--- a/src/components/WhoCanReply.tsx
+++ b/src/components/WhoCanReply.tsx
@@ -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,
-- 
cgit 1.4.1

