cmp / index.html
Lechugaia's picture
Add 3 files
eedadc8 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Medication Leftovers Control System</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#3b82f6',
secondary: '#10b981',
danger: '#ef4444',
}
}
}
}
</script>
<style>
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.fade-in {
animation: fadeIn 0.3s ease-out forwards;
}
.signature-pad {
border: 1px dashed #ccc;
border-radius: 4px;
background-color: #f9fafb;
}
input:focus, select:focus, textarea:focus {
outline: 2px solid #3b82f6;
outline-offset: 2px;
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8 max-w-4xl">
<!-- Header -->
<header class="mb-8 text-center">
<h1 class="text-3xl font-bold text-primary mb-2">
<i class="fas fa-pills mr-2"></i>Medication Leftovers Control
</h1>
<p class="text-gray-600">Track and manage medication leftovers with expiration dates and stability information</p>
</header>
<!-- Control Panel -->
<div class="bg-white rounded-lg shadow-md p-6 mb-8">
<div class="flex flex-wrap gap-4 mb-6">
<button id="scanBtn" class="flex items-center px-4 py-2 bg-primary text-white rounded-lg hover:bg-blue-700 transition">
<i class="fas fa-barcode mr-2"></i> Scan Barcode
</button>
<button id="manualBtn" class="flex items-center px-4 py-2 bg-secondary text-white rounded-lg hover:bg-emerald-700 transition">
<i class="fas fa-keyboard mr-2"></i> Manual Entry
</button>
<button id="clearBtn" class="flex items-center px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition">
<i class="fas fa-trash-alt mr-2"></i> Clear Form
</button>
<button id="saveBtn" class="flex items-center px-4 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600 transition ml-auto">
<i class="fas fa-save mr-2"></i> Save Record
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Left Column -->
<div>
<div class="mb-4">
<label for="medication" class="block text-sm font-medium text-gray-700 mb-1">Medication Name *</label>
<div class="relative">
<input type="text" id="medication" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary" placeholder="Enter medication name">
<div id="medSuggestions" class="absolute z-10 w-full mt-1 bg-white border border-gray-300 rounded-lg shadow-lg hidden"></div>
</div>
</div>
<div class="mb-4">
<label for="batch" class="block text-sm font-medium text-gray-700 mb-1">Batch Number *</label>
<input type="text" id="batch" class="w-full px-4 py-2 border border-gray-300 rounded-lg" placeholder="Enter batch number">
</div>
<div class="mb-4">
<label for="expiration" class="block text-sm font-medium text-gray-700 mb-1">Expiration Date *</label>
<input type="date" id="expiration" class="w-full px-4 py-2 border border-gray-300 rounded-lg">
</div>
<div class="mb-4">
<label for="quantity" class="block text-sm font-medium text-gray-700 mb-1">Quantity Left *</label>
<div class="flex">
<input type="number" id="quantity" class="w-3/4 px-4 py-2 border border-gray-300 rounded-l-lg" placeholder="Enter quantity">
<select id="unit" class="w-1/4 px-2 py-2 border border-gray-300 rounded-r-lg bg-gray-50">
<option value="tablets">tablets</option>
<option value="ml">ml</option>
<option value="mg">mg</option>
<option value="vials">vials</option>
<option value="ampoules">ampoules</option>
</select>
</div>
</div>
</div>
<!-- Right Column -->
<div>
<div class="mb-4">
<label for="productionDate" class="block text-sm font-medium text-gray-700 mb-1">Production Date</label>
<input type="date" id="productionDate" class="w-full px-4 py-2 border border-gray-300 rounded-lg">
</div>
<div class="mb-4">
<label for="stability" class="block text-sm font-medium text-gray-700 mb-1">Stability Information</label>
<select id="stability" class="w-full px-4 py-2 border border-gray-300 rounded-lg">
<option value="">Select stability</option>
<option value="room_temp">Room temperature (15-25°C)</option>
<option value="refrigerated">Refrigerated (2-8°C)</option>
<option value="frozen">Frozen (-20°C or below)</option>
<option value="protected_light">Protected from light</option>
<option value="special">Special conditions (see notes)</option>
</select>
</div>
<div class="mb-4">
<label for="useExpiration" class="block text-sm font-medium text-gray-700 mb-1">Expiration Date After Opening</label>
<input type="date" id="useExpiration" class="w-full px-4 py-2 border border-gray-300 rounded-lg">
</div>
<div class="mb-4">
<label for="laboratory" class="block text-sm font-medium text-gray-700 mb-1">Manufacturer/Laboratory</label>
<input type="text" id="laboratory" class="w-full px-4 py-2 border border-gray-300 rounded-lg" placeholder="Enter manufacturer name">
</div>
</div>
</div>
<!-- Notes Section -->
<div class="mb-6">
<label for="notes" class="block text-sm font-medium text-gray-700 mb-1">Additional Notes</label>
<textarea id="notes" rows="3" class="w-full px-4 py-2 border border-gray-300 rounded-lg" placeholder="Any special instructions or notes about this medication"></textarea>
</div>
<!-- Signature Section -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Responsible Person Signature</label>
<div class="signature-pad p-4 mb-2">
<canvas id="signatureCanvas" width="100%" height="100"></canvas>
</div>
<div class="flex justify-between">
<button id="clearSignature" class="text-sm text-gray-500 hover:text-gray-700">
<i class="fas fa-eraser mr-1"></i> Clear Signature
</button>
<div class="text-sm text-gray-500">
<i class="fas fa-info-circle mr-1"></i> Sign above to confirm
</div>
</div>
</div>
</div>
<!-- Recent Records -->
<div class="bg-white rounded-lg shadow-md p-6">
<h2 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<i class="fas fa-history mr-2"></i> Recent Records
</h2>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Medication</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Batch</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Expiration</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Quantity</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody id="recordsTable" class="bg-white divide-y divide-gray-200">
<!-- Records will be added here dynamically -->
</tbody>
</table>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Sample medication database for autocomplete
const medicationDatabase = [
{ name: "Amoxicillin 500mg", commonBatch: "AMX2023", stability: "room_temp", lab: "PharmaCorp" },
{ name: "Ibuprofen 200mg", commonBatch: "IBU2305", stability: "room_temp", lab: "MediHealth" },
{ name: "Insulin Glargine", commonBatch: "INS456", stability: "refrigerated", lab: "BioSolutions" },
{ name: "Paracetamol 500mg", commonBatch: "PARA789", stability: "room_temp", lab: "GenericMeds" },
{ name: "Loratadine 10mg", commonBatch: "LORA123", stability: "room_temp", lab: "AllerFree" },
{ name: "Omeprazole 20mg", commonBatch: "OME456", stability: "room_temp", lab: "GastroPharm" }
];
// Set today's date as default
const today = new Date();
const todayFormatted = today.toISOString().split('T')[0];
document.getElementById('productionDate').value = todayFormatted;
// Initialize signature pad
const canvas = document.getElementById('signatureCanvas');
const ctx = canvas.getContext('2d');
let isDrawing = false;
let lastX = 0;
let lastY = 0;
// Set canvas size
function resizeCanvas() {
const container = canvas.parentElement;
canvas.width = container.offsetWidth;
canvas.height = 100;
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// Signature drawing functionality
canvas.addEventListener('mousedown', (e) => {
isDrawing = true;
[lastX, lastY] = [e.offsetX, e.offsetY];
});
canvas.addEventListener('mousemove', (e) => {
if (!isDrawing) return;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(e.offsetX, e.offsetY);
ctx.strokeStyle = '#000';
ctx.lineWidth = 2;
ctx.stroke();
[lastX, lastY] = [e.offsetX, e.offsetY];
});
canvas.addEventListener('mouseup', () => isDrawing = false);
canvas.addEventListener('mouseout', () => isDrawing = false);
// Touch support for signature
canvas.addEventListener('touchstart', (e) => {
e.preventDefault();
const touch = e.touches[0];
const mouseEvent = new MouseEvent('mousedown', {
clientX: touch.clientX,
clientY: touch.clientY
});
canvas.dispatchEvent(mouseEvent);
});
canvas.addEventListener('touchmove', (e) => {
e.preventDefault();
const touch = e.touches[0];
const mouseEvent = new MouseEvent('mousemove', {
clientX: touch.clientX,
clientY: touch.clientY
});
canvas.dispatchEvent(mouseEvent);
});
canvas.addEventListener('touchend', () => {
const mouseEvent = new MouseEvent('mouseup');
canvas.dispatchEvent(mouseEvent);
});
// Clear signature
document.getElementById('clearSignature').addEventListener('click', () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
});
// Medication autocomplete
const medicationInput = document.getElementById('medication');
const suggestionsContainer = document.getElementById('medSuggestions');
medicationInput.addEventListener('input', function() {
const input = this.value.toLowerCase();
if (input.length < 2) {
suggestionsContainer.classList.add('hidden');
return;
}
const matches = medicationDatabase.filter(med =>
med.name.toLowerCase().includes(input)
);
if (matches.length > 0) {
suggestionsContainer.innerHTML = '';
matches.forEach(med => {
const div = document.createElement('div');
div.className = 'px-4 py-2 hover:bg-gray-100 cursor-pointer';
div.textContent = med.name;
div.addEventListener('click', () => {
medicationInput.value = med.name;
document.getElementById('batch').value = med.commonBatch;
document.getElementById('stability').value = med.stability;
document.getElementById('laboratory').value = med.lab;
suggestionsContainer.classList.add('hidden');
// Set a future expiration date (1 year from now)
const futureDate = new Date();
futureDate.setFullYear(futureDate.getFullYear() + 1);
document.getElementById('expiration').value = futureDate.toISOString().split('T')[0];
// Set use expiration (30 days from now)
const useDate = new Date();
useDate.setDate(useDate.getDate() + 30);
document.getElementById('useExpiration').value = useDate.toISOString().split('T')[0];
});
suggestionsContainer.appendChild(div);
});
suggestionsContainer.classList.remove('hidden');
} else {
suggestionsContainer.classList.add('hidden');
}
});
// Close suggestions when clicking elsewhere
document.addEventListener('click', (e) => {
if (e.target !== medicationInput) {
suggestionsContainer.classList.add('hidden');
}
});
// Sample records data
let records = [
{
date: '2023-06-15',
medication: 'Amoxicillin 500mg',
batch: 'AMX2023',
expiration: '2024-06-14',
quantity: '15 tablets',
stability: 'Room temperature',
useExpiration: '2023-07-15',
laboratory: 'PharmaCorp',
notes: 'Keep in dry place'
},
{
date: '2023-06-10',
medication: 'Insulin Glargine',
batch: 'INS456',
expiration: '2023-12-10',
quantity: '2 vials',
stability: 'Refrigerated',
useExpiration: '2023-07-10',
laboratory: 'BioSolutions',
notes: 'Do not freeze'
}
];
// Render records table
function renderRecords() {
const tableBody = document.getElementById('recordsTable');
tableBody.innerHTML = '';
records.forEach((record, index) => {
const row = document.createElement('tr');
row.className = 'fade-in';
row.innerHTML = `
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.date}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${record.medication}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.batch}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.expiration}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.quantity}</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button class="text-primary hover:text-blue-700 mr-3 view-btn" data-index="${index}">
<i class="fas fa-eye mr-1"></i> View
</button>
<button class="text-danger hover:text-red-700 delete-btn" data-index="${index}">
<i class="fas fa-trash-alt mr-1"></i> Delete
</button>
</td>
`;
tableBody.appendChild(row);
});
// Add event listeners to buttons
document.querySelectorAll('.view-btn').forEach(btn => {
btn.addEventListener('click', function() {
const index = this.getAttribute('data-index');
viewRecord(index);
});
});
document.querySelectorAll('.delete-btn').forEach(btn => {
btn.addEventListener('click', function() {
const index = this.getAttribute('data-index');
deleteRecord(index);
});
});
}
// View record details
function viewRecord(index) {
const record = records[index];
alert(`Medication: ${record.medication}\nBatch: ${record.batch}\nExpiration: ${record.expiration}\nQuantity: ${record.quantity}\nStability: ${record.stability}\nUse Until: ${record.useExpiration}\nLab: ${record.laboratory}\nNotes: ${record.notes}`);
}
// Delete record
function deleteRecord(index) {
if (confirm('Are you sure you want to delete this record?')) {
records.splice(index, 1);
renderRecords();
}
}
// Save new record
document.getElementById('saveBtn').addEventListener('click', function() {
const medication = document.getElementById('medication').value;
const batch = document.getElementById('batch').value;
const expiration = document.getElementById('expiration').value;
const quantity = document.getElementById('quantity').value + ' ' + document.getElementById('unit').value;
const productionDate = document.getElementById('productionDate').value;
const stability = document.getElementById('stability').options[document.getElementById('stability').selectedIndex].text;
const useExpiration = document.getElementById('useExpiration').value;
const laboratory = document.getElementById('laboratory').value;
const notes = document.getElementById('notes').value;
if (!medication || !batch || !expiration || !quantity) {
alert('Please fill in all required fields (marked with *)');
return;
}
// Check if signature is present
const signatureEmpty = canvas.toDataURL() === document.createElement('canvas').toDataURL();
if (signatureEmpty) {
alert('Please provide a signature to confirm the record');
return;
}
const newRecord = {
date: todayFormatted,
medication,
batch,
expiration,
quantity,
productionDate,
stability,
useExpiration,
laboratory,
notes
};
records.unshift(newRecord);
renderRecords();
// Clear form
document.getElementById('clearBtn').click();
// Show success message
const successMsg = document.createElement('div');
successMsg.className = 'fixed bottom-4 right-4 bg-green-500 text-white px-4 py-2 rounded-lg shadow-lg flex items-center';
successMsg.innerHTML = '<i class="fas fa-check-circle mr-2"></i> Record saved successfully!';
document.body.appendChild(successMsg);
setTimeout(() => {
successMsg.classList.add('opacity-0', 'transition-opacity', 'duration-500');
setTimeout(() => successMsg.remove(), 500);
}, 3000);
});
// Clear form
document.getElementById('clearBtn').addEventListener('click', function() {
document.getElementById('medication').value = '';
document.getElementById('batch').value = '';
document.getElementById('expiration').value = '';
document.getElementById('quantity').value = '';
document.getElementById('unit').value = 'tablets';
document.getElementById('productionDate').value = todayFormatted;
document.getElementById('stability').value = '';
document.getElementById('useExpiration').value = '';
document.getElementById('laboratory').value = '';
document.getElementById('notes').value = '';
ctx.clearRect(0, 0, canvas.width, canvas.height);
});
// Simulate barcode scan
document.getElementById('scanBtn').addEventListener('click', function() {
// Simulate scanning a random medication
const randomMed = medicationDatabase[Math.floor(Math.random() * medicationDatabase.length)];
document.getElementById('medication').value = randomMed.name;
document.getElementById('batch').value = randomMed.commonBatch;
document.getElementById('stability').value = randomMed.stability;
document.getElementById('laboratory').value = randomMed.lab;
// Set dates
const futureDate = new Date();
futureDate.setFullYear(futureDate.getFullYear() + 1);
document.getElementById('expiration').value = futureDate.toISOString().split('T')[0];
const useDate = new Date();
useDate.setDate(useDate.getDate() + 30);
document.getElementById('useExpiration').value = useDate.toISOString().split('T')[0];
// Set random quantity
document.getElementById('quantity').value = Math.floor(Math.random() * 20) + 5;
// Show scan animation
const scanAnimation = document.createElement('div');
scanAnimation.className = 'fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center z-50';
scanAnimation.innerHTML = `
<div class="bg-white p-6 rounded-lg text-center max-w-sm">
<div class="text-4xl mb-4">
<i class="fas fa-barcode animate-pulse text-primary"></i>
</div>
<h3 class="text-xl font-semibold mb-2">Scanning Barcode</h3>
<p class="text-gray-600 mb-4">Detected: ${randomMed.name}</p>
<div class="h-1 w-full bg-gray-200 rounded-full overflow-hidden">
<div class="h-full bg-primary rounded-full animate-progress"></div>
</div>
</div>
`;
document.body.appendChild(scanAnimation);
setTimeout(() => {
scanAnimation.classList.add('opacity-0', 'transition-opacity', 'duration-300');
setTimeout(() => scanAnimation.remove(), 300);
}, 1500);
});
// Initial render of records
renderRecords();
});
</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=Lechugaia/cmp" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>