Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Multi Agent Research</title> | |
<script src="https://unpkg.com/@supabase/supabase-js@2"></script> | |
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> | |
<style> | |
html, body { | |
height: 100%; | |
margin: 0; | |
padding: 0; | |
overflow: hidden; | |
font-family: 'Roboto', sans-serif; | |
} | |
#app { | |
height: 100%; | |
display: flex; | |
flex-direction: column; | |
} | |
.content-wrapper { | |
flex-grow: 1; | |
position: relative; | |
overflow: hidden; | |
} | |
iframe { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
border: none; | |
} | |
.sidebar { | |
position: fixed; | |
left: 0; | |
top: 0; | |
bottom: 0; | |
width: 250px; | |
background-color: #2c3e50; | |
color: white; | |
display: flex; | |
flex-direction: column; | |
transition: transform 0.3s ease-in-out; | |
transform: translateX(-100%); | |
overflow-y: auto; | |
padding-top: 60px; | |
z-index: 1000; | |
} | |
.sidebar.open { | |
transform: translateX(0); | |
} | |
.sidebar button { | |
width: 80%; | |
margin: 10px auto; | |
padding: 15px; | |
background-color: #3498db; | |
color: white; | |
border: none; | |
border-radius: 10px; | |
font-size: 14px; | |
cursor: pointer; | |
text-align: center; | |
transition: all 0.3s ease; | |
display: block; | |
} | |
.sidebar button:hover { | |
background-color: #2980b9; | |
transform: translateY(-2px); | |
box-shadow: 0 4px 8px rgba(0,0,0,0.2); | |
} | |
.toggle-btn { | |
position: fixed; | |
left: 10px; | |
top: 10px; | |
background-color: #3498db; | |
color: white; | |
border: none; | |
border-radius: 10px; | |
font-size: 16px; | |
cursor: pointer; | |
padding: 7px 15px; | |
z-index: 1001; | |
transition: background-color 0.3s ease; | |
} | |
.toggle-btn:hover { | |
background-color: #2980b9; | |
} | |
.category { | |
width: 100%; | |
margin-bottom: 20px; | |
} | |
.category-title { | |
width: 80%; | |
margin: 10px auto; | |
padding: 10px; | |
background-color: #34495e; | |
color: white; | |
border-radius: 10px; | |
font-size: 16px; | |
text-align: center; | |
cursor: pointer; | |
} | |
.category-content { | |
display: none; | |
width: 100%; | |
} | |
.category-content.show { | |
display: block; | |
} | |
.user-info { | |
width: 80%; | |
margin: 20px auto; | |
text-align: center; | |
} | |
.user-name { | |
margin-bottom: 10px; | |
font-weight: bold; | |
} | |
.logout-btn { | |
background-color: #e74c3c; | |
} | |
.logout-btn:hover { | |
background-color: #c0392b; | |
} | |
@media (max-width: 768px) { | |
.sidebar { | |
width: 100%; | |
} | |
.sidebar button, .category-title, .user-info { | |
width: 90%; | |
} | |
} | |
@media (max-width: 480px) { | |
.sidebar button, .category-title, .user-info { | |
width: 95%; | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<div id="app"> | |
<div v-if="loading">Loading...</div> | |
<div v-else-if="error">{{ error }}</div> | |
<div v-else class="content-wrapper"> | |
<div class="sidebar" :class="{ 'open': sidebarOpen }" id="sidebar"> | |
<div v-for="(apps, category) in appData" :key="category" class="category"> | |
<div class="category-title" @click="toggleCategory">{{ category }}</div> | |
<div class="category-content"> | |
<button v-for="app in apps" :key="app.name" @click="switchToApp(app.url)">{{ app.name }}</button> | |
</div> | |
</div> | |
<div class="user-info"> | |
<div class="user-name">{{ userName }}</div> | |
<button class="logout-btn" @click="handleLogout">Logout</button> | |
</div> | |
</div> | |
<button class="toggle-btn" @click="toggleSidebar">☰</button> | |
<iframe :src="currentPage" id="iframe" allowfullscreen allow="clipboard-read; clipboard-write" sandbox="allow-scripts allow-same-origin allow-popups allow-forms allow-downloads"></iframe> | |
</div> | |
</div> | |
<script> | |
const { createApp } = Vue; | |
const { createClient } = supabase; | |
const supabaseClient = createClient('https://ftqmmutydpjseodidugl.supabase.co', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImZ0cW1tdXR5ZHBqc2VvZGlkdWdsIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTQzMTE2MzQsImV4cCI6MjAyOTg4NzYzNH0.2h1uLIPCKrwF8f9enRChU_Q2qkhoQlR4gwlehL-h0a4'); | |
function setCookie(name, value, days) { | |
const expires = new Date(Date.now() + days * 864e5).toUTCString(); | |
document.cookie = name + '=' + encodeURIComponent(JSON.stringify(value)) + '; expires=' + expires + '; path=/; SameSite=Strict'; | |
console.log(`Cookie set: ${name}`, value); | |
} | |
function getCookie(name) { | |
const value = `; ${document.cookie}`; | |
const parts = value.split(`; ${name}=`); | |
if (parts.length === 2) { | |
const cookieValue = parts.pop().split(';').shift(); | |
const decodedValue = JSON.parse(decodeURIComponent(cookieValue)); | |
console.log(`Cookie retrieved: ${name}`, decodedValue); | |
return decodedValue; | |
} | |
console.log(`Cookie not found: ${name}`); | |
return null; | |
} | |
const app = createApp({ | |
data() { | |
return { | |
appData: {}, | |
currentPage: '', | |
loading: true, | |
error: null, | |
sidebarOpen: false, | |
userName: '' | |
} | |
}, | |
methods: { | |
async checkAuth() { | |
try { | |
console.log("Checking authentication"); | |
const { data: { session }, error } = await supabaseClient.auth.getSession(); | |
if (error) throw error; | |
console.log("Session:", session); | |
return session; | |
} catch (error) { | |
console.error("Not authenticated", error); | |
return null; | |
} | |
}, | |
redirectToLogin() { | |
console.log("Redirecting to login"); | |
window.location.href = '/'; | |
}, | |
async checkAllowlist(email) { | |
try { | |
console.log("Checking allowlist for email:", email); | |
const response = await axios.post('/check-allowlist', { email }); | |
console.log("Received response:", response.data); | |
if (response.data.allowed) { | |
console.log("Access allowed, setting app data"); | |
this.appData = response.data.app_data; | |
this.currentPage = this.currentPage || this.appData["Updated Tools"][0].url; | |
// Store app_data and current page URL in cookies | |
setCookie('app_data', this.appData, 7); // Store for 7 days | |
setCookie('current_page', this.currentPage, 7); | |
console.log("Stored app_data and current_page in cookies", this.appData, this.currentPage); | |
} else { | |
console.log("Access denied"); | |
this.error = `Access Denied: Your email (${email}) is not on the allowlist. Server message: ${response.data.message || 'No additional information provided.'}`; | |
} | |
} catch (error) { | |
console.error("Error checking allowlist:", error); | |
let errorMessage = 'An error occurred while checking access.'; | |
if (error.response) { | |
// The request was made and the server responded with a status code | |
// that falls out of the range of 2xx | |
errorMessage += ` Server responded with status ${error.response.status}.`; | |
if (error.response.data && error.response.data.message) { | |
errorMessage += ` Message: ${error.response.data.message}`; | |
} | |
} else if (error.request) { | |
// The request was made but no response was received | |
errorMessage += ' No response received from server.'; | |
} else { | |
// Something happened in setting up the request that triggered an Error | |
errorMessage += ` Error message: ${error.message}`; | |
} | |
this.error = `Error for email (${email}): ${errorMessage}`; | |
} finally { | |
console.log("Setting loading to false"); | |
this.loading = false; | |
} | |
}, | |
toggleSidebar() { | |
this.sidebarOpen = !this.sidebarOpen; | |
}, | |
toggleCategory(event) { | |
const content = event.target.nextElementSibling; | |
content.classList.toggle('show'); | |
}, | |
switchToApp(url) { | |
console.log("Switching to app:", url); | |
this.currentPage = url; | |
setCookie('current_page', url, 7); | |
this.toggleSidebar(); | |
}, | |
async handleLogout() { | |
const loadingElement = document.createElement('div'); | |
loadingElement.textContent = 'Logging out...'; | |
document.body.appendChild(loadingElement); | |
try { | |
const { error } = await supabaseClient.auth.signOut(); | |
if (error) throw error; | |
// Clear cookies | |
document.cookie = 'app_data=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=Strict'; | |
document.cookie = 'current_page=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=Strict'; | |
console.log("Cookies cleared"); | |
localStorage.clear(); | |
this.redirectToLogin(); | |
} catch (error) { | |
console.error("Logout failed:", error); | |
alert("Logout failed. Please try again."); | |
} finally { | |
document.body.removeChild(loadingElement); | |
} | |
}, | |
async fetchProfileInfo() { | |
try { | |
const { data: { user }, error } = await supabaseClient.auth.getUser(); | |
if (error) throw error; | |
this.userName = user.user_metadata.full_name || user.email || 'User'; | |
await this.checkAllowlist(user.email); | |
} catch (error) { | |
console.error("Error fetching profile info:", error); | |
this.error = 'Error loading profile information.'; | |
} | |
} | |
}, | |
async mounted() { | |
console.log("Component mounted"); | |
const storedAppData = getCookie('app_data'); | |
const storedCurrentPage = getCookie('current_page'); | |
if (storedAppData && storedCurrentPage) { | |
console.log("Found stored data in cookies"); | |
this.appData = storedAppData; | |
this.currentPage = storedCurrentPage; | |
this.loading = false; | |
console.log("Set app data and current page from cookies:", this.appData, this.currentPage); | |
} else { | |
console.log("No stored data found in cookies"); | |
const session = await this.checkAuth(); | |
if (!session) { | |
this.redirectToLogin(); | |
} else { | |
await this.fetchProfileInfo(); | |
} | |
} | |
} | |
}); | |
app.mount('#app'); | |
</script> | |
</body> | |
</html> | |