invoicegenius-ai / script.js
Thennarasu87's picture
Report preview entry not found
923bfa5 verified
document.addEventListener('DOMContentLoaded', function() {
initCharts();
// Initialize charts
function initCharts() {
// Revenue Line Chart
const revenueCtx = document.getElementById('revenueChart');
if (revenueCtx) {
new Chart(revenueCtx, {
type: 'line',
data: {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct'],
datasets: [{
label: 'Revenue',
data: [12000, 19000, 15000, 18000, 21000, 25000, 22000, 28000, 26000, 30000],
borderColor: '#6366f1',
backgroundColor: 'rgba(99, 102, 241, 0.1)',
borderWidth: 2,
tension: 0.4,
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
},
scales: {
y: {
beginAtZero: true,
grid: {
display: true,
color: 'rgba(0, 0, 0, 0.05)'
}
},
x: {
grid: {
display: false
}
}
}
}
});
}
// Expense Doughnut Chart
const expenseCtx = document.getElementById('expenseChart');
if (expenseCtx) {
new Chart(expenseCtx, {
type: 'doughnut',
data: {
labels: ['Supplies', 'Software', 'Marketing', 'Salaries', 'Office'],
datasets: [{
data: [12000, 8000, 5000, 30000, 7000],
backgroundColor: [
'#6366f1',
'#8b5cf6',
'#ec4899',
'#f97316',
'#10b981'
],
borderWidth: 0
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right'
}
},
cutout: '70%'
}
});
}
}
// Initialize tooltips
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
// Dark mode toggle functionality
const darkModeToggle = document.getElementById('darkModeToggle');
if (darkModeToggle) {
darkModeToggle.addEventListener('click', function() {
document.documentElement.classList.toggle('dark');
localStorage.setItem('darkMode', document.documentElement.classList.contains('dark'));
});
}
// Check for saved dark mode preference
if (localStorage.getItem('darkMode') === 'true') {
document.documentElement.classList.add('dark');
}
// Invoice generation form handling
const invoiceForm = document.getElementById('invoiceForm');
if (invoiceForm) {
invoiceForm.addEventListener('submit', function(e) {
e.preventDefault();
// Process form data and generate invoice
console.log('Generating invoice...');
});
}
// Responsive sidebar toggle
document.addEventListener('click', function(e) {
if (e.target.closest('#sidebarToggle')) {
document.querySelector('custom-sidebar').classList.toggle('-translate-x-full');
}
});
// Handle form submissions
document.querySelectorAll('form').forEach(form => {
form.addEventListener('submit', function(e) {
e.preventDefault();
// Show loading state
const submitBtn = form.querySelector('button[type="submit"]');
if (submitBtn) {
const originalText = submitBtn.innerHTML;
submitBtn.innerHTML = '<div class="loading-spinner"></div> Processing...';
submitBtn.disabled = true;
// Simulate API call
setTimeout(() => {
submitBtn.innerHTML = originalText;
submitBtn.disabled = false;
alert('Form submitted successfully!');
}, 1500);
}
});
});
});
// AI Processor functionality
document.addEventListener('DOMContentLoaded', function() {
const documentUpload = document.getElementById('documentUpload');
const uploadedDocuments = document.getElementById('uploadedDocuments');
const aiPreviewContainer = document.getElementById('aiPreviewContainer');
const processBtn = document.getElementById('processBtn');
// Handle document upload for AI processor
if (documentUpload) {
documentUpload.addEventListener('change', function(e) {
const files = Array.from(e.target.files);
if (files.length === 0) return;
aiPreviewContainer.classList.remove('hidden');
uploadedDocuments.innerHTML = '';
files.forEach(file => {
const fileContainer = document.createElement('div');
fileContainer.className = 'bg-gray-50 rounded-lg p-4 flex items-start';
const fileIcon = document.createElement('div');
fileIcon.className = 'w-10 h-10 bg-indigo-100 rounded-full flex items-center justify-center mr-3 flex-shrink-0';
let iconName = 'file';
if (file.type.match('image.*')) iconName = 'image';
else if (file.type === 'application/pdf') iconName = 'file-text';
else if (file.type.match('word')) iconName = 'file-text';
fileIcon.innerHTML = `<i data-feather="${iconName}" class="text-indigo-600"></i>`;
const fileInfo = document.createElement('div');
fileInfo.className = 'flex-1 min-w-0';
const fileName = document.createElement('p');
fileName.className = 'text-sm font-medium text-gray-900 truncate';
fileName.textContent = file.name;
const fileDetails = document.createElement('div');
fileDetails.className = 'flex items-center text-xs text-gray-500 mt-1';
fileDetails.innerHTML = `
<span>${(file.size / 1024).toFixed(2)} KB</span>
<span class="mx-2">•</span>
<span>${file.type}</span>
`;
fileInfo.appendChild(fileName);
fileInfo.appendChild(fileDetails);
fileContainer.appendChild(fileIcon);
fileContainer.appendChild(fileInfo);
uploadedDocuments.appendChild(fileContainer);
feather.replace();
});
});
}
// Process button handler
if (processBtn) {
processBtn.addEventListener('click', async function() {
const files = documentUpload.files;
if (files.length === 0) {
alert('Please upload documents first');
return;
}
processBtn.innerHTML = '<div class="loading-spinner"></div> Processing...';
processBtn.disabled = true;
// Simulate AI processing
setTimeout(() => {
processBtn.innerHTML = '<i data-feather="check" class="mr-2"></i> Processing Complete';
feather.replace();
alert('Documents processed successfully! Extracted data can now be reviewed.');
}, 3000);
});
}
});
// File upload and processing
document.addEventListener('DOMContentLoaded', function() {
const invoiceUpload = document.getElementById('invoiceUpload');
const uploadedFiles = document.getElementById('uploadedFiles');
const previewContainer = document.getElementById('previewContainer');
const scanBtn = document.getElementById('scanBtn');
// Handle file upload
invoiceUpload.addEventListener('change', function(e) {
const files = Array.from(e.target.files);
if (files.length === 0) return;
previewContainer.classList.remove('hidden');
uploadedFiles.innerHTML = '';
files.forEach(file => {
const fileContainer = document.createElement('div');
fileContainer.className = 'bg-gray-50 rounded-lg p-3 flex items-center';
const fileIcon = document.createElement('div');
fileIcon.className = 'w-10 h-10 bg-indigo-100 rounded-full flex items-center justify-center mr-3';
fileIcon.innerHTML = '<i data-feather="file" class="text-indigo-600"></i>';
const fileInfo = document.createElement('div');
fileInfo.className = 'flex-1 min-w-0';
const fileName = document.createElement('p');
fileName.className = 'text-sm font-medium text-gray-900 truncate';
fileName.textContent = file.name;
const fileSize = document.createElement('p');
fileSize.className = 'text-xs text-gray-500';
fileSize.textContent = `${(file.size / 1024).toFixed(2)} KB`;
fileInfo.appendChild(fileName);
fileInfo.appendChild(fileSize);
fileContainer.appendChild(fileIcon);
fileContainer.appendChild(fileInfo);
uploadedFiles.appendChild(fileContainer);
feather.replace();
// Process the file
processUploadedFile(file);
});
});
// Scan button handler
scanBtn.addEventListener('click', function() {
// This would trigger mobile device camera in production
alert('Scanning feature would open device camera to capture invoice');
});
});
// Process uploaded file
async function processUploadedFile(file) {
const reader = new FileReader();
reader.onload = async function(e) {
try {
if (file.type === 'application/pdf') {
// Process PDF
const pdfBytes = new Uint8Array(e.target.result);
const pdfDoc = await PDFLib.PDFDocument.load(pdfBytes);
const textContent = await extractTextFromPDF(pdfDoc);
extractLineItems(textContent);
} else if (file.type.match('image.*')) {
// Process image
const imageText = await extractTextFromImage(e.target.result);
extractLineItems(imageText);
}
} catch (error) {
console.error('Error processing file:', error);
}
};
reader.readAsArrayBuffer(file);
}
// Extract text from PDF
async function extractTextFromPDF(pdfDoc) {
const pages = pdfDoc.getPages();
let textContent = '';
for (const page of pages) {
const text = await page.getTextContent();
textContent += text.items.map(item => item.str).join(' ');
}
return textContent;
}
// Extract text from image using OCR
async function extractTextFromImage(imageData) {
const worker = Tesseract.createWorker();
await worker.load();
await worker.loadLanguage('eng');
await worker.initialize('eng');
const { data: { text } } = await worker.recognize(imageData);
await worker.terminate();
return text;
}
// Extract line items from text
function extractLineItems(text) {
// This is a simplified example - in production you'd use more sophisticated NLP
const lines = text.split('\n');
const items = [];
let foundItems = false;
lines.forEach(line => {
// Simple pattern matching for line items
const itemMatch = line.match(/(\d+)\s+([\w\s]+)\s+(\d+\.\d{2})/i);
if (itemMatch) {
items.push({
description: itemMatch[2].trim(),
quantity: parseInt(itemMatch[1]),
rate: parseFloat(itemMatch[3]),
amount: parseInt(itemMatch[1]) * parseFloat(itemMatch[3])
});
foundItems = true;
}
// Look for totals
const totalMatch = line.match(/total.*?(\d+\.\d{2})/i);
if (totalMatch) {
console.log('Found total:', totalMatch[1]);
}
});
if (foundItems) {
populateInvoiceItems(items);
}
}
// Populate invoice items table
function populateInvoiceItems(items) {
const tbody = document.querySelector('table tbody');
tbody.innerHTML = '';
items.forEach(item => {
const row = document.createElement('tr');
row.innerHTML = `
<td class="px-6 py-4 whitespace-nowrap">
<input type="text" value="${item.description}" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500">
</td>
<td class="px-6 py-4 whitespace-nowrap">
<input type="number" class="w-20 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" value="${item.quantity}">
</td>
<td class="px-6 py-4 whitespace-nowrap">
<input type="number" class="w-24 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" value="${item.rate}">
</td>
<td class="px-6 py-4 whitespace-nowrap">${item.amount.toFixed(2)}</td>
<td class="px-6 py-4 whitespace-nowrap">
<button class="text-red-500 hover:text-red-700">
<i data-feather="trash-2"></i>
</button>
</td>
`;
tbody.appendChild(row);
});
feather.replace();
}
// Enhanced AI processing with real API integration
async function processInvoiceData(data) {
try {
// Using OpenAI API for enhanced processing
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${YOUR_OPENAI_KEY}`
},
body: JSON.stringify({
model: "gpt-4",
messages: [{
role: "system",
content: "You are an expert invoice processing AI. Extract all relevant fields from this invoice data."
}, {
role: "user",
content: JSON.stringify(data)
}],
temperature: 0.2
})
});
const result = await response.json();
return parseAIResponse(result.choices[0].message.content);
} catch (error) {
console.error('AI Processing Error:', error);
return null;
}
}
// New AI features
function initAIFeatures() {
// Smart suggestions
document.querySelectorAll('input').forEach(input => {
input.addEventListener('focus', async () => {
const suggestions = await getAISuggestions(input.name);
showAISuggestions(input, suggestions);
});
});
// Auto-categorization
document.querySelectorAll('.category-select').forEach(select => {
select.addEventListener('change', async (e) => {
if (e.target.value === 'auto') {
const items = getLineItems();
const categories = await predictCategories(items);
applyCategories(categories);
}
});
});
}
// Initialize AI features when DOM loads
document.addEventListener('DOMContentLoaded', initAIFeatures);