|
|
<!DOCTYPE html> |
|
|
<html lang="fr"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Salon de Coiffure - File d'attente</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"> |
|
|
<style> |
|
|
.queue-item { |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
.queue-item:hover { |
|
|
transform: translateY(-3px); |
|
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); |
|
|
} |
|
|
.animate-pulse { |
|
|
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; |
|
|
} |
|
|
@keyframes pulse { |
|
|
0%, 100% { opacity: 1; } |
|
|
50% { opacity: 0.5; } |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="bg-gray-50 min-h-screen"> |
|
|
<div class="container mx-auto px-4 py-8"> |
|
|
|
|
|
<header class="flex flex-col md:flex-row justify-between items-center mb-12"> |
|
|
<div class="flex items-center mb-4 md:mb-0"> |
|
|
<i class="fas fa-scissors text-3xl text-indigo-600 mr-3"></i> |
|
|
<h1 class="text-3xl font-bold text-gray-800">Salon Belle Coupe</h1> |
|
|
</div> |
|
|
<div class="flex items-center space-x-4"> |
|
|
<div class="bg-indigo-100 px-4 py-2 rounded-full"> |
|
|
<span class="text-indigo-800 font-medium">Ouvert</span> |
|
|
<span class="ml-2 text-gray-600">9h - 19h</span> |
|
|
</div> |
|
|
<div class="hidden md:block"> |
|
|
<span class="text-gray-600">Tél: </span> |
|
|
<span class="font-medium">01 23 45 67 89</span> |
|
|
</div> |
|
|
</div> |
|
|
</header> |
|
|
|
|
|
|
|
|
<main class="grid grid-cols-1 lg:grid-cols-3 gap-8"> |
|
|
|
|
|
<div class="lg:col-span-2 bg-white rounded-xl shadow-md overflow-hidden"> |
|
|
<div class="bg-indigo-600 px-6 py-4"> |
|
|
<h2 class="text-xl font-bold text-white">Gestion de la file d'attente</h2> |
|
|
</div> |
|
|
|
|
|
<div class="p-6"> |
|
|
|
|
|
<div class="mb-8"> |
|
|
<h3 class="text-lg font-semibold text-gray-700 mb-4">Client actuel</h3> |
|
|
<div id="current-client" class="bg-indigo-50 border-l-4 border-indigo-600 p-4 rounded-lg flex justify-between items-center"> |
|
|
<div class="flex items-center"> |
|
|
<div class="bg-indigo-100 p-3 rounded-full mr-4"> |
|
|
<i class="fas fa-user text-indigo-600 text-xl"></i> |
|
|
</div> |
|
|
<div> |
|
|
<p class="font-medium text-gray-800">Aucun client en cours</p> |
|
|
<p class="text-sm text-gray-500">En attente du prochain client</p> |
|
|
</div> |
|
|
</div> |
|
|
<button id="next-client-btn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg transition duration-200 hidden"> |
|
|
Client suivant <i class="fas fa-arrow-right ml-2"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h3 class="text-lg font-semibold text-gray-700">File d'attente</h3> |
|
|
<span id="queue-count" class="bg-gray-200 text-gray-700 px-3 py-1 rounded-full text-sm font-medium">0 clients</span> |
|
|
</div> |
|
|
|
|
|
<div id="queue-list" class="space-y-3"> |
|
|
|
|
|
<div class="text-center py-8 text-gray-500" id="empty-queue-message"> |
|
|
<i class="fas fa-users-slash text-3xl mb-2"></i> |
|
|
<p>Aucun client dans la file d'attente</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="bg-white rounded-xl shadow-md overflow-hidden"> |
|
|
<div class="bg-indigo-600 px-6 py-4"> |
|
|
<h2 class="text-xl font-bold text-white">Ajouter un client</h2> |
|
|
</div> |
|
|
|
|
|
<div class="p-6"> |
|
|
<form id="add-client-form" class="space-y-4"> |
|
|
<div> |
|
|
<label for="client-name" class="block text-sm font-medium text-gray-700 mb-1">Nom du client</label> |
|
|
<input type="text" id="client-name" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" placeholder="Jean Dupont" required> |
|
|
</div> |
|
|
|
|
|
<div> |
|
|
<label for="client-service" class="block text-sm font-medium text-gray-700 mb-1">Service demandé</label> |
|
|
<select id="client-service" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> |
|
|
<option value="Coupe homme">Coupe homme</option> |
|
|
<option value="Coupe femme">Coupe femme</option> |
|
|
<option value="Coloration">Coloration</option> |
|
|
<option value="Brushing">Brushing</option> |
|
|
<option value="Barbier">Barbier</option> |
|
|
<option value="Autre">Autre</option> |
|
|
</select> |
|
|
</div> |
|
|
|
|
|
<div> |
|
|
<label for="client-phone" class="block text-sm font-medium text-gray-700 mb-1">Téléphone (optionnel)</label> |
|
|
<input type="tel" id="client-phone" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" placeholder="06 12 34 56 78"> |
|
|
</div> |
|
|
|
|
|
<button type="submit" class="w-full bg-indigo-600 hover:bg-indigo-700 text-white py-2 px-4 rounded-lg transition duration-200 flex items-center justify-center"> |
|
|
<i class="fas fa-plus-circle mr-2"></i> Ajouter à la file |
|
|
</button> |
|
|
</form> |
|
|
|
|
|
|
|
|
<div class="mt-8 bg-gray-50 p-4 rounded-lg"> |
|
|
<h3 class="text-lg font-semibold text-gray-700 mb-2">Temps d'attente estimé</h3> |
|
|
<div class="flex items-center"> |
|
|
<i class="fas fa-clock text-indigo-600 text-xl mr-3"></i> |
|
|
<div> |
|
|
<p class="text-gray-800 font-medium" id="wait-time">~ 0 min</p> |
|
|
<p class="text-sm text-gray-500">(environ 15 min par client)</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mt-6 grid grid-cols-2 gap-4"> |
|
|
<div class="bg-blue-50 p-3 rounded-lg"> |
|
|
<p class="text-sm text-blue-600 font-medium">Clients aujourd'hui</p> |
|
|
<p class="text-2xl font-bold text-blue-800" id="today-count">0</p> |
|
|
</div> |
|
|
<div class="bg-green-50 p-3 rounded-lg"> |
|
|
<p class="text-sm text-green-600 font-medium">En attente</p> |
|
|
<p class="text-2xl font-bold text-green-800" id="waiting-count">0</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</main> |
|
|
|
|
|
|
|
|
<footer class="mt-12 pt-6 border-t border-gray-200"> |
|
|
<div class="flex flex-col md:flex-row justify-between items-center"> |
|
|
<p class="text-gray-600 mb-4 md:mb-0">© 2023 Salon Belle Coupe. Tous droits réservés.</p> |
|
|
<div class="flex space-x-4"> |
|
|
<a href="#" class="text-gray-600 hover:text-indigo-600"><i class="fab fa-facebook-f"></i></a> |
|
|
<a href="#" class="text-gray-600 hover:text-indigo-600"><i class="fab fa-instagram"></i></a> |
|
|
<a href="#" class="text-gray-600 hover:text-indigo-600"><i class="fab fa-twitter"></i></a> |
|
|
</div> |
|
|
</div> |
|
|
</footer> |
|
|
</div> |
|
|
|
|
|
<script> |
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
|
|
let queue = JSON.parse(localStorage.getItem('hairSalonQueue')) || []; |
|
|
let currentClient = JSON.parse(localStorage.getItem('currentClient')) || null; |
|
|
let todayCount = parseInt(localStorage.getItem('todayCount')) || 0; |
|
|
|
|
|
|
|
|
const queueList = document.getElementById('queue-list'); |
|
|
const emptyQueueMessage = document.getElementById('empty-queue-message'); |
|
|
const queueCount = document.getElementById('queue-count'); |
|
|
const waitTime = document.getElementById('wait-time'); |
|
|
const todayCountElement = document.getElementById('today-count'); |
|
|
const waitingCountElement = document.getElementById('waiting-count'); |
|
|
const currentClientElement = document.getElementById('current-client'); |
|
|
const nextClientBtn = document.getElementById('next-client-btn'); |
|
|
const addClientForm = document.getElementById('add-client-form'); |
|
|
|
|
|
|
|
|
updateQueueUI(); |
|
|
updateTodayCount(); |
|
|
updateCurrentClientUI(); |
|
|
|
|
|
|
|
|
addClientForm.addEventListener('submit', function(e) { |
|
|
e.preventDefault(); |
|
|
|
|
|
const name = document.getElementById('client-name').value; |
|
|
const service = document.getElementById('client-service').value; |
|
|
const phone = document.getElementById('client-phone').value; |
|
|
|
|
|
const client = { |
|
|
id: Date.now(), |
|
|
name: name, |
|
|
service: service, |
|
|
phone: phone, |
|
|
timestamp: new Date().toISOString() |
|
|
}; |
|
|
|
|
|
queue.push(client); |
|
|
todayCount++; |
|
|
|
|
|
saveQueue(); |
|
|
updateQueueUI(); |
|
|
updateTodayCount(); |
|
|
|
|
|
|
|
|
addClientForm.reset(); |
|
|
document.getElementById('client-name').focus(); |
|
|
|
|
|
|
|
|
showNotification(`Client ${name} ajouté à la file d'attente!`); |
|
|
}); |
|
|
|
|
|
|
|
|
nextClientBtn.addEventListener('click', function() { |
|
|
if (queue.length > 0) { |
|
|
|
|
|
currentClient = queue.shift(); |
|
|
saveQueue(); |
|
|
updateQueueUI(); |
|
|
updateCurrentClientUI(); |
|
|
|
|
|
|
|
|
showNotification(`Prise en charge de ${currentClient.name}`); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
function updateQueueUI() { |
|
|
queueList.innerHTML = ''; |
|
|
|
|
|
if (queue.length === 0) { |
|
|
emptyQueueMessage.classList.remove('hidden'); |
|
|
queueCount.textContent = '0 clients'; |
|
|
waitTime.textContent = '~ 0 min'; |
|
|
waitingCountElement.textContent = '0'; |
|
|
} else { |
|
|
emptyQueueMessage.classList.add('hidden'); |
|
|
queueCount.textContent = `${queue.length} client${queue.length > 1 ? 's' : ''}`; |
|
|
waitTime.textContent = `~ ${queue.length * 15} min`; |
|
|
waitingCountElement.textContent = queue.length; |
|
|
|
|
|
queue.forEach((client, index) => { |
|
|
const queueItem = document.createElement('div'); |
|
|
queueItem.className = 'queue-item bg-white border border-gray-200 rounded-lg p-4 flex justify-between items-center'; |
|
|
|
|
|
queueItem.innerHTML = ` |
|
|
<div class="flex items-center"> |
|
|
<div class="bg-gray-100 p-2 rounded-full mr-3"> |
|
|
<i class="fas fa-user${index === 0 ? '-check text-green-600' : ' text-gray-600'}"></i> |
|
|
</div> |
|
|
<div> |
|
|
<p class="font-medium text-gray-800">${client.name}</p> |
|
|
<p class="text-sm text-gray-500">${client.service}</p> |
|
|
${client.phone ? `<p class="text-xs text-gray-400 mt-1"><i class="fas fa-phone mr-1"></i>${client.phone}</p>` : ''} |
|
|
</div> |
|
|
</div> |
|
|
<div class="text-right"> |
|
|
<span class="text-xs text-gray-500">#${index + 1}</span> |
|
|
${index === 0 ? '<span class="block text-xs text-green-600 font-medium mt-1">Prochain</span>' : ''} |
|
|
</div> |
|
|
`; |
|
|
|
|
|
queueList.appendChild(queueItem); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function updateCurrentClientUI() { |
|
|
if (currentClient) { |
|
|
currentClientElement.innerHTML = ` |
|
|
<div class="flex items-center"> |
|
|
<div class="bg-indigo-100 p-3 rounded-full mr-4"> |
|
|
<i class="fas fa-user text-indigo-600 text-xl"></i> |
|
|
</div> |
|
|
<div> |
|
|
<p class="font-medium text-gray-800">${currentClient.name}</p> |
|
|
<p class="text-sm text-gray-500">${currentClient.service}</p> |
|
|
${currentClient.phone ? `<p class="text-xs text-indigo-500 mt-1"><i class="fas fa-phone mr-1"></i>${currentClient.phone}</p>` : ''} |
|
|
</div> |
|
|
</div> |
|
|
<button id="complete-service-btn" class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg transition duration-200 flex items-center"> |
|
|
Terminer <i class="fas fa-check ml-2"></i> |
|
|
</button> |
|
|
`; |
|
|
|
|
|
document.getElementById('complete-service-btn').addEventListener('click', function() { |
|
|
currentClient = null; |
|
|
localStorage.removeItem('currentClient'); |
|
|
updateCurrentClientUI(); |
|
|
|
|
|
if (queue.length > 0) { |
|
|
nextClientBtn.classList.remove('hidden'); |
|
|
} |
|
|
|
|
|
showNotification('Service terminé avec succès!'); |
|
|
}); |
|
|
|
|
|
nextClientBtn.classList.add('hidden'); |
|
|
} else { |
|
|
currentClientElement.innerHTML = ` |
|
|
<div class="flex items-center"> |
|
|
<div class="bg-indigo-100 p-3 rounded-full mr-4"> |
|
|
<i class="fas fa-user text-indigo-600 text-xl"></i> |
|
|
</div> |
|
|
<div> |
|
|
<p class="font-medium text-gray-800">Aucun client en cours</p> |
|
|
<p class="text-sm text-gray-500">En attente du prochain client</p> |
|
|
</div> |
|
|
</div> |
|
|
${queue.length > 0 ? `<button id="next-client-btn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-lg transition duration-200"> |
|
|
Client suivant <i class="fas fa-arrow-right ml-2"></i> |
|
|
</button>` : ''} |
|
|
`; |
|
|
|
|
|
if (queue.length > 0) { |
|
|
document.getElementById('next-client-btn').addEventListener('click', function() { |
|
|
currentClient = queue.shift(); |
|
|
saveQueue(); |
|
|
updateQueueUI(); |
|
|
updateCurrentClientUI(); |
|
|
|
|
|
showNotification(`Prise en charge de ${currentClient.name}`); |
|
|
}); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function updateTodayCount() { |
|
|
todayCountElement.textContent = todayCount; |
|
|
localStorage.setItem('todayCount', todayCount.toString()); |
|
|
} |
|
|
|
|
|
|
|
|
function saveQueue() { |
|
|
localStorage.setItem('hairSalonQueue', JSON.stringify(queue)); |
|
|
if (currentClient) { |
|
|
localStorage.setItem('currentClient', JSON.stringify(currentClient)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function showNotification(message) { |
|
|
const notification = document.createElement('div'); |
|
|
notification.className = 'fixed bottom-4 right-4 bg-green-600 text-white px-4 py-2 rounded-lg shadow-lg flex items-center animate-pulse'; |
|
|
notification.innerHTML = ` |
|
|
<i class="fas fa-check-circle mr-2"></i> |
|
|
<span>${message}</span> |
|
|
`; |
|
|
|
|
|
document.body.appendChild(notification); |
|
|
|
|
|
setTimeout(() => { |
|
|
notification.classList.remove('animate-pulse'); |
|
|
notification.classList.add('opacity-0', 'transition-opacity', 'duration-500'); |
|
|
|
|
|
setTimeout(() => { |
|
|
notification.remove(); |
|
|
}, 500); |
|
|
}, 3000); |
|
|
} |
|
|
|
|
|
|
|
|
function checkForDayChange() { |
|
|
const lastUpdated = localStorage.getItem('lastUpdated'); |
|
|
const today = new Date().toDateString(); |
|
|
|
|
|
if (!lastUpdated || lastUpdated !== today) { |
|
|
todayCount = 0; |
|
|
localStorage.setItem('todayCount', '0'); |
|
|
localStorage.setItem('lastUpdated', today); |
|
|
updateTodayCount(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
setInterval(checkForDayChange, 3600000); |
|
|
checkForDayChange(); |
|
|
}); |
|
|
</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=aramka/faexpress" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
|
</html> |