// auth.jsx — session hook + Login/Register modals for saraslot. // Loaded after supabase-client.jsx, before data.jsx and pages.jsx. const { useState: useStateAu, useEffect: useEffectAu, useCallback: useCallbackAu, createContext: createContextAu, useContext: useContextAu } = React; const SessionContext = createContextAu({ session: null, ready: false, refresh: () => {} }); function SessionProvider({ children }) { const [session, setSession] = useStateAu(null); const [ready, setReady] = useStateAu(false); useEffectAu(() => { let mounted = true; window.sb.auth.getSession().then(({ data }) => { if (!mounted) return; setSession(data.session || null); setReady(true); }); const { data: sub } = window.sb.auth.onAuthStateChange((_event, sess) => { setSession(sess || null); }); return () => { mounted = false; sub?.subscription?.unsubscribe?.(); }; }, []); const refresh = useCallbackAu(async () => { const { data } = await window.sb.auth.getSession(); setSession(data.session || null); }, []); return {children}; } window.SessionProvider = SessionProvider; function useSession() { return useContextAu(SessionContext); } window.useSession = useSession; async function signOut() { await window.sb.auth.signOut(); } window.signOut = signOut; /* ───────────────────────────────────────────────────────────── Auth modal shell ──────────────────────────────────────────────────────────── */ function AuthModal({ open, onClose, children, title }) { if (!open) return null; return (
e.stopPropagation()}>
{title}
{children}
); } function PhoneField({ value, onChange }) { return ( ); } function PasswordField({ value, onChange, label = "Kata Laluan", autoComplete = "current-password" }) { return ( ); } /* ───────────────────────────────────────────────────────────── LoginModal — phone + password ──────────────────────────────────────────────────────────── */ function LoginModal({ open, onClose, onSwitchToRegister }) { const [phone, setPhone] = useStateAu(""); const [password, setPassword] = useStateAu(""); const [error, setError] = useStateAu(""); const [busy, setBusy] = useStateAu(false); const submit = async (e) => { e.preventDefault(); setError(""); setBusy(true); const email = window.phoneToEmail(phone); const { error: err } = await window.sb.auth.signInWithPassword({ email, password }); setBusy(false); if (err) { setError("Phone or password incorrect."); return; } setPhone(""); setPassword(""); onClose(); }; return (
{error &&
{error}
}
Belum Ada Akaun?
); } window.LoginModal = LoginModal; /* ───────────────────────────────────────────────────────────── RegisterModal — phone + username + password ──────────────────────────────────────────────────────────── */ function RegisterModal({ open, onClose, onSwitchToLogin }) { const [phone, setPhone] = useStateAu(""); const [username, setUsername] = useStateAu(""); const [password, setPassword] = useStateAu(""); const [error, setError] = useStateAu(""); const [busy, setBusy] = useStateAu(false); const submit = async (e) => { e.preventDefault(); setError(""); const digits = String(phone).replace(/\D+/g, ""); if (digits.length < 7) { setError("Enter a valid phone number."); return; } if (!username.trim()) { setError("Pick a username."); return; } setBusy(true); const email = window.phoneToEmail(phone); const { data, error: err } = await window.sb.auth.signUp({ email, password, options: { data: { phone: digits, username: username.trim() } }, }); if (err) { setBusy(false); setError(err.message || "Could not register. Phone may already be in use."); return; } // The handle_new_user trigger inserted a profiles row using new.phone (null for // email signup) or new.id::text fallback. Update the row with the real phone + // username now that the session is live. try { await window.sb.from("profiles").update({ phone: digits, username: username.trim(), }).eq("id", data.user.id); } catch (_) { /* ignore — trigger should have created the row */ } setBusy(false); setPhone(""); setUsername(""); setPassword(""); onClose(); }; return (
{error &&
{error}
}
Sudah Ada Akaun?
); } window.RegisterModal = RegisterModal; /* ───────────────────────────────────────────────────────────── AuthGate — used by pages that require a session ──────────────────────────────────────────────────────────── */ function AuthGate({ children, fallback }) { const { session, ready } = useSession(); if (!ready) return
Loading…
; if (!session) return fallback ||
Please log in to view this page.
; return children; } window.AuthGate = AuthGate;