/* global React, ReactDOM */
const { useState, useEffect, useMemo, useRef } = React;
// =============================================================================
// DEMO MODE — append ?demo=1 to URL. Stubs all /api/* calls with seeded data
// so the admin can be previewed with no backend. Production: do not pass flag.
// =============================================================================
if (location.search.indexOf('demo=1') !== -1) {
const demoUser = { id: 1, name: 'Anita (Demo)', email: 'demo@lacquerynails.in', role: 'admin', permissions: [] };
const today = new Date().toISOString().slice(0, 10);
const tomorrow = new Date(Date.now() + 86400000).toISOString().slice(0, 10);
const minusDays = (n) => new Date(Date.now() - n * 86400000).toISOString().slice(0, 19).replace('T', ' ');
const STUBS = {
'/csrf': { csrf: 'demo-token', user: demoUser },
'/dashboard': {
stats: {
today_appointments: 6,
pending_orders: 3,
refill_due: 4,
low_stock: 2,
total_clients: 142,
completed_this_week: 23,
},
upcoming: [
{ id: 101, name: 'Ananya Reddy', mobile: '+91 98765 43210', service: 'Gel Polish', appt_date: today, appt_time: '11:00 AM', status: 'confirmed' },
{ id: 102, name: 'Priya Sharma', mobile: '+91 99876 54321', service: 'Gel Extensions', appt_date: today, appt_time: '2:30 PM', status: 'pending' },
{ id: 103, name: 'Meera Iyer', mobile: '+91 91234 56789', service: 'Nail Art', appt_date: tomorrow, appt_time: '10:30 AM', status: 'confirmed' },
{ id: 104, name: 'Kavya Nair', mobile: '+91 99887 76655', service: 'Refill', appt_date: tomorrow, appt_time: '4:00 PM', status: 'pending' },
{ id: 105, name: 'Riya Menon', mobile: '+91 98123 45670', service: 'Pedicure', appt_date: tomorrow, appt_time: '6:30 PM', status: 'confirmed' },
],
recent_orders: [
{ id: 201, order_code: 'LQ-260501-A4F2', customer_name: 'Tara Kapoor', product_name: 'Aurora Chrome', total: 999, status: 'pending', created_at: minusDays(0) },
{ id: 202, order_code: 'LQ-260501-B81C', customer_name: 'Aisha Rao', product_name: 'Vintage Rose', total: 1199, status: 'processing', created_at: minusDays(1) },
{ id: 203, order_code: 'LQ-260430-C2E0', customer_name: 'Naina Patel', product_name: 'Pearl Drop', total: 1499, status: 'shipped', created_at: minusDays(2) },
{ id: 204, order_code: 'LQ-260430-D915', customer_name: 'Sanya Joshi', product_name: 'Cat Eye Galaxy', total: 1099, status: 'delivered', created_at: minusDays(3) },
],
},
'/appointments': [
{ id: 101, name: 'Ananya Reddy', mobile: '+91 98765 43210', service: 'Gel Polish', appt_date: today, appt_time: '11:00 AM', status: 'confirmed', source: 'online' },
{ id: 102, name: 'Priya Sharma', mobile: '+91 99876 54321', service: 'Gel Extensions', appt_date: today, appt_time: '2:30 PM', status: 'pending', source: 'whatsapp'},
{ id: 103, name: 'Meera Iyer', mobile: '+91 91234 56789', service: 'Nail Art', appt_date: tomorrow, appt_time: '10:30 AM', status: 'confirmed', source: 'online' },
{ id: 104, name: 'Kavya Nair', mobile: '+91 99887 76655', service: 'Refill', appt_date: tomorrow, appt_time: '4:00 PM', status: 'pending', source: 'walk_in' },
{ id: 105, name: 'Riya Menon', mobile: '+91 98123 45670', service: 'Pedicure', appt_date: tomorrow, appt_time: '6:30 PM', status: 'confirmed', source: 'phone' },
{ id: 106, name: 'Tara Kapoor', mobile: '+91 99988 77665', service: 'Manicure', appt_date: today, appt_time: '5:00 PM', status: 'completed', source: 'online' },
],
'/clients': [
{ id: 1, name: 'Ananya Reddy', mobile: '+91 98765 43210', email: 'ananya@example.com', total_visits: 8, total_spend: 9800, no_show_count: 0, last_visit_at: '2026-04-22 14:30:00', last_service: 'Gel Polish', refill_due_at: null, tags: ['Bestseller'] },
{ id: 2, name: 'Priya Sharma', mobile: '+91 99876 54321', email: 'priya@example.com', total_visits: 4, total_spend: 6800, no_show_count: 1, last_visit_at: '2026-04-15 11:00:00', last_service: 'Gel Extensions', refill_due_at: today, tags: [] },
{ id: 3, name: 'Meera Iyer', mobile: '+91 91234 56789', email: null, total_visits: 12,total_spend: 15200, no_show_count: 0, last_visit_at: '2026-04-28 16:00:00', last_service: 'Nail Art', refill_due_at: null, tags: ['VIP'] },
{ id: 4, name: 'Kavya Nair', mobile: '+91 99887 76655', email: 'kavya@example.com', total_visits: 2, total_spend: 2998, no_show_count: 0, last_visit_at: '2026-04-08 13:00:00', last_service: 'Acrylic Extensions', refill_due_at: minusDays(2).slice(0,10), tags: [] },
],
'/products': [
{ id: 1, name: 'Aurora Chrome', category: 'Chrome', shape: 'Almond', price: 999, purchase_price: 350, stock: 8, low_stock_alert: 3, tags: ['Bestseller'], photo_path: null, is_active: 1 },
{ id: 2, name: 'Vintage Rose', category: 'Florals', shape: 'Coffin', price: 1199, purchase_price: 420, stock: 4, low_stock_alert: 3, tags: ['Hand-painted'], photo_path: null, is_active: 1 },
{ id: 3, name: 'Micro French', category: 'French', shape: 'Stiletto', price: 899, purchase_price: 300, stock: 2, low_stock_alert: 3, tags: [], photo_path: null, is_active: 1 },
{ id: 4, name: 'Pearl Drop', category: '3D Charms', shape: 'Square', price: 1499, purchase_price: 580, stock: 6, low_stock_alert: 3, tags: ['Bridal'], photo_path: null, is_active: 1 },
{ id: 5, name: 'Cat Eye Galaxy',category: 'Glitter', shape: 'Almond', price: 1099, purchase_price: 380, stock: 9, low_stock_alert: 3, tags: ['New'], photo_path: null, is_active: 1 },
{ id: 6, name: 'Butter Nude', category: 'Minimal', shape: 'Short Square', price: 799, purchase_price: 280, stock: 1, low_stock_alert: 3, tags: [], photo_path: null, is_active: 1 },
],
'/orders': [
{ id: 201, order_code: 'LQ-260501-A4F2', customer_name: 'Tara Kapoor', customer_mobile: '+91 99988 77665', product_name: 'Aurora Chrome', quantity: 1, total: 999, status: 'pending', label_printed: 0, created_at: minusDays(0) },
{ id: 202, order_code: 'LQ-260501-B81C', customer_name: 'Aisha Rao', customer_mobile: '+91 99001 23456', product_name: 'Vintage Rose', quantity: 1, total: 1199, status: 'processing', label_printed: 0, created_at: minusDays(1) },
{ id: 203, order_code: 'LQ-260430-C2E0', customer_name: 'Naina Patel', customer_mobile: '+91 90909 90909', product_name: 'Pearl Drop', quantity: 1, total: 1499, status: 'shipped', label_printed: 1, created_at: minusDays(2) },
{ id: 204, order_code: 'LQ-260430-D915', customer_name: 'Sanya Joshi', customer_mobile: '+91 98765 12340', product_name: 'Cat Eye Galaxy', quantity: 2, total: 2198, status: 'delivered', label_printed: 1, created_at: minusDays(3) },
],
'/photos': {},
'/settings/site': { whatsappNumber: '918317451779', phone: '+91 83174 51779', email: 'hello@lacquerynails.in', address: 'Near Shrirampura Metro, Bengaluru', hours: 'Mon to Sun · 10 AM to 9 PM' },
'/settings/offers_banner': { enabled: true, text: 'Festive offer · 20% off all press-on sets · code LACQUER20' },
'/settings/shipping': { provider: 'manual', shiprocket_email: '', shiprocket_password: '' },
'/settings/payment': { razorpay_key_id: '', razorpay_key_secret: '', webhook_secret: '', enable_booking_fee: false, enable_shop_payment: true },
'/settings/refill_rules': { days: 21, services: ['Gel Extensions', 'Acrylic Extensions', 'Permanent Extensions'], message: '' },
'/blog': [
{ id: 1, title: 'Best Gel Polish Salon Near Shrirampura', slug: 'best-gel-polish-shrirampura', status: 'published', updated_at: minusDays(2) },
{ id: 2, title: 'Press-On Nails vs Gel Extensions: What to Pick', slug: 'press-on-vs-gel-extensions', status: 'published', updated_at: minusDays(5) },
{ id: 3, title: 'Bridal Nail Trends 2026 — Bengaluru Edition', slug: 'bridal-nail-trends-2026', status: 'draft', updated_at: minusDays(1) },
],
'/users': [
{ id: 1, name: 'Anita (Demo)', email: 'demo@lacquerynails.in', role: 'admin', permissions: [], is_active: 1, last_login_at: minusDays(0), created_at: minusDays(45) },
{ id: 2, name: 'Sneha Technician', email: 'sneha@lacquerynails.in', role: 'staff', permissions: ['dashboard','appointments','clients','reminders','shipping'], is_active: 1, last_login_at: minusDays(1), created_at: minusDays(20) },
],
'/audit': [
{ id: 1, user_id: 1, user_email: 'demo@lacquerynails.in', action: 'login', entity_type: 'user', entity_id: 1, meta: null, ip: '127.0.0.1', created_at: minusDays(0) },
{ id: 2, user_id: 1, user_email: 'demo@lacquerynails.in', action: 'appointment_create', entity_type: 'appointment', entity_id: 106, meta: { source: 'walk_in' }, ip: '127.0.0.1', created_at: minusDays(0) },
{ id: 3, user_id: 2, user_email: 'sneha@lacquerynails.in', action: 'order_update', entity_type: 'order', entity_id: 203, meta: { fields: ['status'] }, ip: '127.0.0.1', created_at: minusDays(1) },
{ id: 4, user_id: 1, user_email: 'demo@lacquerynails.in', action: 'photo_upload', entity_type: 'photo', entity_id: null, meta: { slot_key: 'hero-photo' },ip: '127.0.0.1', created_at: minusDays(2) },
],
'/reminders': {
one_day: [
{ id: 103, name: 'Meera Iyer', mobile: '+91 91234 56789', service: 'Nail Art', appt_time: '10:30 AM' },
{ id: 104, name: 'Kavya Nair', mobile: '+91 99887 76655', service: 'Refill', appt_time: '4:00 PM' },
],
two_hour: [
{ id: 102, name: 'Priya Sharma', mobile: '+91 99876 54321', service: 'Gel Extensions', appt_time: '2:30 PM' },
],
refill: [
{ id: 2, name: 'Priya Sharma', mobile: '+91 99876 54321', email: 'priya@example.com', last_service: 'Gel Extensions', last_visit_at: '2026-04-15' },
{ id: 4, name: 'Kavya Nair', mobile: '+91 99887 76655', email: 'kavya@example.com', last_service: 'Acrylic Extensions', last_visit_at: '2026-04-08' },
],
},
'/notifications': { max_appointment_id: 106, max_order_id: 204, new_appointments: [], new_orders: [] },
};
window.LQ = {
API_BASE: '/api',
request: function (path) {
const cleanPath = path.split('?')[0];
const data = STUBS[cleanPath];
if (data !== undefined) return Promise.resolve(JSON.parse(JSON.stringify(data)));
return Promise.resolve(null);
},
refreshSession: function () { return Promise.resolve(demoUser); },
login: function () { return Promise.resolve(demoUser); },
logout: function () { return Promise.resolve(); },
requestReset: function () { return Promise.resolve(); },
confirmReset: function () { return Promise.resolve(); },
uploadPhoto: function () { return Promise.resolve({ slot_key: 'demo', file_path: '' }); },
downloadFile: function () { alert('Demo mode: download disabled.'); },
user: function () { return demoUser; },
onAuthChange: function () { return function () {}; },
};
}
// Manual shipping label — opens printable window. No backend required.
window.LQ_printManualLabel = function (order, shipping) {
shipping = shipping || {};
function esc(s) { return String(s == null ? '' : s).replace(/[&<>"]/g, c => ({'&':'&','<':'<','>':'>','"':'"'})[c]); }
const fromBlock = [
esc(shipping.from_name || 'Lacquery Nails'),
esc(shipping.from_address || 'Near Shrirampura Metro'),
[esc(shipping.from_city || 'Bengaluru'), esc(shipping.from_state || 'Karnataka'), esc(shipping.from_pincode || '')].filter(Boolean).join(' · '),
'Phone: ' + esc(shipping.from_phone || '+91 83174 51779'),
shipping.from_gstin ? 'GSTIN: ' + esc(shipping.from_gstin) : ''
].filter(Boolean).join('
');
const toBlock = [
'' + esc(order.customer_name) + '',
esc(order.customer_address || '— address pending, ask on WhatsApp —'),
'Phone: ' + esc(order.customer_mobile),
order.customer_email ? esc(order.customer_email) : ''
].filter(Boolean).join('
');
const html = `