176 lines
5.9 KiB
JavaScript
176 lines
5.9 KiB
JavaScript
/**
|
|
* User Email Lookup Tool
|
|
* Provides hover tooltips showing email addresses when hovering over user names
|
|
*
|
|
* @module UserEmailLookup
|
|
* @description Standalone utility for looking up email addresses from the Associations
|
|
* collection and displaying them as hover tooltips. Integrates with note/conversation
|
|
* sharing UI to enhance user experience when managing shared access.
|
|
* @usage Call window.setupUserEmailLookup(pbInstance, containerSelector) after page load.
|
|
* Pass PocketBase instance and CSS selector for user capsule container.
|
|
* @dependencies PocketBase instance (passed in). Browser APIs: DOM, tooltips via title attribute.
|
|
* @integration Used in index.html note/conversation sharing forms to show email on hover
|
|
* @gotchas Associations collection must have first_name field for lookups. Lookups are
|
|
* performed on hover, so network latency may cause brief delay before tooltip appears.
|
|
* Cache email lookups to minimize PocketBase queries.
|
|
*/
|
|
|
|
// Cache for email lookups to minimize queries
|
|
const emailLookupCache = {};
|
|
let associationsCollectionAvailable = true;
|
|
let associationsWarningShown = false;
|
|
|
|
function getAssociationEmail(record) {
|
|
return record?.emailtext || record?.email || 'Email not found';
|
|
}
|
|
|
|
function handleAssociationsError(error) {
|
|
const statusCode = Number(error?.status || error?.response?.status || 0);
|
|
if (statusCode === 404) {
|
|
associationsCollectionAvailable = false;
|
|
if (!associationsWarningShown) {
|
|
associationsWarningShown = true;
|
|
console.warn("'Associations' collection not found. Email hover lookup disabled.");
|
|
}
|
|
return;
|
|
}
|
|
console.error('Associations lookup failed:', error);
|
|
}
|
|
|
|
/**
|
|
* Fetch email from Associations collection by first name
|
|
* Uses cache to avoid duplicate queries
|
|
*
|
|
* @param {PocketBase} pb - PocketBase instance
|
|
* @param {string} firstName - First name to look up
|
|
* @returns {Promise<string>} Email address or fallback message
|
|
* @example
|
|
* const email = await getEmailByFirstName(pb, 'John');
|
|
* console.log(email); // 'john@example.com' or 'Email not found'
|
|
*/
|
|
async function getEmailByFirstName(pb, firstName) {
|
|
if (!firstName) return 'Email not found';
|
|
if (!associationsCollectionAvailable) return 'Email lookup unavailable';
|
|
|
|
// Check cache first
|
|
if (emailLookupCache[firstName]) {
|
|
return emailLookupCache[firstName];
|
|
}
|
|
|
|
try {
|
|
const records = await pb.collection('Associations').getList(1, 50, {
|
|
filter: `first_name = "${firstName}"`,
|
|
});
|
|
|
|
if (records.items.length === 0) {
|
|
emailLookupCache[firstName] = 'Email not found';
|
|
return 'Email not found';
|
|
}
|
|
|
|
// Use first match's emailtext field
|
|
const firstRecord = records.items[0];
|
|
const email = getAssociationEmail(firstRecord);
|
|
emailLookupCache[firstName] = email;
|
|
return email;
|
|
} catch (error) {
|
|
handleAssociationsError(error);
|
|
return 'Error loading email';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Setup email lookups for user capsules in a container
|
|
* Attaches hover event listeners to show email in tooltip
|
|
*
|
|
* @param {PocketBase} pb - PocketBase instance
|
|
* @param {string} containerSelector - CSS selector for container with user capsules
|
|
* @example
|
|
* window.setupUserEmailLookup(pb, '#selectedUsersContainer');
|
|
*/
|
|
window.setupUserEmailLookup = function(pb, containerSelector) {
|
|
const container = document.querySelector(containerSelector);
|
|
if (!container) {
|
|
console.warn(`setupUserEmailLookup: Container not found: ${containerSelector}`);
|
|
return;
|
|
}
|
|
|
|
console.log(`✓ User Email Lookup initialized for: ${containerSelector}`);
|
|
const observer = new MutationObserver((mutations) => {
|
|
mutations.forEach((mutation) => {
|
|
mutation.addedNodes.forEach((node) => {
|
|
if (node.nodeType === 1 && node.classList?.contains('inline-flex')) {
|
|
attachEmailLookupTooltip(pb, node);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
observer.observe(container, {
|
|
childList: true,
|
|
subtree: true
|
|
});
|
|
|
|
// Also process any existing capsules
|
|
container.querySelectorAll('.inline-flex.items-center.gap-2').forEach((capsule) => {
|
|
attachEmailLookupTooltip(pb, capsule);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Attach email lookup tooltip to a single user capsule
|
|
* Shows email on hover (with caching to prevent redundant queries)
|
|
*
|
|
* @param {PocketBase} pb - PocketBase instance
|
|
* @param {HTMLElement} capsuleEl - The user capsule element
|
|
* @private
|
|
*/
|
|
function attachEmailLookupTooltip(pb, capsuleEl) {
|
|
// Extract first name from capsule text
|
|
const nameSpan = capsuleEl.querySelector('span:not([data-email-loaded])');
|
|
if (!nameSpan || nameSpan.hasAttribute('data-email-loaded')) {
|
|
return;
|
|
}
|
|
|
|
const firstName = nameSpan.textContent.trim();
|
|
if (!firstName) return;
|
|
|
|
console.log(`[Email Lookup] Attached to user: ${firstName}`);
|
|
|
|
// Mark as processed
|
|
nameSpan.setAttribute('data-email-loaded', 'true');
|
|
|
|
// Attach hover listener
|
|
capsuleEl.addEventListener('mouseenter', async () => {
|
|
console.log(`[Email Lookup] Hover on: ${firstName}`);
|
|
// If email already in title, don't query again
|
|
if (capsuleEl.title && !capsuleEl.title.startsWith('Loading')) {
|
|
return;
|
|
}
|
|
|
|
capsuleEl.title = 'Loading email...';
|
|
const email = await getEmailByFirstName(pb, firstName);
|
|
capsuleEl.title = email;
|
|
capsuleEl.classList.add('cursor-help');
|
|
});
|
|
|
|
capsuleEl.addEventListener('mouseleave', () => {
|
|
// Title persists so user can still see it if they hover back quickly
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Clear the email lookup cache
|
|
* Useful if Associations collection is updated and you need fresh data
|
|
*
|
|
* @example
|
|
* window.clearEmailLookupCache();
|
|
*/
|
|
window.clearEmailLookupCache = function() {
|
|
Object.keys(emailLookupCache).forEach(key => delete emailLookupCache[key]);
|
|
associationsCollectionAvailable = true;
|
|
associationsWarningShown = false;
|
|
console.log('✓ Email lookup cache cleared');
|
|
};
|
|
|
|
console.log('✓ User Email Lookup tool loaded - call window.setupUserEmailLookup(pb, containerSelector)');
|