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