mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React from 'react'
2import {StyleSheet, TouchableOpacity, View} from 'react-native'
3import {observer} from 'mobx-react-lite'
4import {Link} from '../util/Link'
5import {Text} from '../util/text/Text'
6import {UserAvatar} from '../util/UserAvatar'
7import * as Toast from '../util/Toast'
8import {s} from 'lib/styles'
9import {usePalette} from 'lib/hooks/usePalette'
10import {useStores} from 'state/index'
11import * as apilib from 'lib/api/index'
12
13export function ProfileCard({
14 handle,
15 displayName,
16 avatar,
17 description,
18 isFollowedBy,
19 noBorder,
20 renderButton,
21}: {
22 handle: string
23 displayName?: string
24 avatar?: string
25 description?: string
26 isFollowedBy?: boolean
27 noBorder?: boolean
28 renderButton?: () => JSX.Element
29}) {
30 const pal = usePalette('default')
31 return (
32 <Link
33 style={[
34 styles.outer,
35 pal.view,
36 pal.border,
37 noBorder && styles.outerNoBorder,
38 ]}
39 href={`/profile/${handle}`}
40 title={handle}
41 noFeedback>
42 <View style={styles.layout}>
43 <View style={styles.layoutAvi}>
44 <UserAvatar
45 size={40}
46 displayName={displayName}
47 handle={handle}
48 avatar={avatar}
49 />
50 </View>
51 <View style={styles.layoutContent}>
52 <Text
53 type="lg"
54 style={[s.bold, pal.text]}
55 numberOfLines={1}
56 lineHeight={1.2}>
57 {displayName || handle}
58 </Text>
59 <Text type="md" style={[pal.textLight]} numberOfLines={1}>
60 @{handle}
61 </Text>
62 {isFollowedBy && (
63 <View style={s.flexRow}>
64 <View style={[s.mt5, pal.btn, styles.pill]}>
65 <Text type="xs">Follows You</Text>
66 </View>
67 </View>
68 )}
69 </View>
70 {renderButton ? (
71 <View style={styles.layoutButton}>{renderButton()}</View>
72 ) : undefined}
73 </View>
74 {description ? (
75 <View style={styles.details}>
76 <Text style={pal.text} numberOfLines={4}>
77 {description}
78 </Text>
79 </View>
80 ) : undefined}
81 </Link>
82 )
83}
84
85export const ProfileCardWithFollowBtn = observer(
86 ({
87 did,
88 declarationCid,
89 handle,
90 displayName,
91 avatar,
92 description,
93 isFollowedBy,
94 }: {
95 did: string
96 declarationCid: string
97 handle: string
98 displayName?: string
99 avatar?: string
100 description?: string
101 isFollowedBy?: boolean
102 }) => {
103 const store = useStores()
104 const isMe = store.me.handle === handle
105 const isFollowing = store.me.follows.isFollowing(did)
106 const onToggleFollow = async () => {
107 if (store.me.follows.isFollowing(did)) {
108 try {
109 await apilib.unfollow(store, store.me.follows.getFollowUri(did))
110 store.me.follows.removeFollow(did)
111 } catch (e: any) {
112 store.log.error('Failed fo delete follow', e)
113 Toast.show('An issue occurred, please try again.')
114 }
115 } else {
116 try {
117 const res = await apilib.follow(store, did, declarationCid)
118 store.me.follows.addFollow(did, res.uri)
119 } catch (e: any) {
120 store.log.error('Failed fo create follow', e)
121 Toast.show('An issue occurred, please try again.')
122 }
123 }
124 }
125 return (
126 <ProfileCard
127 handle={handle}
128 displayName={displayName}
129 avatar={avatar}
130 description={description}
131 isFollowedBy={isFollowedBy}
132 renderButton={
133 isMe
134 ? undefined
135 : () => (
136 <FollowBtn isFollowing={isFollowing} onPress={onToggleFollow} />
137 )
138 }
139 />
140 )
141 },
142)
143
144function FollowBtn({
145 isFollowing,
146 onPress,
147}: {
148 isFollowing: boolean
149 onPress: () => void
150}) {
151 const pal = usePalette('default')
152 return (
153 <TouchableOpacity onPress={onPress}>
154 <View style={[styles.btn, pal.btn]}>
155 <Text type="button" style={[pal.text]}>
156 {isFollowing ? 'Unfollow' : 'Follow'}
157 </Text>
158 </View>
159 </TouchableOpacity>
160 )
161}
162
163const styles = StyleSheet.create({
164 outer: {
165 borderTopWidth: 1,
166 paddingHorizontal: 6,
167 },
168 outerNoBorder: {
169 borderTopWidth: 0,
170 },
171 layout: {
172 flexDirection: 'row',
173 alignItems: 'center',
174 },
175 layoutAvi: {
176 width: 60,
177 paddingLeft: 10,
178 paddingTop: 8,
179 paddingBottom: 10,
180 },
181 avi: {
182 width: 40,
183 height: 40,
184 borderRadius: 20,
185 resizeMode: 'cover',
186 },
187 layoutContent: {
188 flex: 1,
189 paddingRight: 10,
190 paddingTop: 10,
191 paddingBottom: 10,
192 },
193 layoutButton: {
194 paddingRight: 10,
195 },
196 details: {
197 paddingLeft: 60,
198 paddingRight: 10,
199 paddingBottom: 10,
200 },
201 pill: {
202 borderRadius: 4,
203 paddingHorizontal: 6,
204 paddingVertical: 2,
205 },
206 btn: {
207 paddingVertical: 7,
208 borderRadius: 50,
209 marginLeft: 6,
210 paddingHorizontal: 14,
211 },
212})