about summary refs log tree commit diff
path: root/src/components/dms
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/dms')
-rw-r--r--src/components/dms/BlockedByListDialog.tsx62
-rw-r--r--src/components/dms/ConvoMenu.tsx104
-rw-r--r--src/components/dms/LeaveConvoPrompt.tsx55
-rw-r--r--src/components/dms/MessageItem.tsx2
-rw-r--r--src/components/dms/MessagesListBlockedFooter.tsx131
-rw-r--r--src/components/dms/MessagesListHeader.tsx194
-rw-r--r--src/components/dms/ReportConversationPrompt.tsx27
7 files changed, 489 insertions, 86 deletions
diff --git a/src/components/dms/BlockedByListDialog.tsx b/src/components/dms/BlockedByListDialog.tsx
new file mode 100644
index 000000000..a27701605
--- /dev/null
+++ b/src/components/dms/BlockedByListDialog.tsx
@@ -0,0 +1,62 @@
+import React from 'react'
+import {View} from 'react-native'
+import {ModerationCause} from '@atproto/api'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {listUriToHref} from 'lib/strings/url-helpers'
+import {atoms as a, useTheme} from '#/alf'
+import * as Dialog from '#/components/Dialog'
+import {DialogControlProps} from '#/components/Dialog'
+import {InlineLinkText} from '#/components/Link'
+import * as Prompt from '#/components/Prompt'
+import {Text} from '#/components/Typography'
+
+export function BlockedByListDialog({
+  control,
+  listBlocks,
+}: {
+  control: DialogControlProps
+  listBlocks: ModerationCause[]
+}) {
+  const {_} = useLingui()
+  const t = useTheme()
+
+  return (
+    <Prompt.Outer control={control} testID="blockedByListDialog">
+      <Prompt.TitleText>{_(msg`User blocked by list`)}</Prompt.TitleText>
+
+      <View style={[a.gap_sm, a.pb_lg]}>
+        <Text
+          selectable
+          style={[a.text_md, a.leading_snug, t.atoms.text_contrast_high]}>
+          {_(
+            msg`This account is blocked by one or more of your moderation lists. To unblock, please visit the lists directly and remove this user.`,
+          )}{' '}
+        </Text>
+
+        <Text style={[a.text_md, a.leading_snug, t.atoms.text_contrast_high]}>
+          {_(msg`Lists blocking this user:`)}{' '}
+          {listBlocks.map((block, i) =>
+            block.source.type === 'list' ? (
+              <React.Fragment key={block.source.list.uri}>
+                {i === 0 ? null : ', '}
+                <InlineLinkText
+                  to={listUriToHref(block.source.list.uri)}
+                  style={[a.text_md, a.leading_snug]}>
+                  {block.source.list.name}
+                </InlineLinkText>
+              </React.Fragment>
+            ) : null,
+          )}
+        </Text>
+      </View>
+
+      <Prompt.Actions>
+        <Prompt.Action cta={_(msg`I understand`)} onPress={() => {}} />
+      </Prompt.Actions>
+
+      <Dialog.Close />
+    </Prompt.Outer>
+  )
+}
diff --git a/src/components/dms/ConvoMenu.tsx b/src/components/dms/ConvoMenu.tsx
index cf1dbc171..0e5cd12bf 100644
--- a/src/components/dms/ConvoMenu.tsx
+++ b/src/components/dms/ConvoMenu.tsx
@@ -3,25 +3,25 @@ import {Keyboard, Pressable, View} from 'react-native'
 import {
   AppBskyActorDefs,
   ChatBskyConvoDefs,
-  ModerationDecision,
+  ModerationCause,
 } from '@atproto/api'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 import {useNavigation} from '@react-navigation/native'
 
 import {NavigationProp} from '#/lib/routes/types'
-import {listUriToHref} from '#/lib/strings/url-helpers'
 import {Shadow} from '#/state/cache/types'
 import {
   useConvoQuery,
   useMarkAsReadMutation,
 } from '#/state/queries/messages/conversation'
