Files
denya-onecare/app/templates/login.html
T
root 9aa7971a28 feat: Sprint 3 frontend dashboards with Alpine.js + Jinja2
- Login page with JWT auth and role-based redirect
- CS Dashboard: KPI cards, priority breakdown, recent tickets
- FM Dashboard: tech workload, aging analysis, emergency alerts
- CEO Dashboard: executive KPIs, charts, risk indicators
- All Issues: filterable/sortable ticket table with pagination
- Create Issue: form with category tree, property/unit selector, photo uploads
- Issue Detail: full timeline, photo gallery, SLA status, action modals
- Role-based nav bar: CS/FM/Executive links adapt to user role
- Base template: shared Alpine.js app state, toast notifications, loading overlay
2026-07-23 19:01:26 +00:00

75 lines
3.9 KiB
HTML

{% extends "base.html" %}
{% block content %}
<div class="min-h-[80vh] flex items-center justify-center">
<div class="w-full max-w-md" x-data="loginForm()">
<div class="bg-white rounded-2xl shadow-lg p-8">
<div class="text-center mb-8">
<div class="mx-auto w-16 h-16 bg-denya-100 rounded-full flex items-center justify-center mb-4">
<svg class="w-8 h-8 text-denya-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"/>
</svg>
</div>
<h1 class="text-2xl font-bold text-gray-900">Denya OneCare</h1>
<p class="text-gray-500 mt-1">Sign in to your dashboard</p>
</div>
<form @submit.prevent="submitLogin" class="space-y-5">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Email</label>
<input type="email" x-model="email" required
class="w-full px-4 py-2.5 rounded-lg border border-gray-300 focus:ring-2 focus:ring-denya-500 focus:border-transparent outline-none transition"
placeholder="you@example.com">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Password</label>
<input type="password" x-model="password" required
class="w-full px-4 py-2.5 rounded-lg border border-gray-300 focus:ring-2 focus:ring-denya-500 focus:border-transparent outline-none transition"
placeholder="••••••••">
</div>
<div x-show="error" class="text-red-600 text-sm bg-red-50 p-3 rounded-lg" x-text="error"></div>
<button type="submit" :disabled="submitting"
class="w-full py-2.5 px-4 bg-denya-600 hover:bg-denya-700 text-white font-medium rounded-lg transition disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center space-x-2">
<svg x-show="submitting" class="animate-spin h-5 w-5" 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 12h4z"></path>
</svg>
<span x-text="submitting ? 'Signing in...' : 'Sign In'"></span>
</button>
</form>
<div class="mt-6 pt-6 border-t border-gray-200">
<p class="text-xs text-gray-400 text-center">
<strong>Demo Accounts:</strong><br>
bella@denya.com / denya123 — CS Rep<br>
nicholas@denya.com / denya123 — FM Dispatcher<br>
scott@denya.com / denya123 — CEO<br>
jerome@denya.com / denya123 — Admin
</p>
</div>
</div>
</div>
</div>
<script>
function loginForm() {
return {
email: '',
password: '',
error: '',
submitting: false,
async submitLogin() {
this.error = '';
this.submitting = true;
try {
await app().login(this.email, this.password);
} catch (e) {
this.error = e.message || 'Invalid credentials. Please try again.';
} finally {
this.submitting = false;
}
}
}
}
</script>
{% endblock %}