diff options
Diffstat (limited to 'src/view/com')
-rw-r--r-- | src/view/com/modals/InviteCodes.tsx | 105 | ||||
-rw-r--r-- | src/view/com/notifications/InvitedUsers.tsx | 114 |
2 files changed, 68 insertions, 151 deletions
diff --git a/src/view/com/modals/InviteCodes.tsx b/src/view/com/modals/InviteCodes.tsx index 09cfd4de7..a8aa164c3 100644 --- a/src/view/com/modals/InviteCodes.tsx +++ b/src/view/com/modals/InviteCodes.tsx @@ -1,6 +1,7 @@ import React from 'react' import {StyleSheet, TouchableOpacity, View} from 'react-native' import {observer} from 'mobx-react-lite' +import {ComAtprotoServerDefs} from '@atproto/api' import { FontAwesomeIcon, FontAwesomeIconStyle, @@ -14,6 +15,10 @@ import {ScrollView} from './util' import {usePalette} from 'lib/hooks/usePalette' import {isWeb} from 'platform/detection' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {useInvitesState, useInvitesAPI} from '#/state/invites' +import {UserInfoText} from '../util/UserInfoText' +import {makeProfileLink} from '#/lib/routes/links' +import {Link} from '../util/Link' export const snapPoints = ['70%'] @@ -66,7 +71,7 @@ export function Component({}: {}) { <InviteCode testID={`inviteCode-${i}`} key={invite.code} - code={invite.code} + invite={invite} used={invite.available - invite.uses.length <= 0 || invite.disabled} /> ))} @@ -87,52 +92,81 @@ export function Component({}: {}) { const InviteCode = observer(function InviteCodeImpl({ testID, - code, + invite, used, }: { testID: string - code: string + invite: ComAtprotoServerDefs.InviteCode used?: boolean }) { const pal = usePalette('default') const store = useStores() const {invitesAvailable} = store.me + const invitesState = useInvitesState() + const {setInviteCopied} = useInvitesAPI() const onPress = React.useCallback(() => { - Clipboard.setString(code) + Clipboard.setString(invite.code) Toast.show('Copied to clipboard') - store.invitedUsers.setInviteCopied(code) - }, [store, code]) + setInviteCopied(invite.code) + }, [setInviteCopied, invite]) return ( - <TouchableOpacity - testID={testID} - style={[styles.inviteCode, pal.border]} - onPress={onPress} - accessibilityRole="button" - accessibilityLabel={ - invitesAvailable === 1 - ? 'Invite codes: 1 available' - : `Invite codes: ${invitesAvailable} available` - } - accessibilityHint="Opens list of invite codes"> - <Text - testID={`${testID}-code`} - type={used ? 'md' : 'md-bold'} - style={used ? [pal.textLight, styles.strikeThrough] : pal.text}> - {code} - </Text> - <View style={styles.flex1} /> - {!used && store.invitedUsers.isInviteCopied(code) && ( - <Text style={[pal.textLight, styles.codeCopied]}>Copied</Text> - )} - {!used && ( - <FontAwesomeIcon - icon={['far', 'clone']} - style={pal.text as FontAwesomeIconStyle} - /> - )} - </TouchableOpacity> + <View + style={[ + pal.border, + {borderBottomWidth: 1, paddingHorizontal: 20, paddingVertical: 14}, + ]}> + <TouchableOpacity + testID={testID} + style={[styles.inviteCode]} + onPress={onPress} + accessibilityRole="button" + accessibilityLabel={ + invitesAvailable === 1 + ? 'Invite codes: 1 available' + : `Invite codes: ${invitesAvailable} available` + } + accessibilityHint="Opens list of invite codes"> + <Text + testID={`${testID}-code`} + type={used ? 'md' : 'md-bold'} + style={used ? [pal.textLight, styles.strikeThrough] : pal.text}> + {invite.code} + </Text> + <View style={styles.flex1} /> + {!used && invitesState.copiedInvites.includes(invite.code) && ( + <Text style={[pal.textLight, styles.codeCopied]}>Copied</Text> + )} + {!used && ( + <FontAwesomeIcon + icon={['far', 'clone']} + style={pal.text as FontAwesomeIconStyle} + /> + )} + </TouchableOpacity> + {invite.uses.length > 0 ? ( + <View + style={{ + flexDirection: 'column', + gap: 8, + paddingTop: 6, + }}> + <Text style={pal.text}>Used by:</Text> + {invite.uses.map(use => ( + <Link + key={use.usedBy} + href={makeProfileLink({handle: use.usedBy, did: ''})} + style={{ + flexDirection: 'row', + }}> + <Text style={pal.text}>• </Text> + <UserInfoText did={use.usedBy} style={pal.link} /> + </Link> + ))} + </View> + ) : null} + </View> ) }) @@ -176,9 +210,6 @@ const styles = StyleSheet.create({ inviteCode: { flexDirection: 'row', alignItems: 'center', - borderBottomWidth: 1, - paddingHorizontal: 20, - paddingVertical: 14, }, codeCopied: { marginRight: 8, diff --git a/src/view/com/notifications/InvitedUsers.tsx b/src/view/com/notifications/InvitedUsers.tsx deleted file mode 100644 index aaf358b87..000000000 --- a/src/view/com/notifications/InvitedUsers.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import React from 'react' -import { - FontAwesomeIcon, - FontAwesomeIconStyle, -} from '@fortawesome/react-native-fontawesome' -import {StyleSheet, View} from 'react-native' -import {observer} from 'mobx-react-lite' -import {AppBskyActorDefs} from '@atproto/api' -import {UserAvatar} from '../util/UserAvatar' -import {Text} from '../util/text/Text' -import {Link, TextLink} from '../util/Link' -import {Button} from '../util/forms/Button' -import {FollowButton} from '../profile/FollowButton' -import {CenteredView} from '../util/Views.web' -import {useStores} from 'state/index' -import {usePalette} from 'lib/hooks/usePalette' -import {s} from 'lib/styles' -import {sanitizeDisplayName} from 'lib/strings/display-names' -import {makeProfileLink} from 'lib/routes/links' - -export const InvitedUsers = observer(function InvitedUsersImpl() { - const store = useStores() - return ( - <CenteredView> - {store.invitedUsers.profiles.map(profile => ( - <InvitedUser key={profile.did} profile={profile} /> - ))} - </CenteredView> - ) -}) - -function InvitedUser({ - profile, -}: { - profile: AppBskyActorDefs.ProfileViewDetailed -}) { - const pal = usePalette('default') - const store = useStores() - - const onPressDismiss = React.useCallback(() => { - store.invitedUsers.markSeen(profile.did) - }, [store, profile]) - - return ( - <View - testID="invitedUser" - style={[ - styles.layout, - { - backgroundColor: pal.colors.unreadNotifBg, - borderColor: pal.colors.unreadNotifBorder, - }, - ]}> - <View style={styles.layoutIcon}> - <FontAwesomeIcon - icon="user-plus" - size={24} - style={[styles.icon, s.blue3 as FontAwesomeIconStyle]} - /> - </View> - <View style={s.flex1}> - <Link href={makeProfileLink(profile)}> - <UserAvatar avatar={profile.avatar} size={35} /> - </Link> - <Text style={[styles.desc, pal.text]}> - <TextLink - type="md-bold" - style={pal.text} - href={makeProfileLink(profile)} - text={sanitizeDisplayName(profile.displayName || profile.handle)} - />{' '} - joined using your invite code! - </Text> - <View style={styles.btns}> - <FollowButton - unfollowedType="primary" - followedType="primary-light" - profile={profile} - /> - <Button - testID="dismissBtn" - type="primary-light" - label="Dismiss" - onPress={onPressDismiss} - /> - </View> - </View> - </View> - ) -} - -const styles = StyleSheet.create({ - layout: { - flexDirection: 'row', - borderTopWidth: 1, - padding: 10, - }, - layoutIcon: { - width: 70, - alignItems: 'flex-end', - paddingTop: 2, - }, - icon: { - marginRight: 10, - marginTop: 4, - }, - desc: { - paddingVertical: 6, - }, - btns: { - flexDirection: 'row', - gap: 10, - }, -}) |