added login screen

This commit is contained in:
michael 2025-09-09 09:38:04 -05:00
parent d889086fb4
commit 2c0f32d35f
4 changed files with 176 additions and 81 deletions

View file

@ -388,3 +388,43 @@ button#login-btn:hover {
.text-white {
color: #ffffff !important;
}
/* Login Screen Styles */
#login-screen-container {
background: inherit;
transition: opacity 0.3s ease-in-out;
}
#login-screen-container h1 {
text-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* Main App Container Styles */
#main-app-container {
opacity: 1;
transition: opacity 0.3s ease-in-out;
width: 100%;
}
#main-app-container.hidden {
opacity: 0;
pointer-events: none;
}
/* Loading States */
#login-loading {
transition: opacity 0.3s ease-in-out;
}
/* Dark Mode for Login Screen */
.dark-mode #login-screen-container {
color: #f5f5f5;
}
.dark-mode #login-screen-container h1 {
color: var(--primary-text-color) !important;
}
.dark-mode #login-loading p {
color: #d1d5db !important;
}

View file

@ -631,6 +631,10 @@ video {
margin-bottom: 1.5rem;
}
.mb-8 {
margin-bottom: 2rem;
}
.ml-2 {
margin-left: 0.5rem;
}
@ -980,6 +984,11 @@ video {
padding-right: 1.5rem;
}
.px-8 {
padding-left: 2rem;
padding-right: 2rem;
}
.py-2 {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
@ -1017,6 +1026,11 @@ video {
line-height: 2.25rem;
}
.text-4xl {
font-size: 2.25rem;
line-height: 2.5rem;
}
.text-lg {
font-size: 1.125rem;
line-height: 1.75rem;
@ -1049,11 +1063,6 @@ video {
font-weight: 600;
}
.text-blue-600 {
--tw-text-opacity: 1;
color: rgb(37 99 235 / var(--tw-text-opacity, 1));
}
.text-gray-500 {
--tw-text-opacity: 1;
color: rgb(107 114 128 / var(--tw-text-opacity, 1));
@ -1123,6 +1132,12 @@ video {
opacity: 0.6;
}
.shadow-lg {
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.shadow-md {
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
@ -1616,10 +1631,6 @@ body.dark-mode.bg-gray-100 {
background-color: rgb(185 28 28 / var(--tw-bg-opacity, 1));
}
.hover\:underline:hover {
text-decoration-line: underline;
}
.focus\:border-orange-500:focus {
--tw-border-opacity: 1;
border-color: rgb(252 151 41 / var(--tw-border-opacity, 1));
@ -1705,6 +1716,11 @@ body.dark-mode.bg-gray-100 {
line-height: 2.5rem;
}
.md\:text-6xl {
font-size: 3.75rem;
line-height: 1;
}
.md\:text-base {
font-size: 1rem;
line-height: 1.5rem;

View file

@ -28,26 +28,41 @@
</span>
</button>
<!-- Authentication Section -->
<div id="auth-section" class="mb-4 text-center">
<button id="login-btn" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg shadow-md transition duration-150 ease-in-out hidden" style="background-color: #2563eb !important; color: #ffffff !important;">
Sign In with Microsoft
</button>
<button id="logout-btn" class="bg-red-600 hover:bg-red-700 text-white px-6 py-2 rounded-lg shadow-md transition duration-150 ease-in-out hidden" style="background-color: #dc2626 !important; color: #ffffff !important;">
Sign Out
</button>
<div id="user-info" class="mt-2 text-sm font-medium"></div>
<!-- Login Screen Container -->
<div id="login-screen-container" class="min-h-screen flex flex-col items-center justify-center">
<div class="text-center">
<h1 class="text-4xl md:text-6xl font-bold text-orange-600 mb-8">
Runway Gen4
</h1>
<button id="login-btn" class="bg-blue-600 hover:bg-blue-700 text-white px-8 py-3 rounded-lg shadow-lg text-lg font-medium transition duration-150 ease-in-out" style="background-color: #2563eb !important; color: #ffffff !important;">
Sign In with Microsoft
</button>
<div id="login-loading" class="mt-4 hidden">
<i class="fas fa-spinner fa-spin fa-2x text-orange-600"></i>
<p class="text-sm text-gray-600 mt-2">Signing in...</p>
</div>
</div>
</div>
<!-- Header -->
<header class="w-full py-6 bg-gray-50 shadow-sm rounded-b-lg">
<h1 class="text-3xl md:text-4xl font-bold text-orange-600 text-center px-4">
Runway Gen4 Web App
</h1>
</header>
<!-- Main App Container (hidden by default) -->
<div id="main-app-container" class="hidden">
<!-- Authentication Section -->
<div id="auth-section" class="mb-4 text-center">
<button id="logout-btn" class="bg-red-600 hover:bg-red-700 text-white px-6 py-2 rounded-lg shadow-md transition duration-150 ease-in-out" style="background-color: #dc2626 !important; color: #ffffff !important;">
Sign Out
</button>
<div id="user-info" class="mt-2 text-sm font-medium"></div>
</div>
<!-- Main Content Area -->
<main class="w-full max-w-4xl lg:max-w-6xl mx-auto p-4 md:p-8 flex flex-col gap-6 md:gap-8 mt-8">
<!-- Header -->
<header class="w-full py-6 bg-gray-50 shadow-sm rounded-b-lg">
<h1 class="text-3xl md:text-4xl font-bold text-orange-600 text-center px-4">
Runway Gen4 Web App
</h1>
</header>
<!-- Main Content Area -->
<main class="w-full max-w-4xl lg:max-w-6xl mx-auto p-4 md:p-8 flex flex-col gap-6 md:gap-8 mt-8">
<!-- Input Form Section (always visible) -->
<div id="input-form-section" class="w-full">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 md:gap-8">
@ -139,14 +154,15 @@
</button>
</div>
</div>
</main>
</main>
<!-- Loading Overlay -->
<div id="loading-overlay" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center z-50 hidden" role="status" aria-live="polite">
<div class="flex flex-col items-center text-white">
<i class="fas fa-spinner fa-spin fa-3x mb-4"></i>
<p class="text-xl md:text-2xl font-semibold">Generating your video...</p>
<p class="text-sm md:text-base mt-2">This may take a moment.</p>
<!-- Loading Overlay -->
<div id="loading-overlay" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center z-50 hidden" role="status" aria-live="polite">
<div class="flex flex-col items-center text-white">
<i class="fas fa-spinner fa-spin fa-3x mb-4"></i>
<p class="text-xl md:text-2xl font-semibold">Generating your video...</p>
<p class="text-sm md:text-base mt-2">This may take a moment.</p>
</div>
</div>
</div>

View file

@ -9,21 +9,8 @@ let selectedImageFile = null;
// Initialize MSAL or check for existing auth
async function initializeMSAL() {
try {
// First, check if we have auth state from landing page
const storedToken = localStorage.getItem('runway_access_token');
const storedAuthState = localStorage.getItem('runway_auth_state');
if (storedToken && storedAuthState) {
const tokenData = JSON.parse(storedToken);
const authState = JSON.parse(storedAuthState);
// Check if token is still valid (not expired)
if (Date.now() < tokenData.expires_at) {
currentUser = tokenData.user;
updateAuthUI();
return; // Skip MSAL initialization if we have valid token
}
}
// Always start by showing the login screen
showLoginScreen();
// Initialize MSAL for this page
const configResponse = await fetch('backend/config_client.php');
@ -62,16 +49,13 @@ async function initializeMSAL() {
// Clean up the URL (remove auth parameters)
window.history.replaceState({}, document.title, window.location.pathname);
} else {
// Check if user was already authenticated
const accounts = msalInstance.getAllAccounts();
if (accounts.length > 0) {
currentUser = accounts[0];
msalInstance.setActiveAccount(currentUser);
}
// Show main app since user just authenticated
updateAuthUI();
return;
}
updateAuthUI();
// Don't automatically log in - always show login screen first
currentUser = null;
} catch (error) {
console.error('MSAL initialization failed:', error);
showAuthError();
@ -80,6 +64,9 @@ async function initializeMSAL() {
// Sign In function
async function signIn() {
// Show loading state immediately
showLoginLoading();
if (!msalInstance) {
// If MSAL not initialized, redirect to portal for authentication
window.location.href = 'http://localhost:3000/';
@ -104,14 +91,21 @@ async function signIn() {
};
localStorage.setItem('runway_access_token', JSON.stringify(tokenData));
// Hide loading state and update UI
hideLoginLoading();
updateAuthUI();
} catch (error) {
console.error("Login failed:", error);
showErrorMessage(generalErrorMessage, "Login failed: " + error.message);
hideLoginLoading();
// Could show error message on login screen if needed
const generalErrorMessage = document.getElementById('general-error-message');
if (generalErrorMessage) {
showErrorMessage(generalErrorMessage, "Login failed: " + error.message);
}
}
}
// Sign Out function - redirect to portal
// Sign Out function - return to login screen
async function signOut() {
// Clear any stored tokens
localStorage.removeItem('runway_access_token');
@ -120,43 +114,72 @@ async function signOut() {
// Clear current user state
currentUser = null;
// If MSAL is initialized, logout from Microsoft
// If MSAL is initialized, logout from Microsoft silently
if (msalInstance && msalInstance.getAllAccounts().length > 0) {
await msalInstance.logoutRedirect({
postLogoutRedirectUri: 'https://ai-sandbox.oliver.solutions/runway-video/'
});
} else {
// If no MSAL session, just redirect
window.location.href = 'https://ai-sandbox.oliver.solutions/runway-video/';
try {
await msalInstance.logoutSilent();
} catch (error) {
console.log('Silent logout failed, continuing with local logout');
}
}
// Update UI immediately
// Update UI to show login screen
updateAuthUI();
}
// Show Login Screen
function showLoginScreen() {
const loginScreen = document.getElementById('login-screen-container');
const mainApp = document.getElementById('main-app-container');
const loginLoading = document.getElementById('login-loading');
if (loginScreen) loginScreen.classList.remove('hidden');
if (mainApp) mainApp.classList.add('hidden');
if (loginLoading) loginLoading.classList.add('hidden');
}
// Show Main App
function showMainApp() {
const loginScreen = document.getElementById('login-screen-container');
const mainApp = document.getElementById('main-app-container');
if (loginScreen) loginScreen.classList.add('hidden');
if (mainApp) mainApp.classList.remove('hidden');
}
// Show Login Loading State
function showLoginLoading() {
const loginLoading = document.getElementById('login-loading');
const loginBtn = document.getElementById('login-btn');
if (loginBtn) loginBtn.classList.add('hidden');
if (loginLoading) loginLoading.classList.remove('hidden');
}
// Hide Login Loading State
function hideLoginLoading() {
const loginLoading = document.getElementById('login-loading');
const loginBtn = document.getElementById('login-btn');
if (loginLoading) loginLoading.classList.add('hidden');
if (loginBtn) loginBtn.classList.remove('hidden');
}
// Update Authentication UI
function updateAuthUI() {
const loginBtn = document.getElementById('login-btn');
const logoutBtn = document.getElementById('logout-btn');
const userInfo = document.getElementById('user-info');
if (currentUser) {
if (loginBtn) loginBtn.classList.add('hidden');
if (logoutBtn) logoutBtn.classList.remove('hidden');
// User is authenticated - show main app
showMainApp();
if (userInfo) {
userInfo.textContent = `Welcome, ${currentUser.name || currentUser.username}`;
userInfo.classList.remove('text-red-600');
userInfo.classList.add('text-green-600');
}
} else {
// Show sign in option without auto-redirect
if (loginBtn) loginBtn.classList.remove('hidden');
if (logoutBtn) logoutBtn.classList.add('hidden');
if (userInfo) {
userInfo.innerHTML = 'Please sign in to generate videos | <a href="http://localhost:3000/" class="text-blue-600 hover:underline">← Back to Portal</a>';
userInfo.classList.remove('text-green-600');
userInfo.classList.add('text-red-600');
}
// User is not authenticated - show login screen
showLoginScreen();
}
// Update generate button state only if the function exists
@ -167,9 +190,9 @@ function updateAuthUI() {
// Show authentication error
function showAuthError() {
const userInfo = document.getElementById('user-info');
userInfo.innerHTML = 'Authentication initialization failed. <a href="http://localhost:3000/" class="text-blue-600 hover:underline">← Back to Portal</a>';
userInfo.classList.add('text-red-600');
// Show login screen with error state
showLoginScreen();
hideLoginLoading();
}
// Navigate back to portal