// Aurelle Bride — Admin panel (hidden route /kr/pk/admin/moon) // NOTE: This is a UI-only mock. Real auth + persistence requires a backend. const { useState: aS, useEffect: aE, useMemo: aM } = React; const Logo = window.Logo; const I = window.I; const Placeholder = window.Placeholder; const useApp = window.useApp; const ADMIN_KEY = 'aurelle_admin_session'; const ADMIN_DATA_KEY = 'aurelle_admin_data'; /* Default mock data, persisted to localStorage so admin actions feel real */ function emptyData(){ return { products:[], inquiries:[], customs:[], specials:[], users:[], posts:[], settings:{} }; } async function loadAdminDataFromApi(token){ const h = { 'Authorization': `Bearer ${token}` }; const [products,inquiries,customs,specials,posts,users,settings] = await Promise.all([ fetch('/api/products.php').then(r=>r.json()), fetch('/api/inquiries.php',{headers:h}).then(r=>r.json()), fetch('/api/customs.php',{headers:h}).then(r=>r.json()), fetch('/api/specials.php',{headers:h}).then(r=>r.json()), fetch('/api/posts.php',{headers:h}).then(r=>r.json()), fetch('/api/users.php',{headers:h}).then(r=>r.json()), fetch('/api/settings.php').then(r=>r.json()), ]); return { products, inquiries, customs, specials, posts, users, settings }; } function authToken(){ try { return JSON.parse(sessionStorage.getItem(ADMIN_KEY))?.token; } catch { return null; } } /* ==== LOGIN ==== */ function AdminLogin({ onAuth }){ const [email, setEmail] = aS('info@aurellebride.com'); const [pwd, setPwd] = aS(''); const [err, setErr] = aS(''); const [loading, setLoading] = aS(false); const submit = async (e) => { e.preventDefault(); setErr(''); setLoading(true); try { const r = await fetch('/api/auth.php?action=login', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({ email, password: pwd }) }); if (!r.ok) throw new Error('bad'); const { token, user } = await r.json(); const session = { ...user, token, ts: Date.now() }; sessionStorage.setItem(ADMIN_KEY, JSON.stringify(session)); onAuth(session); } catch { setErr('Invalid credentials.'); setLoading(false); } }; return (
SECURE LOGIN

Atelier admin.

Authorized personnel only. All access is logged.

