mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import {Pressable, ScrollView, View} from 'react-native'
2import {moderateProfile, type ModerationOpts} from '@atproto/api'
3import {msg, Trans} from '@lingui/macro'
4import {useLingui} from '@lingui/react'
5
6import {createHitslop, HITSLOP_10} from '#/lib/constants'
7import {makeProfileLink} from '#/lib/routes/links'
8import {sanitizeDisplayName} from '#/lib/strings/display-names'
9import {sanitizeHandle} from '#/lib/strings/handles'
10import {useModerationOpts} from '#/state/preferences/moderation-opts'
11import {UserAvatar} from '#/view/com/util/UserAvatar'
12import {BlockDrawerGesture} from '#/view/shell/BlockDrawerGesture'
13import {atoms as a} from '#/alf'
14import {Button, ButtonIcon} from '#/components/Button'
15import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
16import * as Layout from '#/components/Layout'
17import {Link} from '#/components/Link'
18import {Text} from '#/components/Typography'
19import {useSimpleVerificationState} from '#/components/verification'
20import {VerificationCheck} from '#/components/verification/VerificationCheck'
21import type * as bsky from '#/types/bsky'
22
23export function SearchHistory({
24 searchHistory,
25 selectedProfiles,
26 onItemClick,
27 onProfileClick,
28 onRemoveItemClick,
29 onRemoveProfileClick,
30}: {
31 searchHistory: string[]
32 selectedProfiles: bsky.profile.AnyProfileView[]
33 onItemClick: (item: string) => void
34 onProfileClick: (profile: bsky.profile.AnyProfileView) => void
35 onRemoveItemClick: (item: string) => void
36 onRemoveProfileClick: (profile: bsky.profile.AnyProfileView) => void
37}) {
38 const {_} = useLingui()
39 const moderationOpts = useModerationOpts()
40
41 return (
42 <Layout.Content
43 keyboardDismissMode="interactive"
44 keyboardShouldPersistTaps="handled">
45 <View style={[a.w_full, a.gap_md]}>
46 {(searchHistory.length > 0 || selectedProfiles.length > 0) && (
47 <View style={[a.px_lg, a.pt_sm]}>
48 <Text style={[a.text_md, a.font_semi_bold]}>
49 <Trans>Recent Searches</Trans>
50 </Text>
51 </View>
52 )}
53
54 {selectedProfiles.length > 0 && (
55 <View>
56 <BlockDrawerGesture>
57 <ScrollView
58 horizontal
59 keyboardShouldPersistTaps="handled"
60 showsHorizontalScrollIndicator={false}
61 contentContainerStyle={[
62 a.px_lg,
63 a.flex_row,
64 a.flex_nowrap,
65 a.gap_xl,
66 ]}>
67 {moderationOpts &&
68 selectedProfiles.map(profile => (
69 <RecentProfileItem
70 key={profile.did}
71 profile={profile}
72 moderationOpts={moderationOpts}
73 onPress={() => onProfileClick(profile)}
74 onRemove={() => onRemoveProfileClick(profile)}
75 />
76 ))}
77 </ScrollView>
78 </BlockDrawerGesture>
79 </View>
80 )}
81
82 {searchHistory.length > 0 && (
83 <View style={[a.px_lg, a.pt_sm]}>
84 {searchHistory.slice(0, 5).map((historyItem, index) => (
85 <View key={index} style={[a.flex_row, a.align_center]}>
86 <Pressable
87 accessibilityRole="button"
88 onPress={() => onItemClick(historyItem)}
89 hitSlop={HITSLOP_10}
90 style={[a.flex_1, a.py_sm]}>
91 <Text style={[a.text_md]}>{historyItem}</Text>
92 </Pressable>
93 <Button
94 label={_(msg`Remove ${historyItem}`)}
95 onPress={() => onRemoveItemClick(historyItem)}
96 size="small"
97 variant="ghost"
98 color="secondary"
99 shape="round">
100 <ButtonIcon icon={XIcon} />
101 </Button>
102 </View>
103 ))}
104 </View>
105 )}
106 </View>
107 </Layout.Content>
108 )
109}
110
111function RecentProfileItem({
112 profile,
113 moderationOpts,
114 onPress,
115 onRemove,
116}: {
117 profile: bsky.profile.AnyProfileView
118 moderationOpts: ModerationOpts
119 onPress: () => void
120 onRemove: () => void
121}) {
122 const {_} = useLingui()
123 const width = 80
124
125 const moderation = moderateProfile(profile, moderationOpts)
126 const name = sanitizeDisplayName(
127 profile.displayName || sanitizeHandle(profile.handle),
128 moderation.ui('displayName'),
129 )
130 const verification = useSimpleVerificationState({profile})
131
132 return (
133 <View style={[a.relative]}>
134 <Link
135 to={makeProfileLink(profile)}
136 label={profile.handle}
137 onPress={onPress}
138 style={[
139 a.flex_col,
140 a.align_center,
141 a.gap_xs,
142 {
143 width,
144 },
145 ]}>
146 <UserAvatar
147 avatar={profile.avatar}
148 type={profile.associated?.labeler ? 'labeler' : 'user'}
149 size={width - 8}
150 moderation={moderation.ui('avatar')}
151 />
152 <View style={[a.flex_row, a.align_center, a.justify_center, a.w_full]}>
153 <Text emoji style={[a.text_xs, a.leading_snug]} numberOfLines={1}>
154 {name}
155 </Text>
156 {verification.showBadge && (
157 <View style={[a.pl_2xs]}>
158 <VerificationCheck
159 width={10}
160 verifier={verification.role === 'verifier'}
161 />
162 </View>
163 )}
164 </View>
165 </Link>
166 <Button
167 label={_(msg`Remove profile`)}
168 hitSlop={createHitslop(6)}
169 size="tiny"
170 variant="outline"
171 color="secondary"
172 shape="round"
173 onPress={onRemove}
174 style={[
175 a.absolute,
176 {
177 top: 0,
178 right: 0,
179 height: 18,
180 width: 18,
181 },
182 ]}>
183 <ButtonIcon icon={XIcon} />
184 </Button>
185 </View>
186 )
187}