Fix sloppy filter(Boolean) types (#4830)

* Fix sloppy filter(Boolean) in threadgate

* Fix sloppy filter(Boolean) in Explore

* Fix sloppy filter(Boolean) in post-feed

* Harden FeedPostSliceItem.reason type def

* Harden parentAuthor types

* Fix lying component types, handle blocks
zio/stable
dan 2024-07-25 19:53:12 +01:00 committed by GitHub
parent fac1af43b0
commit 4291711f1d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 88 additions and 56 deletions

View File

@ -78,7 +78,10 @@ export interface FeedPostSliceItem {
uri: string uri: string
post: AppBskyFeedDefs.PostView post: AppBskyFeedDefs.PostView
record: AppBskyFeedPost.Record record: AppBskyFeedPost.Record
reason?: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource reason?:
| AppBskyFeedDefs.ReasonRepost
| ReasonFeedSource
| {[k: string]: unknown; $type: string}
feedContext: string | undefined feedContext: string | undefined
moderation: ModerationDecision moderation: ModerationDecision
parentAuthor?: AppBskyActorDefs.ProfileViewBasic parentAuthor?: AppBskyActorDefs.ProfileViewBasic
@ -323,7 +326,7 @@ export function usePostFeedQuery(
) )
} }
return { const feedPostSlice: FeedPostSlice = {
_reactKey: slice._reactKey, _reactKey: slice._reactKey,
_isFeedPostSlice: true, _isFeedPostSlice: true,
rootUri: slice.rootItem.post.uri, rootUri: slice.rootItem.post.uri,
@ -341,15 +344,23 @@ export function usePostFeedQuery(
AppBskyFeedPost.validateRecord(item.post.record) AppBskyFeedPost.validateRecord(item.post.record)
.success .success
) { ) {
const parentAuthor = const parent = item.reply?.parent
item.reply?.parent?.author ?? let parentAuthor:
slice.items[i + 1]?.reply?.grandparentAuthor | AppBskyActorDefs.ProfileViewBasic
| undefined
if (AppBskyFeedDefs.isPostView(parent)) {
parentAuthor = parent.author
}
if (!parentAuthor) {
parentAuthor =
slice.items[i + 1]?.reply?.grandparentAuthor
}
const replyRef = item.reply const replyRef = item.reply
const isParentBlocked = AppBskyFeedDefs.isBlockedPost( const isParentBlocked = AppBskyFeedDefs.isBlockedPost(
replyRef?.parent, replyRef?.parent,
) )
return { const feedPostSliceItem: FeedPostSliceItem = {
_reactKey: `${slice._reactKey}-${i}-${item.post.uri}`, _reactKey: `${slice._reactKey}-${i}-${item.post.uri}`,
uri: item.post.uri, uri: item.post.uri,
post: item.post, post: item.post,
@ -363,13 +374,15 @@ export function usePostFeedQuery(
parentAuthor, parentAuthor,
isParentBlocked, isParentBlocked,
} }
return feedPostSliceItem
} }
return undefined return undefined
}) })
.filter(Boolean) as FeedPostSliceItem[], .filter(<T>(n?: T): n is T => Boolean(n)),
} }
return feedPostSlice
}) })
.filter(Boolean) as FeedPostSlice[], .filter(<T>(n?: T): n is T => Boolean(n)),
})), })),
], ],
} }

View File

