@@ -5,7 +5,11 @@ import { CategoryComponents } from '@app/components/header/components/HeaderSear
55import { Btn , InputSearch } from '../HeaderSearch/HeaderSearch.styles' ;
66import { useTranslation } from 'react-i18next' ;
77import { 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' ;
913interface 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 - f A - F 0 - 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