// screens-me.jsx — member account: credits, packs, history, stats, settings const { fmtIDR, findClass, findCoach, findFriend, minutesUntil, DAYS_SHORT } = window.NADI_HELPERS; function MeScreen({ user, setUser, setTab, openCheckout, onSignOut, openSettings, showToast, enterAdmin, upcomingBookings }) { const getAppToday = window.NADI_HELPERS.getAppToday; const parseLocalDate = window.NADI_HELPERS.parseLocalDate; const total = (user.creditPacks || []).reduce((s, p) => s + p.credits, 0); // Parse local date time for sorting const parseLocalDateTime = (dateStr, timeStr) => { if (!dateStr || !timeStr) return null; const [year, month, day] = dateStr.split('-').map(Number); const [hours, minutes] = timeStr.split(':').map(Number); return new Date(year, month - 1, day, hours, minutes); }; const upcoming = (upcomingBookings || []) .map(b => { const s = window.NADI.SCHEDULE.find(x => x.id === b.session_id); if (!s) return null; return { ...s, bookingId: b.id, date: b.date, }; }) .filter(Boolean) .filter(s => { const d = parseLocalDateTime(s.date, s.time); return d && d >= getAppToday(); }) .sort((a, b) => parseLocalDateTime(a.date, a.time) - parseLocalDateTime(b.date, b.time)); return (
{/* Hero */}
my account

{user.visibleByDefault ? user.name.split(" ")[0] : "Anonymous"}

member since {user.joined.toLowerCase()}
{/* Default privacy toggle — applies to every new booking */}
default for new bookings
{user.visibleByDefault ? "Visible to your circle" : "Going anonymously"}
{user.visibleByDefault ? "friends see you in class lists" : "you appear as +1 anon"} · override per class
{ if (!setUser) return; setUser({ ...user, visibleByDefault: !v }); showToast && showToast(v ? "Going incognito by default." : "Visible to your friends."); }} />
{/* Credits big card */}
credits remaining
{total} credit{total === 1 ? "" : "s"}
{/* Stats row */}
h.date && (h.date.includes(new Date().toLocaleDateString("en-US", { month: "short" })) || h.date.includes("May") || h.date.includes("may"))).length} suffix="visits" />
{/* Activity sparkline */}
activity · last 6 months
{/* Active packs */}
active packs
{(user.creditPacks || []) .slice().sort((a, b) => new Date(a.expires) - new Date(b.expires)) .map((p, i) => { const getStartOfDay = (dateObj) => new Date(dateObj.getFullYear(), dateObj.getMonth(), dateObj.getDate()); const expiryDate = parseLocalDate(p.expires); const todayDate = getStartOfDay(getAppToday()); const daysLeft = Math.max(0, Math.round((expiryDate - todayDate) / 86400000)); const pct = Math.round((p.credits / p.total) * 100); const urgent = daysLeft <= 10; return (
{i === 0 ? "spending next" : "queued"} {daysLeft} days left

{p.packageName}

{p.credits} of {p.total} credits {pct}%
); })}
{/* Upcoming + History tabs */}
your classes
{upcoming.length > 0 && ( <>
upcoming tap to change privacy
{upcoming.map((s) => )}
)} history {(user.history || []).map((h) => )}
{enterAdmin && (
)}
); } function StatCell({ label, value, suffix, accent }) { return (
{label}
{value}
{suffix}
); } function ActivityBars({ monthly }) { const max = Math.max(1, ...monthly.map((x) => x.n)); return (
{monthly.map((row, i) => { const h = Math.round((row.n / max) * 100); const isLast = i === monthly.length - 1; return (
{row.n}
); })}
{monthly.map((row) => {row.m.toLowerCase()})}
); } function ClassRow({ s, upcoming, user, setUser, showToast }) { const c = findClass(s.classId), co = findCoach(s.coachId); const privacy = (user && user.bookingPrivacy && user.bookingPrivacy[s.id]) || (user && user.visibleByDefault ? "self" : "anon"); const isAnon = privacy === "anon"; const flipPrivacy = (e) => { e && e.stopPropagation(); if (!user || !setUser) return; const next = isAnon ? "self" : "anon"; setUser({ ...user, bookingPrivacy: { ...(user.bookingPrivacy || {}), [s.id]: next }, }); showToast && showToast(next === "anon" ? "Going anonymously." : "Visible to your circle."); }; const dateStr = s.date ? window.NADI_HELPERS.parseLocalDate(s.date).toLocaleDateString("en-GB", { weekday: "short", day: "2-digit", month: "short" }).toLowerCase() : DAYS_SHORT[s.day].toLowerCase(); return (
{s.time}
{dateStr}
{c.name}
{co.firstName.toLowerCase()} · {s.roomShort.toLowerCase()}
{upcoming ? ( ) : null}
); } function HistoryRow({ h }) { const c = findClass(h.classId), co = findCoach(h.coachId); return (
{c.name}
{co.firstName.toLowerCase()} · {h.roomShort.toLowerCase()}
{h.date.toLowerCase()}
); } Object.assign(window, { MeScreen });