Skip to content

Commit d657ee7

Browse files
committed
implement simple search to app
1 parent 736da68 commit d657ee7

1 file changed

Lines changed: 86 additions & 3 deletions

File tree

src/components/header/components/searchDropdown/SearchDropdown.tsx

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ import { CategoryComponents } from '@app/components/header/components/HeaderSear
55
import { Btn, InputSearch } from '../HeaderSearch/HeaderSearch.styles';
66
import { useTranslation } from 'react-i18next';
77
import { BasePopover } from '@app/components/common/BasePopover/BasePopover';
8-
8+
import { NDKUserProfile, useNDK } from '@nostr-dev-kit/ndk-hooks';
9+
import usePaidSubscribers from '@app/hooks/usePaidSubscribers';
10+
import { convertNDKUserProfileToSubscriberProfile } from '@app/utils/utils';
11+
import { SubscriberProfile } from '@app/hooks/usePaidSubscribers';
12+
import { SubscriberDetailModal } from '@app/components/relay-dashboard/paid-subscribers/SubscriberDetailModal';
913
interface SearchOverlayProps {
1014
query: string;
1115
setQuery: (query: string) => void;
@@ -22,7 +26,12 @@ export const SearchDropdown: React.FC<SearchOverlayProps> = ({
2226
setOverlayOpen,
2327
}) => {
2428
const [isFilterOpen, setFilterOpen] = useState(false);
25-
29+
const [isSubscriberDetailModalOpen, setSubscriberDetailModalOpen] = useState(false);
30+
const [fetchingProfile, setFetchingProfile] = useState(false);
31+
const [fetchingFailed, setFetchingFailed] = useState(false);
32+
const [subscriberProfile, setSubscriberProfile] = useState<SubscriberProfile | null>(null);
33+
const { subscribers } = usePaidSubscribers();
34+
const ndkInstance = useNDK();
2635
const { t } = useTranslation();
2736

2837
useEffect(() => {
@@ -32,6 +41,66 @@ export const SearchDropdown: React.FC<SearchOverlayProps> = ({
3241
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3342
const ref = useRef<any>(null);
3443

44+
const fetchProfile = async (pubkey: string): Promise<NDKUserProfile | null> => {
45+
if (!ndkInstance) return null;
46+
47+
try {
48+
setFetchingProfile(true);
49+
const profile = await ndkInstance.ndk?.getUser({ pubkey: pubkey }).fetchProfile();
50+
51+
if (profile) {
52+
setFetchingProfile(false);
53+
setFetchingFailed(false);
54+
return profile;
55+
} else {
56+
console.error('Profile not found for pubkey:', pubkey);
57+
setFetchingProfile(false);
58+
setFetchingFailed(true);
59+
return null;
60+
}
61+
} catch (error) {
62+
console.error('Error fetching profile:', error);
63+
setFetchingProfile(false);
64+
setFetchingFailed(true);
65+
return null;
66+
}
67+
};
68+
69+
const handleSearchProfile = async () => {
70+
if (!query) return;
71+
//verify that it's a pubkey
72+
if (/^[a-fA-F0-9]{64}$/.test(query)) {
73+
setSubscriberDetailModalOpen(true);
74+
75+
//See if the pubkey exists in the subscribers
76+
const pubkey = query;
77+
const subscriber = subscribers.find((sub) => sub.pubkey === query);
78+
// If it exists, open the modal with the subscriber details. If name,picture, or about are not set, fetch profile.
79+
//if It doesnt exist, fetch the profile from NDK
80+
//once fetched, convert it to SubscriberProfile and open the modal
81+
if (subscriber) {
82+
if (!subscriber.name || !subscriber.picture || !subscriber.about) {
83+
const profile = await fetchProfile(pubkey);
84+
if (profile) {
85+
const subscriberProfile: SubscriberProfile = convertNDKUserProfileToSubscriberProfile(pubkey, profile);
86+
// Open the modal with the fetched subscriber profile
87+
setSubscriberProfile(subscriberProfile);
88+
}
89+
}
90+
} else {
91+
const profile = await fetchProfile(pubkey);
92+
if (profile) {
93+
const subscriberProfile: SubscriberProfile = convertNDKUserProfileToSubscriberProfile(pubkey, profile);
94+
// Open the modal with the fetched subscriber profile
95+
setSubscriberProfile(subscriberProfile);
96+
}
97+
}
98+
}
99+
};
100+
const onCloseSubscriberDetailModal = () => {
101+
setSubscriberDetailModalOpen(false);
102+
setSubscriberProfile(null);
103+
};
35104
return (
36105
<>
37106
<BasePopover
@@ -45,7 +114,7 @@ export const SearchDropdown: React.FC<SearchOverlayProps> = ({
45114
<InputSearch
46115
width="100%"
47116
value={query}
48-
placeholder={t('header.search')}
117+
placeholder={t('header.search') + ' pubkey'}
49118
filter={
50119
<Btn
51120
size="small"
@@ -57,9 +126,23 @@ export const SearchDropdown: React.FC<SearchOverlayProps> = ({
57126
onChange={(event) => setQuery(event.target.value)}
58127
enterButton={null}
59128
addonAfter={null}
129+
onKeyDown={(event) => {
130+
if (event.key === 'Enter') {
131+
handleSearchProfile();
132+
}
133+
}}
60134
/>
61135
<div ref={ref} />
62136
</HeaderActionWrapper>
137+
{isSubscriberDetailModalOpen && (
138+
<SubscriberDetailModal
139+
loading={fetchingProfile}
140+
fetchFailed={fetchingFailed}
141+
isVisible={isSubscriberDetailModalOpen}
142+
subscriber={subscriberProfile}
143+
onClose={onCloseSubscriberDetailModal}
144+
/>
145+
)}
63146
</BasePopover>
64147
</>
65148
);

0 commit comments

Comments
 (0)