Files
cs249r_book/tinytorch/site/extra/community/app.js
2026-02-27 17:06:38 -05:00

184 lines
7.0 KiB
JavaScript

import { injectStyles } from './modules/styles.js';
import { renderLayout, updateNavState } from './modules/ui.js';
import { getSession } from './modules/state.js';
import { openModal, closeModal, handleToggle, handleAuth, handleLogout, setMode, verifySession, signInWithSocial, supabase } from './modules/auth.js';
import { openProfileModal, closeProfileModal, handleProfileUpdate, geocodeAndSetCoordinates, checkAndAutoUpdateLocation, setupProfileDeleteEvents } from './modules/profile.js';
import { setupCameraEvents } from './modules/camera.js';
import { getBasePath } from './modules/config.js';
(function() {
// 1. Inject CSS
injectStyles();
// 2. Render Layout
renderLayout();
// 2.5 Attach Social Login Listeners
const btnGoogle = document.getElementById('btn-login-google');
const btnGithub = document.getElementById('btn-login-github');
if (btnGoogle) {
btnGoogle.addEventListener('click', (e) => {
e.preventDefault();
signInWithSocial('google');
closeModal();
});
}
if (btnGithub) {
btnGithub.addEventListener('click', (e) => {
e.preventDefault();
signInWithSocial('github');
closeModal();
});
}
// Initialize profile events
setupProfileDeleteEvents();
supabase.auth.getSession().then(({ data: { session } }) => {
if (session) {
localStorage.setItem("tinytorch_token", session.access_token);
if (session.refresh_token) localStorage.setItem("tinytorch_refresh_token", session.refresh_token);
if (session.user) localStorage.setItem("tinytorch_user", JSON.stringify(session.user));
// Clean URL of tokens/code (Supabase puts tokens in hash or code in query)
if ((window.location.hash && window.location.hash.includes('access_token')) ||
(window.location.search && window.location.search.includes('code='))) {
// Remove sensitive parameters while preserving non-sensitive ones
const url = new URL(window.location);
url.hash = '';
url.searchParams.delete('code');
url.searchParams.delete('type');
window.history.replaceState({}, document.title, url.toString());
}
updateNavState();
}
// 3. Verify Session (Async)
verifySession();
// 3.5 Check and Auto-update Location (Async, non-blocking)
checkAndAutoUpdateLocation();
});
// 2.7 Listen for Auth Changes (Fixes OAuth redirect lag)
supabase.auth.onAuthStateChange((event, session) => {
if (event === 'SIGNED_IN' && session) {
localStorage.setItem("tinytorch_token", session.access_token);
if (session.refresh_token) localStorage.setItem("tinytorch_refresh_token", session.refresh_token);
if (session.user) localStorage.setItem("tinytorch_user", JSON.stringify(session.user));
updateNavState();
} else if (event === 'SIGNED_OUT') {
localStorage.removeItem("tinytorch_token");
updateNavState();
}
});
// 4. Add Event Listeners
const menuBtn = document.getElementById('menuBtn');
const sidebar = document.getElementById('sidebar');
const authBtn = document.getElementById('authBtn');
const authOverlay = document.getElementById('authOverlay');
const authClose = document.getElementById('authClose');
const authForm = document.getElementById('authForm');
const authToggle = document.getElementById('authToggle');
const forgotLink = document.getElementById('authForgotLink');
// Profile Modal Elements
const profileOverlay = document.getElementById('profileOverlay');
const profileClose = document.getElementById('profileClose');
const profileForm = document.getElementById('profileForm');
const profileLogoutBtn = document.getElementById('profileLogoutBtn');
// Camera & Image Logic
setupCameraEvents();
// Wire up events
if (menuBtn && sidebar) {
document.addEventListener('click', (e) => {
if (sidebar.classList.contains('active') &&
!sidebar.contains(e.target) &&
!menuBtn.contains(e.target)) {
menuBtn.classList.remove('active');
sidebar.classList.remove('active');
}
});
menuBtn.addEventListener('click', (e) => {
e.stopPropagation();
menuBtn.classList.toggle('active');
sidebar.classList.toggle('active');
});
}
if (authBtn) {
authBtn.addEventListener('click', (e) => {
e.preventDefault();
const { isLoggedIn } = getSession();
if (isLoggedIn) {
openProfileModal();
} else {
openModal();
}
});
}
if (authClose) authClose.addEventListener('click', closeModal);
if (authOverlay) {
// authOverlay.addEventListener('click', (e) => {
// if (e.target === authOverlay) closeModal();
// });
}
if (authToggle) authToggle.addEventListener('click', handleToggle);
if (forgotLink) forgotLink.addEventListener('click', () => setMode('forgot'));
if (authForm) authForm.addEventListener('submit', handleAuth);
// Profile Modal Events
if (profileClose) profileClose.addEventListener('click', closeProfileModal);
if (profileOverlay) {
// profileOverlay.addEventListener('click', (e) => {
// if (e.target === profileOverlay) closeProfileModal();
// });
}
if (profileLogoutBtn) profileLogoutBtn.addEventListener('click', handleLogout);
if (profileForm) profileForm.addEventListener('submit', handleProfileUpdate);
// Add blur event listener for geocoding the location
const profileLocationInput = document.getElementById('profileLocation');
if (profileLocationInput) {
profileLocationInput.addEventListener('blur', () => {
geocodeAndSetCoordinates(profileLocationInput.value);
});
}
// Check for redirect action
const params = new URLSearchParams(window.location.search);
const action = params.get('action');
if (action === 'login') {
const { isLoggedIn } = getSession();
if (!isLoggedIn) {
localStorage.removeItem("tinytorch_token");
localStorage.removeItem("tinytorch_refresh_token");
localStorage.removeItem("tinytorch_user");
updateNavState();
}
openModal('login');
} else if (action === 'profile') {
const { isLoggedIn } = getSession();
if (isLoggedIn) {
openProfileModal();
} else {
openModal('login');
}
} else if (action === 'join') {
const { isLoggedIn } = getSession();
if (!isLoggedIn) {
openModal('signup');
}
} else if (params.get('community')) {
window.location.href = getBasePath() + '/community.html';
return;
}
})();