auto-bill / index.html
malickba's picture
remove the dealer information part. on top right just put login button. Login should only require a dealer's name (from doropdown menu) and their 4 digit pin. The admin can add new dealer's and set a pin for them. The admin can login an dmanage the dealers and see previous bills of sale, download them by pdf in a bulk or singles. For the VIN portion, the user can also just paste the VIN info and the reast (year make model) should auto populate. On the customer information add a box (same address as license). When the box is checked , the address from the scanned license should auto populate. If unchecked the user can write the customer's address. For the address, add another field for street, city and zip code. When the zip code i entered, the city and state are automatically populated. Update and show me. - Initial Deployment
33d60a7 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AutoBill - Digital Bill of Sale Solution</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/signature_pad.umd.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.signature-pad {
border: 1px solid #e5e7eb;
border-radius: 0.375rem;
background-color: white;
}
.barcode-scanner {
position: relative;
overflow: hidden;
width: 100%;
height: 200px;
background-color: #f3f4f6;
border: 2px dashed #9ca3af;
border-radius: 0.5rem;
}
.barcode-scanner video {
width: 100%;
height: 100%;
object-fit: cover;
}
.barcode-scanner canvas {
display: none;
}
.receipt-preview {
background-color: white;
border: 1px solid #e5e7eb;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
@media print {
.no-print {
display: none !important;
}
.receipt-preview {
box-shadow: none;
border: none;
}
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8">
<!-- Header -->
<header class="mb-8">
<div class="flex justify-between items-center">
<h1 class="text-3xl font-bold text-blue-800">AutoBill</h1>
<button id="loginBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
<i class="fas fa-sign-in-alt mr-2"></i>Login
</button>
</div>
<p class="text-gray-600 mt-2">Digital Bill of Sale Solution for Auto Dealers</p>
</header>
<!-- Main Content -->
<main class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Left Panel - Form -->
<div class="lg:col-span-2 bg-white rounded-xl shadow-md p-6">
<h2 class="text-2xl font-semibold mb-6 text-blue-700">Create New Bill of Sale</h2>
<!-- Vehicle Information -->
<div class="mb-6">
<h3 class="font-medium text-lg text-gray-800 mb-4">Vehicle Information</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">VIN Number</label>
<div class="flex">
<input type="text" id="vinNumber" class="w-full px-3 py-2 border border-gray-300 rounded-l-md" placeholder="Scan or enter VIN">
<button id="scanVinBtn" class="bg-blue-600 text-white px-4 py-2 rounded-r-md hover:bg-blue-700">
<i class="fas fa-barcode mr-1"></i> Scan
</button>
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Mileage</label>
<input type="number" id="mileage" class="w-full px-3 py-2 border border-gray-300 rounded-md" placeholder="Enter mileage">
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Year</label>
<input type="text" id="vehicleYear" class="w-full px-3 py-2 border border-gray-300 rounded-md" readonly>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Make</label>
<input type="text" id="vehicleMake" class="w-full px-3 py-2 border border-gray-300 rounded-md" readonly>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Model</label>
<input type="text" id="vehicleModel" class="w-full px-3 py-2 border border-gray-300 rounded-md" readonly>
</div>
</div>
</div>
<!-- Customer Information -->
<div class="mb-6">
<h3 class="font-medium text-lg text-gray-800 mb-4">Customer Information</h3>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Driver's License</label>
<div class="flex">
<input type="text" id="dlNumber" class="w-full px-3 py-2 border border-gray-300 rounded-l-md" placeholder="Scan DL barcode">
<button id="scanDLBtn" class="bg-blue-600 text-white px-4 py-2 rounded-r-md hover:bg-blue-700">
<i class="fas fa-id-card mr-1"></i> Scan
</button>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">First Name</label>
<input type="text" id="customerFirstName" class="w-full px-3 py-2 border border-gray-300 rounded-md">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Last Name</label>
<input type="text" id="customerLastName" class="w-full px-3 py-2 border border-gray-300 rounded-md">
</div>
</div>
<div class="mb-4">
<label class="inline-flex items-center">
<input type="checkbox" id="useLicenseAddress" class="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50">
<span class="ml-2 text-sm text-gray-700">Use address from license</span>
</label>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Street</label>
<input type="text" id="customerStreet" class="w-full px-3 py-2 border border-gray-300 rounded-md">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">City</label>
<input type="text" id="customerCity" class="w-full px-3 py-2 border border-gray-300 rounded-md" readonly>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">State</label>
<input type="text" id="customerState" class="w-full px-3 py-2 border border-gray-300 rounded-md" readonly>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Zip Code</label>
<input type="text" id="customerZip" class="w-full px-3 py-2 border border-gray-300 rounded-md">
</div>
</div>
</div>
<!-- Additional Information -->
<div class="mb-6">
<h3 class="font-medium text-lg text-gray-800 mb-4">Additional Information</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Is the title present?</label>
<select id="titlePresent" class="w-full px-3 py-2 border border-gray-300 rounded-md">
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Sale Price ($)</label>
<input type="number" id="salePrice" class="w-full px-3 py-2 border border-gray-300 rounded-md" placeholder="Enter sale price">
</div>
</div>
</div>
<!-- Signature Section -->
<div class="mb-6">
<h3 class="font-medium text-lg text-gray-800 mb-4">Customer Signature</h3>
<div class="signature-pad-container mb-4">
<canvas id="signaturePad" class="signature-pad w-full h-48"></canvas>
</div>
<div class="flex justify-between">
<button id="clearSignatureBtn" class="bg-gray-200 hover:bg-gray-300 px-4 py-2 rounded-lg">
<i class="fas fa-eraser mr-2"></i>Clear
</button>
<div class="w-1/2">
<label class="block text-sm font-medium text-gray-700 mb-1">Date</label>
<input type="date" id="signatureDate" class="w-full px-3 py-2 border border-gray-300 rounded-md">
</div>
</div>
</div>
<!-- Submit Button -->
<div class="flex justify-end mt-8">
<button id="generateBillBtn" class="bg-green-600 hover:bg-green-700 text-white px-6 py-3 rounded-lg font-medium">
<i class="fas fa-file-pdf mr-2"></i>Generate Bill of Sale
</button>
</div>
</div>
<!-- Right Panel - Preview -->
<div class="bg-white rounded-xl shadow-md p-6">
<h2 class="text-2xl font-semibold mb-6 text-blue-700">Bill of Sale Preview</h2>
<div class="receipt-preview p-6 rounded-lg mb-6">
<div class="text-center mb-6">
<h3 class="text-xl font-bold">BILL OF SALE</h3>
<p class="text-sm text-gray-600">AutoBill Digital Solution</p>
</div>
<div class="mb-6">
<div class="flex justify-between border-b border-gray-200 py-2">
<span class="font-medium">Dealer:</span>
<span id="previewDealerName" class="text-right">-</span>
</div>
<div class="flex justify-between border-b border-gray-200 py-2">
<span class="font-medium">Dealer ID:</span>
<span id="previewDealerId" class="text-right">-</span>
</div>
</div>
<div class="mb-6">
<h4 class="font-medium border-b border-gray-200 pb-1 mb-2">Vehicle Information</h4>
<div class="grid grid-cols-2 gap-2 mb-2">
<div>Year:</div>
<div id="previewVehicleYear" class="text-right">-</div>
<div>Make:</div>
<div id="previewVehicleMake" class="text-right">-</div>
<div>Model:</div>
<div id="previewVehicleModel" class="text-right">-</div>
<div>VIN:</div>
<div id="previewVinNumber" class="text-right">-</div>
<div>Mileage:</div>
<div id="previewMileage" class="text-right">-</div>
</div>
</div>
<div class="mb-6">
<h4 class="font-medium border-b border-gray-200 pb-1 mb-2">Customer Information</h4>
<div class="grid grid-cols-2 gap-2 mb-2">
<div>Name:</div>
<div id="previewCustomerName" class="text-right">-</div>
<div>Address:</div>
<div id="previewCustomerAddress" class="text-right">-</div>
<div>DL Number:</div>
<div id="previewDlNumber" class="text-right">-</div>
</div>
</div>
<div class="mb-6">
<h4 class="font-medium border-b border-gray-200 pb-1 mb-2">Sale Details</h4>
<div class="grid grid-cols-2 gap-2 mb-2">
<div>Title Present:</div>
<div id="previewTitlePresent" class="text-right">-</div>
<div>Sale Price:</div>
<div id="previewSalePrice" class="text-right">-</div>
<div>Admin Fee:</div>
<div id="previewAdminFee" class="text-right">$150.00</div>
<div>System Fee:</div>
<div id="previewSystemFee" class="text-right">$20.00</div>
<div class="font-medium">Total:</div>
<div id="previewTotal" class="font-medium text-right">-</div>
</div>
</div>
<div class="mt-8">
<div class="mb-4">
<p class="text-sm mb-2">Customer Signature:</p>
<div id="previewSignature" class="border-t border-gray-300 h-20"></div>
</div>
<div>
<p class="text-sm">Date: <span id="previewSignatureDate">-</span></p>
</div>
</div>
</div>
<div class="flex justify-between no-print">
<button id="printBillBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg hidden">
<i class="fas fa-print mr-2"></i>Print
</button>
<button id="saveBillBtn" class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg hidden">
<i class="fas fa-save mr-2"></i>Save
</button>
</div>
</div>
</main>
</div>
<!-- Barcode Scanner Modal -->
<div id="scannerModal" class="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 hidden">
<div class="bg-white rounded-lg p-6 w-full max-w-md">
<h3 class="text-xl font-semibold mb-4">Scan Barcode</h3>
<div class="barcode-scanner mb-4">
<video id="scannerVideo" playsinline></video>
<canvas id="scannerCanvas"></canvas>
</div>
<div class="flex justify-between">
<button id="cancelScanBtn" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-lg">
Cancel
</button>
<button id="switchCameraBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
Switch Camera
</button>
</div>
</div>
</div>
<!-- Login Modal -->
<div id="loginModal" class="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 hidden">
<div class="bg-white rounded-lg p-6 w-full max-w-md">
<h3 class="text-xl font-semibold mb-4">Dealer Login</h3>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Dealer Name</label>
<select id="dealerName" class="w-full px-3 py-2 border border-gray-300 rounded-md">
<option value="">Select Dealer</option>
</select>
</div>
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-1">4-Digit PIN</label>
<input type="password" id="dealerPin" class="w-full px-3 py-2 border border-gray-300 rounded-md" maxlength="4" inputmode="numeric">
</div>
<div class="flex justify-between">
<button id="adminLoginBtn" class="bg-gray-200 hover:bg-gray-300 px-4 py-2 rounded-lg">
<i class="fas fa-user-shield mr-2"></i>Admin
</button>
<button id="confirmLoginBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
Login
</button>
</div>
</div>
</div>
<!-- Admin Dashboard Modal -->
<div id="adminDashboardModal" class="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 hidden overflow-y-auto">
<div class="bg-white rounded-lg p-6 w-full max-w-6xl max-h-screen overflow-y-auto">
<div class="flex justify-between items-center mb-6">
<h3 class="text-xl font-semibold">Admin Dashboard</h3>
<button id="closeAdminDashboardBtn" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<!-- Sales Summary -->
<div class="bg-blue-50 p-4 rounded-lg">
<h4 class="font-medium text-blue-800 mb-2">Sales Summary</h4>
<div class="grid grid-cols-2 gap-2">
<div>Today:</div>
<div id="salesToday" class="text-right font-medium">$0.00</div>
<div>This Week:</div>
<div id="salesWeek" class="text-right font-medium">$0.00</div>
<div>This Month:</div>
<div id="salesMonth" class="text-right font-medium">$0.00</div>
<div>Total:</div>
<div id="salesTotal" class="text-right font-medium">$0.00</div>
</div>
</div>
<!-- System Fees -->
<div class="bg-green-50 p-4 rounded-lg">
<h4 class="font-medium text-green-800 mb-2">System Fees</h4>
<div class="grid grid-cols-2 gap-2">
<div>Today:</div>
<div id="feesToday" class="text-right font-medium">$0.00</div>
<div>This Week:</div>
<div id="feesWeek" class="text-right font-medium">$0.00</div>
<div>This Month:</div>
<div id="feesMonth" class="text-right font-medium">$0.00</div>
<div>Total:</div>
<div id="feesTotal" class="text-right font-medium">$0.00</div>
</div>
</div>
<!-- Dealer Management -->
<div class="bg-purple-50 p-4 rounded-lg">
<h4 class="font-medium text-purple-800 mb-2">Dealer Management</h4>
<div class="grid grid-cols-2 gap-2">
<div>Total Dealers:</div>
<div id="totalDealers" class="text-right font-medium">0</div>
</div>
<button id="addDealerBtn" class="mt-4 w-full bg-purple-600 hover:bg-purple-700 text-white px-4 py-2 rounded-lg">
<i class="fas fa-plus mr-2"></i>Add New Dealer
</button>
</div>
</div>
<!-- Sales History -->
<div class="mb-8">
<h4 class="font-medium text-lg mb-4">Recent Sales</h4>
<div class="overflow-x-auto">
<table class="min-w-full bg-white">
<thead>
<tr class="bg-gray-100">
<th class="py-2 px-4 border">Date</th>
<th class="py-2 px-4 border">Dealer</th>
<th class="py-2 px-4 border">Vehicle</th>
<th class="py-2 px-4 border">Customer</th>
<th class="py-2 px-4 border">Total</th>
<th class="py-2 px-4 border">Actions</th>
</tr>
</thead>
<tbody id="salesHistoryTable">
<!-- Will be populated by JavaScript -->
</tbody>
</table>
</div>
</div>
<!-- Dealer List -->
<div>
<h4 class="font-medium text-lg mb-4">Dealer Accounts</h4>
<div class="overflow-x-auto">
<table class="min-w-full bg-white">
<thead>
<tr class="bg-gray-100">
<th class="py-2 px-4 border">ID</th>
<th class="py-2 px-4 border">Name</th>
<th class="py-2 px-4 border">Email</th>
<th class="py-2 px-4 border">Sales Count</th>
<th class="py-2 px-4 border">Actions</th>
</tr>
</thead>
<tbody id="dealersTable">
<!-- Will be populated by JavaScript -->
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Add Dealer Modal -->
<div id="addDealerModal" class="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 hidden">
<div class="bg-white rounded-lg p-6 w-full max-w-md">
<h3 class="text-xl font-semibold mb-4">Add New Dealer</h3>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Full Name</label>
<input type="text" id="newDealerName" class="w-full px-3 py-2 border border-gray-300 rounded-md">
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Email</label>
<input type="email" id="newDealerEmail" class="w-full px-3 py-2 border border-gray-300 rounded-md">
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Password</label>
<input type="password" id="newDealerPassword" class="w-full px-3 py-2 border border-gray-300 rounded-md">
</div>
<div class="flex justify-between">
<button id="cancelAddDealerBtn" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-lg">
Cancel
</button>
<button id="confirmAddDealerBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
Add Dealer
</button>
</div>
</div>
</div>
<!-- View Bill Modal -->
<div id="viewBillModal" class="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 hidden overflow-y-auto">
<div class="bg-white rounded-lg p-6 w-full max-w-4xl max-h-screen overflow-y-auto">
<div class="flex justify-between items-center mb-6">
<h3 class="text-xl font-semibold">Bill of Sale Details</h3>
<button id="closeViewBillBtn" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-times"></i>
</button>
</div>
<div id="billDetailsContent" class="receipt-preview p-6 rounded-lg">
<!-- Bill content will be inserted here -->
</div>
<div class="flex justify-end mt-4">
<button id="printBillModalBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg mr-2">
<i class="fas fa-print mr-2"></i>Print
</button>
<button id="closeBillModalBtn" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-lg">
Close
</button>
</div>
</div>
</div>
<script>
// Initialize Signature Pad
const canvas = document.getElementById('signaturePad');
const signaturePad = new SignaturePad(canvas, {
backgroundColor: 'rgb(255, 255, 255)',
penColor: 'rgb(0, 0, 0)'
});
// Sample data for demonstration
let dealers = [
{ id: 'DL001', name: 'John Doe', email: '[email protected]', salesCount: 12 },
{ id: 'DL002', name: 'Jane Smith', email: '[email protected]', salesCount: 8 }
];
let salesHistory = [
{
id: 'SALE001',
date: '2023-06-15',
dealerId: 'DL001',
dealerName: 'John Doe',
vehicle: '2020 Toyota Camry',
customer: 'Michael Johnson',
total: 12500.00,
details: {
vin: 'JT2BF22K1W0123456',
year: '2020',
make: 'Toyota',
model: 'Camry',
mileage: '45,678',
customerName: 'Michael Johnson',
customerAddress: '123 Main St, Anytown, USA',
dlNumber: 'DL12345678',
titlePresent: 'yes',
salePrice: 12350.00,
adminFee: 150.00,
systemFee: 20.00,
signature: 'data:image/png;base64,...', // would be actual signature data
signatureDate: '2023-06-15'
}
},
{
id: 'SALE002',
date: '2023-06-10',
dealerId: 'DL002',
dealerName: 'Jane Smith',
vehicle: '2018 Honda Accord',
customer: 'Sarah Williams',
total: 11800.00,
details: {
vin: '1HGCR2F38JA123456',
year: '2018',
make: 'Honda',
model: 'Accord',
mileage: '52,345',
customerName: 'Sarah Williams',
customerAddress: '456 Oak Ave, Somewhere, USA',
dlNumber: 'DL87654321',
titlePresent: 'yes',
salePrice: 11630.00,
adminFee: 150.00,
systemFee: 20.00,
signature: 'data:image/png;base64,...', // would be actual signature data
signatureDate: '2023-06-10'
}
}
];
// Dealers data with pins
let dealers = [
{ id: 'DL001', name: 'John Doe', pin: '1234' },
{ id: 'DL002', name: 'Jane Smith', pin: '5678' }
];
let currentDealer = null;
// Populate dealer dropdown
const dealerSelect = document.getElementById('dealerName');
dealers.forEach(dealer => {
const option = document.createElement('option');
option.value = dealer.id;
option.textContent = dealer.name;
dealerSelect.appendChild(option);
});
// Update preview as user fills out form
document.getElementById('vinNumber').addEventListener('input', function() {
document.getElementById('previewVinNumber').textContent = this.value || '-';
if (this.value.length === 17) {
simulateVinLookup(this.value);
}
});
document.getElementById('mileage').addEventListener('input', function() {
document.getElementById('previewMileage').textContent = this.value ? this.value + ' miles' : '-';
});
document.getElementById('vehicleYear').addEventListener('input', function() {
document.getElementById('previewVehicleYear').textContent = this.value || '-';
});
document.getElementById('vehicleMake').addEventListener('input', function() {
document.getElementById('previewVehicleMake').textContent = this.value || '-';
});
document.getElementById('vehicleModel').addEventListener('input', function() {
document.getElementById('previewVehicleModel').textContent = this.value || '-';
});
document.getElementById('customerFirstName').addEventListener('input', updateCustomerName);
document.getElementById('customerLastName').addEventListener('input', updateCustomerName);
function updateCustomerName() {
const firstName = document.getElementById('customerFirstName').value;
const lastName = document.getElementById('customerLastName').value;
const fullName = (firstName || lastName) ? `${firstName} ${lastName}` : '-';
document.getElementById('previewCustomerName').textContent = fullName;
}
document.getElementById('useLicenseAddress').addEventListener('change', function() {
if (this.checked && scannedLicenseAddress) {
const [street, city, state, zip] = scannedLicenseAddress.split('|');
document.getElementById('customerStreet').value = street;
document.getElementById('customerCity').value = city;
document.getElementById('customerState').value = state;
document.getElementById('customerZip').value = zip;
updatePreviewAddress();
}
});
document.getElementById('customerZip').addEventListener('input', function() {
if (this.value.length === 5) {
// Simulate zip code lookup
const zipData = {
'12345': ['Anytown', 'NY'],
'67890': ['Somewhere', 'CA']
};
if (zipData[this.value]) {
document.getElementById('customerCity').value = zipData[this.value][0];
document.getElementById('customerState').value = zipData[this.value][1];
}
}
updatePreviewAddress();
});
function updatePreviewAddress() {
const street = document.getElementById('customerStreet').value;
const city = document.getElementById('customerCity').value;
const state = document.getElementById('customerState').value;
const zip = document.getElementById('customerZip').value;
let address = '';
if (street) address += street;
if (city) address += (address ? ', ' : '') + city;
if (state) address += (address ? ', ' : '') + state;
if (zip) address += (address ? ' ' : '') + zip;
document.getElementById('previewCustomerAddress').textContent = address || '-';
}
document.getElementById('dlNumber').addEventListener('input', function() {
document.getElementById('previewDlNumber').textContent = this.value || '-';
});
document.getElementById('titlePresent').addEventListener('change', function() {
document.getElementById('previewTitlePresent').textContent = this.value === 'yes' ? 'Yes' : 'No';
});
document.getElementById('salePrice').addEventListener('input', function() {
const salePrice = parseFloat(this.value) || 0;
const adminFee = 150;
const systemFee = 20;
const total = salePrice + adminFee + systemFee;
document.getElementById('previewSalePrice').textContent = salePrice ? '$' + salePrice.toFixed(2) : '-';
document.getElementById('previewAdminFee').textContent = '$' + adminFee.toFixed(2);
document.getElementById('previewSystemFee').textContent = '$' + systemFee.toFixed(2);
document.getElementById('previewTotal').textContent = total ? '$' + total.toFixed(2) : '-';
});
document.getElementById('signatureDate').addEventListener('change', function() {
document.getElementById('previewSignatureDate').textContent = this.value || '-';
});
// Clear signature button
document.getElementById('clearSignatureBtn').addEventListener('click', function() {
signaturePad.clear();
document.getElementById('previewSignature').innerHTML = '';
});
// Generate Bill of Sale button
document.getElementById('generateBillBtn').addEventListener('click', function() {
// Validate required fields
if (!validateForm()) {
return;
}
// Update preview signature
if (!signaturePad.isEmpty()) {
const signatureData = signaturePad.toDataURL();
const signatureImg = document.createElement('img');
signatureImg.src = signatureData;
signatureImg.style.maxWidth = '200px';
document.getElementById('previewSignature').innerHTML = '';
document.getElementById('previewSignature').appendChild(signatureImg);
}
// Show print and save buttons
document.getElementById('printBillBtn').classList.remove('hidden');
document.getElementById('saveBillBtn').classList.remove('hidden');
// Scroll to preview
document.querySelector('.receipt-preview').scrollIntoView({ behavior: 'smooth' });
});
function validateForm() {
const requiredFields = [
'vinNumber', 'mileage', 'vehicleYear', 'vehicleMake', 'vehicleModel',
'customerFirstName', 'customerLastName', 'customerAddress', 'dlNumber',
'salePrice', 'signatureDate'
];
let isValid = true;
for (const fieldId of requiredFields) {
const field = document.getElementById(fieldId);
if (!field.value) {
alert(`Please fill in ${field.placeholder || field.name || 'this field'}`);
field.focus();
isValid = false;
break;
}
}
if (isValid && signaturePad.isEmpty()) {
alert('Please provide a customer signature');
isValid = false;
}
return isValid;
}
// Print button
document.getElementById('printBillBtn').addEventListener('click', function() {
window.print();
});
// Save button
document.getElementById('saveBillBtn').addEventListener('click', function() {
// Create a new sale record
const newSale = {
id: 'SALE' + Math.floor(1000 + Math.random() * 9000),
date: new Date().toISOString().split('T')[0],
dealerId: currentDealer.id,
dealerName: currentDealer.name,
vehicle: `${document.getElementById('vehicleYear').value} ${document.getElementById('vehicleMake').value} ${document.getElementById('vehicleModel').value}`,
customer: `${document.getElementById('customerFirstName').value} ${document.getElementById('customerLastName').value}`,
total: parseFloat(document.getElementById('salePrice').value) + 150 + 20,
details: {
vin: document.getElementById('vinNumber').value,
year: document.getElementById('vehicleYear').value,
make: document.getElementById('vehicleMake').value,
model: document.getElementById('vehicleModel').value,
mileage: document.getElementById('mileage').value,
customerName: `${document.getElementById('customerFirstName').value} ${document.getElementById('customerLastName').value}`,
customerAddress: document.getElementById('customerAddress').value,
dlNumber: document.getElementById('dlNumber').value,
titlePresent: document.getElementById('titlePresent').value,
salePrice: parseFloat(document.getElementById('salePrice').value),
adminFee: 150,
systemFee: 20,
signature: signaturePad.isEmpty() ? '' : signaturePad.toDataURL(),
signatureDate: document.getElementById('signatureDate').value
}
};
// Add to sales history
salesHistory.unshift(newSale);
// Update dealer sales count
const dealer = dealers.find(d => d.id === currentDealer.id);
if (dealer) {
dealer.salesCount = (dealer.salesCount || 0) + 1;
}
alert('Bill of sale saved successfully!');
// Reset form
resetForm();
});
function resetForm() {
document.getElementById('vinNumber').value = '';
document.getElementById('mileage').value = '';
document.getElementById('vehicleYear').value = '';
document.getElementById('vehicleMake').value = '';
document.getElementById('vehicleModel').value = '';
document.getElementById('dlNumber').value = '';
document.getElementById('customerFirstName').value = '';
document.getElementById('customerLastName').value = '';
document.getElementById('customerAddress').value = '';
document.getElementById('titlePresent').value = 'yes';
document.getElementById('salePrice').value = '';
document.getElementById('signatureDate').value = '';
signaturePad.clear();
// Reset preview
document.querySelectorAll('#previewDealerName, #previewDealerId, #previewVinNumber, #previewMileage, #previewVehicleYear, #previewVehicleMake, #previewVehicleModel, #previewCustomerName, #previewCustomerAddress, #previewDlNumber, #previewTitlePresent, #previewSalePrice, #previewTotal, #previewSignatureDate').forEach(el => {
el.textContent = '-';
});
document.getElementById('previewSignature').innerHTML = '';
// Hide print and save buttons
document.getElementById('printBillBtn').classList.add('hidden');
document.getElementById('saveBillBtn').classList.add('hidden');
}
// Barcode scanning functionality
let scannerModalOpenFor = null; // 'vin' or 'dl'
let currentStream = null;
document.getElementById('scanVinBtn').addEventListener('click', function() {
scannerModalOpenFor = 'vin';
document.getElementById('scannerModal').classList.remove('hidden');
initScanner();
});
document.getElementById('scanDLBtn').addEventListener('click', function() {
scannerModalOpenFor = 'dl';
document.getElementById('scannerModal').classList.remove('hidden');
initScanner();
});
document.getElementById('cancelScanBtn').addEventListener('click', function() {
closeScanner();
document.getElementById('scannerModal').classList.add('hidden');
});
document.getElementById('switchCameraBtn').addEventListener('click', function() {
if (currentStream) {
currentStream.getTracks().forEach(track => track.stop());
}
initScanner(true);
});
function initScanner(switchCamera = false) {
const video = document.getElementById('scannerVideo');
const canvas = document.getElementById('scannerCanvas');
const ctx = canvas.getContext('2d');
// This is a simulation - in a real app you would use a barcode scanning library
// like QuaggaJS or Dynamsoft Barcode Reader
navigator.mediaDevices.getUserMedia({
video: {
facingMode: switchCamera ? { exact: 'environment' } : 'user',
width: { ideal: 1280 },
height: { ideal: 720 }
},
audio: false
}).then(function(stream) {
currentStream = stream;
video.srcObject = stream;
video.play();
// Simulate barcode scanning
setTimeout(() => {
if (Math.random() > 0.3) { // 70% chance of "finding" a barcode
simulateBarcodeFound();
}
}, 2000);
}).catch(function(err) {
console.error("Error accessing camera: ", err);
alert("Could not access the camera. Please make sure you have granted camera permissions.");
document.getElementById('scannerModal').classList.add('hidden');
});
}
function simulateBarcodeFound() {
closeScanner();
document.getElementById('scannerModal').classList.add('hidden');
if (scannerModalOpenFor === 'vin') {
// Simulate VIN scan
const fakeVins = [
'1G1ZT51806F128009', // Chevy
'JT2BF22K1W0123456', // Toyota
'1HGCR2F38JA123456', // Honda
'5YJSA1DN9CFP01728', // Tesla
'WAUZZZ4G6BN123456' // Audi
];
const randomVin = fakeVins[Math.floor(Math.random() * fakeVins.length)];
document.getElementById('vinNumber').value = randomVin;
// Simulate vehicle info lookup based on VIN
simulateVinLookup(randomVin);
} else if (scannerModalOpenFor === 'dl') {
// Simulate DL scan
const fakeDLs = [
{ number: 'DL12345678', name: 'John Michael Doe', address: '123 Main St, Anytown, USA' },
{ number: 'DL87654321', name: 'Jane Mary Smith', address: '456 Oak Ave, Somewhere, USA' },
{ number: 'DL13579246', name: 'Robert James Johnson', address: '789 Pine Rd, Anycity, USA' }
];
const randomDL = fakeDLs[Math.floor(Math.random() * fakeDLs.length)];
document.getElementById('dlNumber').value = randomDL.number;
// Split name into first and last
const nameParts = randomDL.name.split(' ');
const firstName = nameParts[0];
const lastName = nameParts.slice(1).join(' ');
document.getElementById('customerFirstName').value = firstName;
document.getElementById('customerLastName').value = lastName;
document.getElementById('customerAddress').value = randomDL.address;
// Update preview
updateCustomerName();
document.getElementById('previewDlNumber').textContent = randomDL.number;
document.getElementById('previewCustomerAddress').textContent = randomDL.address;
}
}
function simulateVinLookup(vin) {
// This is a simulation - in a real app you would call a VIN decoding API
const vinPrefix = vin.substring(0, 3);
let year, make, model;
if (vinPrefix === '1G1') {
year = '2006';
make = 'Chevrolet';
model = 'Corvette';
} else if (vinPrefix === 'JT2') {
year = '1998';
make = 'Toyota';
model = 'Camry';
} else if (vinPrefix === '1HG') {
year = '2018';
make = 'Honda';
model = 'Accord';
} else if (vinPrefix === '5YJ') {
year = '2012';
make = 'Tesla';
model = 'Model S';
} else if (vinPrefix === 'WAU') {
year = '2011';
make = 'Audi';
model = 'A4';
} else {
year = '2015';
make = 'Generic';
model = 'Vehicle';
}
document.getElementById('vehicleYear').value = year;
document.getElementById('vehicleMake').value = make;
document.getElementById('vehicleModel').value = model;
// Update preview
document.getElementById('previewVehicleYear').textContent = year;
document.getElementById('previewVehicleMake').textContent = make;
document.getElementById('previewVehicleModel').textContent = model;
}
function closeScanner() {
const video = document.getElementById('scannerVideo');
if (video.srcObject) {
video.srcObject.getTracks().forEach(track => track.stop());
video.srcObject = null;
}
currentStream = null;
}
// Admin functionality
document.getElementById('adminBtn').addEventListener('click', function() {
document.getElementById('adminLoginModal').classList.remove('hidden');
});
document.getElementById('cancelAdminLoginBtn').addEventListener('click', function() {
document.getElementById('adminLoginModal').classList.add('hidden');
});
document.getElementById('confirmAdminLoginBtn').addEventListener('click', function() {
const username = document.getElementById('adminUsername').value;
const password = document.getElementById('adminPassword').value;
// Simple admin login check
if (username === 'admin' && password === 'admin123') {
document.getElementById('adminLoginModal').classList.add('hidden');
document.getElementById('logoutBtn').classList.remove('hidden');
showAdminDashboard();
} else {
alert('Invalid admin credentials');
}
});
document.getElementById('logoutBtn').addEventListener('click', function() {
document.getElementById('logoutBtn').classList.add('hidden');
document.getElementById('adminDashboardModal').classList.add('hidden');
});
document.getElementById('closeAdminDashboardBtn').addEventListener('click', function() {
document.getElementById('adminDashboardModal').classList.add('hidden');
});
function showAdminDashboard() {
// Calculate sales totals
const today = new Date().toISOString().split('T')[0];
const thisWeekSales = salesHistory.filter(sale => {
const saleDate = new Date(sale.date);
const now = new Date();
const startOfWeek = new Date(now.setDate(now.getDate() - now.getDay()));
return saleDate >= startOfWeek;
});
const thisMonthSales = salesHistory.filter(sale => {
const saleDate = new Date(sale.date);
const now = new Date();
return saleDate.getMonth() === now.getMonth() && saleDate.getFullYear() === now.getFullYear();
});
const todayTotal = salesHistory.filter(sale => sale.date === today)
.reduce((sum, sale) => sum + sale.total, 0);
const weekTotal = thisWeekSales.reduce((sum, sale) => sum + sale.total, 0);
const monthTotal = thisMonthSales.reduce((sum, sale) => sum + sale.total, 0);
const allTimeTotal = salesHistory.reduce((sum, sale) => sum + sale.total, 0);
const todayFees = salesHistory.filter(sale => sale.date === today)
.reduce((sum, sale) => sum + sale.details.systemFee, 0);
const weekFees = thisWeekSales.reduce((sum, sale) => sum + sale.details.systemFee, 0);
const monthFees = thisMonthSales.reduce((sum, sale) => sum + sale.details.systemFee, 0);
const allTimeFees = salesHistory.reduce((sum, sale) => sum + sale.details.systemFee, 0);
// Update dashboard numbers
document.getElementById('salesToday').textContent = '$' + todayTotal.toFixed(2);
document.getElementById('salesWeek').textContent = '$' + weekTotal.toFixed(2);
document.getElementById('salesMonth').textContent = '$' + monthTotal.toFixed(2);
document.getElementById('salesTotal').textContent = '$' + allTimeTotal.toFixed(2);
document.getElementById('feesToday').textContent = '$' + todayFees.toFixed(2);
document.getElementById('feesWeek').textContent = '$' + weekFees.toFixed(2);
document.getElementById('feesMonth').textContent = '$' + monthFees.toFixed(2);
document.getElementById('feesTotal').textContent = '$' + allTimeFees.toFixed(2);
document.getElementById('totalDealers').textContent = dealers.length;
// Populate sales history table
const salesTable = document.getElementById('salesHistoryTable');
salesTable.innerHTML = '';
salesHistory.slice(0, 10).forEach(sale => {
const row = document.createElement('tr');
row.className = 'border-b';
row.innerHTML = `
<td class="py-2 px-4 border">${sale.date}</td>
<td class="py-2 px-4 border">${sale.dealerName}</td>
<td class="py-2 px-4 border">${sale.vehicle}</td>
<td class="py-2 px-4 border">${sale.customer}</td>
<td class="py-2 px-4 border">$${sale.total.toFixed(2)}</td>
<td class="py-2 px-4 border">
<button class="view-sale-btn text-blue-600 hover:text-blue-800" data-sale-id="${sale.id}">
<i class="fas fa-eye"></i>
</button>
</td>
`;
salesTable.appendChild(row);
});
// Add event listeners to view buttons
document.querySelectorAll('.view-sale-btn').forEach(btn => {
btn.addEventListener('click', function() {
const saleId = this.getAttribute('data-sale-id');
viewSaleDetails(saleId);
});
});
// Populate dealers table
const dealersTable = document.getElementById('dealersTable');
dealersTable.innerHTML = '';
dealers.forEach(dealer => {
const row = document.createElement('tr');
row.className = 'border-b';
row.innerHTML = `
<td class="py-2 px-4 border">${dealer.id}</td>
<td class="py-2 px-4 border">${dealer.name}</td>
<td class="py-2 px-4 border">${dealer.email}</td>
<td class="py-2 px-4 border">${dealer.salesCount || 0}</td>
<td class="py-2 px-4 border">
<button class="delete-dealer-btn text-red-600 hover:text-red-800" data-dealer-id="${dealer.id}">
<i class="fas fa-trash-alt"></i>
</button>
</td>
`;
dealersTable.appendChild(row);
});
// Add event listeners to delete buttons
document.querySelectorAll('.delete-dealer-btn').forEach(btn => {
btn.addEventListener('click', function() {
const dealerId = this.getAttribute('data-dealer-id');
if (confirm(`Are you sure you want to delete dealer ${dealerId}?`)) {
deleteDealer(dealerId);
}
});
});
// Show the dashboard
document.getElementById('adminDashboardModal').classList.remove('hidden');
}
function viewSaleDetails(saleId) {
const sale = salesHistory.find(s => s.id === saleId);
if (!sale) return;
const billContent = document.getElementById('billDetailsContent');
billContent.innerHTML = `
<div class="text-center mb-6">
<h3 class="text-xl font-bold">BILL OF SALE</h3>
<p class="text-sm text-gray-600">AutoBill Digital Solution</p>
<p class="text-sm text-gray-600">Sale ID: ${sale.id}</p>
</div>
<div class="mb-6">
<div class="flex justify-between border-b border-gray-200 py-2">
<span class="font-medium">Date:</span>
<span class="text-right">${sale.date}</span>
</div>
<div class="flex justify-between border-b border-gray-200 py-2">
<span class="font-medium">Dealer:</span>
<span class="text-right">${sale.dealerName} (${sale.dealerId})</span>
</div>
</div>
<div class="mb-6">
<h4 class="font-medium border-b border-gray-200 pb-1 mb-2">Vehicle Information</h4>
<div class="grid grid-cols-2 gap-2 mb-2">
<div>Year:</div>
<div class="text-right">${sale.details.year}</div>
<div>Make:</div>
<div class="text-right">${sale.details.make}</div>
<div>Model:</div>
<div class="text-right">${sale.details.model}</div>
<div>VIN:</div>
<div class="text-right">${sale.details.vin}</div>
<div>Mileage:</div>
<div class="text-right">${sale.details.mileage} miles</div>
</div>
</div>
<div class="mb-6">
<h4 class="font-medium border-b border-gray-200 pb-1 mb-2">Customer Information</h4>
<div class="grid grid-cols-2 gap-2 mb-2">
<div>Name:</div>
<div class="text-right">${sale.details.customerName}</div>
<div>Address:</div>
<div class="text-right">${sale.details.customerAddress}</div>
<div>DL Number:</div>
<div class="text-right">${sale.details.dlNumber}</div>
</div>
</div>
<div class="mb-6">
<h4 class="font-medium border-b border-gray-200 pb-1 mb-2">Sale Details</h4>
<div class="grid grid-cols-2 gap-2 mb-2">
<div>Title Present:</div>
<div class="text-right">${sale.details.titlePresent === 'yes' ? 'Yes' : 'No'}</div>
<div>Sale Price:</div>
<div class="text-right">$${sale.details.salePrice.toFixed(2)}</div>
<div>Admin Fee:</div>
<div class="text-right">$${sale.details.adminFee.toFixed(2)}</div>
<div>System Fee:</div>
<div class="text-right">$${sale.details.systemFee.toFixed(2)}</div>
<div class="font-medium">Total:</div>
<div class="font-medium text-right">$${sale.total.toFixed(2)}</div>
</div>
</div>
<div class="mt-8">
<div class="mb-4">
<p class="text-sm mb-2">Customer Signature:</p>
${sale.details.signature ? `<img src="${sale.details.signature}" style="max-width: 200px;">` : '<div class="border-t border-gray-300 h-20"></div>'}
</div>
<div>
<p class="text-sm">Date: ${sale.details.signatureDate}</p>
</div>
</div>
`;
document.getElementById('viewBillModal').classList.remove('hidden');
}
document.getElementById('closeViewBillBtn').addEventListener('click', function() {
document.getElementById('viewBillModal').classList.add('hidden');
});
document.getElementById('printBillModalBtn').addEventListener('click', function() {
const printContent = document.getElementById('billDetailsContent').innerHTML;
const originalContent = document.body.innerHTML;
document.body.innerHTML = printContent;
window.print();
document.body.innerHTML = originalContent;
// Re-add event listeners
document.getElementById('closeViewBillBtn').addEventListener('click', function() {
document.getElementById('viewBillModal').classList.add('hidden');
});
});
document.getElementById('closeBillModalBtn').addEventListener('click', function() {
document.getElementById('viewBillModal').classList.add('hidden');
});
// Add dealer functionality
document.getElementById('addDealerBtn').addEventListener('click', function() {
document.getElementById('addDealerModal').classList.remove('hidden');
});
document.getElementById('cancelAddDealerBtn').addEventListener('click', function() {
document.getElementById('addDealerModal').classList.add('hidden');
});
document.getElementById('confirmAddDealerBtn').addEventListener('click', function() {
const name = document.getElementById('newDealerName').value;
const email = document.getElementById('newDealerEmail').value;
const password = document.getElementById('newDealerPassword').value;
if (!name || !email || !password) {
alert('Please fill in all fields');
return;
}
const newDealer = {
id: 'DL' + Math.floor(100 + Math.random() * 900),
name: name,
email: email,
salesCount: 0
};
dealers.push(newDealer);
// Reset form
document.getElementById('newDealerName').value = '';
document.getElementById('newDealerEmail').value = '';
document.getElementById('newDealerPassword').value = '';
// Close modal
document.getElementById('addDealerModal').classList.add('hidden');
// Refresh dashboard
showAdminDashboard();
alert(`New dealer ${newDealer.id} added successfully!`);
});
function deleteDealer(dealerId) {
dealers = dealers.filter(d => d.id !== dealerId);
showAdminDashboard();
}
// Initialize date field with today's date
document.getElementById('signatureDate').valueAsDate = new Date();
document.getElementById('previewSignatureDate').textContent = new Date().toISOString().split('T')[0];
// Initialize preview with dealer info
document.getElementById('previewDealerName').textContent = currentDealer.name;
document.getElementById('previewDealerId').textContent = currentDealer.id;
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=malickba/auto-bill" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>