mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React from 'react'
2import {View} from 'react-native'
3import {
4 AppBskyGraphDefs,
5 AtUri,
6 moderateUserList,
7 ModerationUI,
8} from '@atproto/api'
9import {msg, Trans} from '@lingui/macro'
10import {useLingui} from '@lingui/react'
11import {useQueryClient} from '@tanstack/react-query'
12
13import {sanitizeHandle} from '#/lib/strings/handles'
14import {useModerationOpts} from '#/state/preferences/moderation-opts'
15import {precacheList} from '#/state/queries/feed'
16import {useSession} from '#/state/session'
17import {atoms as a, useTheme} from '#/alf'
18import {
19 Avatar,
20 Description,
21 Header,
22 Outer,
23 SaveButton,
24} from '#/components/FeedCard'
25import {Link as InternalLink, LinkProps} from '#/components/Link'
26import * as Hider from '#/components/moderation/Hider'
27import {Text} from '#/components/Typography'
28import * as bsky from '#/types/bsky'
29
30/*
31 * This component is based on `FeedCard` and is tightly coupled with that
32 * component. Please refer to `FeedCard` for more context.
33 */
34
35export {
36 Avatar,
37 AvatarPlaceholder,
38 Description,
39 Header,
40 Outer,
41 SaveButton,
42 TitleAndBylinePlaceholder,
43} from '#/components/FeedCard'
44
45const CURATELIST = 'app.bsky.graph.defs#curatelist'
46const MODLIST = 'app.bsky.graph.defs#modlist'
47
48type Props = {
49 view: AppBskyGraphDefs.ListView
50 showPinButton?: boolean
51}
52
53export function Default(props: Props) {
54 const {view, showPinButton} = props
55 const moderationOpts = useModerationOpts()
56 const moderation = moderationOpts
57 ? moderateUserList(view, moderationOpts)
58 : undefined
59
60 return (
61 <Link {...props}>
62 <Outer>
63 <Header>
64 <Avatar src={view.avatar} />
65 <TitleAndByline
66 title={view.name}
67 creator={view.creator}
68 purpose={view.purpose}
69 modUi={moderation?.ui('contentView')}
70 />
71 {showPinButton && view.purpose === CURATELIST && (
72 <SaveButton view={view} pin />
73 )}
74 </Header>
75 <Description description={view.description} />
76 </Outer>
77 </Link>
78 )
79}
80
81export function Link({
82 view,
83 children,
84 ...props
85}: Props & Omit<LinkProps, 'to' | 'label'>) {
86 const queryClient = useQueryClient()
87
88 const href = React.useMemo(() => {
89 return createProfileListHref({list: view})
90 }, [view])
91
92 React.useEffect(() => {
93 precacheList(queryClient, view)
94 }, [view, queryClient])
95
96 return (
97 <InternalLink label={view.name} to={href} {...props}>
98 {children}
99 </InternalLink>
100 )
101}
102
103export function TitleAndByline({
104 title,
105 creator,
106 purpose = CURATELIST,
107 modUi,
108}: {
109 title: string
110 creator?: bsky.profile.AnyProfileView
111 purpose?: AppBskyGraphDefs.ListView['purpose']
112 modUi?: ModerationUI
113}) {
114 const t = useTheme()
115 const {_} = useLingui()
116 const {currentAccount} = useSession()
117
118 return (
119 <View style={[a.flex_1]}>
120 <Hider.Outer
121 modui={modUi}
122 isContentVisibleInitialState={
123 creator && currentAccount?.did === creator.did
124 }
125 allowOverride={creator && currentAccount?.did === creator.did}>
126 <Hider.Mask>
127 <Text
128 style={[a.text_md, a.font_bold, a.leading_snug, a.italic]}
129 numberOfLines={1}>
130 <Trans>Hidden list</Trans>
131 </Text>
132 </Hider.Mask>
133 <Hider.Content>
134 <Text
135 emoji
136 style={[a.text_md, a.font_bold, a.leading_snug]}
137 numberOfLines={1}>
138 {title}
139 </Text>
140 </Hider.Content>
141 </Hider.Outer>
142
143 {creator && (
144 <Text
145 emoji
146 style={[a.leading_snug, t.atoms.text_contrast_medium]}
147 numberOfLines={1}>
148 {purpose === MODLIST
149 ? _(msg`Moderation list by ${sanitizeHandle(creator.handle, '@')}`)
150 : _(msg`List by ${sanitizeHandle(creator.handle, '@')}`)}
151 </Text>
152 )}
153 </View>
154 )
155}
156
157export function createProfileListHref({
158 list,
159}: {
160 list: AppBskyGraphDefs.ListView
161}) {
162 const urip = new AtUri(list.uri)
163 const handleOrDid = list.creator.handle || list.creator.did
164 return `/profile/${handleOrDid}/lists/${urip.rkey}`
165}