-import {useLeaveConvo} from '#/state/queries/messages/leave-conversation'
 import {useMuteConvo} from '#/state/queries/messages/mute-conversation'
 import {useProfileBlockMutationQueue} from '#/state/queries/profile'
 import * as Toast from '#/view/com/util/Toast'
 import {atoms as a, useTheme} from '#/alf'
-import * as Dialog from '#/components/Dialog'
+import {BlockedByListDialog} from '#/components/dms/BlockedByListDialog'
+import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt'
+import {ReportConversationPrompt} from '#/components/dms/ReportConversationPrompt'
 import {ArrowBoxLeft_Stroke2_Corner0_Rounded as ArrowBoxLeft} from '#/components/icons/ArrowBoxLeft'
 import {DotGrid_Stroke2_Corner0_Rounded as DotsHorizontal} from '#/components/icons/DotGrid'
 import {Flag_Stroke2_Corner0_Rounded as Flag} from '#/components/icons/Flag'
@@ -30,10 +30,8 @@ import {Person_Stroke2_Corner0_Rounded as Person} from '#/components/icons/Perso
 import {PersonCheck_Stroke2_Corner0_Rounded as PersonCheck} from '#/components/icons/PersonCheck'
 import {PersonX_Stroke2_Corner0_Rounded as PersonX} from '#/components/icons/PersonX'
 import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/icons/Speaker'
-import {InlineLinkText} from '#/components/Link'
 import * as Menu from '#/components/Menu'
 import * as Prompt from '#/components/Prompt'
