PRAGADEESHWARAN's picture
create a application for my laundry shop
d6d429a verified
Raw
History Blame Contribute Delete
11.4 kB
// Suds & Bubbles Laundromat - Main JavaScript
// Theme Management
const themeManager = {
init() {
const savedTheme = localStorage.getItem('theme') || 'light';
this.setTheme(savedTheme);
// Listen for theme toggle from web components
document.addEventListener('theme-change', (e) => {
this.setTheme(e.detail.theme);
});
},
setTheme(theme) {
const html = document.documentElement;
if (theme === 'dark') {
html.classList.add('dark');
} else {
html.classList.remove('dark');
}
localStorage.setItem('theme', theme);
},
toggle() {
const isDark = document.documentElement.classList.contains('dark');
this.setTheme(isDark ? 'light' : 'dark');
}
};
// Testimonials Data
const testimonials = [
{
name: "Sarah Johnson",
role: "Busy Mom",
image: "http://static.photos/people/200x200/1",
rating: 5,
text: "Suds & Bubbles has been a lifesaver! With three kids, I never have time for laundry. Their pickup and delivery service is incredible."
},
{
name: "Michael Chen",
role: "Software Engineer",
image: "http://static.photos/people/200x200/2",
rating: 5,
text: "The app makes it so easy to track my orders. I love getting notifications when my clothes are ready. Highly recommend!"
},
{
name: "Emily Rodriguez",
role: "Restaurant Owner",
image: "http://static.photos/people/200x200/3",
rating: 5,
text: "We use their commercial service for our restaurant linens. Always pristine, always on time. Best laundry service in the city!"
}
];
// Render Testimonials
function renderTestimonials() {
const container = document.getElementById('testimonials');
if (!container) return;
container.innerHTML = testimonials.map(t => `
<div class="testimonial-card p-6 rounded-2xl bg-gray-50 dark:bg-gray-700 relative">
<div class="flex items-center gap-1 mb-4">
${Array(t.rating).fill('<i data-feather="star" class="w-4 h-4 text-yellow-400 fill-current"></i>').join('')}
</div>
<p class="text-gray-600 dark:text-gray-300 mb-6 relative z-10">${t.text}</p>
<div class="flex items-center gap-3">
<img src="${t.image}" alt="${t.name}" class="w-12 h-12 rounded-full object-cover">
<div>
<div class="font-semibold text-gray-900 dark:text-white">${t.name}</div>
<div class="text-sm text-gray-500 dark:text-gray-400">${t.role}</div>
</div>
</div>
</div>
`).join('');
// Re-initialize feather icons for new content
if (typeof feather !== 'undefined') {
feather.replace();
}
}
// Order Tracking Simulation
const orderTracker = {
statuses: [
{ id: 'received', label: 'Order Received', icon: 'inbox', time: '9:00 AM' },
{ id: 'picked', label: 'Picked Up', icon: 'truck', time: '10:30 AM' },
{ id: 'processing', label: 'In Progress', icon: 'loader', time: '2:00 PM' },
{ id: 'ready', label: 'Ready for Delivery', icon: 'package', time: '5:00 PM' },
{ id: 'delivered', label: 'Delivered', icon: 'check-circle', time: '6:30 PM' }
],
simulateProgress(orderId) {
const container = document.getElementById('tracking-timeline');
if (!container) return;
let currentStep = 0;
const updateTimeline = () => {
const progress = (currentStep / (this.statuses.length - 1)) * 100;
container.innerHTML = `
<div class="relative">
<div class="timeline-line"></div>
<div class="timeline-line-progress" style="height: ${progress}%"></div>
${this.statuses.map((status, index) => `
<div class="relative flex items-start gap-4 mb-8 ${index <= currentStep ? 'opacity-100' : 'opacity-40'}">
<div class="w-10 h-10 rounded-full flex items-center justify-center ${index <= currentStep ? 'bg-primary-500 text-white' : 'bg-gray-200 dark:bg-gray-600 text-gray-500'} relative z-10">
<i data-feather="${status.icon}" class="w-5 h-5"></i>
</div>
<div>
<div class="font-semibold text-gray-900 dark:text-white">${status.label}</div>
<div class="text-sm text-gray-500 dark:text-gray-400">${index <= currentStep ? status.time : 'Pending'}</div>
</div>
</div>
`).join('')}
</div>
`;
if (typeof feather !== 'undefined') {
feather.replace();
}
if (currentStep < this.statuses.length - 1) {
currentStep++;
setTimeout(updateTimeline, 2000);
}
};
updateTimeline();
}
};
// Service Pricing Data
const services = {
washFold: {
name: 'Wash & Fold',
basePrice: 1.50,
unit: 'lb',
options: [
{ name: 'Regular', price: 1.50 },
{ name: 'Eco-Friendly', price: 2.00 },
{ name: 'Hypoallergenic', price: 2.50 }
]
},
dryCleaning: {
name: 'Dry Cleaning',
items: [
{ name: 'Shirt/Blouse', price: 5.99 },
{ name: 'Pants/Skirt', price: 7.99 },
{ name: 'Suit (2pc)', price: 14.99 },
{ name: 'Dress', price: 12.99 },
{ name: 'Coat/Jacket', price: 15.99 }
]
},
homeItems: {
name: 'Home Items',
items: [
{ name: 'Bedding Set', price: 25.99 },
{ name: 'Comforter', price: 35.99 },
{ name: 'Curtains (per panel)', price: 15.99 },
{ name: 'Rug (small)', price: 29.99 },
{ name: 'Rug (large)', price: 49.99 }
]
}
};
// Calculate Order Total
function calculateTotal(items) {
return items.reduce((sum, item) => sum + (item.price * item.quantity), 0);
}
// Format Currency
function formatCurrency(amount) {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(amount);
}
// Toast Notification
function showToast(message, type = 'success') {
const toast = document.createElement('div');
toast.className = `fixed bottom-4 right-4 px-6 py-3 rounded-xl shadow-lg transform translate-y-full transition-transform duration-300 z-50 ${type === 'success' ? 'bg-green-500' : 'bg-red-500'} text-white`;
toast.textContent = message;
document.body.appendChild(toast);
setTimeout(() => toast.classList.remove('translate-y-full'), 100);
setTimeout(() => {
toast.classList.add('translate-y-full');
setTimeout(() => toast.remove(), 300);
}, 3000);
}
// Form Validation
function validateForm(form) {
const required = form.querySelectorAll('[required]');
let valid = true;
required.forEach(field => {
if (!field.value.trim()) {
field.classList.add('border-red-500');
valid = false;
} else {
field.classList.remove('border-red-500');
}
});
return valid;
}
// Initialize on DOM Ready
document.addEventListener('DOMContentLoaded', () => {
themeManager.init();
renderTestimonials();
// Initialize feather icons
if (typeof feather !== 'undefined') {
feather.replace();
}
// Handle tracking form
const trackForm = document.getElementById('track-form');
if (trackForm) {
trackForm.addEventListener('submit', (e) => {
e.preventDefault();
const orderId = document.getElementById('order-id').value;
if (orderId) {
orderTracker.simulateProgress(orderId);
}
});
}
// Handle order form
const orderForm = document.getElementById('order-form');
if (orderForm) {
orderForm.addEventListener('submit', (e) => {
e.preventDefault();
if (validateForm(orderForm)) {
showToast('Order placed successfully! Order #LB' + Date.now().toString().slice(-6));
orderForm.reset();
} else {
showToast('Please fill in all required fields', 'error');
}
});
}
// Service item quantity controls
document.querySelectorAll('.qty-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
const input = e.target.closest('.qty-control').querySelector('input');
const action = e.target.dataset.action;
let value = parseInt(input.value) || 0;
if (action === 'inc') value++;
if (action === 'dec' && value > 0) value--;
input.value = value;
updateOrderSummary();
});
});
});
// Update Order Summary (for order page)
function updateOrderSummary() {
const summary = document.getElementById('order-summary');
if (!summary) return;
const items = [];
document.querySelectorAll('.service-item').forEach(item => {
const qty = parseInt(item.querySelector('input').value) || 0;
if (qty > 0) {
const price = parseFloat(item.dataset.price);
const name = item.dataset.name;
items.push({ name, price, quantity: qty });
}
});
const subtotal = calculateTotal(items);
const tax = subtotal * 0.08;
const total = subtotal + tax;
summary.innerHTML = `
<div class="space-y-2 mb-4">
${items.map(i => `
<div class="flex justify-between text-sm">
<span class="text-gray-600 dark:text-gray-300">${i.name} x${i.quantity}</span>
<span class="font-medium text-gray-900 dark:text-white">${formatCurrency(i.price * i.quantity)}</span>
</div>
`).join('')}
</div>
<div class="border-t border-gray-200 dark:border-gray-700 pt-4 space-y-2">
<div class="flex justify-between text-sm">
<span class="text-gray-600 dark:text-gray-300">Subtotal</span>
<span class="font-medium text-gray-900 dark:text-white">${formatCurrency(subtotal)}</span>
</div>
<div class="flex justify-between text-sm">
<span class="text-gray-600 dark:text-gray-300">Tax (8%)</span>
<span class="font-medium text-gray-900 dark:text-white">${formatCurrency(tax)}</span>
</div>
<div class="flex justify-between text-lg font-bold pt-2 border-t border-gray-200 dark:border-gray-700">
<span class="text-gray-900 dark:text-white">Total</span>
<span class="text-primary-600 dark:text-primary-400">${formatCurrency(total)}</span>
</div>
</div>
`;
}
// Export for use in other scripts
window.SudsBubbles = {
themeManager,
orderTracker,
services,
calculateTotal,
formatCurrency,
showToast,
validateForm
};