diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/api/build-suggested-posts.ts | 120 | ||||
-rw-r--r-- | src/lib/constants.ts | 36 | ||||
-rw-r--r-- | src/lib/styles.ts | 4 |
3 files changed, 158 insertions, 2 deletions
diff --git a/src/lib/api/build-suggested-posts.ts b/src/lib/api/build-suggested-posts.ts new file mode 100644 index 000000000..6250f4a9c --- /dev/null +++ b/src/lib/api/build-suggested-posts.ts @@ -0,0 +1,120 @@ +import {RootStoreModel} from 'state/index' +import { + AppBskyFeedFeedViewPost, + AppBskyFeedGetAuthorFeed as GetAuthorFeed, +} from '@atproto/api' +type ReasonRepost = AppBskyFeedFeedViewPost.ReasonRepost + +async function getMultipleAuthorsPosts( + rootStore: RootStoreModel, + authors: string[], + cursor: string | undefined = undefined, + limit: number = 10, +) { + const responses = await Promise.all( + authors.map((author, index) => + rootStore.api.app.bsky.feed + .getAuthorFeed({ + author, + limit, + before: cursor ? cursor.split(',')[index] : undefined, + }) + .catch(_err => ({success: false, headers: {}, data: {feed: []}})), + ), + ) + return responses +} + +function mergePosts( + responses: GetAuthorFeed.Response[], + {repostsOnly, bestOfOnly}: {repostsOnly?: boolean; bestOfOnly?: boolean}, +) { + let posts: AppBskyFeedFeedViewPost.Main[] = [] + + if (bestOfOnly) { + for (const res of responses) { + if (res.success) { + // filter the feed down to the post with the most upvotes + res.data.feed = res.data.feed.reduce( + (acc: AppBskyFeedFeedViewPost.Main[], v) => { + if (!acc?.[0] && !v.reason) { + return [v] + } + if ( + acc && + !v.reason && + v.post.upvoteCount > acc[0].post.upvoteCount + ) { + return [v] + } + return acc + }, + [], + ) + } + } + } + + // merge into one array + for (const res of responses) { + if (res.success) { + posts = posts.concat(res.data.feed) + } + } + + // filter down to reposts of other users + const uris = new Set() + posts = posts.filter(p => { + if (repostsOnly && !isARepostOfSomeoneElse(p)) { + return false + } + if (uris.has(p.post.uri)) { + return false + } + uris.add(p.post.uri) + return true + }) + + // sort by index time + posts.sort((a, b) => { + return ( + Number(new Date(b.post.indexedAt)) - Number(new Date(a.post.indexedAt)) + ) + }) + + return posts +} + +function isARepostOfSomeoneElse(post: AppBskyFeedFeedViewPost.Main): boolean { + return ( + post.reason?.$type === 'app.bsky.feed.feedViewPost#reasonRepost' && + post.post.author.did !== (post.reason as ReasonRepost).by.did + ) +} + +function getCombinedCursors(responses: GetAuthorFeed.Response[]) { + let hasCursor = false + const cursors = responses.map(r => { + if (r.data.cursor) { + hasCursor = true + return r.data.cursor + } + return '' + }) + if (!hasCursor) { + return undefined + } + const combinedCursors = cursors.join(',') + return combinedCursors +} + +function isCombinedCursor(cursor: string) { + return cursor.includes(',') +} + +export { + getMultipleAuthorsPosts, + mergePosts, + getCombinedCursors, + isCombinedCursor, +} diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 062fc1aa8..a93301b34 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -4,6 +4,31 @@ export const FEEDBACK_FORM_URL = export const MAX_DISPLAY_NAME = 64 export const MAX_DESCRIPTION = 256 +export const PROD_TEAM_HANDLES = [ + 'jay.bsky.social', + 'paul.bsky.social', + 'dan.bsky.social', + 'divy.bsky.social', + 'why.bsky.social', + 'iamrosewang.bsky.social', +] +export const STAGING_TEAM_HANDLES = [ + 'arcalinea.staging.bsky.dev', + 'paul.staging.bsky.dev', + 'paul2.staging.bsky.dev', +] +export const DEV_TEAM_HANDLES = ['alice.test', 'bob.test', 'carla.test'] + +export function TEAM_HANDLES(serviceUrl: string) { + if (serviceUrl.includes('localhost')) { + return DEV_TEAM_HANDLES + } else if (serviceUrl.includes('staging')) { + return STAGING_TEAM_HANDLES + } else { + return PROD_TEAM_HANDLES + } +} + export const PROD_SUGGESTED_FOLLOWS = [ 'john', 'visakanv', @@ -55,14 +80,21 @@ export const PROD_SUGGESTED_FOLLOWS = [ 'jay', 'paul', ].map(handle => `${handle}.bsky.social`) - export const STAGING_SUGGESTED_FOLLOWS = ['arcalinea', 'paul', 'paul2'].map( handle => `${handle}.staging.bsky.dev`, ) - export const DEV_SUGGESTED_FOLLOWS = ['alice', 'bob', 'carla'].map( handle => `${handle}.test`, ) +export function SUGGESTED_FOLLOWS(serviceUrl: string) { + if (serviceUrl.includes('localhost')) { + return DEV_SUGGESTED_FOLLOWS + } else if (serviceUrl.includes('staging')) { + return STAGING_SUGGESTED_FOLLOWS + } else { + return PROD_SUGGESTED_FOLLOWS + } +} export const POST_IMG_MAX_WIDTH = 2000 export const POST_IMG_MAX_HEIGHT = 2000 diff --git a/src/lib/styles.ts b/src/lib/styles.ts index dd3c86910..f6e26d53f 100644 --- a/src/lib/styles.ts +++ b/src/lib/styles.ts @@ -62,6 +62,10 @@ export const s = StyleSheet.create({ footerSpacer: {height: 100}, contentContainer: {paddingBottom: 200}, border1: {borderWidth: 1}, + borderTop1: {borderTopWidth: 1}, + borderRight1: {borderRightWidth: 1}, + borderBottom1: {borderBottomWidth: 1}, + borderLeft1: {borderLeftWidth: 1}, // font weights fw600: {fontWeight: '600'}, |