Fix alert system initialization - clean up testAlertSound function scope
This commit is contained in:
+99
@@ -333,6 +333,35 @@
|
||||
|
||||
console.log('✓ Capture tools initialized successfully');
|
||||
console.log('Available: window.captureScreenshot, window.captureSnip, window.canvasToFile, window.recordScreen');
|
||||
|
||||
// Alert sound function
|
||||
window.testAlertSound = async function() {
|
||||
try {
|
||||
console.log('🔔 Testing alert sound...');
|
||||
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
||||
const now = audioContext.currentTime;
|
||||
|
||||
const playBell = (startTime, volume = 1) => {
|
||||
const osc = audioContext.createOscillator();
|
||||
const gain = audioContext.createGain();
|
||||
osc.connect(gain);
|
||||
gain.connect(audioContext.destination);
|
||||
osc.frequency.setValueAtTime(1000, startTime);
|
||||
osc.frequency.exponentialRampToValueAtTime(600, startTime + 0.15);
|
||||
gain.gain.setValueAtTime(0.3 * volume, startTime);
|
||||
gain.gain.exponentialRampToValueAtTime(0.01, startTime + 0.2);
|
||||
osc.start(startTime);
|
||||
osc.stop(startTime + 0.2);
|
||||
};
|
||||
|
||||
playBell(now, 1);
|
||||
playBell(now + 0.2, 0.7);
|
||||
console.log('✓ Sound played');
|
||||
} catch (error) {
|
||||
console.error('Failed to play sound:', error);
|
||||
}
|
||||
};
|
||||
console.log('✓ testAlertSound available - call window.testAlertSound()');
|
||||
</script>
|
||||
</head>
|
||||
<body class="bg-gradient-to-br from-primary to-secondary p-4 sm:p-8 flex flex-col items-center justify-center font-sans relative h-screen overflow-hidden">
|
||||
@@ -1358,6 +1387,76 @@
|
||||
console.log(`User display name: ${displayName}`);
|
||||
console.log(`User email: ${email}`);
|
||||
console.log('PB token:', pb.authStore.token ? '(present)' : '(missing)');
|
||||
|
||||
// Initialize user alert system for shared notes
|
||||
try {
|
||||
const alertedNotes = new Set();
|
||||
|
||||
async function verifyUserMatch(firstName) {
|
||||
try {
|
||||
console.log(` Checking: firstName="${firstName}", email="${email}"`);
|
||||
const records = await pb.collection('Associations').getList(1, 50, {
|
||||
filter: `first_name = "${firstName}"`,
|
||||
});
|
||||
|
||||
console.log(` Found ${records.items.length} records`);
|
||||
|
||||
const match = records.items.find((record) => {
|
||||
console.log(` Checking: ${record.first_name} ${record.last_name} (${record.email})`);
|
||||
return record.email === email;
|
||||
});
|
||||
|
||||
return !!match;
|
||||
} catch (error) {
|
||||
console.error('Error verifying user match:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('🔔 Starting user alert monitoring...');
|
||||
await pb.collection('Notes').subscribe('*', async (event) => {
|
||||
try {
|
||||
const note = event.record;
|
||||
console.log(`📝 Note event (${event.action}):`, note.title, `shared=${note.shared}`);
|
||||
|
||||
if (!note.shared) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sharedWithNames = Array.isArray(note.shared_with)
|
||||
? note.shared_with
|
||||
: typeof note.shared_with === 'string'
|
||||
? note.shared_with.split(',').map((n) => n.trim())
|
||||
: [];
|
||||
|
||||
console.log(` → shared_with:`, sharedWithNames);
|
||||
|
||||
let userIsRecipient = false;
|
||||
for (const sharedName of sharedWithNames) {
|
||||
const firstName = sharedName.split(' ')[0];
|
||||
if (await verifyUserMatch(firstName)) {
|
||||
userIsRecipient = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!userIsRecipient || alertedNotes.has(note.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
alertedNotes.add(note.id);
|
||||
console.log(`🔔🔔 ALERT! Note "${note.title}" shared with you`);
|
||||
await window.testAlertSound();
|
||||
} catch (error) {
|
||||
console.error('Error processing note event:', error);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('✓ User alert monitoring started');
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize user alert system:', error);
|
||||
}
|
||||
|
||||
updateAuthUI();
|
||||
await checkTokens();
|
||||
} catch (error) {
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* User Alert System
|
||||
* Monitors shared notes and alerts when someone shares a note with the current user
|
||||
*/
|
||||
|
||||
export class UserAlertSystem {
|
||||
constructor(pocketbaseInstance, userEmail, userName) {
|
||||
this.pb = pocketbaseInstance;
|
||||
this.userEmail = userEmail;
|
||||
this.userName = userName;
|
||||
this.alertedNotes = new Set(); // Track already-alerted notes to avoid duplicates
|
||||
this.unsubscribe = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Play notification sound - double bell/chime
|
||||
*/
|
||||
async playNotificationSound() {
|
||||
try {
|
||||
// Create a simple double bell tone using Web Audio API
|
||||
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
||||
const now = audioContext.currentTime;
|
||||
|
||||
// First bell
|
||||
this.playBell(audioContext, now, 0);
|
||||
// Second bell (offset by 200ms)
|
||||
this.playBell(audioContext, now + 0.2, 0.7);
|
||||
} catch (error) {
|
||||
console.error('Failed to play notification sound:', error);
|
||||
// Fallback: try to play a system notification beep
|
||||
try {
|
||||
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
||||
const osc = audioContext.createOscillator();
|
||||
const gain = audioContext.createGain();
|
||||
osc.connect(gain);
|
||||
gain.connect(audioContext.destination);
|
||||
osc.frequency.value = 800;
|
||||
gain.gain.setValueAtTime(0.3, audioContext.currentTime);
|
||||
gain.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.1);
|
||||
osc.start(audioContext.currentTime);
|
||||
osc.stop(audioContext.currentTime + 0.1);
|
||||
} catch (e) {
|
||||
console.error('Fallback notification sound also failed:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Play a single bell tone
|
||||
*/
|
||||
playBell(audioContext, startTime, volume = 1) {
|
||||
const osc = audioContext.createOscillator();
|
||||
const gain = audioContext.createGain();
|
||||
|
||||
osc.connect(gain);
|
||||
gain.connect(audioContext.destination);
|
||||
|
||||
// Bell frequency (higher pitch for notification)
|
||||
osc.frequency.setValueAtTime(1000, startTime);
|
||||
osc.frequency.exponentialRampToValueAtTime(600, startTime + 0.15);
|
||||
|
||||
// Bell envelope (fade out)
|
||||
gain.gain.setValueAtTime(0.3 * volume, startTime);
|
||||
gain.gain.exponentialRampToValueAtTime(0.01, startTime + 0.2);
|
||||
|
||||
osc.start(startTime);
|
||||
osc.stop(startTime + 0.2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a name matches the current user
|
||||
* Searches Associations collection for first_name match and verifies email
|
||||
*/
|
||||
async verifyUserMatch(firstName) {
|
||||
try {
|
||||
console.log(`Checking for user match: firstName="${firstName}", currentEmail="${this.userEmail}"`);
|
||||
|
||||
// Search Associations collection for matching first_name
|
||||
const records = await this.pb.collection('Associations').getList(1, 50, {
|
||||
filter: `first_name = "${firstName}"`,
|
||||
});
|
||||
|
||||
console.log(`Found ${records.items.length} records with first_name="${firstName}"`);
|
||||
|
||||
if (records.items.length === 0) {
|
||||
console.log(`No user found with first name: ${firstName}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if any matching record has the current user's email
|
||||
const match = records.items.find((record) => {
|
||||
console.log(`Checking record: ${record.first_name} ${record.last_name} (${record.email})`);
|
||||
return record.email === this.userEmail;
|
||||
});
|
||||
|
||||
if (match) {
|
||||
console.log(`✓ User match confirmed: ${firstName} (${this.userEmail})`);
|
||||
return true;
|
||||
}
|
||||
|
||||
console.log(`No email match for ${firstName} and ${this.userEmail}`);
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error('Error verifying user match:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize real-time monitoring of Notes collection
|
||||
*/
|
||||
async startMonitoring() {
|
||||
try {
|
||||
console.log('🔔 Starting user alert monitoring...');
|
||||
|
||||
// Subscribe to Notes collection changes
|
||||
this.unsubscribe = await this.pb.collection('Notes').subscribe('*', async (event) => {
|
||||
try {
|
||||
const note = event.record;
|
||||
console.log(`📝 Note event (${event.action}):`, note.title, `shared=${note.shared}`, `shared_with=`, note.shared_with);
|
||||
|
||||
// Only process shared notes
|
||||
if (!note.shared) {
|
||||
console.log(' → Skipped: not shared');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if current user is in shared_with list
|
||||
const sharedWithNames = Array.isArray(note.shared_with)
|
||||
? note.shared_with
|
||||
: typeof note.shared_with === 'string'
|
||||
? note.shared_with.split(',').map((n) => n.trim())
|
||||
: [];
|
||||
|
||||
console.log(` → shared_with names:`, sharedWithNames);
|
||||
|
||||
// Extract first names from shared_with and check for match
|
||||
let userIsRecipient = false;
|
||||
for (const sharedName of sharedWithNames) {
|
||||
const firstName = sharedName.split(' ')[0];
|
||||
console.log(` → Checking if ${firstName} matches...`);
|
||||
const isMatch = await this.verifyUserMatch(firstName);
|
||||
if (isMatch) {
|
||||
userIsRecipient = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!userIsRecipient) {
|
||||
console.log(' → Skipped: user not in shared_with');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we've already alerted for this note
|
||||
if (this.alertedNotes.has(note.id)) {
|
||||
console.log(' → Skipped: already alerted for this note');
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark as alerted and play sound
|
||||
this.alertedNotes.add(note.id);
|
||||
console.log(`🔔 Alert! Note "${note.title}" shared with you`);
|
||||
await this.playNotificationSound();
|
||||
} catch (error) {
|
||||
console.error('Error processing note event:', error);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('✓ User alert monitoring started');
|
||||
} catch (error) {
|
||||
console.error('Failed to start monitoring:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop monitoring
|
||||
*/
|
||||
stopMonitoring() {
|
||||
if (this.unsubscribe) {
|
||||
this.unsubscribe();
|
||||
this.unsubscribe = null;
|
||||
console.log('⏹ User alert monitoring stopped');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize user alert system
|
||||
* Call this after user authentication
|
||||
*/
|
||||
export async function initializeUserAlert(pb, userEmail, userName) {
|
||||
const alertSystem = new UserAlertSystem(pb, userEmail, userName);
|
||||
await alertSystem.startMonitoring();
|
||||
return alertSystem;
|
||||
}
|
||||
Reference in New Issue
Block a user