feat: Ajouter logs de debug pour la recherche globale

- Logs détaillés dans GlobalSearchBar pour fetchSuggestions
- Logs pour chaque étape de la recherche (tracks, playlists, users)
- Logs de performance avec durée des requêtes
- Logs dans Search component pour interactions utilisateur
- Logs pour navigation et sélection de résultats
- Utilisation de console.log avec préfixes [🔍] pour faciliter le filtrage dans DevTools
This commit is contained in:
senke 2026-01-18 12:38:53 +01:00
parent 52ace207fc
commit b5d6bc2f12
2 changed files with 186 additions and 4 deletions

View file

@ -33,11 +33,21 @@ export function GlobalSearchBar({
// Fetch autocomplete suggestions
const fetchSuggestions = useCallback(
async (query: string): Promise<SearchResult[]> => {
console.log('[🔍 GlobalSearchBar] fetchSuggestions called', { query });
logger.debug('Fetching search suggestions', { query, component: 'GlobalSearchBar' });
if (!query.trim()) {
console.log('[🔍 GlobalSearchBar] Empty query, returning empty results');
return [];
}
try {
const startTime = performance.now();
console.log('[🔍 GlobalSearchBar] Starting parallel search requests', {
query,
playlistSearchEnabled: isFeatureEnabled('PLAYLIST_SEARCH'),
});
// Fetch suggestions from all sources in parallel
// FIX: Gérer les feature flags (PLAYLIST_SEARCH peut être désactivé)
const searchPromises: Array<Promise<any>> = [
@ -47,10 +57,12 @@ export function GlobalSearchBar({
// Ajouter la recherche de playlists seulement si la feature est activée
if (isFeatureEnabled('PLAYLIST_SEARCH')) {
console.log('[🔍 GlobalSearchBar] Playlist search enabled, adding to promises');
searchPromises.push(
playlistsApi.search({ q: query, page: 1, limit: 3 }),
);
} else {
console.log('[🔍 GlobalSearchBar] Playlist search disabled, using empty result');
// Si désactivé, retourner une promesse résolue avec un résultat vide
searchPromises.push(Promise.resolve({ playlists: [], total: 0 }));
}
@ -59,11 +71,21 @@ export function GlobalSearchBar({
searchPromises,
);
const duration = performance.now() - startTime;
console.log('[🔍 GlobalSearchBar] Search requests completed', {
duration: `${duration.toFixed(2)}ms`,
tracksStatus: tracksData.status,
usersStatus: usersData.status,
playlistsStatus: playlistsData.status,
});
const results: SearchResult[] = [];
// Add track suggestions
// FIX: searchTracks retourne PaginatedResponse<Track> avec propriété 'data'
if (tracksData.status === 'fulfilled' && tracksData.value?.data) {
const tracksCount = tracksData.value.data.length;
console.log('[🔍 GlobalSearchBar] Adding track suggestions', { count: tracksCount });
tracksData.value.data.forEach((track: any) => {
results.push({
id: track.id,
@ -73,6 +95,12 @@ export function GlobalSearchBar({
image: track.cover_url || track.cover || track.thumbnail_url,
});
});
} else {
console.log('[🔍 GlobalSearchBar] No track suggestions', {
status: tracksData.status,
hasData: tracksData.status === 'fulfilled' && !!tracksData.value?.data,
error: tracksData.status === 'rejected' ? tracksData.reason : undefined,
});
}
// Add playlist suggestions (seulement si la feature est activée)
@ -81,6 +109,8 @@ export function GlobalSearchBar({
playlistsData.status === 'fulfilled' &&
playlistsData.value?.playlists
) {
const playlistsCount = playlistsData.value.playlists.length;
console.log('[🔍 GlobalSearchBar] Adding playlist suggestions', { count: playlistsCount });
playlistsData.value.playlists.forEach((playlist: any) => {
results.push({
id: playlist.id,
@ -90,10 +120,18 @@ export function GlobalSearchBar({
image: playlist.cover_url || playlist.thumbnail_url,
});
});
} else {
console.log('[🔍 GlobalSearchBar] No playlist suggestions', {
featureEnabled: isFeatureEnabled('PLAYLIST_SEARCH'),
status: playlistsData.status,
hasData: playlistsData.status === 'fulfilled' && !!playlistsData.value?.playlists,
});
}
// Add user suggestions
if (usersData.status === 'fulfilled' && usersData.value?.users) {
const usersCount = usersData.value.users.length;
console.log('[🔍 GlobalSearchBar] Adding user suggestions', { count: usersCount });
usersData.value.users.forEach((user: any) => {
results.push({
id: user.id,
@ -103,13 +141,44 @@ export function GlobalSearchBar({
image: user.avatar_url,
});
});
} else {
console.log('[🔍 GlobalSearchBar] No user suggestions', {
status: usersData.status,
hasData: usersData.status === 'fulfilled' && !!usersData.value?.users,
error: usersData.status === 'rejected' ? usersData.reason : undefined,
});
}
return results.slice(0, 8); // Limit to 8 total suggestions
const finalResults = results.slice(0, 8); // Limit to 8 total suggestions
console.log('[🔍 GlobalSearchBar] Final suggestions', {
total: results.length,
limited: finalResults.length,
breakdown: {
tracks: finalResults.filter((r) => r.type === 'track').length,
playlists: finalResults.filter((r) => r.type === 'playlist').length,
users: finalResults.filter((r) => r.type === 'user').length,
},
});
logger.debug('Search suggestions fetched', {
query,
totalResults: results.length,
limitedResults: finalResults.length,
component: 'GlobalSearchBar',
});
return finalResults;
} catch (error) {
console.error('[🔍 GlobalSearchBar] Error fetching suggestions', {
error,
query,
errorMessage: error instanceof Error ? error.message : String(error),
errorStack: error instanceof Error ? error.stack : undefined,
});
logger.error('Error fetching search suggestions', {
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
query,
component: 'GlobalSearchBar',
});
return [];
}
@ -120,9 +189,15 @@ export function GlobalSearchBar({
// Handle search action - navigation vers la page de recherche
const handleSearch = useCallback(
(query: string) => {
console.log('[🔍 GlobalSearchBar] handleSearch called', { query });
if (query.trim()) {
navigate(`/search?q=${encodeURIComponent(query)}`);
const searchUrl = `/search?q=${encodeURIComponent(query)}`;
console.log('[🔍 GlobalSearchBar] Navigating to search page', { searchUrl });
navigate(searchUrl);
onSearch?.(query);
logger.debug('Search submitted', { query, component: 'GlobalSearchBar' });
} else {
console.log('[🔍 GlobalSearchBar] Empty query, skipping navigation');
}
},
[navigate, onSearch],
@ -131,6 +206,17 @@ export function GlobalSearchBar({
// Handle result selection
const handleResultSelect = useCallback(
(result: SearchResult) => {
console.log('[🔍 GlobalSearchBar] handleResultSelect called', {
type: result.type,
id: result.id,
title: result.title,
});
logger.debug('Search result selected', {
type: result.type,
id: result.id,
component: 'GlobalSearchBar',
});
switch (result.type) {
case 'track':
navigate(`/tracks/${result.id}`);

View file

@ -67,28 +67,72 @@ export function Search({
// Debounce de la query pour la recherche
const debouncedQuery = useDebounce(query, debounceDelay);
// Log query changes
useEffect(() => {
console.log('[🔍 Search] Query changed', {
rawQuery: query,
debouncedQuery,
debounceDelay,
});
}, [query, debouncedQuery, debounceDelay]);
// Fetch suggestions lorsque la query change
useEffect(() => {
console.log('[🔍 Search] useEffect triggered for suggestions', {
debouncedQuery,
hasFetchSuggestions: !!fetchSuggestions,
showSuggestions,
});
if (!debouncedQuery.trim() || !fetchSuggestions || !showSuggestions) {
console.log('[🔍 Search] Skipping suggestions fetch', {
reason: !debouncedQuery.trim()
? 'empty query'
: !fetchSuggestions
? 'no fetchSuggestions'
: 'showSuggestions disabled',
});
setSuggestions([]);
setIsLoading(false);
return;
}
console.log('[🔍 Search] Starting suggestions fetch', { debouncedQuery });
setIsLoading(true);
const loadSuggestions = async () => {
const startTime = performance.now();
try {
const results = await Promise.resolve(fetchSuggestions(debouncedQuery));
const duration = performance.now() - startTime;
console.log('[🔍 Search] Suggestions fetched', {
count: results.length,
duration: `${duration.toFixed(2)}ms`,
results: results.map((r) => ({ type: r.type, title: r.title })),
});
setSuggestions(results);
logger.debug('Suggestions loaded', {
query: debouncedQuery,
count: results.length,
component: 'Search',
});
} catch (error) {
const duration = performance.now() - startTime;
console.error('[🔍 Search] Error fetching suggestions', {
error,
query: debouncedQuery,
duration: `${duration.toFixed(2)}ms`,
errorMessage: error instanceof Error ? error.message : String(error),
});
logger.error('Error fetching suggestions', {
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
query: debouncedQuery,
component: 'Search',
});
setSuggestions([]);
} finally {
setIsLoading(false);
console.log('[🔍 Search] Suggestions fetch completed', { isLoading: false });
}
};
@ -120,12 +164,18 @@ export function Search({
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
console.log('[🔍 Search] Input changed', { value, length: value.length });
setQuery(value);
setShowDropdown(true);
setActiveIndex(-1);
};
const handleInputFocus = () => {
console.log('[🔍 Search] Input focused', {
query,
hasHistory: showHistory && history.length > 0,
historyCount: history.length,
});
if (query.trim() || (showHistory && history.length > 0)) {
setShowDropdown(true);
}
@ -137,17 +187,33 @@ export function Search({
...suggestions,
];
console.log('[🔍 Search] Key pressed', {
key: e.key,
activeIndex,
itemsCount: items.length,
query,
});
switch (e.key) {
case 'ArrowDown':
e.preventDefault();
setActiveIndex((prev) => (prev < items.length - 1 ? prev + 1 : prev));
const newIndexDown = activeIndex < items.length - 1 ? activeIndex + 1 : activeIndex;
console.log('[🔍 Search] ArrowDown', { previousIndex: activeIndex, newIndex: newIndexDown });
setActiveIndex(newIndexDown);
break;
case 'ArrowUp':
e.preventDefault();
setActiveIndex((prev) => (prev > 0 ? prev - 1 : -1));
const newIndexUp = activeIndex > 0 ? activeIndex - 1 : -1;
console.log('[🔍 Search] ArrowUp', { previousIndex: activeIndex, newIndex: newIndexUp });
setActiveIndex(newIndexUp);
break;
case 'Enter':
e.preventDefault();
console.log('[🔍 Search] Enter pressed', {
activeIndex,
itemsCount: items.length,
query,
});
if (activeIndex >= 0 && activeIndex < items.length) {
if (
activeIndex <
@ -155,6 +221,7 @@ export function Search({
) {
// C'est un item de l'historique
const historyItem = history[activeIndex];
console.log('[🔍 Search] Selecting history item', { historyItem, index: activeIndex });
setQuery(historyItem);
handleSearch(historyItem);
} else {
@ -165,13 +232,19 @@ export function Search({
? Math.min(history.length, 5)
: 0);
const result = suggestions[suggestionIndex];
console.log('[🔍 Search] Selecting suggestion', {
suggestionIndex,
result: result ? { type: result.type, title: result.title } : null,
});
handleResultSelect(result);
}
} else if (query.trim()) {
console.log('[🔍 Search] Submitting query directly', { query });
handleSearch(query);
}
break;
case 'Escape':
console.log('[🔍 Search] Escape pressed, closing dropdown');
setShowDropdown(false);
setActiveIndex(-1);
inputRef.current?.blur();
@ -181,6 +254,7 @@ export function Search({
const handleSearch = useCallback(
(searchQuery: string) => {
console.log('[🔍 Search] handleSearch called', { searchQuery });
if (searchQuery.trim()) {
// Ajouter à l'historique
if (showHistory) {
@ -190,11 +264,23 @@ export function Search({
0,
maxHistoryItems,
);
console.log('[🔍 Search] History updated', {
previousCount: prev.length,
newCount: updated.length,
added: searchQuery,
});
return updated;
});
}
setShowDropdown(false);
console.log('[🔍 Search] Calling onSearch callback', { searchQuery });
onSearch(searchQuery);
logger.debug('Search submitted from Search component', {
query: searchQuery,
component: 'Search',
});
} else {
console.log('[🔍 Search] Empty search query, skipping');
}
},
[onSearch, showHistory, setHistory, maxHistoryItems],
@ -202,10 +288,20 @@ export function Search({
const handleResultSelect = useCallback(
(result: SearchResult) => {
console.log('[🔍 Search] handleResultSelect called', {
type: result.type,
id: result.id,
title: result.title,
});
setQuery(result.title);
setShowDropdown(false);
setActiveIndex(-1);
onResultSelect?.(result);
logger.debug('Search result selected from Search component', {
type: result.type,
id: result.id,
component: 'Search',
});
},
[onResultSelect],
);