@ -4,7 +4,7 @@ export type ThreadgateSetting =
| {type: 'nobody'} | {type: 'nobody'}
| {type: 'mention'} | {type: 'mention'}
| {type: 'following'} | {type: 'following'}
| {type: 'list'; list: string} | {type: 'list'; list: unknown}
export function threadgateViewToSettings( export function threadgateViewToSettings(
threadgate: AppBskyFeedDefs.ThreadgateView | undefined, threadgate: AppBskyFeedDefs.ThreadgateView | undefined,
@ -21,18 +21,18 @@ export function threadgateViewToSettings(
if (!record.allow?.length) { if (!record.allow?.length) {
return [{type: 'nobody'}] return [{type: 'nobody'}]
} }
return record.allow const settings: ThreadgateSetting[] = record.allow
.map(allow => { .map(allow => {
let setting: ThreadgateSetting | undefined
if (allow.$type === 'app.bsky.feed.threadgate#mentionRule') { if (allow.$type === 'app.bsky.feed.threadgate#mentionRule') {
return {type: 'mention'} setting = {type: 'mention'}
} else if (allow.$type === 'app.bsky.feed.threadgate#followingRule') {
setting = {type: 'following'}
} else if (allow.$type === 'app.bsky.feed.threadgate#listRule') {
setting = {type: 'list', list: allow.list}
} }
if (allow.$type === 'app.bsky.feed.threadgate#followingRule') { return setting
return {type: 'following'}
}
if (allow.$type === 'app.bsky.feed.threadgate#listRule') {
return {type: 'list', list: allow.list}
}
return undefined
}) })
.filter(Boolean) as ThreadgateSetting[] .filter(<T>(n?: T): n is T => Boolean(n))
return settings
} }

View File

@ -48,7 +48,11 @@ import {Repost_Stroke2_Corner2_Rounded as Repost} from '#/components/icons/Repos
interface FeedItemProps { interface FeedItemProps {
record: AppBskyFeedPost.Record record: AppBskyFeedPost.Record
reason: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource | undefined reason:
| AppBskyFeedDefs.ReasonRepost
| ReasonFeedSource
| {[k: string]: unknown; $type: string}
| undefined
moderation: ModerationDecision moderation: ModerationDecision
parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
showReplyTo: boolean showReplyTo: boolean
@ -337,9 +341,11 @@ let FeedItemInner = ({
postHref={href} postHref={href}
onOpenAuthor={onOpenAuthor} onOpenAuthor={onOpenAuthor}
/> />
{!isThreadChild && showReplyTo && parentAuthor && ( {!isThreadChild &&
<ReplyToLabel blocked={isParentBlocked} profile={parentAuthor} /> showReplyTo &&
)} (parentAuthor || isParentBlocked) && (
<ReplyToLabel blocked={isParentBlocked} profile={parentAuthor} />
)}
<LabelsOnMyPost post={post} /> <LabelsOnMyPost post={post} />
<PostContent <PostContent
moderation={moderation} moderation={moderation}
@ -431,12 +437,46 @@ function ReplyToLabel({
profile, profile,
blocked, blocked,
}: { }: {
profile: AppBskyActorDefs.ProfileViewBasic profile: AppBskyActorDefs.ProfileViewBasic | undefined
blocked?: boolean blocked?: boolean
}) { }) {
const pal = usePalette('default') const pal = usePalette('default')
const {currentAccount} = useSession() const {currentAccount} = useSession()
const isMe = profile.did === currentAccount?.did
let label
if (blocked) {
label = <Trans context="description">Reply to a blocked post</Trans>
} else if (profile != null) {
const isMe = profile.did === currentAccount?.did
if (isMe) {
label = <Trans context="description">Reply to you</Trans>
} else {
label = (
<Trans context="description">
Reply to{' '}
<ProfileHoverCard inline did={profile.did}>
<TextLinkOnWebOnly
type="md"
style={pal.textLight}
lineHeight={1.2}
numberOfLines={1}
href={makeProfileLink(profile)}
text={
profile.displayName
? sanitizeDisplayName(profile.displayName)
: sanitizeHandle(profile.handle)
}
/>
</ProfileHoverCard>
</Trans>
)
}
}
if (!label) {
// Should not happen.
return null
}
return ( return (
<View style={[s.flexRow, s.mb2, s.alignCenter]}> <View style={[s.flexRow, s.mb2, s.alignCenter]}>
@ -450,29 +490,7 @@ function ReplyToLabel({
style={[pal.textLight, s.mr2]} style={[pal.textLight, s.mr2]}
lineHeight={1.2} lineHeight={1.2}
numberOfLines={1}> numberOfLines={1}>
{isMe ? ( {label}
<Trans context="description">Reply to you</Trans>
) : blocked ? (
<Trans context="description">Reply to a blocked post</Trans>
) : (
<Trans context="description">
Reply to{' '}
<ProfileHoverCard inline did={profile.did}>
<TextLinkOnWebOnly
type="md"
style={pal.textLight}
lineHeight={1.2}
numberOfLines={1}
href={makeProfileLink(profile)}
text={
profile.displayName
? sanitizeDisplayName(profile.displayName)
: sanitizeHandle(profile.handle)
}
/>
</ProfileHoverCard>
</Trans>
)}
</Text> </Text>
</View> </View>
) )

View File

@ -75,17 +75,17 @@ function SuggestedItemsHeader({
) )
} }
type LoadMoreItems = type LoadMoreItem =
| { | {
type: 'profile' type: 'profile'
key: string key: string
avatar: string avatar: string | undefined
moderation: ModerationDecision moderation: ModerationDecision
} }
| { | {
type: 'feed' type: 'feed'
key: string key: string
avatar: string avatar: string | undefined
moderation: undefined moderation: undefined
} }
@ -98,27 +98,28 @@ function LoadMore({
}) { }) {
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {_} = useLingui()
const items = React.useMemo(() => { const items: LoadMoreItem[] = React.useMemo(() => {
return item.items return item.items
.map(_item => { .map(_item => {
let loadMoreItem: LoadMoreItem | undefined
if (_item.type === 'profile') { if (_item.type === 'profile') {
return { loadMoreItem = {
type: 'profile', type: 'profile',
key: _item.profile.did, key: _item.profile.did,
avatar: _item.profile.avatar, avatar: _item.profile.avatar,
moderation: moderateProfile(_item.profile, moderationOpts!), moderation: moderateProfile(_item.profile, moderationOpts!),
} }
} else if (_item.type === 'feed') { } else if (_item.type === 'feed') {
return { loadMoreItem = {
type: 'feed', type: 'feed',
key: _item.feed.uri, key: _item.feed.uri,
avatar: _item.feed.avatar, avatar: _item.feed.avatar,
moderation: undefined, moderation: undefined,
} }
} }
return undefined return loadMoreItem
}) })
.filter(Boolean) as LoadMoreItems[] .filter(<T,>(n?: T): n is T => Boolean(n))
}, [item.items, moderationOpts]) }, [item.items, moderationOpts])
if (items.length === 0) return null if (items.length === 0) return null