Files
orion/static/admin/login.html

164 lines
8.1 KiB
HTML

<!DOCTYPE html>
<html :class="{ 'theme-dark': dark }" x-data="loginData()" lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Admin Login - Multi-Tenant Platform</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/static/admin/css/tailwind.output.css" />
<style>
[x-cloak] { display: none !important; }
</style>
</head>
<body>
<div class="flex items-center min-h-screen p-6 bg-gray-50 dark:bg-gray-900" x-cloak>
<div class="flex-1 h-full max-w-4xl mx-auto overflow-hidden bg-white rounded-lg shadow-xl dark:bg-gray-800">
<div class="flex flex-col overflow-y-auto md:flex-row">
<div class="h-32 md:h-auto md:w-1/2">
<img aria-hidden="true" class="object-cover w-full h-full dark:hidden"
src="/static/admin/img/login-office.jpeg" alt="Office" />
<img aria-hidden="true" class="hidden object-cover w-full h-full dark:block"
src="/static/admin/img/login-office-dark.jpeg" alt="Office" />
</div>
<div class="flex items-center justify-center p-6 sm:p-12 md:w-1/2">
<div class="w-full">
<h1 class="mb-4 text-xl font-semibold text-gray-700 dark:text-gray-200">
Admin Login
</h1>
<!-- Alert Messages -->
<div x-show="error" x-text="error"
class="px-4 py-3 mb-4 text-sm text-red-700 bg-red-100 rounded-lg dark:bg-red-200 dark:text-red-800"
x-transition></div>
<div x-show="success" x-text="success"
class="px-4 py-3 mb-4 text-sm text-green-700 bg-green-100 rounded-lg dark:bg-green-200 dark:text-green-800"
x-transition></div>
<!-- Login Form -->
<form @submit.prevent="handleLogin">
<label class="block text-sm">
<span class="text-gray-700 dark:text-gray-400">Username</span>
<input x-model="credentials.username"
:disabled="loading"
@input="clearErrors"
class="block w-full mt-1 text-sm dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:text-gray-300 dark:focus:shadow-outline-gray form-input"
:class="{ 'border-red-600': errors.username }"
placeholder="Enter your username"
required />
<span x-show="errors.username" x-text="errors.username"
class="text-xs text-red-600 dark:text-red-400"></span>
</label>
<label class="block mt-4 text-sm">
<span class="text-gray-700 dark:text-gray-400">Password</span>
<input x-model="credentials.password"
:disabled="loading"
@input="clearErrors"
class="block w-full mt-1 text-sm dark:border-gray-600 dark:bg-gray-700 focus:border-purple-400 focus:outline-none focus:shadow-outline-purple dark:text-gray-300 dark:focus:shadow-outline-gray form-input"
:class="{ 'border-red-600': errors.password }"
placeholder="***************"
type="password"
required />
<span x-show="errors.password" x-text="errors.password"
class="text-xs text-red-600 dark:text-red-400"></span>
</label>
<button type="submit" :disabled="loading"
class="block w-full px-4 py-2 mt-4 text-sm font-medium leading-5 text-center text-white transition-colors duration-150 bg-purple-600 border border-transparent rounded-lg active:bg-purple-600 hover:bg-purple-700 focus:outline-none focus:shadow-outline-purple disabled:opacity-50 disabled:cursor-not-allowed">
<span x-show="!loading">Log in</span>
<span x-show="loading">
<svg class="inline w-4 h-4 mr-2 animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
Signing in...
</span>
</button>
</form>
<hr class="my-8" />
<p class="mt-4">
<a class="text-sm font-medium text-purple-600 dark:text-purple-400 hover:underline"
href="#">
Forgot your password?
</a>
</p>
</div>
</div>
</div>
</div>
</div>
<!-- Alpine.js v3 -->
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.0/dist/cdn.min.js"></script>
<!-- API Client -->
<script src="/static/shared/js/api-client.js"></script>
<!-- Login Logic -->
<script>
function loginData() {
return {
dark: false,
loading: false,
error: '',
success: '',
credentials: {
username: '',
password: ''
},
errors: {
username: '',
password: ''
},
clearErrors() {
this.error = '';
this.errors = { username: '', password: '' };
},
async handleLogin() {
this.clearErrors();
this.loading = true;
try {
// Your existing API call
const response = await fetch('/api/v1/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(this.credentials)
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || 'Login failed');
}
// Store token
localStorage.setItem('token', data.access_token);
// Show success
this.success = 'Login successful! Redirecting...';
// Redirect to dashboard
setTimeout(() => {
window.location.href = '/static/admin/dashboard.html';
}, 1000);
} catch (error) {
this.error = error.message || 'Invalid username or password';
console.error('Login error:', error);
} finally {
this.loading = false;
}
}
}
}
</script>
</body>
</html>