// 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.
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 →
);
}
/* ==== 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.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}}/>
| Image | Name | Category | Price | Status | |
{list.map(p => (
{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 (

{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.email}
))}
{item ? (
<>
{item.name}
{item.email}
{item.detail || item.summary}
>
) : (
Select an entry
)}
);
}
/* ==== ADMIN JOURNAL ==== */
function AdminJournal({ data, update }){
const { showToast } = useApp();
const [editing, setEditing] = aS(null);
const [search, setSearch] = aS('');
const list = (data.posts || []).filter(p =>
(p.title || '').toLowerCase().includes(search.toLowerCase())
).sort((a,b) => new Date(b.date) - new Date(a.date));
const blank = {
id: Date.now(),
title: 'Untitled post',
tag: 'Guides',
body: '',
cover_url: '',
status: 'draft',
date: new Date().toISOString().slice(0,10),
};
const save = (p) => {
if ((data.posts || []).find(x => x.id === p.id)){
update({ posts: data.posts.map(x => x.id === p.id ? p : x) });
showToast(`${p.title} updated`);
} else {
update({ posts: [p, ...(data.posts || [])] });
showToast(`${p.title} created`);
}
setEditing(null);
};
const del = (id) => {
if (confirm('Delete this post?')){
update({ posts: data.posts.filter(p => p.id !== id) });
showToast('Post deleted');
}
};
const tags = ['Guides','Atelier','Style','Trends','Care'];
const statuses = ['draft','published','scheduled'];
return (
Journal
setSearch(e.target.value)} style={{maxWidth:320}}/>
| Cover | Title | Tag | Status | Date | |
{list.length === 0 && | No posts yet. Create your first one. |
}
{list.map(p => (
{p.cover_url
? 
:
}
|
{p.title} |
{p.tag} |
{p.status} |
{p.date} |
|
))}
{editing && (
setEditing(null)}>
e.stopPropagation()} style={{maxWidth:760}}>
{(data.posts || []).find(x => x.id === editing.id) ? 'Edit post' : 'New post'}
setEditing({...editing, title:e.target.value})}/>
setEditing({...editing, cover_url:e.target.value})}
placeholder="/uploads/abc123_dress.jpg or full https URL"
/>
TIP · COPY ANY UPLOADED PRODUCT IMAGE URL FROM THE PRODUCTS PAGE
{editing.cover_url && (

{e.target.style.display='none';}} style={{width:'100%', height:'100%', objectFit:'cover', display:'block'}}/>
)}
setEditing({...editing, date:e.target.value})}/>
)}
);
}
function AdminUsers({ data, update }) {
const { showToast } = useApp();
const session = JSON.parse(sessionStorage.getItem(ADMIN_KEY) || '{}');
const token = session.token;
const currentUserId = session.user?.id || session.id;
const isSuperAdmin = !!(session.user?.is_super_admin || session.is_super_admin);
const PERMISSIONS = [
{ key:'products', label:'Products' },
{ key:'inquiries', label:'Inquiries' },
{ key:'customs', label:'Custom Briefs' },
{ key:'specials', label:'Special Requests' },
{ key:'journal', label:'Journal' },
{ key:'analytics', label:'Analytics' },
{ key:'settings', label:'Settings' },
{ key:'users', label:'Users Page' },
{ key:'manage_users', label:'Manage Users' },
{ key:'reset_passwords', label:'Reset Passwords' }
];
const headers = {
'Content-Type':'application/json',
'Authorization': `Bearer ${token}`
};
const emptyUser = {
id:null,
name:'',
email:'',
role:'staff',
password:'',
permissions:[],
is_super_admin:false
};
const [search, setSearch] = aS('');
const [adding, setAdding] = aS(false);
const [editing, setEditing] = aS(null);
const [saving, setSaving] = aS(false);
const [form, setForm] = aS(emptyUser);
const filteredUsers = (data.users || []).filter(u => {
const q = search.toLowerCase();
return (
(u.name || '').toLowerCase().includes(q) ||
(u.email || '').toLowerCase().includes(q) ||
(u.role || '').toLowerCase().includes(q)
);
});
const togglePermission = (perm) => {
const exists = form.permissions.includes(perm);
setForm({
...form,
permissions: exists
? form.permissions.filter(p => p !== perm)
: [...form.permissions, perm]
});
};
const openAdd = () => {
setForm(emptyUser);
setAdding(true);
};
const openEdit = (user) => {
setForm({
id:user.id,
name:user.name || '',
email:user.email || '',
role:user.role || 'staff',
password:'',
permissions:user.permissions || [],
is_super_admin:!!user.is_super_admin
});
setEditing(user);
};
const closeModal = () => {
setAdding(false);
setEditing(null);
setForm(emptyUser);
};
const saveNewUser = async () => {
if (!isSuperAdmin) {
showToast('Only super admin can add users', 'error');
return;
}
if (!form.name || !form.email || !form.password) {
showToast('Complete all required fields', 'error');
return;
}
try {
setSaving(true);
const res = await fetch('/api/users.php', {
method:'POST',
headers,
body: JSON.stringify(form)
});
const json = await res.json();
if (!res.ok) {
showToast(json.error || 'Failed to create user', 'error');
return;
}
showToast('User created');
closeModal();
update();
} catch {
showToast('Network error', 'error');
} finally {
setSaving(false);
}
};
const saveEditUser = async () => {
if (!isSuperAdmin) {
showToast('Only super admin can edit users', 'error');
return;
}
try {
setSaving(true);
const res = await fetch('/api/users.php', {
method:'PUT',
headers,
body: JSON.stringify(form)
});
const json = await res.json();
if (!res.ok) {
showToast(json.error || 'Update failed', 'error');
return;
}
showToast('User updated');
closeModal();
update();
} catch {
showToast('Network error', 'error');
} finally {
setSaving(false);
}
};
const del = async (user) => {
if (!isSuperAdmin) {
showToast('Only super admin can delete users', 'error');
return;
}
if (user.is_super_admin) {
showToast('Super admin cannot be deleted', 'error');
return;
}
if (user.id == currentUserId) {
showToast('You cannot delete yourself', 'error');
return;
}
if (!confirm(`Delete ${user.name || user.email}?`)) return;
try {
const res = await fetch('/api/users.php', {
method:'DELETE',
headers,
body: JSON.stringify({ id:user.id })
});
const json = await res.json();
if (!res.ok) {
showToast(json.error || 'Delete failed', 'error');
return;
}
showToast('User removed');
update();
} catch {
showToast('Network error', 'error');
}
};
const resetPassword = async (user) => {
if (!isSuperAdmin) {
showToast('Only super admin can reset passwords', 'error');
return;
}
const pwd = prompt(`Set new password for ${user.email}`);
if (!pwd) return;
try {
const res = await fetch('/api/users.php', {
method:'PUT',
headers,
body: JSON.stringify({
...user,
password: pwd
})
});
const json = await res.json();
if (!res.ok) {
showToast(json.error || 'Password reset failed', 'error');
return;
}
showToast('Password updated');
update();
} catch {
showToast('Network error', 'error');
}
};
return (
| Name |
Email |
Role |
Permissions |
Last Login |
|
{filteredUsers.length === 0 ? (
|
No users found
|
) : (
filteredUsers.map(user => (
|
{user.name || 'Unnamed'}
{user.is_super_admin && (
SUPER ADMIN
)}
|
{user.email} |
{user.role || 'staff'}
|
{(user.permissions || []).slice(0,3).map(p => (
{p}
))}
{(user.permissions || []).length > 3 && (
+{user.permissions.length - 3}
)}
|
{user.last || '-'} |
{isSuperAdmin && (
<>
{!user.is_super_admin && user.id != currentUserId && (
)}
>
)}
|
))
)}
{(adding || editing) && (
e.stopPropagation()}
style={{maxWidth:850}}
>
{editing ? 'Edit User' : 'Add User'}
)}
);
}
/* ==== ANALYTICS ==== */
function AdminAnalytics({ data }){
const visits = [320,280,410,500,470,620,580,710,690,820,790,880,940,1020,990,1100,1080,1170,1240,1320,1280,1410,1480,1540,1620,1580,1700,1820,1890,1950];
const max = Math.max(...visits);
const stats = [
['Page views (30d)', '32,418', '+18%'],
['Unique visitors', '12,094', '+22%'],
['Avg session', '4m 12s', '+8%'],
['Conversion', '3.4%', '+0.6%'],
];
return (
Analytics
{stats.map(([l,v,d]) => (
))}
Traffic · 30 days
UNIQUE VISITORS · DAILY
{visits.map((v,i) => (
))}
Top products
{data.products.slice(0,5).map((p,i)=>(
{p.name}
{p.col.toUpperCase()}
{Math.floor(2400/(i+1))} views
))}
Top sources
{[['Direct',42],['Instagram',28],['Google',18],['Pinterest',8],['Referral',4]].map(([s,p],i)=>(
))}
);
}
function AdminSettings({ data, update }) {
const { showToast } = useApp();
const defaultSettings = {
brandName: 'Aurelle Bride',
contactEmail: 'info@aurellebride.com',
whatsapp: '+92',
heroHeadline: 'Luxury Bridal Couture',
heroSub: 'Timeless bridal craftsmanship for modern elegance.',
adsenseId: '',
adsensePlacements: {
homepage: false,
products: false,
blog: false,
checkout: false
},
shippingUplift: {
pakistan: 0,
gcc: 15,
usa: 25,
uk: 22,
europe: 20
}
};
const [s, setS] = aS({
...defaultSettings,
...(data?.settings || {}),
adsensePlacements: {
...defaultSettings.adsensePlacements,
...(data?.settings?.adsensePlacements || {})
},
shippingUplift: {
...defaultSettings.shippingUplift,
...(data?.settings?.shippingUplift || {})
}
});
const save = () => {
update({ settings: s });
showToast('Settings saved');
};
const setField = (k, v) =>
setS(prev => ({
...prev,
[k]: v
}));
return (
Settings
International Shipping Uplift
Percentage added to base PKR price for each region.
{Object.entries(s.shippingUplift || {}).map(([k, v]) => (
))}
);
}
/* ==== ROUTER ==== */
function AdminRouter({ subroute }){
const [session, setSession] = aS(null);
const [checking, setChecking] = aS(true);
aE(()=>{
(async () => {
try {
const raw = sessionStorage.getItem(ADMIN_KEY);
if (!raw) { setChecking(false); return; }
const stored = JSON.parse(raw);
// Verify token is still valid against the server
const r = await fetch('/api/inquiries.php', { headers: { 'Authorization': `Bearer ${stored.token}` } });
if (r.ok) setSession(stored);
else sessionStorage.removeItem(ADMIN_KEY);
} catch(e){ sessionStorage.removeItem(ADMIN_KEY); }
setChecking(false);
})();
},[]);
if (checking) return
;
const logout = () => {
try { sessionStorage.removeItem(ADMIN_KEY); } catch(e){}
setSession(null);
window.location.href = '/kr/pk/admin/moon';
};
if (!session) return
;
return ;
}
window.AdminRouter = AdminRouter;