114 lines
4.5 KiB
JavaScript
114 lines
4.5 KiB
JavaScript
// --- Configuration ---
|
|
// IMPORTANT: For production, use a SEARCH-ONLY API Key.
|
|
// NEVER expose your Admin API Key in client-side code.
|
|
// Best practice is to proxy requests through your backend
|
|
// or use Typesense Scoped Search Keys.
|
|
const TYPESENSE_CONFIG = {
|
|
nodes: [{
|
|
host: '192.168.2.203', // Or your Typesense host
|
|
port: '8108',
|
|
protocol: 'http'
|
|
}],
|
|
apiKey: 'imdiowenxodjioqwenlj', // Generate a search-only API key in Typesense
|
|
connectionTimeoutSeconds: 2
|
|
};
|
|
|
|
const typesenseClient = new Typesense.Client(TYPESENSE_CONFIG);
|
|
|
|
// --- DOM Elements ---
|
|
const searchInput = document.getElementById('user-search-input');
|
|
const suggestionsList = document.getElementById('suggestions-list');
|
|
const selectedUserIdEl = document.getElementById('selected-user-id');
|
|
const selectedUserNameEl = document.getElementById('selected-user-name');
|
|
|
|
// --- Debounce Function (to limit API calls) ---
|
|
let debounceTimer;
|
|
function debounce(func, delay) {
|
|
return function(...args) {
|
|
clearTimeout(debounceTimer);
|
|
debounceTimer = setTimeout(() => func.apply(this, args), delay);
|
|
};
|
|
}
|
|
|
|
// --- Fetch and Display Suggestions ---
|
|
async function fetchSuggestions(query) {
|
|
if (!query.trim()) {
|
|
suggestionsList.innerHTML = '';
|
|
suggestionsList.style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
const searchParameters = {
|
|
'q': query,
|
|
'query_by': 'user_name', // Field to search in
|
|
'per_page': 5, // Number of suggestions to show
|
|
// 'sort_by': '_text_match:desc', // Default, or 'user_name_lowercase_sort:asc' if you use that field
|
|
'infix': 'always', // Ensure infix search is active if not default for the field
|
|
// 'filter_by': 'is_active:=true' // Example: if you have an is_active boolean field
|
|
};
|
|
|
|
try {
|
|
const searchResults = await typesenseClient.collections('users').documents().search(searchParameters);
|
|
displaySuggestions(searchResults.hits || []);
|
|
} catch (error) {
|
|
console.error('Typesense search error:', error);
|
|
suggestionsList.innerHTML = '<li>Error fetching suggestions</li>';
|
|
suggestionsList.style.display = 'block';
|
|
}
|
|
}
|
|
|
|
function displaySuggestions(hits) {
|
|
suggestionsList.innerHTML = ''; // Clear previous suggestions
|
|
if (hits.length === 0) {
|
|
suggestionsList.style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
hits.forEach(hit => {
|
|
const user = hit.document; // The actual document data
|
|
const li = document.createElement('li');
|
|
|
|
// Create a highlighted version of the name if available
|
|
let displayName = user.user_name;
|
|
if (hit.highlights && hit.highlights.length > 0) {
|
|
const nameHighlight = hit.highlights.find(h => h.field === 'user_name');
|
|
if (nameHighlight && nameHighlight.snippet) {
|
|
displayName = nameHighlight.snippet; // Use Typesense's highlighted version
|
|
}
|
|
}
|
|
li.innerHTML = displayName; // Display name (can be highlighted)
|
|
|
|
// Store full user data (or just ID) for selection
|
|
li.dataset.userId = user.user_id;
|
|
li.dataset.userName = user.user_name; // Store the original, non-highlighted name
|
|
|
|
li.addEventListener('click', () => {
|
|
searchInput.value = user.user_name; // Fill input with selected name
|
|
selectedUserIdEl.textContent = user.user_id;
|
|
selectedUserNameEl.textContent = user.user_name;
|
|
suggestionsList.innerHTML = ''; // Clear suggestions
|
|
suggestionsList.style.display = 'none';
|
|
|
|
// You now have user.user_id and user.user_name
|
|
console.log('Selected:', { id: user.user_id, name: user.user_name });
|
|
// Here, you might want to submit a form, make another API call, etc.
|
|
});
|
|
suggestionsList.appendChild(li);
|
|
});
|
|
suggestionsList.style.display = 'block';
|
|
}
|
|
|
|
// --- Event Listeners ---
|
|
searchInput.addEventListener('input', debounce((event) => {
|
|
fetchSuggestions(event.target.value);
|
|
}, 300)); // 300ms debounce
|
|
|
|
// Optional: Hide suggestions when clicking outside
|
|
document.addEventListener('click', (event) => {
|
|
if (!searchInput.contains(event.target) && !suggestionsList.contains(event.target)) {
|
|
suggestionsList.style.display = 'none';
|
|
}
|
|
});
|
|
|
|
console.log("Autocomplete App Initialized. Make sure your Typesense server is running and accessible.");
|
|
console.log("And ensure you've replaced 'YOUR_SEARCH_ONLY_API_KEY' with a valid key."); |