[APP-562] Persist 'copied' state of invite codes (#535)
* Persist 'copied' state of invite codes (close APP-562) * Dont show copied message if invite used
This commit is contained in:
parent
e1fd50d014
commit
f33a355a1a
2 changed files with 57 additions and 40 deletions
|
@ -4,6 +4,7 @@ import {RootStoreModel} from './root-store'
|
||||||
import {isObj, hasProp, isStrArray} from 'lib/type-guards'
|
import {isObj, hasProp, isStrArray} from 'lib/type-guards'
|
||||||
|
|
||||||
export class InvitedUsers {
|
export class InvitedUsers {
|
||||||
|
copiedInvites: string[] = []
|
||||||
seenDids: string[] = []
|
seenDids: string[] = []
|
||||||
profiles: AppBskyActorDefs.ProfileViewDetailed[] = []
|
profiles: AppBskyActorDefs.ProfileViewDetailed[] = []
|
||||||
|
|
||||||
|
@ -20,13 +21,20 @@ export class InvitedUsers {
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize() {
|
serialize() {
|
||||||
return {seenDids: this.seenDids}
|
return {seenDids: this.seenDids, copiedInvites: this.copiedInvites}
|
||||||
}
|
}
|
||||||
|
|
||||||
hydrate(v: unknown) {
|
hydrate(v: unknown) {
|
||||||
if (isObj(v) && hasProp(v, 'seenDids') && isStrArray(v.seenDids)) {
|
if (isObj(v) && hasProp(v, 'seenDids') && isStrArray(v.seenDids)) {
|
||||||
this.seenDids = v.seenDids
|
this.seenDids = v.seenDids
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
isObj(v) &&
|
||||||
|
hasProp(v, 'copiedInvites') &&
|
||||||
|
isStrArray(v.copiedInvites)
|
||||||
|
) {
|
||||||
|
this.copiedInvites = v.copiedInvites
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetch(invites: ComAtprotoServerDefs.InviteCode[]) {
|
async fetch(invites: ComAtprotoServerDefs.InviteCode[]) {
|
||||||
|
@ -63,6 +71,16 @@ export class InvitedUsers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isInviteCopied(invite: string) {
|
||||||
|
return this.copiedInvites.includes(invite)
|
||||||
|
}
|
||||||
|
|
||||||
|
setInviteCopied(invite: string) {
|
||||||
|
if (!this.isInviteCopied(invite)) {
|
||||||
|
this.copiedInvites.push(invite)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
markSeen(did: string) {
|
markSeen(did: string) {
|
||||||
this.seenDids.push(did)
|
this.seenDids.push(did)
|
||||||
this.profiles = this.profiles.filter(profile => profile.did !== did)
|
this.profiles = this.profiles.filter(profile => profile.did !== did)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||||
|
import {observer} from 'mobx-react-lite'
|
||||||
import {
|
import {
|
||||||
FontAwesomeIcon,
|
FontAwesomeIcon,
|
||||||
FontAwesomeIconStyle,
|
FontAwesomeIconStyle,
|
||||||
|
@ -82,46 +83,42 @@ export function Component({}: {}) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function InviteCode({
|
const InviteCode = observer(
|
||||||
testID,
|
({testID, code, used}: {testID: string; code: string; used?: boolean}) => {
|
||||||
code,
|
const pal = usePalette('default')
|
||||||
used,
|
const store = useStores()
|
||||||
}: {
|
|
||||||
testID: string
|
|
||||||
code: string
|
|
||||||
used?: boolean
|
|
||||||
}) {
|
|
||||||
const pal = usePalette('default')
|
|
||||||
const [wasCopied, setWasCopied] = React.useState(false)
|
|
||||||
|
|
||||||
const onPress = React.useCallback(() => {
|
const onPress = React.useCallback(() => {
|
||||||
Clipboard.setString(code)
|
Clipboard.setString(code)
|
||||||
Toast.show('Copied to clipboard')
|
Toast.show('Copied to clipboard')
|
||||||
setWasCopied(true)
|
store.invitedUsers.setInviteCopied(code)
|
||||||
}, [code])
|
}, [store, code])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
testID={testID}
|
testID={testID}
|
||||||
style={[styles.inviteCode, pal.border]}
|
style={[styles.inviteCode, pal.border]}
|
||||||
onPress={onPress}>
|
onPress={onPress}>
|
||||||
<Text
|
<Text
|
||||||
testID={`${testID}-code`}
|
testID={`${testID}-code`}
|
||||||
type={used ? 'md' : 'md-bold'}
|
type={used ? 'md' : 'md-bold'}
|
||||||
style={used ? [pal.textLight, styles.strikeThrough] : pal.text}>
|
style={used ? [pal.textLight, styles.strikeThrough] : pal.text}>
|
||||||
{code}
|
{code}
|
||||||
</Text>
|
</Text>
|
||||||
{wasCopied ? (
|
<View style={styles.flex1} />
|
||||||
<Text style={pal.textLight}>Copied</Text>
|
{!used && store.invitedUsers.isInviteCopied(code) && (
|
||||||
) : !used ? (
|
<Text style={[pal.textLight, styles.codeCopied]}>Copied</Text>
|
||||||
<FontAwesomeIcon
|
)}
|
||||||
icon={['far', 'clone']}
|
{!used && (
|
||||||
style={pal.text as FontAwesomeIconStyle}
|
<FontAwesomeIcon
|
||||||
/>
|
icon={['far', 'clone']}
|
||||||
) : undefined}
|
style={pal.text as FontAwesomeIconStyle}
|
||||||
</TouchableOpacity>
|
/>
|
||||||
)
|
)}
|
||||||
}
|
</TouchableOpacity>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -163,11 +160,13 @@ const styles = StyleSheet.create({
|
||||||
inviteCode: {
|
inviteCode: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
paddingHorizontal: 20,
|
paddingHorizontal: 20,
|
||||||
paddingVertical: 14,
|
paddingVertical: 14,
|
||||||
},
|
},
|
||||||
|
codeCopied: {
|
||||||
|
marginRight: 8,
|
||||||
|
},
|
||||||
strikeThrough: {
|
strikeThrough: {
|
||||||
textDecorationLine: 'line-through',
|
textDecorationLine: 'line-through',
|
||||||
textDecorationStyle: 'solid',
|
textDecorationStyle: 'solid',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue