329 lines
11 KiB
JavaScript
329 lines
11 KiB
JavaScript
// 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 = '<p class="text-center text-gray-500 py-8">No job selected</p>';
|
|
return;
|
|
}
|
|
|
|
const job = await pb.collection(jobsCollectionName).getOne(jobId);
|
|
const noteRefs = job.Note_Ref || [];
|
|
|
|
if (noteRefs.length === 0) {
|
|
document.getElementById('notesList').innerHTML = '<p class="text-center text-gray-500 py-8">No notes for this job</p>';
|
|
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 = '<p class="text-center text-gray-500 py-8">No notes found</p>';
|
|
return;
|
|
}
|
|
|
|
displayNotes(validNotes, true);
|
|
} catch (error) {
|
|
console.error('Error loading job notes:', error);
|
|
document.getElementById('notesList').innerHTML = '<p class="text-center text-red-500 py-8">Error loading notes</p>';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 = '<p class="text-center text-gray-500 py-8">No notes</p>';
|
|
return;
|
|
}
|
|
|
|
container.innerHTML = notes.map(note => {
|
|
const date = note.created ? new Date(note.created).toLocaleString() : '-';
|
|
const content = note.content || '';
|
|
const sentiment = note.sentiment || '-';
|
|
|
|
return `
|
|
<div class="p-4 bg-white border border-gray-200 rounded-lg">
|
|
<div class="flex justify-between items-start mb-2">
|
|
<div>
|
|
<div class="text-sm font-medium text-gray-900">${sentiment}</div>
|
|
<div class="text-xs text-gray-500">${date}</div>
|
|
</div>
|
|
${showDelete ? `<button onclick="deleteNoteFromJob('${note.id}')" class="text-red-600 hover:text-red-700 text-sm">Delete</button>` : ''}
|
|
</div>
|
|
<div class="text-sm text-gray-700 mt-2">${content}</div>
|
|
</div>
|
|
`;
|
|
}).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 `
|
|
<tr class="hover:bg-gray-50">
|
|
<td class="px-3 sm:px-6 py-4 whitespace-nowrap text-sm text-gray-900">${jobName}</td>
|
|
<td class="px-3 sm:px-6 py-4 text-sm text-gray-900">${content}</td>
|
|
<td class="px-3 sm:px-6 py-4 whitespace-nowrap text-sm text-gray-900">${sentiment}</td>
|
|
<td class="px-3 sm:px-6 py-4 whitespace-nowrap text-sm text-gray-900">${date}</td>
|
|
<td class="px-3 sm:px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
|
<button onclick="openNoteModal('${note.id}')" class="text-indigo-600 hover:text-indigo-700 mr-4">Edit</button>
|
|
<button onclick="deleteNote('${note.id}')" class="text-red-600 hover:text-red-700">Delete</button>
|
|
</td>
|
|
</tr>
|
|
`;
|
|
}).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([]);
|
|
}
|
|
}
|
|
|