about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2023-04-25 20:47:07 -0500
committerGitHub <noreply@github.com>2023-04-25 20:47:07 -0500
commitf33a355a1ac1fb3e3d91e7e55a9fe9df53313e66 (patch)
tree107961d843cf4b8cb24e2b8d9f536a5dd2b1912d
parente1fd50d014749fc7757a322839ea46b4156ba8c4 (diff)
downloadvoidsky-f33a355a1ac1fb3e3d91e7e55a9fe9df53313e66.tar.zst
[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
-rw-r--r--src/state/models/invited-users.ts20
-rw-r--r--src/view/com/modals/InviteCodes.tsx77
2 files changed, 57 insertions, 40 deletions
diff --git a/src/state/models/invited-users.ts b/src/state/models/invited-users.ts
index 121161a32..a28e0309a 100644
--- a/src/state/models/invited-users.ts
+++ b/src/state/models/invited-users.ts
@@ -4,6 +4,7 @@ import {RootStoreModel} from './root-store'
 import {isObj, hasProp, isStrArray} from 'lib/type-guards'
 
 export class InvitedUsers {
+  copiedInvites: string[] = []
   seenDids: string[] = []
   profiles: AppBskyActorDefs.ProfileViewDetailed[] = []
 
@@ -20,13 +21,20 @@ export class InvitedUsers {
   }
 
   serialize() {
-    return {seenDids: this.seenDids}
+    return {seenDids: this.seenDids, copiedInvites: this.copiedInvites}
   }
 
   hydrate(v: unknown) {
     if (isObj(v) && hasProp(v, 'seenDids') && isStrArray(v.seenDids)) {
       this.seenDids = v.seenDids
     }
+    if (
+      isObj(v) &&
+      hasProp(v, 'copiedInvites') &&
+      isStrArray(v.copiedInvites)
+    ) {
+      this.copiedInvites = v.copiedInvites
+    }
   }
 
   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) {
     this.seenDids.push(did)
     this.profiles = this.profiles.filter(profile => profile.did !== did)
diff --git a/src/view/com/modals/InviteCodes.tsx b/src/view/com/modals/InviteCodes.tsx
index 5e31e16a8..8d54a50b1 100644
--- a/src/view/com/modals/InviteCodes.tsx
+++ b/src/view/com/modals/InviteCodes.tsx
@@ -1,5 +1,6 @@
 import React from 'react'
 import {StyleSheet, TouchableOpacity, View} from 'react-native'
+import {observer} from 'mobx-react-lite'
 import {
   FontAwesomeIcon,
   FontAwesomeIconStyle,
@@ -82,46 +83,42 @@ export function Component({}: {}) {
   )
 }
 
-function InviteCode({
-  testID,
-  code,
-  used,
-}: {
-  testID: string
-  code: string
-  used?: boolean
-}) {
-  const pal = usePalette('default')
-  const [wasCopied, setWasCopied] = React.useState(false)
+const InviteCode = observer(
+  ({testID, code, used}: {testID: string; code: string; used?: boolean}) => {
+    const pal = usePalette('default')
+    const store = useStores()
 
-  const onPress = React.useCallback(() => {
-    Clipboard.setString(code)
-    Toast.show('Copied to clipboard')
-    setWasCopied(true)
-  }, [code])
+    const onPress = React.useCallback(() => {
+      Clipboard.setString(code)
+      Toast.show('Copied to clipboard')
+      store.invitedUsers.setInviteCopied(code)
+    }, [store, code])
 
-  return (
-    <TouchableOpacity
-      testID={testID}
-      style={[styles.inviteCode, pal.border]}
-      onPress={onPress}>
-      <Text
-        testID={`${testID}-code`}
-        type={used ? 'md' : 'md-bold'}
-        style={used ? [pal.textLight, styles.strikeThrough] : pal.text}>
-        {code}
-      </Text>
-      {wasCopied ? (
-        <Text style={pal.textLight}>Copied</Text>
-      ) : !used ? (
-        <FontAwesomeIcon
-          icon={['far', 'clone']}
-          style={pal.text as FontAwesomeIconStyle}
-        />
-      ) : undefined}
-    </TouchableOpacity>
-  )
-}
+    return (
+      <TouchableOpacity
+        testID={testID}
+        style={[styles.inviteCode, pal.border]}
+        onPress={onPress}>
+        <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>
+    )
+  },
+)
 
 const styles = StyleSheet.create({
   container: {
@@ -163,11 +160,13 @@ const styles = StyleSheet.create({
   inviteCode: {
     flexDirection: 'row',
     alignItems: 'center',
-    justifyContent: 'space-between',
     borderBottomWidth: 1,
     paddingHorizontal: 20,
     paddingVertical: 14,
   },
+  codeCopied: {
+    marginRight: 8,
+  },
   strikeThrough: {
     textDecorationLine: 'line-through',
     textDecorationStyle: 'solid',