-import {Text} from '#/components/Typography'
 import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '../icons/Bubble'
 
 let ConvoMenu = ({
@@ -44,7 +42,7 @@ let ConvoMenu = ({
   showMarkAsRead,
   hideTrigger,
   triggerOpacity,
-  moderation,
+  blockInfo,
 }: {
   convo: ChatBskyConvoDefs.ConvoView
   profile: Shadow<AppBskyActorDefs.ProfileViewBasic>
@@ -53,7 +51,10 @@ let ConvoMenu = ({
   showMarkAsRead?: boolean
   hideTrigger?: boolean
   triggerOpacity?: number
-  moderation: ModerationDecision
+  blockInfo: {
+    listBlocks: ModerationCause[]
+    userBlock?: ModerationCause
+  }
 }): React.ReactNode => {
   const navigation = useNavigation<NavigationProp>()
   const {_} = useLingui()
@@ -62,17 +63,9 @@ let ConvoMenu = ({
   const reportControl = Prompt.usePromptControl()
   const blockedByListControl = Prompt.usePromptControl()
   const {mutate: markAsRead} = useMarkAsReadMutation()
-  const modui = moderation.ui('profileView')
-  const {listBlocks, userBlock} = React.useMemo(() => {
-    const blocks = modui.alerts.filter(alert => alert.type === 'blocking')
-    const listBlocks = blocks.filter(alert => alert.source.type === 'list')
-    const userBlock = blocks.find(alert => alert.source.type === 'user')
-    return {
-      listBlocks,
-      userBlock,
-    }
-  }, [modui])
-  const isBlocking = !!userBlock || !!listBlocks.length
+
+  const {listBlocks, userBlock} = blockInfo
+  const isBlocking = userBlock || !!listBlocks.length
 
   const {data: convo} = useConvoQuery(initialConvo)
 
@@ -108,17 +101,6 @@ let ConvoMenu = ({
     }
   }, [userBlock, listBlocks, blockedByListControl, queueBlock, queueUnblock])
 
-  const {mutate: leaveConvo} = useLeaveConvo(convo?.id, {
-    onSuccess: () => {
-      if (currentScreen === 'conversation') {
-        navigation.replace('Messages')
-      }
-    },
-    onError: () => {
-      Toast.show(_(msg`Could not leave chat`))
-    },
-  })
-
   return (
     <>
       <Menu.Root control={control}>
@@ -218,67 +200,19 @@ let ConvoMenu = ({
         </Menu.Outer>
       </Menu.Root>
 
-      <Prompt.Basic
+      <LeaveConvoPrompt
         control={leaveConvoControl}
-        title={_(msg`Leave conversation`)}
-        description={_(
-          msg`Are you sure you want to leave this conversation? Your messages will be deleted for you, but not for the other participant.`,
-        )}
-        confirmButtonCta={_(msg`Leave`)}
-        confirmButtonColor="negative"
-        onConfirm={() => leaveConvo()}
+        convoId={convo.id}
+        currentScreen={currentScreen}
       />
-
-      <Prompt.Basic
-        control={reportControl}
-        title={_(msg`Report conversation`)}
-        description={_(
-          msg`To report a conversation, please report one of its messages via the conversation screen. This lets our moderators understand the context of your issue.`,
-        )}
-        confirmButtonCta={_(msg`I understand`)}
-        onConfirm={noop}
+      <ReportConversationPrompt control={reportControl} />
+      <BlockedByListDialog
+        control={blockedByListControl}
+        listBlocks={listBlocks}
       />
-
-      <Prompt.Outer control={blockedByListControl} testID="blockedByListDialog">
-        <Prompt.TitleText>{_(msg`User blocked by list`)}</Prompt.TitleText>
-
-        <View style={[a.gap_sm, a.pb_lg]}>
-          <Text
-            selectable
-            style={[a.text_md, a.leading_snug, t.atoms.text_contrast_high]}>
-            {_(
-              msg`This account is blocked by one or more of your moderation lists. To unblock, please visit the lists directly and remove this user.`,
-            )}{' '}
-          </Text>
-
-          <Text style={[a.text_md, a.leading_snug, t.atoms.text_contrast_high]}>
-            {_(msg`Lists blocking this user:`)}{' '}
-            {listBlocks.map((block, i) =>
-              block.source.type === 'list' ? (
-                <React.Fragment key={block.source.list.uri}>
-                  {i === 0 ? null : ', '}
-                  <InlineLinkText
-                    to={listUriToHref(block.source.list.uri)}
-                    style={[a.text_md, a.leading_snug]}>
-                    {block.source.list.name}
-                  </InlineLinkText>
-                </React.Fragment>
-              ) : null,
-            )}
-          </Text>
-        </View>
-
-        <Prompt.Actions>
-          <Prompt.Cancel cta={_(msg`I understand`)} />
-        </Prompt.Actions>
-
-        <Dialog.Close />
-      </Prompt.Outer>
     </>
   )
 }
 ConvoMenu = React.memo(ConvoMenu)
 
 export {ConvoMenu}
-
-function noop() {}
diff --git a/src/components/dms/LeaveConvoPrompt.tsx b/src/components/dms/LeaveConvoPrompt.tsx
new file mode 100644
index 000000000..1c42dbca0
--- /dev/null
+++ b/src/components/dms/LeaveConvoPrompt.tsx
@@ -0,0 +1,55 @@
+import React from 'react'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+import {useNavigation} from '@react-navigation/native'
+
+import {NavigationProp} from 'lib/routes/types'
+import {isNative} from 'platform/detection'
+import {useLeaveConvo} from 'state/queries/messages/leave-conversation'
+import * as Toast from 'view/com/util/Toast'
+import {DialogOuterProps} from '#/components/Dialog'
+import * as Prompt from '#/components/Prompt'
+
+export function LeaveConvoPrompt({
+  control,
+  convoId,
+  currentScreen,
+}: {
+  control: DialogOuterProps['control']
+  convoId: string
+  currentScreen: 'list' | 'conversation'
+}) {
+  const {_} = useLingui()
+  const navigation = useNavigation<NavigationProp>()
+
+  const {mutate: leaveConvo} = useLeaveConvo(convoId, {
+    onSuccess: () => {
+      if (currentScreen === 'conversation') {
+        navigation.replace(
+          'Messages',
+          isNative
+            ? {
+                animation: 'pop',
+              }
+            : {},
+        )
+      }
+    },
+    onError: () => {
+      Toast.show(_(msg`Could not leave chat`))
+    },
+  })
+
+  return (
+    <Prompt.Basic
+      control={control}
+      title={_(msg`Leave conversation`)}
+      description={_(
+        msg`Are you sure you want to leave this conversation? Your messages will be deleted for you, but not for the other participant.`,
+      )}
+      confirmButtonCta={_(msg`Leave`)}
+      confirmButtonColor="negative"
+      onConfirm={leaveConvo}
+    />
+  )
+}
diff --git a/src/components/dms/MessageItem.tsx b/src/components/dms/MessageItem.tsx
index f456fa474..c5ff81091 100644
--- a/src/components/dms/MessageItem.tsx
+++ b/src/components/dms/MessageItem.tsx
@@ -75,7 +75,7 @@ let MessageItem = ({
   }, [message.text, message.facets])
 
   return (
-    <View>
+    <View style={[isFromSelf ? a.mr_md : a.ml_md]}>
       <ActionsWrapper isFromSelf={isFromSelf} message={message}>
         <View
           style={[
diff --git a/src/components/dms/MessagesListBlockedFooter.tsx b/src/components/dms/MessagesListBlockedFooter.tsx
new file mode 100644
index 000000000..a018b8623
--- /dev/null
+++ b/src/components/dms/MessagesListBlockedFooter.tsx
@@ -0,0 +1,131 @@
+import React from 'react'
+import {View} from 'react-native'
+import {AppBskyActorDefs, ModerationCause} from '@atproto/api'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {useProfileShadow} from 'state/cache/profile-shadow'
+import {useProfileBlockMutationQueue} from 'state/queries/profile'
+import {atoms as a, useBreakpoints, useTheme} from '#/alf'
+import {Button, ButtonText} from '#/components/Button'
+import {useDialogControl} from '#/components/Dialog'
+import {Divider} from '#/components/Divider'
+import {BlockedByListDialog} from '#/components/dms/BlockedByListDialog'
+import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt'
+import {ReportConversationPrompt} from '#/components/dms/ReportConversationPrompt'
+import {Text} from '#/components/Typography'
+
+export function MessagesListBlockedFooter({
+  recipient: initialRecipient,
+  convoId,
+  hasMessages,
+  blockInfo,
+}: {
+  recipient: AppBskyActorDefs.ProfileViewBasic
+  convoId: string
+  hasMessages: boolean
+  blockInfo: {
+    listBlocks: ModerationCause[]
+    userBlock: ModerationCause | undefined
+  }
+}) {
+  const t = useTheme()
+  const {gtMobile} = useBreakpoints()
+  const {_} = useLingui()
+  const recipient = useProfileShadow(initialRecipient)
+  const [__, queueUnblock] = useProfileBlockMutationQueue(recipient)
+
+  const leaveConvoControl = useDialogControl()
+  const reportControl = useDialogControl()
+  const blockedByListControl = useDialogControl()
+
+  const {listBlocks, userBlock} = blockInfo
+  const isBlocking = !!userBlock || !!listBlocks.length
+
+  const onUnblockPress = React.useCallback(() => {
+    if (listBlocks.length) {
+      blockedByListControl.open()
+    } else {
+      queueUnblock()
+    }
+  }, [blockedByListControl, listBlocks, queueUnblock])
+
+  return (
+    <View style={[hasMessages && a.pt_md, a.pb_xl, a.gap_lg]}>
+      <Divider />
+      <Text style={[a.text_md, a.font_bold, a.text_center]}>
+        {isBlocking ? (
+          <Trans>You have blocked this user</Trans>
+        ) : (
+          <Trans>This user has blocked you</Trans>
+        )}
+      </Text>
+
+      <View style={[a.flex_row, a.justify_between, a.gap_lg, a.px_md]}>
+        <Button
+          label={_(msg`Leave chat`)}
+          color="secondary"
+          variant="solid"
+          size="small"
+          style={[a.flex_1]}
+          onPress={leaveConvoControl.open}>
+          <ButtonText style={{color: t.palette.negative_500}}>
+            <Trans>Leave chat</Trans>
+          </ButtonText>
+        </Button>
+        <Button
+          label={_(msg`Report`)}
+          color="secondary"
+          variant="solid"
+          size="small"
+          style={[a.flex_1]}
+          onPress={reportControl.open}>
+          <ButtonText style={{color: t.palette.negative_500}}>
+            <Trans>Report</Trans>
+          </ButtonText>
+        </Button>
+        {isBlocking && gtMobile && (
+          <Button
+            label={_(msg`Unblock`)}
+            color="secondary"
+            variant="solid"
+            size="small"
+            style={[a.flex_1]}
+            onPress={onUnblockPress}>
+            <ButtonText style={{color: t.palette.primary_500}}>
+              <Trans>Unblock</Trans>
+            </ButtonText>
+          </Button>
+        )}
+      </View>
+      {isBlocking && !gtMobile && (
+        <View style={[a.flex_row, a.justify_center, a.px_md]}>
+          <Button
+            label={_(msg`Unblock`)}
+            color="secondary"
+            variant="solid"
+            size="small"
+            style={[a.flex_1]}
+            onPress={onUnblockPress}>
+            <ButtonText style={{color: t.palette.primary_500}}>
+              <Trans>Unblock</Trans>
+            </ButtonText>
+          </Button>
+        </View>
+      )}
+
+      <LeaveConvoPrompt
+        control={leaveConvoControl}
+        currentScreen="conversation"
+        convoId={convoId}
+      />
+
+      <ReportConversationPrompt control={reportControl} />
+
+      <BlockedByListDialog
+        control={blockedByListControl}
+        listBlocks={listBlocks}
+      />
+    </View>
+  )
+}
diff --git a/src/components/dms/MessagesListHeader.tsx b/src/components/dms/MessagesListHeader.tsx
new file mode 100644
index 000000000..a6dff4032
--- /dev/null
+++ b/src/components/dms/MessagesListHeader.tsx
@@ -0,0 +1,194 @@
+import React, {useCallback} from 'react'
+import {TouchableOpacity, View} from 'react-native'
+import {
+  AppBskyActorDefs,
+  ModerationCause,
+  ModerationDecision,
+} from '@atproto/api'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+import {useNavigation} from '@react-navigation/native'
+
+import {BACK_HITSLOP} from 'lib/constants'
+import {makeProfileLink} from 'lib/routes/links'
+import {NavigationProp} from 'lib/routes/types'
+import {sanitizeDisplayName} from 'lib/strings/display-names'
+import {isWeb} from 'platform/detection'
+import {useProfileShadow} from 'state/cache/profile-shadow'
+import {isConvoActive, useConvo} from 'state/messages/convo'
+import {PreviewableUserAvatar} from 'view/com/util/UserAvatar'
+import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
+import {ConvoMenu} from '#/components/dms/ConvoMenu'
+import {Link} from '#/components/Link'
+import {Text} from '#/components/Typography'
+
+const PFP_SIZE = isWeb ? 40 : 34
+
+export let MessagesListHeader = ({
+  profile,
+  moderation,
+  blockInfo,
+}: {
+  profile?: AppBskyActorDefs.ProfileViewBasic
+  moderation?: ModerationDecision
+  blockInfo?: {
+    listBlocks: ModerationCause[]
+    userBlock?: ModerationCause
+  }
+}): React.ReactNode => {
+  const t = useTheme()
+  const {_} = useLingui()
+  const {gtTablet} = useBreakpoints()
+  const navigation = useNavigation<NavigationProp>()
+
+  const onPressBack = useCallback(() => {
+    if (isWeb) {
+      navigation.replace('Messages', {})
+    } else {
+      navigation.goBack()
+    }
+  }, [navigation])
+
+  return (
+    <View
+      style={[
+        t.atoms.bg,
+        t.atoms.border_contrast_low,
+        a.border_b,
+        a.flex_row,
+        a.align_center,
+        a.gap_sm,
+        gtTablet ? a.pl_lg : a.pl_xl,
+        a.pr_lg,
+        a.py_sm,
+      ]}>
+      {!gtTablet && (
+        <TouchableOpacity
+          testID="conversationHeaderBackBtn"
+          onPress={onPressBack}
+          hitSlop={BACK_HITSLOP}
+          style={{width: 30, height: 30}}
+          accessibilityRole="button"
+          accessibilityLabel={_(msg`Back`)}
+          accessibilityHint="">
+          <FontAwesomeIcon
+            size={18}
+            icon="angle-left"
+            style={{
+              marginTop: 6,
+            }}
+            color={t.atoms.text.color}
+          />
+        </TouchableOpacity>
+      )}
+
+      {profile && moderation && blockInfo ? (
+        <HeaderReady
+          profile={profile}
+          moderation={moderation}
+          blockInfo={blockInfo}
+        />
+      ) : (
+        <>
+          <View style={[a.flex_row, a.align_center, a.gap_md, a.flex_1]}>
+            <View
+              style={[
+                {width: PFP_SIZE, height: PFP_SIZE},
+                a.rounded_full,
+                t.atoms.bg_contrast_25,
+              ]}
+            />
+            <View style={a.gap_xs}>
+              <View
+                style={[
+                  {width: 120, height: 16},
+                  a.rounded_xs,
+                  t.atoms.bg_contrast_25,
+                  a.mt_xs,
+                ]}
+              />
+              <View
+                style={[
+                  {width: 175, height: 12},
+                  a.rounded_xs,
+                  t.atoms.bg_contrast_25,
+                ]}
+              />
+            </View>
+          </View>
+
+          <View style={{width: 30}} />
+        </>
+      )}
+    </View>
+  )
+}
+MessagesListHeader = React.memo(MessagesListHeader)
+
+function HeaderReady({
+  profile: profileUnshadowed,
+  moderation,
+  blockInfo,
+}: {
+  profile: AppBskyActorDefs.ProfileViewBasic
+  moderation: ModerationDecision
+  blockInfo: {
+    listBlocks: ModerationCause[]
+    userBlock?: ModerationCause
+  }
+}) {
+  const t = useTheme()
+  const convoState = useConvo()
+  const profile = useProfileShadow(profileUnshadowed)
+
+  const isDeletedAccount = profile?.handle === 'missing.invalid'
+  const displayName = isDeletedAccount
+    ? 'Deleted Account'
+    : sanitizeDisplayName(
+        profile.displayName || profile.handle,
+        moderation.ui('displayName'),
+      )
+
+  return (
+    <>
+      <Link
+        style={[a.flex_row, a.align_center, a.gap_md, a.flex_1, a.pr_md]}
+        to={makeProfileLink(profile)}>
+        <PreviewableUserAvatar
+          size={PFP_SIZE}
+          profile={profile}
+          moderation={moderation.ui('avatar')}
+          disableHoverCard={moderation.blocked}
+        />
+        <View style={a.flex_1}>
+          <Text
+            style={[a.text_md, a.font_bold, web(a.leading_normal)]}
+            numberOfLines={1}>
+            {displayName}
+          </Text>
+          {!isDeletedAccount && (
+            <Text
+              style={[
+                t.atoms.text_contrast_medium,
+                a.text_sm,
+                web([a.leading_normal, {marginTop: -2}]),
+              ]}
+              numberOfLines={1}>
+              @{profile.handle}
+            </Text>
+          )}
+        </View>
+      </Link>
+
+      {isConvoActive(convoState) && (
+        <ConvoMenu
+          convo={convoState.convo}
+          profile={profile}
+          currentScreen="conversation"
+          blockInfo={blockInfo}
+        />
+      )}
+    </>
+  )
+}
diff --git a/src/components/dms/ReportConversationPrompt.tsx b/src/components/dms/ReportConversationPrompt.tsx
new file mode 100644
index 000000000..610cfbcf9
--- /dev/null
+++ b/src/components/dms/ReportConversationPrompt.tsx
@@ -0,0 +1,27 @@
+import React from 'react'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {DialogControlProps} from '#/components/Dialog'
+import * as Prompt from '#/components/Prompt'
+
+export function ReportConversationPrompt({
+  control,
+}: {
+  control: DialogControlProps
+}) {
+  const {_} = useLingui()
+
+  return (
+    <Prompt.Basic
+      control={control}
+      title={_(msg`Report conversation`)}
+      description={_(
+        msg`To report a conversation, please report one of its messages via the conversation screen. This lets our moderators understand the context of your issue.`,
+      )}
+      confirmButtonCta={_(msg`I understand`)}
+      onConfirm={() => {}}
+      showCancel={false}
+    />
+  )
+}