diff --git a/package.json b/package.json index baf4f284..32629d02 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "@segment/analytics-react-native": "^2.10.1", "@segment/sovran-react-native": "^0.4.5", "@sentry/react-native": "5.5.0", + "@tanstack/react-query": "^4.33.0", "@tiptap/core": "^2.0.0-beta.220", "@tiptap/extension-document": "^2.0.0-beta.220", "@tiptap/extension-hard-break": "^2.0.3", diff --git a/src/App.native.tsx b/src/App.native.tsx index 09782a87..d43155bf 100644 --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -16,6 +16,8 @@ import * as notifications from 'lib/notifications/notifications' import * as analytics from 'lib/analytics/analytics' import * as Toast from './view/com/util/Toast' import {handleLink} from './Navigation' +import {QueryClientProvider} from '@tanstack/react-query' +import {queryClient} from 'lib/react-query' SplashScreen.preventAutoHideAsync() @@ -51,17 +53,19 @@ const App = observer(function AppImpl() { return null } return ( - - - - - - - - - - - + + + + + + + + + + + + + ) }) diff --git a/src/App.web.tsx b/src/App.web.tsx index 41a7189d..a9123cc5 100644 --- a/src/App.web.tsx +++ b/src/App.web.tsx @@ -9,6 +9,8 @@ import {Shell} from './view/shell/index' import {ToastContainer} from './view/com/util/Toast.web' import {ThemeProvider} from 'lib/ThemeContext' import {observer} from 'mobx-react-lite' +import {QueryClientProvider} from '@tanstack/react-query' +import {queryClient} from 'lib/react-query' const App = observer(function AppImpl() { const [rootStore, setRootStore] = useState( @@ -30,18 +32,20 @@ const App = observer(function AppImpl() { } return ( - - - - - - - - - - - - + + + + + + + + + + + + + + ) }) diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 94551e6e..001cdf8c 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -148,110 +148,3 @@ export const HITSLOP_10 = createHitslop(10) export const HITSLOP_20 = createHitslop(20) export const HITSLOP_30 = createHitslop(30) export const BACK_HITSLOP = HITSLOP_30 - -export const RECOMMENDED_FEEDS = [ - { - did: 'did:plc:hsqwcidfez66lwm3gxhfv5in', - rkey: 'aaaf2pqeodmpy', - }, - { - did: 'did:plc:gekdk2nd47gkk3utfz2xf7cn', - rkey: 'aaap4tbjcfe5y', - }, - { - did: 'did:plc:5rw2on4i56btlcajojaxwcat', - rkey: 'aaao6g552b33o', - }, - { - did: 'did:plc:jfhpnnst6flqway4eaeqzj2a', - rkey: 'for-science', - }, - { - did: 'did:plc:7q4nnnxawajbfaq7to5dpbsy', - rkey: 'bsky-news', - }, - { - did: 'did:plc:jcoy7v3a2t4rcfdh6i4kza25', - rkey: 'astro', - }, - { - did: 'did:plc:tenurhgjptubkk5zf5qhi3og', - rkey: 'h-nba', - }, - { - did: 'did:plc:vpkhqolt662uhesyj6nxm7ys', - rkey: 'devfeed', - }, - { - did: 'did:plc:cndfx4udwgvpjaakvxvh7wm5', - rkey: 'flipboard-tech', - }, - { - did: 'did:plc:w4xbfzo7kqfes5zb7r6qv3rw', - rkey: 'blacksky', - }, - { - did: 'did:plc:lptjvw6ut224kwrj7ub3sqbe', - rkey: 'aaaotfjzjplna', - }, - { - did: 'did:plc:gkvpokm7ec5j5yxls6xk4e3z', - rkey: 'formula-one', - }, - { - did: 'did:plc:q6gjnaw2blty4crticxkmujt', - rkey: 'positivifeed', - }, - { - did: 'did:plc:l72uci4styb4jucsgcrrj5ap', - rkey: 'aaao5dzfm36u4', - }, - { - did: 'did:plc:k3jkadxv5kkjgs6boyon7m6n', - rkey: 'aaaavlyvqzst2', - }, - { - did: 'did:plc:nkahctfdi6bxk72umytfwghw', - rkey: 'aaado2uvfsc6w', - }, - { - did: 'did:plc:epihigio3d7un7u3gpqiy5gv', - rkey: 'aaaekwsc7zsvs', - }, - { - did: 'did:plc:qiknc4t5rq7yngvz7g4aezq7', - rkey: 'aaaejxlobe474', - }, - { - did: 'did:plc:mlq4aycufcuolr7ax6sezpc4', - rkey: 'aaaoudweck6uy', - }, - { - did: 'did:plc:rcez5hcvq3vzlu5x7xrjyccg', - rkey: 'aaadzjxbcddzi', - }, - { - did: 'did:plc:lnxbuzaenlwjrncx6sc4cfdr', - rkey: 'aaab2vesjtszc', - }, - { - did: 'did:plc:x3cya3wkt4n6u4ihmvpsc5if', - rkey: 'aaacynbxwimok', - }, - { - did: 'did:plc:abv47bjgzjgoh3yrygwoi36x', - rkey: 'aaagt6amuur5e', - }, - { - did: 'did:plc:ffkgesg3jsv2j7aagkzrtcvt', - rkey: 'aaacjerk7gwek', - }, - { - did: 'did:plc:geoqe3qls5mwezckxxsewys2', - rkey: 'aaai43yetqshu', - }, - { - did: 'did:plc:2wqomm3tjqbgktbrfwgvrw34', - rkey: 'authors', - }, -] diff --git a/src/lib/react-query.ts b/src/lib/react-query.ts new file mode 100644 index 00000000..2a8f1d75 --- /dev/null +++ b/src/lib/react-query.ts @@ -0,0 +1,3 @@ +import {QueryClient} from '@tanstack/react-query' + +export const queryClient = new QueryClient() diff --git a/src/view/com/auth/onboarding/RecommendedFeeds.tsx b/src/view/com/auth/onboarding/RecommendedFeeds.tsx index 99cdcafd..8e29a589 100644 --- a/src/view/com/auth/onboarding/RecommendedFeeds.tsx +++ b/src/view/com/auth/onboarding/RecommendedFeeds.tsx @@ -1,5 +1,5 @@ import React from 'react' -import {FlatList, StyleSheet, View} from 'react-native' +import {ActivityIndicator, FlatList, StyleSheet, View} from 'react-native' import {observer} from 'mobx-react-lite' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {TabletOrDesktop, Mobile} from 'view/com/util/layouts/Breakpoints' @@ -10,7 +10,10 @@ import {Button} from 'view/com/util/forms/Button' import {RecommendedFeedsItem} from './RecommendedFeedsItem' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {usePalette} from 'lib/hooks/usePalette' -import {RECOMMENDED_FEEDS} from 'lib/constants' +import {useQuery} from '@tanstack/react-query' +import {useStores} from 'state/index' +import {CustomFeedModel} from 'state/models/feeds/custom-feed' +import {ErrorMessage} from 'view/com/util/error/ErrorMessage' type Props = { next: () => void @@ -18,8 +21,31 @@ type Props = { export const RecommendedFeeds = observer(function RecommendedFeedsImpl({ next, }: Props) { + const store = useStores() const pal = usePalette('default') const {isTabletOrMobile} = useWebMediaQueries() + const {isLoading, data: recommendedFeeds} = useQuery({ + staleTime: Infinity, // fixed list rn, never refetch + queryKey: ['onboarding', 'recommended_feeds'], + async queryFn() { + try { + const { + data: {feeds}, + success, + } = await store.agent.app.bsky.feed.getSuggestedFeeds() + + if (!success) return + + return (feeds.length ? feeds : []).map(feed => { + return new CustomFeedModel(store, feed) + }) + } catch (e) { + return + } + }, + }) + + const hasFeeds = recommendedFeeds && recommendedFeeds.length const title = ( <> @@ -86,12 +112,20 @@ export const RecommendedFeeds = observer(function RecommendedFeedsImpl({ horizontal titleStyle={isTabletOrMobile ? undefined : {minWidth: 470}} contentStyle={{paddingHorizontal: 0}}> - } - keyExtractor={item => item.did + item.rkey} - style={{flex: 1}} - /> + {hasFeeds ? ( + } + keyExtractor={item => item.uri} + style={{flex: 1}} + /> + ) : isLoading ? ( + + + + ) : ( + + )} @@ -106,12 +140,20 @@ export const RecommendedFeeds = observer(function RecommendedFeedsImpl({ pinned feeds. - } - keyExtractor={item => item.did + item.rkey} - style={{flex: 1}} - /> + {hasFeeds ? ( + } + keyExtractor={item => item.uri} + style={{flex: 1}} + /> + ) : isLoading ? ( + + + + ) : ( + + )}