235 lines
8.7 KiB
JavaScript
235 lines
8.7 KiB
JavaScript
document.addEventListener('DOMContentLoaded', () => {
|
|
const chatContainer = document.getElementById('chat-container');
|
|
const chatForm = document.getElementById('chat-form');
|
|
const messageInput = document.getElementById('message-input');
|
|
const reportsTab = document.getElementById('reports-tab');
|
|
const reportsContainer = document.getElementById('reports-container');
|
|
const uploadBtn = document.getElementById('upload-btn');
|
|
const uploadModal = new bootstrap.Modal(document.getElementById('uploadModal'));
|
|
const uploadForm = document.getElementById('upload-form');
|
|
const uploadCaseIdInput = document.getElementById('upload-case-id');
|
|
const fileInput = document.getElementById('file-input');
|
|
|
|
|
|
const scrollToBottom = () => {
|
|
chatContainer.scrollTop = chatContainer.scrollHeight;
|
|
};
|
|
|
|
const addMessage = (role, content, isThinking = false) => {
|
|
const bubble = document.createElement('div');
|
|
bubble.classList.add('chat-bubble', role);
|
|
|
|
if (isThinking) {
|
|
bubble.innerHTML = `<div class="thinking-indicator"><span></span><span></span><span></span></div>`;
|
|
bubble.id = 'thinking-bubble';
|
|
} else {
|
|
const pre = document.createElement('pre');
|
|
pre.innerHTML = content; // Use innerHTML to render links
|
|
bubble.appendChild(pre);
|
|
}
|
|
|
|
chatContainer.appendChild(bubble);
|
|
scrollToBottom();
|
|
return bubble;
|
|
};
|
|
|
|
const handleUploadCommand = (firNo) => {
|
|
// Simple check, backend will do the real validation
|
|
if(firNo) {
|
|
uploadCaseIdInput.value = firNo; // We'll use FIR no to find case in backend
|
|
const modalBody = document.querySelector('#uploadModal .modal-body p');
|
|
modalBody.innerHTML = `Select a file to upload for case <strong>${firNo}</strong>.`;
|
|
uploadModal.show();
|
|
} else {
|
|
addMessage('ai', 'Please specify a case FIR number to upload a file for, e.g., `upload file for case 123/25`.');
|
|
}
|
|
};
|
|
|
|
uploadBtn.addEventListener('click', () => {
|
|
// This just opens the modal. The user needs to have specified the case first.
|
|
const modalBody = document.querySelector('#uploadModal .modal-body p');
|
|
modalBody.innerHTML = 'To upload a file, please first type the command: `upload file for case [FIR NO]`';
|
|
uploadModal.show();
|
|
});
|
|
|
|
uploadForm.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const formData = new FormData(uploadForm);
|
|
const caseId = uploadCaseIdInput.value; // This is the FIR no
|
|
formData.set('case_id', caseId); // Ensure case_id is set
|
|
|
|
if (!fileInput.files || fileInput.files.length === 0) {
|
|
addMessage('ai', 'Please select a file to upload.');
|
|
return;
|
|
}
|
|
|
|
uploadModal.hide();
|
|
addMessage('user', `Uploading file "${fileInput.files[0].name}" for case ${caseId}...`);
|
|
const thinkingBubble = addMessage('ai', '', true);
|
|
|
|
try {
|
|
const response = await fetch('api.php', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const result = await response.json();
|
|
thinkingBubble.remove();
|
|
|
|
if (result.success) {
|
|
addMessage('ai', `File uploaded successfully. You can view it here: <a href="${result.file_path}" target="_blank">${result.file_path}</a>`);
|
|
} else {
|
|
addMessage('ai', `Upload failed: ${result.message || 'Unknown error'}`);
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Error uploading file:', error);
|
|
thinkingBubble.remove();
|
|
addMessage('ai', 'An error occurred during the file upload.');
|
|
} finally {
|
|
uploadForm.reset();
|
|
}
|
|
});
|
|
|
|
chatForm.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const message = messageInput.value.trim();
|
|
if (!message) return;
|
|
|
|
addMessage('user', message);
|
|
messageInput.value = '';
|
|
|
|
const uploadMatch = message.match(/upload file for case ([\w\/-]+)/i);
|
|
if (uploadMatch && uploadMatch[1]) {
|
|
handleUploadCommand(uploadMatch[1]);
|
|
return;
|
|
}
|
|
|
|
const thinkingBubble = addMessage('ai', '', true);
|
|
|
|
try {
|
|
const response = await fetch('api.php', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({ message })
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
thinkingBubble.remove();
|
|
addMessage('ai', data.reply);
|
|
|
|
} catch (error) {
|
|
console.error('Error fetching AI response:', error);
|
|
thinkingBubble.remove();
|
|
addMessage('ai', 'Sorry, something went wrong while connecting to the assistant.');
|
|
}
|
|
});
|
|
|
|
const fetchReports = async () => {
|
|
try {
|
|
const response = await fetch('api.php?action=get_reports');
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
const reports = await response.json();
|
|
renderReports(reports);
|
|
} catch (error) {
|
|
console.error('Error fetching reports:', error);
|
|
reportsContainer.innerHTML = '<p class="text-danger">Failed to load reports.</p>';
|
|
}
|
|
};
|
|
|
|
const renderReports = (reports) => {
|
|
if (!reports || reports.length === 0) {
|
|
reportsContainer.innerHTML = '<p>No reports generated yet.</p>';
|
|
return;
|
|
}
|
|
|
|
const table = document.createElement('table');
|
|
table.className = 'table table-striped';
|
|
table.innerHTML = `
|
|
<thead>
|
|
<tr>
|
|
<th>Report ID</th>
|
|
<th>FIR No.</th>
|
|
<th>Type</th>
|
|
<th>Date</th>
|
|
<th>Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
</tbody>
|
|
`;
|
|
const tbody = table.querySelector('tbody');
|
|
reports.forEach(report => {
|
|
const tr = document.createElement('tr');
|
|
tr.innerHTML = `
|
|
<td>${report.id}</td>
|
|
<td>${report.fir_no}</td>
|
|
<td>${report.report_type}</td>
|
|
<td>${new Date(report.created_at).toLocaleString()}</td>
|
|
<td><button class="btn btn-sm btn-primary view-report-btn" data-id="${report.id}">View</button></td>
|
|
`;
|
|
tbody.appendChild(tr);
|
|
});
|
|
|
|
reportsContainer.innerHTML = '';
|
|
reportsContainer.appendChild(table);
|
|
};
|
|
|
|
reportsContainer.addEventListener('click', async (e) => {
|
|
if (e.target.classList.contains('view-report-btn')) {
|
|
const reportId = e.target.dataset.id;
|
|
try {
|
|
const response = await fetch(`api.php?action=get_report&id=${reportId}`);
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
const report = await response.json();
|
|
|
|
const modal = new bootstrap.Modal(document.getElementById('report-modal'));
|
|
document.getElementById('report-modal-title').textContent = `Report #${reportId}`;
|
|
document.getElementById('report-modal-body').textContent = report.content;
|
|
modal.show();
|
|
|
|
} catch (error) {
|
|
console.error('Error fetching report content:', error);
|
|
alert('Failed to load report content.');
|
|
}
|
|
}
|
|
});
|
|
|
|
reportsTab.addEventListener('show.bs.tab', fetchReports);
|
|
|
|
// Initial scroll to bottom
|
|
scrollToBottom();
|
|
|
|
// Add a modal for viewing reports to the body
|
|
const modalHtml = `
|
|
<div class="modal fade" id="report-modal" tabindex="-1" aria-labelledby="report-modal-label" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="report-modal-title">Report</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<pre id="report-modal-body"></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
document.body.insertAdjacentHTML('beforeend', modalHtml);
|
|
});
|