clqms-be/app/Views/pages/login.php
2025-12-22 16:54:19 +07:00

234 lines
9.0 KiB
PHP

<?= $this->extend('layouts/v2_auth') ?>
<?= $this->section('content') ?>
<div class="card lg:card-side bg-base-100/95 glass-card shadow-2xl border border-white/20 overflow-hidden max-w-4xl mx-auto card-glow" x-data="loginForm" x-ref="loginCard">
<!-- Illustration Side -->
<div class="card-body lg:w-1/2 flex flex-col justify-center items-center text-center p-10 relative overflow-hidden bg-gradient-to-br from-primary via-primary to-secondary">
<!-- Abstract geometric patterns -->
<div class="absolute inset-0 opacity-20">
<div class="absolute top-0 left-0 w-full h-full">
<svg viewBox="0 0 400 400" class="w-full h-full" preserveAspectRatio="xMidYMid slice">
<defs>
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="white" stroke-width="0.5"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid)"/>
</svg>
</div>
</div>
<!-- Floating molecules decoration -->
<div class="absolute top-8 right-8 opacity-30">
<i data-lucide="atom" class="w-12 h-12 text-white float-animation"></i>
</div>
<div class="absolute bottom-12 left-8 opacity-30">
<i data-lucide="flask-conical" class="w-10 h-10 text-white float-animation-delayed"></i>
</div>
<div class="relative z-10 space-y-6">
<!-- Logo -->
<div class="relative">
<div class="bg-white/20 backdrop-blur-md rounded-3xl w-28 h-28 flex items-center justify-center ring-4 ring-white/10 mx-auto shadow-2xl">
<img src="<?= base_url('assets/images/logo.png') ?>" alt="CLQMS Logo" class="w-16 h-16 drop-shadow-lg">
</div>
<div class="absolute -bottom-2 left-1/2 -translate-x-1/2">
<span class="badge badge-sm bg-white/20 text-white border-0 backdrop-blur-sm">Secure</span>
</div>
</div>
<!-- Title -->
<div class="space-y-2 pt-4">
<h1 class="text-4xl font-extrabold text-white tracking-tight drop-shadow-lg">CLQMS</h1>
<div class="h-1 w-16 bg-white/40 rounded-full mx-auto"></div>
</div>
<!-- Description -->
<p class="text-white/85 text-lg max-w-xs mx-auto leading-relaxed">
Clinical Laboratory<br>
<span class="font-semibold">Quality Management System</span>
</p>
<!-- Features badges -->
<div class="flex flex-wrap justify-center gap-2 pt-4">
<span class="badge badge-lg bg-white/15 text-white border-white/20 gap-1 backdrop-blur-sm">
<i data-lucide="shield-check" class="w-3 h-3"></i>
ISO 15189
</span>
<span class="badge badge-lg bg-white/15 text-white border-white/20 gap-1 backdrop-blur-sm">
<i data-lucide="lock" class="w-3 h-3"></i>
HIPAA
</span>
</div>
<!-- Version badge -->
<div class="badge badge-outline badge-lg text-white/60 border-white/20 mt-4">v2.0.0</div>
</div>
<!-- Bottom gradient fade -->
<div class="absolute bottom-0 w-full h-32 bg-gradient-to-t from-black/20 to-transparent"></div>
</div>
<!-- Form Side -->
<div class="card-body lg:w-1/2 p-8 lg:p-12 bg-base-100/50">
<!-- Header -->
<div class="mb-8 text-center lg:text-left">
<h2 class="text-2xl font-bold text-base-content mb-2">Welcome Back!</h2>
<p class="text-base-content/60">Sign in to access your laboratory dashboard</p>
</div>
<!-- Error Alert -->
<template x-if="error">
<div class="alert alert-error mb-6 shadow-lg rounded-xl text-sm" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0 -translate-y-2" x-transition:enter-end="opacity-100 translate-y-0">
<i data-lucide="alert-circle" class="w-5 h-5"></i>
<span x-text="error"></span>
<button @click="error = null" class="btn btn-ghost btn-xs btn-circle">
<i data-lucide="x" class="w-4 h-4"></i>
</button>
</div>
</template>
<!-- Login Form -->
<form @submit.prevent="submitLogin" class="space-y-5">
<!-- Username Field -->
<div class="form-control w-full">
<label class="label pb-1">
<span class="label-text font-semibold text-base-content/80">Username</span>
</label>
<input
type="text"
class="input input-bordered w-full focus:input-primary focus:shadow-lg focus:shadow-primary/10 transition-all"
placeholder="Enter your username"
x-model="username"
:disabled="isLoading"
autocomplete="username"
autofocus
/>
</div>
<!-- Password Field -->
<div class="form-control w-full">
<label class="label pb-1 justify-between">
<span class="label-text font-semibold text-base-content/80">Password</span>
<a href="#" class="link link-primary link-hover text-xs font-medium">Forgot password?</a>
</label>
<input
:type="showPassword ? 'text' : 'password'"
class="input input-bordered w-full focus:input-primary focus:shadow-lg focus:shadow-primary/10 transition-all"
placeholder="Enter your password"
x-model="password"
:disabled="isLoading"
autocomplete="current-password"
/>
</div>
<!-- Remember Me -->
<div class="form-control">
<label class="label cursor-pointer justify-start gap-3 py-3 hover:bg-base-200/50 rounded-xl px-2 -mx-2 transition-colors">
<input
type="checkbox"
class="checkbox checkbox-primary checkbox-sm"
x-model="rememberMe"
:disabled="isLoading"
/>
<span class="label-text text-base-content/70">Remember me on this device</span>
</label>
</div>
<!-- Submit Button -->
<div class="form-control pt-2">
<button
type="submit"
class="btn btn-primary btn-block shadow-xl shadow-primary/30 hover:shadow-primary/50 hover:scale-[1.02] active:scale-[0.98] transition-all duration-200 font-bold text-base rounded-xl h-12"
:disabled="isLoading"
>
<template x-if="isLoading">
<span class="loading loading-spinner loading-sm"></span>
</template>
<span x-text="isLoading ? 'Signing in...' : 'Sign In'"></span>
<i x-show="!isLoading" data-lucide="arrow-right" class="w-4 h-4"></i>
</button>
</div>
</form>
<!-- Divider -->
<div class="divider text-xs text-base-content/30 my-6">SECURE CONNECTION</div>
<!-- Footer -->
<div class="text-center space-y-2">
<div class="flex justify-center gap-4">
<span class="badge badge-ghost badge-sm gap-1">
<i data-lucide="shield" class="w-3 h-3"></i>
256-bit SSL
</span>
<span class="badge badge-ghost badge-sm gap-1">
<i data-lucide="check-circle" class="w-3 h-3"></i>
Protected
</span>
</div>
<p class="text-xs text-base-content/40 pt-2">
&copy; <?= date('Y') ?> Clinical Laboratory QMS
</p>
</div>
</div>
</div>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('loginForm', () => ({
username: '',
password: '',
rememberMe: false,
showPassword: false,
isLoading: false,
error: null,
togglePassword() {
this.showPassword = !this.showPassword;
this.$nextTick(() => lucide.createIcons());
},
async submitLogin() {
this.error = null;
if (!this.username || !this.password) {
this.error = 'Please enter both username and password.';
return;
}
this.isLoading = true;
try {
await new Promise(r => setTimeout(r, 800));
const form = document.createElement('form');
form.method = 'POST';
form.action = '';
const u = document.createElement('input'); u.name = 'username'; u.value = this.username; form.appendChild(u);
const p = document.createElement('input'); p.name = 'password'; p.value = this.password; form.appendChild(p);
if(this.rememberMe) {
const r = document.createElement('input'); r.name = 'remember'; r.value = '1'; form.appendChild(r);
}
document.body.appendChild(form);
form.submit();
} catch (e) {
this.error = 'An unexpected error occurred. Please try again.';
this.isLoading = false;
}
}
}));
});
</script>
<?= $this->endSection() ?>