13 changed files with 938 additions and 764 deletions
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,84 @@ |
|||||||
|
/** |
||||||
|
* Service class for handling event search operations |
||||||
|
* AI-NOTE: 2025-01-24 - Extracted from EventSearch component for better separation of concerns |
||||||
|
*/ |
||||||
|
export class EventSearchService { |
||||||
|
/** |
||||||
|
* Determines the search type from a query string |
||||||
|
*/ |
||||||
|
getSearchType(query: string): { type: string; term: string } | null { |
||||||
|
const lowerQuery = query.toLowerCase(); |
||||||
|
|
||||||
|
if (lowerQuery.startsWith("d:")) { |
||||||
|
const dTag = query.slice(2).trim().toLowerCase(); |
||||||
|
return dTag ? { type: "d", term: dTag } : null; |
||||||
|
} |
||||||
|
|
||||||
|
if (lowerQuery.startsWith("t:")) { |
||||||
|
const searchTerm = query.slice(2).trim(); |
||||||
|
return searchTerm ? { type: "t", term: searchTerm } : null; |
||||||
|
} |
||||||
|
|
||||||
|
if (lowerQuery.startsWith("n:")) { |
||||||
|
const searchTerm = query.slice(2).trim(); |
||||||
|
return searchTerm ? { type: "n", term: searchTerm } : null; |
||||||
|
} |
||||||
|
|
||||||
|
if (query.includes("@")) { |
||||||
|
return { type: "nip05", term: query }; |
||||||
|
} |
||||||
|
|
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks if a search value matches the current event |
||||||
|
*/ |
||||||
|
isCurrentEventMatch(searchValue: string, event: any, relays: string[]): boolean { |
||||||
|
const currentEventId = event.id; |
||||||
|
let currentNaddr = null; |
||||||
|
let currentNevent = null; |
||||||
|
let currentNpub = null; |
||||||
|
let currentNprofile = null; |
||||||
|
|
||||||
|
try { |
||||||
|
const { neventEncode, naddrEncode, nprofileEncode } = require("$lib/utils"); |
||||||
|
const { getMatchingTags, toNpub } = require("$lib/utils/nostrUtils"); |
||||||
|
|
||||||
|
currentNevent = neventEncode(event, relays); |
||||||
|
} catch {} |
||||||
|
|
||||||
|
try { |
||||||
|
const { naddrEncode } = require("$lib/utils"); |
||||||
|
const { getMatchingTags } = require("$lib/utils/nostrUtils"); |
||||||
|
|
||||||
|
currentNaddr = getMatchingTags(event, "d")[0]?.[1] |
||||||
|
? naddrEncode(event, relays) |
||||||
|
: null; |
||||||
|
} catch {} |
||||||
|
|
||||||
|
try { |
||||||
|
const { toNpub } = require("$lib/utils/nostrUtils"); |
||||||
|
currentNpub = event.kind === 0 ? toNpub(event.pubkey) : null; |
||||||
|
} catch {} |
||||||
|
|
||||||
|
if ( |
||||||
|
searchValue && |
||||||
|
searchValue.startsWith("nprofile1") && |
||||||
|
event.kind === 0 |
||||||
|
) { |
||||||
|
try { |
||||||
|
const { nprofileEncode } = require("$lib/utils"); |
||||||
|
currentNprofile = nprofileEncode(event.pubkey, relays); |
||||||
|
} catch {} |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
searchValue === currentEventId || |
||||||
|
(currentNaddr && searchValue === currentNaddr) || |
||||||
|
(currentNevent && searchValue === currentNevent) || |
||||||
|
(currentNpub && searchValue === currentNpub) || |
||||||
|
(currentNprofile && searchValue === currentNprofile) |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,62 @@ |
|||||||
|
/** |
||||||
|
* Service class for managing search state operations |
||||||
|
* AI-NOTE: 2025-01-24 - Extracted from EventSearch component for better separation of concerns |
||||||
|
*/ |
||||||
|
export class SearchStateManager { |
||||||
|
/** |
||||||
|
* Updates the search state with new values |
||||||
|
*/ |
||||||
|
updateSearchState( |
||||||
|
state: { |
||||||
|
searching: boolean; |
||||||
|
searchCompleted: boolean; |
||||||
|
searchResultCount: number | null; |
||||||
|
searchResultType: string | null; |
||||||
|
}, |
||||||
|
onLoadingChange?: (loading: boolean) => void |
||||||
|
): void { |
||||||
|
if (onLoadingChange) { |
||||||
|
onLoadingChange(state.searching); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Resets all search state to initial values |
||||||
|
*/ |
||||||
|
resetSearchState( |
||||||
|
callbacks: { |
||||||
|
onSearchResults: (events: any[], secondOrder: any[], tTagEvents: any[], eventIds: Set<string>, addresses: Set<string>) => void; |
||||||
|
cleanupSearch: () => void; |
||||||
|
clearTimeout: () => void; |
||||||
|
} |
||||||
|
): void { |
||||||
|
callbacks.cleanupSearch(); |
||||||
|
callbacks.onSearchResults([], [], [], new Set(), new Set()); |
||||||
|
callbacks.clearTimeout(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Handles search errors with consistent error handling |
||||||
|
*/ |
||||||
|
handleSearchError( |
||||||
|
error: unknown, |
||||||
|
defaultMessage: string, |
||||||
|
callbacks: { |
||||||
|
setLocalError: (error: string | null) => void; |
||||||
|
cleanupSearch: () => void; |
||||||
|
updateSearchState: (state: any) => void; |
||||||
|
resetProcessingFlags: () => void; |
||||||
|
} |
||||||
|
): void { |
||||||
|
const errorMessage = error instanceof Error ? error.message : defaultMessage; |
||||||
|
callbacks.setLocalError(errorMessage); |
||||||
|
callbacks.cleanupSearch(); |
||||||
|
callbacks.updateSearchState({ |
||||||
|
searching: false, |
||||||
|
searchCompleted: false, |
||||||
|
searchResultCount: null, |
||||||
|
searchResultType: null |
||||||
|
}); |
||||||
|
callbacks.resetProcessingFlags(); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
/** |
||||||
|
* Utility class for formatting search result messages |
||||||
|
* AI-NOTE: 2025-01-24 - Extracted from EventSearch component for better separation of concerns |
||||||
|
*/ |
||||||
|
export class SearchResultFormatter { |
||||||
|
/** |
||||||
|
* Formats a result message based on search count and type |
||||||
|
*/ |
||||||
|
formatResultMessage(searchResultCount: number | null, searchResultType: string | null): string { |
||||||
|
if (searchResultCount === 0) { |
||||||
|
return "Search completed. No results found."; |
||||||
|
} |
||||||
|
|
||||||
|
const typeLabel = |
||||||
|
searchResultType === "n" |
||||||
|
? "profile" |
||||||
|
: searchResultType === "nip05" |
||||||
|
? "NIP-05 address" |
||||||
|
: "event"; |
||||||
|
const countLabel = searchResultType === "n" ? "profiles" : "events"; |
||||||
|
|
||||||
|
return searchResultCount === 1 |
||||||
|
? `Search completed. Found 1 ${typeLabel}.` |
||||||
|
: `Search completed. Found ${searchResultCount} ${countLabel}.`; |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue