about summary refs log tree commit diff
path: root/src/view/com/feeds/FeedSourceCard.tsx
diff options
context:
space:
mode:
authorEric Bailey <git@esb.lol>2023-11-12 13:31:11 -0600
committerGitHub <noreply@github.com>2023-11-12 11:31:11 -0800
commit05b728fffcdb17708fdb52685725faf7fdc545bc (patch)
treeb6523916d965f921d3f03d101dc60a7e74569bce /src/view/com/feeds/FeedSourceCard.tsx
parentc8c308e31e63607280648e3e9f1f56a371adcd05 (diff)
downloadvoidsky-05b728fffcdb17708fdb52685725faf7fdc545bc.tar.zst
Eric/preferences (#1873)
* Add initial preferences query, couple mutations

* Remove unused

* Clean up labels, migrate getModerationOpts

* Add birth date handling

* Migrate feed prefs

* Migrate thread view prefs

* Migrate homeFeed to use existing key name

* Fix up saved feeds in response, no impl yet

* Migrate saved feeds to new hooks

* Clean up more of preferences

* Fix PreferencesThreads load state

* Fix modal dismissal

* Small spacing fix

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>
Diffstat (limited to 'src/view/com/feeds/FeedSourceCard.tsx')
-rw-r--r--src/view/com/feeds/FeedSourceCard.tsx145
1 files changed, 145 insertions, 0 deletions
diff --git a/src/view/com/feeds/FeedSourceCard.tsx b/src/view/com/feeds/FeedSourceCard.tsx
index 63af52619..6f9687be5 100644
--- a/src/view/com/feeds/FeedSourceCard.tsx
+++ b/src/view/com/feeds/FeedSourceCard.tsx
@@ -16,6 +16,151 @@ import * as Toast from 'view/com/util/Toast'
 import {sanitizeHandle} from 'lib/strings/handles'
 import {logger} from '#/logger'
 import {useModalControls} from '#/state/modals'
+import {
+  usePreferencesQuery,
+  useSaveFeedMutation,
+  useRemoveFeedMutation,
+} from '#/state/queries/preferences'
+import {useFeedSourceInfoQuery} from '#/state/queries/feed'
+
+export const NewFeedSourceCard = observer(function FeedSourceCardImpl({
+  feedUri,
+  style,
+  showSaveBtn = false,
+  showDescription = false,
+  showLikes = false,
+}: {
+  feedUri: string
+  style?: StyleProp<ViewStyle>
+  showSaveBtn?: boolean
+  showDescription?: boolean
+  showLikes?: boolean
+}) {
+  const pal = usePalette('default')
+  const navigation = useNavigation<NavigationProp>()
+  const {openModal} = useModalControls()
+  const {data: preferences} = usePreferencesQuery()
+  const {data: info} = useFeedSourceInfoQuery({uri: feedUri})
+  const {isPending: isSavePending, mutateAsync: saveFeed} =
+    useSaveFeedMutation()
+  const {isPending: isRemovePending, mutateAsync: removeFeed} =
+    useRemoveFeedMutation()
+
+  const isSaved = Boolean(preferences?.feeds?.saved?.includes(feedUri))
+
+  const onToggleSaved = React.useCallback(async () => {
+    // Only feeds can be un/saved, lists are handled elsewhere
+    if (info?.type !== 'feed') return
+
+    if (isSaved) {
+      openModal({
+        name: 'confirm',
+        title: 'Remove from my feeds',
+        message: `Remove ${info?.displayName} from my feeds?`,
+        onPressConfirm: async () => {
+          try {
+            await removeFeed({uri: feedUri})
+            // await item.unsave()
+            Toast.show('Removed from my feeds')
+          } catch (e) {
+            Toast.show('There was an issue contacting your server')
+            logger.error('Failed to unsave feed', {error: e})
+          }
+        },
+      })
+    } else {
+      try {
+        await saveFeed({uri: feedUri})
+        Toast.show('Added to my feeds')
+      } catch (e) {
+        Toast.show('There was an issue contacting your server')
+        logger.error('Failed to save feed', {error: e})
+      }
+    }
+  }, [isSaved, openModal, info, feedUri, removeFeed, saveFeed])
+
+  if (!info || !preferences) return null
+
+  return (
+    <Pressable
+      testID={`feed-${info.displayName}`}
+      accessibilityRole="button"
+      style={[styles.container, pal.border, style]}
+      onPress={() => {
+        if (info.type === 'feed') {
+          navigation.push('ProfileFeed', {
+            name: info.creatorDid,
+            rkey: new AtUri(info.uri).rkey,
+          })
+        } else if (info.type === 'list') {
+          navigation.push('ProfileList', {
+            name: info.creatorDid,
+            rkey: new AtUri(info.uri).rkey,
+          })
+        }
+      }}
+      key={info.uri}>
+      <View style={[styles.headerContainer]}>
+        <View style={[s.mr10]}>
+          <UserAvatar type="algo" size={36} avatar={info.avatar} />
+        </View>
+        <View style={[styles.headerTextContainer]}>
+          <Text style={[pal.text, s.bold]} numberOfLines={3}>
+            {info.displayName}
+          </Text>
+          <Text style={[pal.textLight]} numberOfLines={3}>
+            {info.type === 'feed' ? 'Feed' : 'List'} by{' '}
+            {sanitizeHandle(info.creatorHandle, '@')}
+          </Text>
+        </View>
+
+        {showSaveBtn && info.type === 'feed' && (
+          <View>
+            <Pressable
+              disabled={isSavePending || isRemovePending}
+              accessibilityRole="button"
+              accessibilityLabel={
+                isSaved ? 'Remove from my feeds' : 'Add to my feeds'
+              }
+              accessibilityHint=""
+              onPress={onToggleSaved}
+              hitSlop={15}
+              style={styles.btn}>
+              {isSaved ? (
+                <FontAwesomeIcon
+                  icon={['far', 'trash-can']}
+                  size={19}
+                  color={pal.colors.icon}
+                />
+              ) : (
+                <FontAwesomeIcon
+                  icon="plus"
+                  size={18}
+                  color={pal.colors.link}
+                />
+              )}
+            </Pressable>
+          </View>
+        )}
+      </View>
+
+      {showDescription && info.description ? (
+        <RichText
+          style={[pal.textLight, styles.description]}
+          richText={info.description}
+          numberOfLines={3}
+        />
+      ) : null}
+
+      {showLikes && info.type === 'feed' ? (
+        <Text type="sm-medium" style={[pal.text, pal.textLight]}>
+          Liked by {info.likeCount || 0}{' '}
+          {pluralize(info.likeCount || 0, 'user')}
+        </Text>
+      ) : null}
+    </Pressable>
+  )
+})
 
 export const FeedSourceCard = observer(function FeedSourceCardImpl({
   item,