setEmail(e.target.value)} required autoFocus/>
setPwd(e.target.value)} required/>
{err &&
{err}
}
DEMO · admin / admin · OR info@aurellebride.com / Aurelle@2026
); } /* ==== SHELL ==== */ function AdminShell({ session, sub, onLogout }){ const { theme, toggleTheme, navigate } = useApp(); const [data, setData] = aS(emptyData()); const [showSidebar, setShowSidebar] = aS(true); const [loadingData, setLoadingData] = aS(true); aE(()=>{ (async ()=>{ try { const fresh = await loadAdminDataFromApi(authToken()); setData(fresh); } catch(e){} setLoadingData(false); })(); },[]); const ENDPOINTS = { products:'products', inquiries:'inquiries', customs:'customs', specials:'specials', posts:'posts', users:'users', settings:'settings' }; const update = (patch) => { setData(d => ({ ...d, ...patch })); const tok = authToken(); Object.entries(patch).forEach(([key, value]) => { if (!ENDPOINTS[key]) return; fetch(`/api/${ENDPOINTS[key]}.php`, { method:'PUT', headers:{ 'Content-Type':'application/json', 'Authorization': `Bearer ${tok}` }, body: JSON.stringify(value) }).catch(()=>{}); }); }; const nav = [ { id:'', label:'Dashboard', icon:'grid' }, { id:'products', label:'Products', icon:'box', count:data.products.length }, { id:'inquiries', label:'Inquiries', icon:'mail', count:data.inquiries.filter(x=>x.status==='new').length }, { id:'customs', label:'Custom briefs',icon:'sparkle', count:data.customs.filter(x=>x.status==='new').length }, { id:'specials', label:'Special requests', icon:'star', count:data.specials.filter(x=>x.status==='new').length }, { id:'journal', label:'Journal', icon:'edit', count:data.posts.length }, { id:'users', label:'Users', icon:'user', count:data.users.length }, { id:'analytics', label:'Analytics', icon:'chart' }, { id:'settings', label:'Settings', icon:'cog' }, ]; const NavIcon = ({ k }) => { const nav = [ { id:'', label:'Dashboard', icon:'grid' }, { id:'products', label:'Products', icon:'box', count:data.products.length }, { id:'inquiries', label:'Inquiries', icon:'mail', count:data.inquiries.filter(x=>x.status==='new').length }, { id:'customs', label:'Custom briefs',icon:'sparkle', count:data.customs.filter(x=>x.status==='new').length }, { id:'specials', label:'Special requests', icon:'star', count:data.specials.filter(x=>x.status==='new').length }, { id:'journal', label:'Journal', icon:'edit', count:data.posts.length }, { id:'users', label:'Users', icon:'user', count:data.users.length }, { id:'analytics', label:'Analytics', icon:'chart' }, { id:'settings', label:'Settings', icon:'cog' }, ]; const map = { grid: , box: , mail: , sparkle: , star: , edit: , user: , chart: , cog: , }; return map[k]; }; const Page = () => { if (sub === '' || sub === '/') return ; if (sub.startsWith('products')) return ; if (sub.startsWith('inquiries')) return ; if (sub.startsWith('customs')) return ; if (sub.startsWith('specials')) return ; if (sub.startsWith('journal')) return ; if (sub.startsWith('users')) return ; if (sub.startsWith('analytics')) return ; if (sub.startsWith('settings')) return ; return ; }; return (
· ADMIN · {sub.toUpperCase() || 'DASHBOARD'}
View site →
{session.email}
); } /* ==== DASHBOARD ==== */ function AdminDashboard({ data }){ const newInq = data.inquiries.filter(x=>x.status==='new').length; const newCustom = data.customs.filter(x=>x.status==='new').length; const newSpecial = data.specials.filter(x=>x.status==='new').length; const stats = [ { label:'Total products', val:data.products.length, delta:'+3 this month' }, { label:'New inquiries', val:newInq, delta:`${data.inquiries.length} total` }, { label:'Custom briefs', val:newCustom, delta:`${data.customs.length} total` }, { label:'Special requests', val:newSpecial, delta:`${data.specials.length} total` }, ]; const recent = [...data.inquiries.map(x=>({...x,k:'Inquiry'})), ...data.customs.map(x=>({...x,k:'Custom'})), ...data.specials.map(x=>({...x,k:'Special'}))] .sort((a,b) => new Date(b.date) - new Date(a.date)).slice(0, 6); return (

Good morning, Aurelle.

{new Date().toLocaleDateString('en-US', { weekday:'long', month:'long', day:'numeric', year:'numeric' })}

Add new piece
{stats.map(s => (
{s.label}
{s.val}
{s.delta}
))}

Recent activity

View all →
{recent.map((r,i)=>(
{r.k}
{r.name} · {r.subject||r.summary||r.evt||r.detail?.slice(0,40)}
{r.email} · {r.date}
{r.status}
))}

Quick actions

· SYSTEM HEALTH
{[['Storefront','operational'],['Image CDN','operational'],['Email service','operational'],['Backup','last 4h ago']].map(([k,v])=>(
{k}● {v}
))}
); } /* ==== PRODUCTS ==== */ function AdminProducts({ data, update }){ const [editing, setEditing] = aS(null); const [search, setSearch] = aS(''); const { showToast, formatPrice } = useApp(); const list = data.products.filter(p => p.name.toLowerCase().includes(search.toLowerCase())); const blank = { id: Date.now(), name:'New piece', col:'Lehenga', priceValue:150000, status:'1 OF 1', desc:'', tone:'rich', date: new Date().toISOString().slice(0,10) }; const save = (p) => { if (data.products.find(x => x.id === p.id)) { update({ products: data.products.map(x => x.id === p.id ? p : x) }); showToast(`${p.name} updated`); } else { update({ products: [p, ...data.products] }); showToast(`${p.name} added`); } setEditing(null); }; const del = (id) => { if (confirm('Delete this product?')) { update({ products: data.products.filter(p => p.id !== id) }); showToast('Product deleted'); } }; return (

Products

setSearch(e.target.value)} style={{maxWidth:320}}/>
{list.map(p => ( ))}
ImageNameCategoryPriceStatus
{p.image_url ? : }
{p.name}
{p.col} {formatPrice(p.priceValue)} {p.status}
{editing && (
setEditing(null)}>
e.stopPropagation()}>

{data.products.find(x=>x.id===editing.id) ? 'Edit piece' : 'New piece'}

setEditing({...editing, name:e.target.value})}/>
setEditing({...editing, priceValue: parseInt(e.target.value||0)})}/>
setEditing({...editing, date:e.target.value})}/>
{/* Already-uploaded gallery */} {Array.isArray(editing.gallery) && editing.gallery.length > 0 && ( <>
· UPLOADED
{editing.gallery.map((g) => { const isHero = editing.image_url === g.url; return (
{g.label {isHero && HERO}
{!isHero && ( )}
); })}
)} {/* Staging area: selected but not yet uploaded */} {Array.isArray(editing._staged) && editing._staged.length > 0 && ( <>
· READY TO UPLOAD ({editing._staged.length})
{editing._staged.map((s, idx) => (
{s.file.name}
))}
)} {/* Picker */}
document.getElementById('p-img-input').click()}>

