Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[🐴] DM button on profile #4097

Merged
merged 6 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions src/components/dms/MessageProfileButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react'
import {AppBskyActorDefs} from '@atproto/api'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'

import {useMaybeConvoForUser} from '#/state/queries/messages/get-convo-for-members'
import {atoms as a, useTheme} from '#/alf'
import {Message_Stroke2_Corner0_Rounded as Message} from '../icons/Message'
import {Link} from '../Link'

export function MessageProfileButton({
profile,
}: {
profile: AppBskyActorDefs.ProfileView
}) {
const {_} = useLingui()
const t = useTheme()

const {data: convoId} = useMaybeConvoForUser(profile.did)

if (!convoId) return null

return (
<Link
testID="dmBtn"
size="small"
color="secondary"
variant="solid"
shape="round"
label={_(msg`Message ${profile.handle}`)}
to={`/messages/${convoId}`}
style={[a.justify_center, {width: 36, height: 36}]}>
<Message
style={[t.atoms.text, {marginLeft: 1, marginBottom: 1}]}
size="md"
/>
</Link>
)
}
6 changes: 3 additions & 3 deletions src/screens/Profile/Header/ProfileHeaderLabeler.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ let ProfileHeaderLabeler = ({

const onPressSubscribe = React.useCallback(
() =>
requireAuth(async () => {
requireAuth(async (): Promise<void> => {
if (!canSubscribe) {
cantSubscribePrompt.open()
return
Expand Down Expand Up @@ -197,7 +197,6 @@ let ProfileHeaderLabeler = ({
<View
style={[
{
paddingVertical: 12,
backgroundColor:
isSubscribed || !canSubscribe
? state.hovered || state.pressed
Expand All @@ -207,7 +206,8 @@ let ProfileHeaderLabeler = ({
? tokens.color.temp_purple_dark
: tokens.color.temp_purple,
},
a.px_lg,
a.py_sm,
a.px_md,
a.rounded_sm,
a.gap_sm,
]}>
Expand Down
56 changes: 35 additions & 21 deletions src/screens/Profile/Header/ProfileHeaderStandard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {ProfileMenu} from '#/view/com/profile/ProfileMenu'
import * as Toast from '#/view/com/util/Toast'
import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {MessageProfileButton} from '#/components/dms/MessageProfileButton'
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
import * as Prompt from '#/components/Prompt'
Expand Down Expand Up @@ -156,7 +157,14 @@ let ProfileHeaderStandard = ({
style={[a.px_lg, a.pt_md, a.pb_sm]}
pointerEvents={isIOS ? 'auto' : 'box-none'}>
<View
style={[a.flex_row, a.justify_end, a.gap_sm, a.pb_sm]}
style={[
{paddingLeft: 90},
a.flex_row,
a.justify_end,
a.gap_sm,
a.pb_sm,
a.flex_wrap,
]}
pointerEvents={isIOS ? 'auto' : 'box-none'}>
{isMe ? (
<Button
Expand All @@ -166,7 +174,7 @@ let ProfileHeaderStandard = ({
variant="solid"
onPress={onPressEditProfile}
label={_(msg`Edit profile`)}
style={a.rounded_full}>
style={[a.rounded_full, a.py_sm]}>
<ButtonText>
<Trans>Edit Profile</Trans>
</ButtonText>
Expand All @@ -181,7 +189,7 @@ let ProfileHeaderStandard = ({
label={_(msg`Unblock`)}
disabled={!hasSession}
onPress={() => unblockPromptControl.open()}
style={a.rounded_full}>
style={[a.rounded_full, a.py_sm]}>
<ButtonText>
<Trans context="action">Unblock</Trans>
</ButtonText>
Expand All @@ -190,24 +198,30 @@ let ProfileHeaderStandard = ({
) : !profile.viewer?.blockedBy ? (
<>
{hasSession && (
<Button
testID="suggestedFollowsBtn"
size="small"
color={showSuggestedFollows ? 'primary' : 'secondary'}
variant="solid"
shape="round"
onPress={() => setShowSuggestedFollows(!showSuggestedFollows)}
label={_(msg`Show follows similar to ${profile.handle}`)}>
<FontAwesomeIcon
icon="user-plus"
style={
showSuggestedFollows
? {color: t.palette.white}
: t.atoms.text
<>
<MessageProfileButton profile={profile} />
<Button
testID="suggestedFollowsBtn"
size="small"
color={showSuggestedFollows ? 'primary' : 'secondary'}
variant="solid"
shape="round"
onPress={() =>
setShowSuggestedFollows(!showSuggestedFollows)
}
size={14}
/>
</Button>
label={_(msg`Show follows similar to ${profile.handle}`)}
style={{width: 36, height: 36}}>
<FontAwesomeIcon
icon="user-plus"
style={
showSuggestedFollows
? {color: t.palette.white}
: t.atoms.text
}
size={14}
/>
</Button>
</>
)}

<Button
Expand All @@ -223,7 +237,7 @@ let ProfileHeaderStandard = ({
onPress={
profile.viewer?.following ? onPressUnfollow : onPressFollow
}
style={[a.rounded_full, a.gap_xs]}>
style={[a.rounded_full, a.gap_xs, a.py_sm]}>
<ButtonIcon
position="left"
icon={profile.viewer?.following ? Check : Plus}
Expand Down
32 changes: 31 additions & 1 deletion src/state/queries/messages/get-convo-for-members.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import {ChatBskyConvoGetConvoForMembers} from '@atproto/api'
import {useMutation, useQueryClient} from '@tanstack/react-query'
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'

import {logger} from '#/logger'
import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
import {useAgent} from '#/state/session'
import {STALE} from '..'
import {RQKEY as CONVO_KEY} from './conversation'

const RQKEY_ROOT = 'convo-for-user'
export const RQKEY = (did: string) => [RQKEY_ROOT, did]

export function useGetConvoForMembers({
onSuccess,
onError,
Expand Down Expand Up @@ -35,3 +39,29 @@ export function useGetConvoForMembers({
},
})
}

/**
* Gets the conversation ID for a given DID. Returns null if it's not possible to message them.
*/
export function useMaybeConvoForUser(did: string) {
const {getAgent} = useAgent()

return useQuery({
queryKey: RQKEY(did),
queryFn: async () => {
const convo = await getAgent()
.api.chat.bsky.convo.getConvoForMembers(
{members: [did]},
{headers: DM_SERVICE_HEADERS},
)
.catch(() => ({success: null}))

if (convo.success) {
return convo.data.convo.id
} else {
return null
}
},
staleTime: STALE.INFINITY,
})
}
34 changes: 17 additions & 17 deletions src/view/com/profile/ProfileMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,42 @@
import React, {memo} from 'react'
import {TouchableOpacity} from 'react-native'
import {AppBskyActorDefs} from '@atproto/api'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {useQueryClient} from '@tanstack/react-query'
import * as Toast from 'view/com/util/Toast'
import {EventStopper} from 'view/com/util/EventStopper'
import {useSession} from 'state/session'
import * as Menu from '#/components/Menu'
import {useTheme} from '#/alf'
import {usePalette} from 'lib/hooks/usePalette'

import {logger} from '#/logger'
import {useAnalytics} from 'lib/analytics/analytics'
import {HITSLOP_10} from 'lib/constants'
import {usePalette} from 'lib/hooks/usePalette'
import {makeProfileLink} from 'lib/routes/links'
import {shareUrl} from 'lib/sharing'
import {toShareUrl} from 'lib/strings/url-helpers'
import {makeProfileLink} from 'lib/routes/links'
import {useAnalytics} from 'lib/analytics/analytics'
import {Shadow} from 'state/cache/types'
import {useModalControls} from 'state/modals'
import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog'
import {
RQKEY as profileQueryKey,
useProfileBlockMutationQueue,
useProfileFollowMutationQueue,
useProfileMuteMutationQueue,
} from 'state/queries/profile'
import {useSession} from 'state/session'
import {EventStopper} from 'view/com/util/EventStopper'
import * as Toast from 'view/com/util/Toast'
import {useTheme} from '#/alf'
import {ArrowOutOfBox_Stroke2_Corner0_Rounded as Share} from '#/components/icons/ArrowOutOfBox'
import {Flag_Stroke2_Corner0_Rounded as Flag} from '#/components/icons/Flag'
import {ListSparkle_Stroke2_Corner0_Rounded as List} from '#/components/icons/ListSparkle'
import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute'
import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/icons/Speaker'
import {Flag_Stroke2_Corner0_Rounded as Flag} from '#/components/icons/Flag'
import {PeopleRemove2_Stroke2_Corner0_Rounded as UserMinus} from '#/components/icons/PeopleRemove2'
import {PersonCheck_Stroke2_Corner0_Rounded as PersonCheck} from '#/components/icons/PersonCheck'
import {PersonX_Stroke2_Corner0_Rounded as PersonX} from '#/components/icons/PersonX'
import {PeopleRemove2_Stroke2_Corner0_Rounded as UserMinus} from '#/components/icons/PeopleRemove2'
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
import {logger} from '#/logger'
import {Shadow} from 'state/cache/types'
import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/icons/Speaker'
import * as Menu from '#/components/Menu'
import * as Prompt from '#/components/Prompt'
import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog'

let ProfileMenu = ({
profile,
Expand Down Expand Up @@ -192,9 +193,8 @@ let ProfileMenu = ({
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 10,
padding: 8,
borderRadius: 50,
paddingHorizontal: 16,
},
pal.btn,
]}>
Expand Down
Loading