1(function () { 2 'use strict'; 3 const form = document.getElementById('portal-login-form'); 4 const message = document.getElementById('portal-login-message'); 5 const submit = form.querySelector('[type="submit"]'); 6 const stagingSdk = 'https://cdn.jsdelivr.net/npm/@supabase/[email protected]/dist/umd/supabase.min.js'; 7 const stagingSdkIntegrity = 'sha384-AkNSQdptcXlJ0/NBZc4qGk86cDVXcCevwoWgEKIpHOEfbvlXGLlIkimQtONt8KNf'; 8 9 const ROUTES = Object.freeze({ 10 admin: { auth: () => window.AvanaStagingAuth, target: 'index.html' }, 11 student: { auth: () => window.AvanaStagingStudentAuth, target: 'student-portal.html' }, 12 teacher: { auth: () => window.AvanaStagingTeacherAuth, target: 'teacher-portal.html' }, 13 family: { auth: () => window.AvanaStagingFamilyAuth, target: 'family-portal.html' } 14 }); 15 16 function setBusy(busy) { 17 submit.disabled = busy; 18 form.elements.email.disabled = busy; 19 form.elements.password.disabled = busy; 20 } 21 22 function showMessage(text) { message.textContent = text; } 23 24 function ensureSupabaseSdk() { 25 if (window.supabase?.createClient) return Promise.resolve(); 26 return new Promise((resolve, reject) => { 27 const script = document.createElement('script'); 28 script.src = stagingSdk; 29 script.crossOrigin = 'anonymous'; 30 script.integrity = stagingSdkIntegrity; 31 script.onload = () => window.supabase?.createClient ? resolve() : reject(new Error('Sign-in is temporarily unavailable.')); 32 script.onerror = () => reject(new Error('Sign-in is temporarily unavailable.')); 33 document.head.appendChild(script); 34 }); 35 } 36 37 // A single sign-in against a non-persistent client is used only to look up the 38 // signed-in user's role. The actual, persisted session (in the correct role's own 39 // storage slot) is then established by handing off to that role's own, already 40 // fully-tested signIn(), rather than inventing a fourth storage key or reaching into 41 // any of the three staging auth modules' internals. 42 async function detectRole(email, password) { 43 const config = AvanaConfig.configure({ dataSource: 'staging', explicitStaging: true }); 44 const client = AvanaSupabase.createClient(config, (...args) => window.supabase.createClient(...args)); 45 const signInResult = await client.auth.signInWithPassword({ email, password }); 46 if (signInResult.error || !signInResult.data?.user) return { ok: false }; 47 const profileResult = await client.from('profiles').select('role,account_active').eq('id', signInResult.data.user.id).limit(2); 48 const profiles = profileResult.data || []; 49 if (profileResult.error || profiles.length !== 1) return { ok: false }; 50 const profile = profiles[0]; 51 if (profile.account_active !== true) return { ok: false }; 52 return { ok: true, role: profile.role }; 53 } 54 55 async function continueExistingSession() { 56 setBusy(true); 57 try { 58 // Only a role whose own session flag is already set gets a client created at all -- 59 // on a normal fresh visit (the common case) this creates none, avoiding three 60 // simultaneous Supabase client instances for no reason. 61 const candidates = Object.keys(ROUTES).filter(key => ROUTES[key].auth().isStagingRequested()); 62 if (candidates.length) { 63 await ensureSupabaseSdk(); 64 for (const key of candidates) { 65 const route = ROUTES[key]; 66 const result = await route.auth().resume(); 67 if (result.ok) { location.replace(route.target); return; } 68 } 69 } 70 } catch (_error) { /* fall through to the sign-in form */ } 71 setBusy(false); 72 } 73 74 form.addEventListener('submit', async event => { 75 event.preventDefault(); 76 setBusy(true); 77 showMessage('Signing inâ¦'); 78 const email = form.elements.email.value.trim(); 79 const password = form.elements.password.value; 80 form.elements.password.value = ''; 81 try { 82 await ensureSupabaseSdk(); 83 const detection = await detectRole(email, password); 84 const route = detection.ok ? ROUTES[detection.role] : null; 85 if (!route) { 86 showMessage('Sign-in was not authorized.'); 87 setBusy(false); 88 return; 89 } 90 const result = await route.auth().signIn(email, password); 91 if (!result.ok) { 92 showMessage(result.reason === 'unavailable' ? 'Sign-in is temporarily unavailable.' : 'Sign-in was not authorized.'); 93 setBusy(false); 94 return; 95 } 96 location.replace(route.target); 97 } catch (_error) { 98 showMessage('Sign-in is temporarily unavailable.'); 99 setBusy(false); 100 } 101 }); 102 103 continueExistingSession(); 104})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.