// Notes/reports operations let notesCollectionName = 'notes'; // Default, will be loaded from config let jobsCollectionName = 'Job_Info'; // Default, will be loaded from config /** * Initialize configuration */ async function initNotesConfig() { try { if (typeof getNotesCollection !== 'undefined') { notesCollectionName = await getNotesCollection(); } if (typeof getJobsCollection !== 'undefined') { jobsCollectionName = await getJobsCollection(); } } catch (error) { console.error('Error initializing notes config:', error); // Use defaults if config fails to load } } // Initialize config when script loads if (typeof getNotesCollection !== 'undefined' || typeof getJobsCollection !== 'undefined') { initNotesConfig(); } // Get note editor instance from global scope or window function getNoteEditor() { return window.noteEditorInstance || noteEditorInstance || null; } /** * Load notes for a specific job */ async function loadJobNotes() { try { const jobId = document.getElementById('jobId').value; if (!jobId) { document.getElementById('notesList').innerHTML = '

No job selected

'; return; } const job = await pb.collection(jobsCollectionName).getOne(jobId); const noteRefs = job.Note_Ref || []; if (noteRefs.length === 0) { document.getElementById('notesList').innerHTML = '

No notes for this job

'; return; } // Fetch all notes const notes = await Promise.all( noteRefs.map(noteId => pb.collection(notesCollectionName).getOne(noteId).catch(() => null) ) ); const validNotes = notes.filter(note => note !== null); if (validNotes.length === 0) { document.getElementById('notesList').innerHTML = '

No notes found

'; return; } displayNotes(validNotes, true); } catch (error) { console.error('Error loading job notes:', error); document.getElementById('notesList').innerHTML = '

Error loading notes

'; } } /** * Load all notes */ async function loadAllNotes() { try { const result = await pb.collection(notesCollectionName).getList(1, 100, { sort: '-created', expand: 'job' }); if (result.items.length === 0) { document.getElementById('loadingIndicator').classList.add('hidden'); document.getElementById('emptyState').classList.remove('hidden'); return; } document.getElementById('loadingIndicator').classList.add('hidden'); document.getElementById('emptyState').classList.add('hidden'); document.getElementById('reportsTableContainer').classList.remove('hidden'); displayNotesTable(result.items); } catch (error) { console.error('Error loading notes:', error); document.getElementById('loadingIndicator').classList.add('hidden'); document.getElementById('emptyState').classList.remove('hidden'); } } /** * Display notes in list format (for job modal) */ function displayNotes(notes, showDelete = false) { const container = document.getElementById('notesList'); if (!notes || notes.length === 0) { container.innerHTML = '

No notes

'; return; } container.innerHTML = notes.map(note => { const date = note.created ? new Date(note.created).toLocaleString() : '-'; const content = note.content || ''; const sentiment = note.sentiment || '-'; return `
${sentiment}
${date}
${showDelete ? `` : ''}
${content}
`; }).join(''); } /** * Display notes in table format (for notes page) */ function displayNotesTable(notes) { const tbody = document.getElementById('notesTableBody'); tbody.innerHTML = notes.map(note => { const date = note.created ? new Date(note.created).toLocaleString() : '-'; const content = note.content ? note.content.substring(0, 100) + '...' : '-'; const jobName = note.job ? (note.job.Job_Number || note.job.Job_Name || '-') : '-'; const sentiment = note.sentiment || '-'; return ` ${jobName} ${content} ${sentiment} ${date} `; }).join(''); } /** * Load note for editing */ async function loadNoteForEdit(noteId) { try { const note = await pb.collection(notesCollectionName).getOne(noteId); document.getElementById('noteId').value = note.id; document.getElementById('noteSentiment').value = note.sentiment || ''; document.getElementById('noteDate').value = note.date ? new Date(note.date).toISOString().slice(0, 16) : ''; if (note.job) { document.getElementById('noteJob').value = note.job; } // Set Quill editor content const editor = getNoteEditor(); if (editor && note.content) { editor.root.innerHTML = note.content; } // Load jobs for select if not already loaded await loadJobsForSelect(); } catch (error) { console.error('Error loading note:', error); showMessage('Error loading note: ' + (error.message || 'Unknown error'), 'error'); } } /** * Save note (create or update) */ async function saveNote() { try { const noteId = document.getElementById('noteId')?.value; const jobId = document.getElementById('noteJob')?.value || document.getElementById('jobId')?.value; const editor = getNoteEditor(); const content = document.getElementById('noteContent')?.value || editor?.root.innerHTML || ''; const sentiment = document.getElementById('noteSentiment')?.value || ''; const date = document.getElementById('noteDate')?.value || new Date().toISOString(); if (!jobId && !noteId) { showMessage('Please select a job', 'error'); return; } const noteData = { content: content, sentiment: sentiment, date: date }; let savedNote; if (noteId) { // Update existing note savedNote = await pb.collection(notesCollectionName).update(noteId, noteData); showMessage('Note updated successfully', 'success'); } else { // Create new note savedNote = await pb.collection(notesCollectionName).create(noteData); showMessage('Note created successfully', 'success'); // Link note to job if (jobId) { await linkNoteToJob(savedNote.id, jobId); } } // Close modal and reload if (document.getElementById('noteModal')) { closeNoteModal(); loadAllNotes(); } else { // In job modal cancelAddNote(); loadJobNotes(); } } catch (error) { console.error('Error saving note:', error); showMessage('Error saving note: ' + (error.message || 'Unknown error'), 'error'); } } /** * Link note to job */ async function linkNoteToJob(noteId, jobId) { try { const job = await pb.collection(jobsCollectionName).getOne(jobId); const noteRefs = job.Note_Ref || []; if (!noteRefs.includes(noteId)) { noteRefs.push(noteId); await pb.collection(jobsCollectionName).update(jobId, { Note_Ref: noteRefs }); } } catch (error) { console.error('Error linking note to job:', error); } } /** * Delete note */ async function deleteNote(noteId) { if (!confirm('Are you sure you want to delete this note?')) { return; } try { await pb.collection(notesCollectionName).delete(noteId); showMessage('Note deleted successfully', 'success'); loadAllNotes(); } catch (error) { console.error('Error deleting note:', error); showMessage('Error deleting note: ' + (error.message || 'Unknown error'), 'error'); } } /** * Delete note from job (unlink) */ async function deleteNoteFromJob(noteId) { if (!confirm('Are you sure you want to delete this note?')) { return; } try { const jobId = document.getElementById('jobId').value; if (jobId) { const job = await pb.collection(jobsCollectionName).getOne(jobId); const noteRefs = (job.Note_Ref || []).filter(id => id !== noteId); await pb.collection(jobsCollectionName).update(jobId, { Note_Ref: noteRefs }); } await pb.collection(notesCollectionName).delete(noteId); showMessage('Note deleted successfully', 'success'); loadJobNotes(); } catch (error) { console.error('Error deleting note:', error); showMessage('Error deleting note: ' + (error.message || 'Unknown error'), 'error'); } } /** * Show add note form (in job modal) */ function showAddNoteForm() { document.getElementById('addNoteForm').classList.remove('hidden'); const editor = getNoteEditor(); if (editor) { editor.setContents([]); } } /** * Cancel add note form */ function cancelAddNote() { document.getElementById('addNoteForm').classList.add('hidden'); const editor = getNoteEditor(); if (editor) { editor.setContents([]); } }