Click to select images

JPG · PNG · MULTIPLE OK · LABEL EACH AFTER SELECTING

{ const files = Array.from(e.target.files || []); if (!files.length) return; files.forEach(f => { const reader = new FileReader(); reader.onload = (ev) => { setEditing(prev => ({...prev, _staged: [...(prev._staged || []), { file:f, preview: ev.target.result, label:'' }]})); }; reader.readAsDataURL(f); }); e.target.value = ''; }}/>
)}
); } /* ==== INBOX (shared for inquiries / customs / specials) ==== */ function AdminInbox({ data, update, kind }) { const titles = { inquiries: 'Inquiries', customs: 'Custom briefs', specials: 'Special requests' }; const items = data[kind] || []; const [selected, setSelected] = aS(items[0]?.id || null); const [filter, setFilter] = aS('all'); const [replyText, setReplyText] = aS(''); const [sending, setSending] = aS(false); const { showToast } = useApp(); const filtered = filter === 'all' ? items : items.filter(i => i.status === filter); const item = items.find(i => i.id === selected); aE(() => { setReplyText(''); }, [selected]); const authHeaders = () => ({ 'Content-Type': 'application/json', 'Authorization': `Bearer ${authToken()}` }); const setStatus = async (id, status) => { try { await fetch(`/api/${kind}.php`, { method: 'PUT', headers: authHeaders(), body: JSON.stringify({ id, status }) }); update({ [kind]: items.map(i => i.id === id ? { ...i, status } : i ) }); showToast(`Marked as ${status}`); } catch { showToast('Update failed', 'error'); } }; const sendReply = async () => { if (!item) return; if (!replyText.trim()) { showToast('Write a reply first', 'error'); return; } try { setSending(true); const r = await fetch(`/api/${kind}.php`, { method: 'PUT', headers: authHeaders(), body: JSON.stringify({ id: item.id, reply: replyText }) }); const j = await r.json(); if (!j.ok) { showToast(j.error || 'Email send failed', 'error'); return; } update({ [kind]: items.map(i => i.id === item.id ? { ...i, status: 'replied' } : i ) }); setReplyText(''); showToast('Reply sent successfully'); } catch { showToast('Email send failed', 'error'); } finally { setSending(false); } }; const del = async (id) => { if (!confirm('Delete this entry?')) return; try { await fetch(`/api/${kind}.php`, { method: 'DELETE', headers: authHeaders(), body: JSON.stringify({ id }) }); update({ [kind]: items.filter(i => i.id !== id) }); if (selected === id) { setSelected(null); } showToast('Deleted'); } catch { showToast('Delete failed', 'error'); } }; return (

{titles[kind]}

{['all','new','in-review','replied'].map(f => ( ))}
{filtered.map(i => (
setSelected(i.id)} className={`admin-list-item ${selected===i.id?'active':''}`} >
{i.name}
{i.status}
{i.email}
))}
{item ? ( <>

{item.name}

{item.email}

{item.detail || item.summary}