about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEric Bailey <git@esb.lol>2024-02-29 19:30:30 -0600
committerGitHub <noreply@github.com>2024-02-29 19:30:30 -0600
commitcecb6e4e69eaccedf56f503589a59044fd7c6d19 (patch)
tree90dd52ea6a797f4f251a13ccc675c7ef6cbe851f /src
parent21bdddcfbe6ae85c15a4544fe5fd751b7e94d960 (diff)
downloadvoidsky-cecb6e4e69eaccedf56f503589a59044fd7c6d19.tar.zst
Bump API SDK, add validation to MutedWords (#3055)
* Bump API SDK, add validation to MutedWords

* Tweaks to error state

* Comment

* Early return
Diffstat (limited to 'src')
-rw-r--r--src/components/TagMenu/index.tsx6
-rw-r--r--src/components/TagMenu/index.web.tsx5
-rw-r--r--src/components/dialogs/MutedWords.tsx60
3 files changed, 55 insertions, 16 deletions
diff --git a/src/components/TagMenu/index.tsx b/src/components/TagMenu/index.tsx
index 2fec7a188..c18c0d6a2 100644
--- a/src/components/TagMenu/index.tsx
+++ b/src/components/TagMenu/index.tsx
@@ -215,14 +215,12 @@ export function TagMenu({
                           if (isMuted) {
                             resetUpsert()
                             removeMutedWord({
-                              value: sanitizedTag,
+                              value: tag,
                               targets: ['tag'],
                             })
                           } else {
                             resetRemove()
-                            upsertMutedWord([
-                              {value: sanitizedTag, targets: ['tag']},
-                            ])
+                            upsertMutedWord([{value: tag, targets: ['tag']}])
                           }
                         })
                       }}>
diff --git a/src/components/TagMenu/index.web.tsx b/src/components/TagMenu/index.web.tsx
index 3aebfbba2..4fcb4c812 100644
--- a/src/components/TagMenu/index.web.tsx
+++ b/src/components/TagMenu/index.web.tsx
@@ -104,9 +104,9 @@ export function TagMenu({
           : _(msg`Mute ${truncatedTag}`),
         onPress() {
           if (isMuted) {
-            removeMutedWord({value: sanitizedTag, targets: ['tag']})
+            removeMutedWord({value: tag, targets: ['tag']})
           } else {
-            upsertMutedWord([{value: sanitizedTag, targets: ['tag']}])
+            upsertMutedWord([{value: tag, targets: ['tag']}])
           }
         },
         testID: 'tagMenuMute',
@@ -127,7 +127,6 @@ export function TagMenu({
     preferences,
     tag,
     truncatedTag,
-    sanitizedTag,
     upsertMutedWord,
     removeMutedWord,
   ])
diff --git a/src/components/dialogs/MutedWords.tsx b/src/components/dialogs/MutedWords.tsx
index 7c0d4fbca..453b13513 100644
--- a/src/components/dialogs/MutedWords.tsx
+++ b/src/components/dialogs/MutedWords.tsx
@@ -2,7 +2,7 @@ import React from 'react'
 import {View} from 'react-native'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
-import {AppBskyActorDefs} from '@atproto/api'
+import {AppBskyActorDefs, sanitizeMutedWordValue} from '@atproto/api'
 
 import {
   usePreferencesQuery,
@@ -10,7 +10,14 @@ import {
   useRemoveMutedWordMutation,
 } from '#/state/queries/preferences'
 import {isNative} from '#/platform/detection'
-import {atoms as a, useTheme, useBreakpoints, ViewStyleProp, web} from '#/alf'
+import {
+  atoms as a,
+  useTheme,
+  useBreakpoints,
+  ViewStyleProp,
+  web,
+  native,
+} from '#/alf'
 import {Text} from '#/components/Typography'
 import {Button, ButtonIcon, ButtonText} from '#/components/Button'
 import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
@@ -48,24 +55,29 @@ function MutedWordsInner({}: {control: Dialog.DialogOuterProps['control']}) {
   const {isPending, mutateAsync: addMutedWord} = useUpsertMutedWordsMutation()
   const [field, setField] = React.useState('')
   const [options, setOptions] = React.useState(['content'])
-  const [_error, setError] = React.useState('')
+  const [error, setError] = React.useState('')
 
   const submit = React.useCallback(async () => {
-    const value = field.trim()
+    const sanitizedValue = sanitizeMutedWordValue(field)
     const targets = ['tag', options.includes('content') && 'content'].filter(
       Boolean,
     ) as AppBskyActorDefs.MutedWord['targets']
 
-    if (!value || !targets.length) return
+    if (!sanitizedValue || !targets.length) {
+      setField('')
+      setError(_(msg`Please enter a valid word, tag, or phrase to mute`))
+      return
+    }
 
     try {
-      await addMutedWord([{value, targets}])
+      // send raw value and rely on SDK as sanitization source of truth
+      await addMutedWord([{value: field, targets}])
       setField('')
     } catch (e: any) {
       logger.error(`Failed to save muted word`, {message: e.message})
       setError(e.message)
     }
-  }, [field, options, addMutedWord, setField])
+  }, [_, field, options, addMutedWord, setField])
 
   return (
     <Dialog.ScrollableInner label={_(msg`Manage your muted words and tags`)}>
@@ -87,7 +99,12 @@ function MutedWordsInner({}: {control: Dialog.DialogOuterProps['control']}) {
           label={_(msg`Enter a word or tag`)}
           placeholder={_(msg`Enter a word or tag`)}
           value={field}
-          onChangeText={setField}
+          onChangeText={value => {
+            if (error) {
+              setError('')
+            }
+            setField(value)
+          }}
           onSubmitEditing={submit}
         />
 
@@ -99,7 +116,7 @@ function MutedWordsInner({}: {control: Dialog.DialogOuterProps['control']}) {
           <View
             style={[
               a.pt_sm,
-              a.pb_md,
+              a.py_sm,
               a.flex_row,
               a.align_center,
               a.gap_sm,
@@ -151,8 +168,33 @@ function MutedWordsInner({}: {control: Dialog.DialogOuterProps['control']}) {
           </View>
         </Toggle.Group>
 
+        {error && (
+          <View
+            style={[
+              a.mb_lg,
+              a.flex_row,
+              a.rounded_sm,
+              a.p_md,
+              a.mb_xs,
+              t.atoms.bg_contrast_25,
+              {
+                backgroundColor: t.palette.negative_400,
+              },
+            ]}>
+            <Text
+              style={[
+                a.italic,
+                {color: t.palette.white},
+                native({marginTop: 2}),
+              ]}>
+              {error}
+            </Text>
+          </View>
+        )}
+
         <Text
           style={[
+            a.pt_xs,
             a.text_sm,
             a.italic,
             a.leading_snug,