about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2024-04-13 19:49:52 -0700
committerGitHub <noreply@github.com>2024-04-13 19:49:52 -0700
commit0b43d728e4b95fe2f8085b8d01e34963f8663c0d (patch)
treea12b42404dfeff36837c3cfb761f429001663a6c /src
parent23056daa292905b0019565dc0c42870037ed98fe (diff)
downloadvoidsky-0b43d728e4b95fe2f8085b8d01e34963f8663c0d.tar.zst
Improve the language behaviors around the PWI (#3545)
* Handle leftnav overflow with longer languages' copy

* Update the language dropdown to set ALL language prefs

* Add hackfix to language cachebusting on PWI

* Reset feeds on language change
Diffstat (limited to 'src')
-rw-r--r--src/components/AppLanguageDropdown.tsx10
-rw-r--r--src/components/AppLanguageDropdown.web.tsx10
-rw-r--r--src/lib/api/feed/custom.ts81
-rw-r--r--src/state/preferences/languages.tsx8
-rw-r--r--src/state/queries/post-feed.ts8
-rw-r--r--src/view/shell/NavSignupCard.tsx8
6 files changed, 111 insertions, 14 deletions
diff --git a/src/components/AppLanguageDropdown.tsx b/src/components/AppLanguageDropdown.tsx
index dea9e66fb..02cd0ce2d 100644
--- a/src/components/AppLanguageDropdown.tsx
+++ b/src/components/AppLanguageDropdown.tsx
@@ -1,16 +1,19 @@
 import React from 'react'
 import {View} from 'react-native'
 import RNPickerSelect, {PickerSelectProps} from 'react-native-picker-select'
+import {useQueryClient} from '@tanstack/react-query'
 
 import {sanitizeAppLanguageSetting} from '#/locale/helpers'
 import {APP_LANGUAGES} from '#/locale/languages'
 import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences'
+import {resetPostsFeedQueries} from '#/state/queries/post-feed'
 import {atoms as a, useTheme} from '#/alf'
 import {ChevronBottom_Stroke2_Corner0_Rounded as ChevronDown} from '#/components/icons/Chevron'
 
 export function AppLanguageDropdown() {
   const t = useTheme()
 
+  const queryClient = useQueryClient()
   const langPrefs = useLanguagePrefs()
   const setLangPrefs = useLanguagePrefsApi()
   const sanitizedLang = sanitizeAppLanguageSetting(langPrefs.appLanguage)
@@ -21,8 +24,13 @@ export function AppLanguageDropdown() {
       if (sanitizedLang !== value) {
         setLangPrefs.setAppLanguage(sanitizeAppLanguageSetting(value))
       }
+      setLangPrefs.setPrimaryLanguage(value)
+      setLangPrefs.setContentLanguage(value)
+
+      // reset feeds to refetch content
+      resetPostsFeedQueries(queryClient)
     },
-    [sanitizedLang, setLangPrefs],
+    [sanitizedLang, setLangPrefs, queryClient],
   )
 
   return (
diff --git a/src/components/AppLanguageDropdown.web.tsx b/src/components/AppLanguageDropdown.web.tsx
index 8052a4ef3..aea1b2b90 100644
--- a/src/components/AppLanguageDropdown.web.tsx
+++ b/src/components/AppLanguageDropdown.web.tsx
@@ -1,9 +1,11 @@
 import React from 'react'
 import {View} from 'react-native'
+import {useQueryClient} from '@tanstack/react-query'
 
 import {sanitizeAppLanguageSetting} from '#/locale/helpers'
 import {APP_LANGUAGES} from '#/locale/languages'
 import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences'
+import {resetPostsFeedQueries} from '#/state/queries/post-feed'
 import {atoms as a, useTheme} from '#/alf'
 import {ChevronBottom_Stroke2_Corner0_Rounded as ChevronDown} from '#/components/icons/Chevron'
 import {Text} from '#/components/Typography'
@@ -11,6 +13,7 @@ import {Text} from '#/components/Typography'
 export function AppLanguageDropdown() {
   const t = useTheme()
 
+  const queryClient = useQueryClient()
   const langPrefs = useLanguagePrefs()
   const setLangPrefs = useLanguagePrefsApi()
 
@@ -24,8 +27,13 @@ export function AppLanguageDropdown() {
       if (sanitizedLang !== value) {
         setLangPrefs.setAppLanguage(sanitizeAppLanguageSetting(value))
       }
+      setLangPrefs.setPrimaryLanguage(value)
+      setLangPrefs.setContentLanguage(value)
+
+      // reset feeds to refetch content
+      resetPostsFeedQueries(queryClient)
     },
-    [sanitizedLang, setLangPrefs],
+    [sanitizedLang, setLangPrefs, queryClient],
   )
 
   return (
diff --git a/src/lib/api/feed/custom.ts b/src/lib/api/feed/custom.ts
index 41c5367e5..bd30d58ac 100644
--- a/src/lib/api/feed/custom.ts
+++ b/src/lib/api/feed/custom.ts
@@ -1,10 +1,12 @@
 import {
   AppBskyFeedDefs,
   AppBskyFeedGetFeed as GetCustomFeed,
+  AtpAgent,
 } from '@atproto/api'
-import {FeedAPI, FeedAPIResponse} from './types'
-import {getAgent} from '#/state/session'
+
 import {getContentLanguages} from '#/state/preferences/languages'
+import {getAgent} from '#/state/session'
+import {FeedAPI, FeedAPIResponse} from './types'
 
 export class CustomFeedAPI implements FeedAPI {
   constructor(public params: GetCustomFeed.QueryParams) {}
@@ -29,14 +31,17 @@ export class CustomFeedAPI implements FeedAPI {
     limit: number
   }): Promise<FeedAPIResponse> {
     const contentLangs = getContentLanguages().join(',')
-    const res = await getAgent().app.bsky.feed.getFeed(
-      {
-        ...this.params,
-        cursor,
-        limit,
-      },
-      {headers: {'Accept-Language': contentLangs}},
-    )
+    const agent = getAgent()
+    const res = agent.session
+      ? await getAgent().app.bsky.feed.getFeed(
+          {
+            ...this.params,
+            cursor,
+            limit,
+          },
+          {headers: {'Accept-Language': contentLangs}},
+        )
+      : await loggedOutFetch({...this.params, cursor, limit})
     if (res.success) {
       // NOTE
       // some custom feeds fail to enforce the pagination limit
@@ -55,3 +60,59 @@ export class CustomFeedAPI implements FeedAPI {
     }
   }
 }
+
+// HACK
+// we want feeds to give language-specific results immediately when a
+// logged-out user changes their language. this comes with two problems:
+// 1. not all languages have content, and
+// 2. our public caching layer isnt correctly busting against the accept-language header
+// for now we handle both of these with a manual workaround
+// -prf
+async function loggedOutFetch({
+  feed,
+  limit,
+  cursor,
+}: {
+  feed: string
+  limit: number
+  cursor?: string
+}) {
+  let contentLangs = getContentLanguages().join(',')
+
+  // manually construct fetch call so we can add the `lang` cache-busting param
+  let res = await AtpAgent.fetch!(
+    `https://api.bsky.app/xrpc/app.bsky.feed.getFeed?feed=${feed}${
+      cursor ? `&cursor=${cursor}` : ''
+    }&limit=${limit}&lang=${contentLangs}`,
+    'GET',
+    {'Accept-Language': contentLangs},
+    undefined,
+  )
+  if (res.body?.feed?.length) {
+    return {
+      success: true,
+      data: res.body,
+    }
+  }
+
+  // no data, try again with language headers removed
+  res = await AtpAgent.fetch!(
+    `https://api.bsky.app/xrpc/app.bsky.feed.getFeed?feed=${feed}${
+      cursor ? `&cursor=${cursor}` : ''
+    }&limit=${limit}`,
+    'GET',
+    {'Accept-Language': ''},
+    undefined,
+  )
+  if (res.body?.feed?.length) {
+    return {
+      success: true,
+      data: res.body,
+    }
+  }
+
+  return {
+    success: false,
+    data: {feed: []},
+  }
+}
diff --git a/src/state/preferences/languages.tsx b/src/state/preferences/languages.tsx
index df774c05e..b7494c1f9 100644
--- a/src/state/preferences/languages.tsx
+++ b/src/state/preferences/languages.tsx
@@ -1,6 +1,7 @@
 import React from 'react'
-import * as persisted from '#/state/persisted'
+
 import {AppLanguage} from '#/locale/languages'
+import * as persisted from '#/state/persisted'
 
 type SetStateCb = (
   s: persisted.Schema['languagePrefs'],
@@ -9,6 +10,7 @@ type StateContext = persisted.Schema['languagePrefs']
 type ApiContext = {
   setPrimaryLanguage: (code2: string) => void
   setPostLanguage: (commaSeparatedLangCodes: string) => void
+  setContentLanguage: (code2: string) => void
   toggleContentLanguage: (code2: string) => void
   togglePostLanguage: (code2: string) => void
   savePostLanguageToHistory: () => void
@@ -21,6 +23,7 @@ const stateContext = React.createContext<StateContext>(
 const apiContext = React.createContext<ApiContext>({
   setPrimaryLanguage: (_: string) => {},
   setPostLanguage: (_: string) => {},
+  setContentLanguage: (_: string) => {},
   toggleContentLanguage: (_: string) => {},
   togglePostLanguage: (_: string) => {},
   savePostLanguageToHistory: () => {},
@@ -53,6 +56,9 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
       setPostLanguage(commaSeparatedLangCodes: string) {
         setStateWrapped(s => ({...s, postLanguage: commaSeparatedLangCodes}))
       },
+      setContentLanguage(code2: string) {
+        setStateWrapped(s => ({...s, contentLanguages: [code2]}))
+      },
       toggleContentLanguage(code2: string) {
         setStateWrapped(s => {
           const exists = s.contentLanguages.includes(code2)
diff --git a/src/state/queries/post-feed.ts b/src/state/queries/post-feed.ts
index ee22bac69..3453a7764 100644
--- a/src/state/queries/post-feed.ts
+++ b/src/state/queries/post-feed.ts
@@ -459,6 +459,14 @@ function assertSomePostsPassModeration(feed: AppBskyFeedDefs.FeedViewPost[]) {
   }
 }
 
+export function resetPostsFeedQueries(queryClient: QueryClient, timeout = 0) {
+  setTimeout(() => {
+    queryClient.resetQueries({
+      predicate: query => query.queryKey[0] === RQKEY_ROOT,
+    })
+  }, timeout)
+}
+
 export function resetProfilePostsQueries(
   queryClient: QueryClient,
   did: string,
diff --git a/src/view/shell/NavSignupCard.tsx b/src/view/shell/NavSignupCard.tsx
index aa807f0cc..12bfa7ea0 100644
--- a/src/view/shell/NavSignupCard.tsx
+++ b/src/view/shell/NavSignupCard.tsx
@@ -48,7 +48,13 @@ let NavSignupCard = ({}: {}): React.ReactNode => {
         </Text>
       </View>
 
-      <View style={{flexDirection: 'row', paddingTop: 12, gap: 8}}>
+      <View
+        style={{
+          flexDirection: 'row',
+          flexWrap: 'wrap',
+          paddingTop: 12,
+          gap: 8,
+        }}>
         <Button
           onPress={showCreateAccount}
           accessibilityHint={_(msg`Sign up`)}