COGOTUD4_ADM / index.html
Lukeetah's picture
Update index.html
dd96b1b verified
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>La Cogotuda - Panel de Fabricación</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;900&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Inter', sans-serif;
background-color: #FDFBF8;
color: #1a202c;
}
.logo-font {
font-weight: 900;
letter-spacing: -0.05em;
}
.dashboard-bg {
background-color: #f0eada;
}
.btn-primary {
background-color: #D95F43;
color: white;
transition: background-color 0.3s ease;
}
.btn-primary:hover {
background-color: #b94e36;
}
.btn-secondary {
background-color: #2C4A6E;
color: white;
transition: background-color 0.3s ease;
}
.btn-secondary:hover {
background-color: #1f3550;
}
.btn-success {
background-color: #4CAF50;
color: white;
}
.btn-success:hover {
background-color: #45a049;
}
.btn-warning {
background-color: #FF9800;
color: white;
}
.btn-warning:hover {
background-color: #e68900;
}
.status-pending {
background-color: #FFF3E0;
color: #FF9800;
}
.status-processing {
background-color: #E3F2FD;
color: #2196F3;
}
.status-shipped {
background-color: #E8F5E9;
color: #4CAF50;
}
.status-completed {
background-color: #F3E5F5;
color: #9C27B0;
}
.progress-bar {
height: 8px;
background-color: #e2e8f0;
border-radius: 4px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background-color: #D95F43;
border-radius: 4px;
transition: width 0.3s ease;
}
.card {
background: white;
border-radius: 12px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
border: 1px solid #e2e8f0;
}
.notification {
animation: slideIn 0.3s ease-out;
}
@keyframes slideIn {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
</style>
</head>
<body>
<!-- Header -->
<header class="bg-white/80 backdrop-blur-lg sticky top-0 z-40 border-b border-gray-200">
<div class="container mx-auto px-6 py-4 flex justify-between items-center">
<div class="flex items-center space-x-3">
<img src="https://huggingface.co/spaces/Lukeetah/COGOTUDA/resolve/main/cogotuda.png" alt="Logo La Cogotuda" class="h-10 w-10 object-cover rounded-md shadow-sm">
<span class="text-2xl logo-font text-gray-800">LA COGOTUDA</span>
</div>
<div class="flex items-center space-x-4">
<span class="text-gray-600">Panel de Fabricación</span>
<div class="flex items-center space-x-2">
<div class="w-3 h-3 bg-green-500 rounded-full"></div>
<span class="text-sm text-gray-600">En línea</span>
</div>
</div>
</div>
</header>
<main class="py-8">
<div class="container mx-auto px-6">
<!-- Dashboard Header -->
<div class="mb-8">
<h1 class="text-3xl font-black text-gray-800 mb-2">Panel de Control de Fabricación</h1>
<p class="text-gray-600">Gestiona pedidos, producción y envíos en tiempo real</p>
</div>
<!-- Stats Cards -->
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
<div class="card p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">Pedidos Pendientes</p>
<p class="text-3xl font-bold text-gray-800" id="pending-count">12</p>
</div>
<div class="bg-orange-100 p-3 rounded-lg">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#D95F43" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>
</div>
</div>
</div>
<div class="card p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">En Producción</p>
<p class="text-3xl font-bold text-gray-800" id="processing-count">8</p>
</div>
<div class="bg-blue-100 p-3 rounded-lg">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#2C4A6E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path><polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline><line x1="12" y1="22.08" x2="12" y2="12"></line></svg>
</div>
</div>
</div>
<div class="card p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">Listos para Enviar</p>
<p class="text-3xl font-bold text-gray-800" id="ready-count">5</p>
</div>
<div class="bg-green-100 p-3 rounded-lg">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#4CAF50" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg>
</div>
</div>
</div>
<div class="card p-6">
<div class="flex items-center justify-between">
<div>
<p class="text-gray-500 text-sm">Total Hoy</p>
<p class="text-3xl font-bold text-gray-800" id="total-count">25</p>
</div>
<div class="bg-purple-100 p-3 rounded-lg">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#9C27B0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z"></path><line x1="3" y1="6" x2="21" y2="6"></line><path d="M16 10a4 4 0 0 1-8 0"></path></svg>
</div>
</div>
</div>
</div>
<!-- Orders Section -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Pending Orders -->
<div class="lg:col-span-2">
<div class="card">
<div class="p-6 border-b border-gray-200">
<h2 class="text-xl font-bold text-gray-800">Pedidos Pendientes</h2>
<p class="text-gray-500 text-sm">Pedidos que requieren atención inmediata</p>
</div>
<div class="p-6">
<div class="space-y-4" id="pending-orders">
<!-- Pending orders will be populated here -->
</div>
</div>
</div>
</div>
<!-- Production Queue -->
<div>
<div class="card mb-6">
<div class="p-6 border-b border-gray-200">
<h2 class="text-xl font-bold text-gray-800">Cola de Producción</h2>
<p class="text-gray-500 text-sm">Pedidos en proceso de fabricación</p>
</div>
<div class="p-6">
<div class="space-y-4" id="production-queue">
<!-- Production queue will be populated here -->
</div>
</div>
</div>
<!-- Shipping Queue -->
<div class="card">
<div class="p-6 border-b border-gray-200">
<h2 class="text-xl font-bold text-gray-800">Listos para Enviar</h2>
<p class="text-gray-500 text-sm">Pedidos completados y preparados</p>
</div>
<div class="p-6">
<div class="space-y-4" id="shipping-queue">
<!-- Shipping queue will be populated here -->
</div>
</div>
</div>
</div>
</div>
</div>
</main>
<!-- Order Detail Modal -->
<div id="order-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
<div class="bg-white rounded-lg shadow-xl w-full max-w-2xl mx-4 max-h-[90vh] overflow-y-auto">
<div class="p-6 border-b border-gray-200 flex justify-between items-center">
<h3 class="text-2xl font-bold text-gray-800">Detalles del Pedido</h3>
<button id="close-modal" class="text-gray-500 hover:text-gray-700">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
</button>
</div>
<div class="p-6" id="order-details-content">
<!-- Order details will be populated here -->
</div>
</div>
</div>
<!-- Notification Container -->
<div id="notification-container" class="fixed bottom-4 right-4 space-y-2 z-50"></div>
<script>
// Mock data for orders
const orders = [
{
id: "ORD-001",
customer: "María González",
email: "maria@example.com",
date: "2024-01-15",
items: [
{ name: "Kit 50x70cm", type: "Lino Premium", quantity: 1, price: 4500 }
],
total: 4500,
status: "pending",
address: "Av. Corrientes 1234, Buenos Aires",
phone: "+54 11 1234-5678",
notes: "Entrega urgente para exposición"
},
{
id: "ORD-002",
customer: "Juan Pérez",
email: "juan@example.com",
date: "2024-01-15",
items: [
{ name: "Kit 30x40cm", type: "Algodón Universal", quantity: 2, price: 2200 },
{ name: "Kit 80x100cm", type: "Lino Premium", quantity: 1, price: 8900 }
],
total: 13300,
status: "processing",
address: "Calle Florida 567, Buenos Aires",
phone: "+54 11 9876-5432",
notes: "Incluir tarjeta de regalo"
},
{
id: "ORD-003",
customer: "Ana Rodríguez",
email: "ana@example.com",
date: "2024-01-14",
items: [
{ name: "Kit 50x70cm", type: "Algodón Universal", quantity: 1, price: 3000 }
],
total: 3000,
status: "shipped",
address: "Av. Santa Fe 890, Buenos Aires",
phone: "+54 11 5555-4444",
tracking: "TRK-789456123"
},
{
id: "ORD-004",
customer: "Carlos López",
email: "carlos@example.com",
date: "2024-01-14",
items: [
{ name: "Kit 80x100cm", type: "Lino Premium", quantity: 3, price: 26700 }
],
total: 26700,
status: "completed",
address: "San Martín 321, Rosario",
phone: "+54 341 123-4567",
tracking: "TRK-159753468"
},
{
id: "ORD-005",
customer: "Laura Martínez",
email: "laura@example.com",
date: "2024-01-16",
items: [
{ name: "Kit 30x40cm", type: "Lino Premium", quantity: 1, price: 1650 }
],
total: 1650,
status: "pending",
address: "Belgrano 456, Córdoba",
phone: "+54 351 987-6543",
notes: "Cliente nuevo, verificar datos"
}
];
// DOM Elements
const pendingOrdersEl = document.getElementById('pending-orders');
const productionQueueEl = document.getElementById('production-queue');
const shippingQueueEl = document.getElementById('shipping-queue');
const orderModal = document.getElementById('order-modal');
const closeModal = document.getElementById('close-modal');
const orderDetailsContent = document.getElementById('order-details-content');
const notificationContainer = document.getElementById('notification-container');
// Initialize dashboard
document.addEventListener('DOMContentLoaded', () => {
renderOrders();
updateStats();
});
// Render orders in their respective sections
function renderOrders() {
// Clear sections
pendingOrdersEl.innerHTML = '';
productionQueueEl.innerHTML = '';
shippingQueueEl.innerHTML = '';
// Filter orders by status
const pendingOrders = orders.filter(order => order.status === 'pending');
const processingOrders = orders.filter(order => order.status === 'processing');
const readyOrders = orders.filter(order => order.status === 'shipped' || order.status === 'completed');
// Render pending orders
if (pendingOrders.length === 0) {
pendingOrdersEl.innerHTML = '<p class="text-gray-500 text-center py-4">No hay pedidos pendientes</p>';
} else {
pendingOrders.forEach(order => {
pendingOrdersEl.appendChild(createOrderCard(order));
});
}
// Render production queue
if (processingOrders.length === 0) {
productionQueueEl.innerHTML = '<p class="text-gray-500 text-center py-4">No hay pedidos en producción</p>';
} else {
processingOrders.forEach(order => {
productionQueueEl.appendChild(createOrderCard(order));
});
}
// Render shipping queue
if (readyOrders.length === 0) {
shippingQueueEl.innerHTML = '<p class="text-gray-500 text-center py-4">No hay pedidos listos para enviar</p>';
} else {
readyOrders.forEach(order => {
shippingQueueEl.appendChild(createOrderCard(order));
});
}
}
// Create order card element
function createOrderCard(order) {
const card = document.createElement('div');
card.className = 'border border-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow cursor-pointer';
card.onclick = () => showOrderDetails(order);
let statusClass = '';
let statusText = '';
switch(order.status) {
case 'pending':
statusClass = 'status-pending';
statusText = 'Pendiente';
break;
case 'processing':
statusClass = 'status-processing';
statusText = 'En Producción';
break;
case 'shipped':
statusClass = 'status-shipped';
statusText = 'Enviado';
break;
case 'completed':
statusClass = 'status-completed';
statusText = 'Completado';
break;
}
card.innerHTML = `
<div class="flex justify-between items-start mb-3">
<div>
<h4 class="font-bold text-gray-800">${order.id}</h4>
<p class="text-gray-600 text-sm">${order.customer}</p>
</div>
<span class="px-2 py-1 rounded-full text-xs font-medium ${statusClass}">${statusText}</span>
</div>
<div class="mb-3">
<p class="text-gray-800 font-semibold">$${order.total.toLocaleString('es-AR')}</p>
<p class="text-gray-500 text-sm">${order.date}</p>
</div>
<div class="text-sm text-gray-600">
${order.items.map(item => `${item.quantity}x ${item.name} (${item.type})`).join('<br>')}
</div>
`;
return card;
}
// Show order details modal
function showOrderDetails(order) {
let statusClass = '';
let statusText = '';
switch(order.status) {
case 'pending':
statusClass = 'status-pending';
statusText = 'Pendiente';
break;
case 'processing':
statusClass = 'status-processing';
statusText = 'En Producción';
break;
case 'shipped':
statusClass = 'status-shipped';
statusText = 'Enviado';
break;
case 'completed':
statusClass = 'status-completed';
statusText = 'Completado';
break;
}
orderDetailsContent.innerHTML = `
<div class="mb-6">
<div class="flex justify-between items-start mb-4">
<div>
<h3 class="text-xl font-bold text-gray-800">${order.id}</h3>
<p class="text-gray-600">${order.customer}</p>
</div>
<span class="px-3 py-1 rounded-full text-sm font-medium ${statusClass}">${statusText}</span>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<p class="text-gray-500 text-sm">Email</p>
<p class="text-gray-800">${order.email}</p>
</div>
<div>
<p class="text-gray-500 text-sm">Teléfono</p>
<p class="text-gray-800">${order.phone}</p>
</div>
<div>
<p class="text-gray-500 text-sm">Fecha</p>
<p class="text-gray-800">${order.date}</p>
</div>
<div>
<p class="text-gray-500 text-sm">Total</p>
<p class="text-xl font-bold text-gray-800">$${order.total.toLocaleString('es-AR')}</p>
</div>
</div>
</div>
<div class="mb-6">
<h4 class="font-bold text-gray-800 mb-3">Dirección de Envío</h4>
<p class="text-gray-800">${order.address}</p>
</div>
<div class="mb-6">
<h4 class="font-bold text-gray-800 mb-3">Artículos</h4>
<div class="space-y-3">
${order.items.map(item => `
<div class="flex justify-between items-center p-3 bg-gray-50 rounded-lg">
<div>
<p class="font-medium text-gray-800">${item.name}</p>
<p class="text-gray-600 text-sm">${item.type}</p>
</div>
<div class="text-right">
<p class="font-medium text-gray-800">x${item.quantity}</p>
<p class="text-gray-600 text-sm">$${item.price.toLocaleString('es-AR')}</p>
</div>
</div>
`).join('')}
</div>
</div>
${order.notes ? `
<div class="mb-6">
<h4 class="font-bold text-gray-800 mb-3">Notas del Cliente</h4>
<p class="text-gray-800 bg-yellow-50 p-3 rounded-lg">${order.notes}</p>
</div>
` : ''}
${order.tracking ? `
<div class="mb-6">
<h4 class="font-bold text-gray-800 mb-3">Número de Seguimiento</h4>
<p class="text-gray-800 font-mono bg-blue-50 p-3 rounded-lg">${order.tracking}</p>
</div>
` : ''}
<div class="flex flex-wrap gap-3 pt-4 border-t border-gray-200">
${order.status === 'pending' ? `
<button onclick="updateOrderStatus('${order.id}', 'processing')" class="btn-primary px-4 py-2 rounded-lg font-medium">Iniciar Producción</button>
<button onclick="updateOrderStatus('${order.id}', 'shipped')" class="btn-warning px-4 py-2 rounded-lg font-medium">Marcar como Enviado</button>
` : ''}
${order.status === 'processing' ? `
<button onclick="updateOrderStatus('${order.id}', 'shipped')" class="btn-success px-4 py-2 rounded-lg font-medium">Marcar como Enviado</button>
<button onclick="updateOrderStatus('${order.id}', 'completed')" class="btn-secondary px-4 py-2 rounded-lg font-medium">Completar Pedido</button>
` : ''}
${order.status === 'shipped' ? `
<button onclick="updateOrderStatus('${order.id}', 'completed')" class="btn-success px-4 py-2 rounded-lg font-medium">Completar Pedido</button>
` : ''}
<button onclick="deleteOrder('${order.id}')" class="ml-auto text-red-500 hover:text-red-700 px-4 py-2 rounded-lg font-medium">Eliminar Pedido</button>
</div>
`;
orderModal.classList.remove('hidden');
}
// Close modal
closeModal.addEventListener('click', () => {
orderModal.classList.add('hidden');
});
// Close modal when clicking outside
orderModal.addEventListener('click', (e) => {
if (e.target === orderModal) {
orderModal.classList.add('hidden');
}
});
// Update order status
function updateOrderStatus(orderId, newStatus) {
const order = orders.find(o => o.id === orderId);
if (order) {
order.status = newStatus;
renderOrders();
updateStats();
let statusText = '';
switch(newStatus) {
case 'processing':
statusText = 'En Producción';
break;
case 'shipped':
statusText = 'Enviado';
break;
case 'completed':
statusText = 'Completado';
break;
}
showNotification(`Pedido ${orderId} actualizado a: ${statusText}`, 'success');
orderModal.classList.add('hidden');
}
}
// Delete order
function deleteOrder(orderId) {
const index = orders.findIndex(o => o.id === orderId);
if (index !== -1) {
const order = orders[index];
orders.splice(index, 1);
renderOrders();
updateStats();
showNotification(`Pedido ${orderId} eliminado`, 'warning');
orderModal.classList.add('hidden');
}
}
// Update statistics
function updateStats() {
const pendingCount = orders.filter(o => o.status === 'pending').length;
const processingCount = orders.filter(o => o.status === 'processing').length;
const readyCount = orders.filter(o => o.status === 'shipped' || o.status === 'completed').length;
const totalCount = orders.length;
document.getElementById('pending-count').textContent = pendingCount;
document.getElementById('processing-count').textContent = processingCount;
document.getElementById('ready-count').textContent = readyCount;
document.getElementById('total-count').textContent = totalCount;
}
// Show notification
function showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `notification px-4 py-3 rounded-lg shadow-lg max-w-md transform transition-all duration-300`;
let bgColor = '';
switch(type) {
case 'success':
bgColor = 'bg-green-500 text-white';
break;
case 'warning':
bgColor = 'bg-yellow-500 text-white';
break;
case 'error':
bgColor = 'bg-red-500 text-white';
break;
default:
bgColor = 'bg-blue-500 text-white';
}
notification.className += ` ${bgColor}`;
notification.textContent = message;
notificationContainer.appendChild(notification);
// Remove notification after 3 seconds
setTimeout(() => {
notification.style.opacity = '0';
setTimeout(() => {
if (notification.parentNode) {
notification.parentNode.removeChild(notification);
}
}, 300);
}, 3000);
}
// Simulate real-time updates
setInterval(() => {
// This would normally be replaced with WebSocket or API calls
// For demo purposes, we'll just update the timestamp
const now = new Date();
if (now.getSeconds() % 30 === 0) {
// Simulate a new order every 30 seconds
// In a real app, this would come from a server push
}
}, 1000);
</script>
</body>
</html>