336 lines
11 KiB
HTML
336 lines
11 KiB
HTML
{% extends 'portal_base.html' %}
|
|
{% load static i18n %}
|
|
|
|
{% block title %}{% trans "Agency Portal Login" %} - ATS{% endblock %}
|
|
|
|
{% block customCSS %}
|
|
<style>
|
|
/* KAAT-S UI Variables */
|
|
:root {
|
|
--kaauh-teal: #00636e;
|
|
--kaauh-teal-dark: #004a53;
|
|
--kaauh-border: #eaeff3;
|
|
--kaauh-primary-text: #343a40;
|
|
--kaauh-success: #28a745;
|
|
--kaauh-info: #17a2b8;
|
|
--kaauh-danger: #dc3545;
|
|
--kaauh-warning: #ffc107;
|
|
}
|
|
|
|
body {
|
|
background: linear-gradient(135deg, var(--kaauh-teal) 0%, var(--kaauh-teal-dark) 100%);
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.login-container {
|
|
min-height: 100vh;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 2rem 0;
|
|
}
|
|
|
|
.login-card {
|
|
background: white;
|
|
border-radius: 1rem;
|
|
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
|
|
border: none;
|
|
max-width: 650px;
|
|
width: 100%;
|
|
margin: 0 1rem;
|
|
}
|
|
|
|
.login-header {
|
|
background: linear-gradient(135deg, var(--kaauh-teal) 0%, var(--kaauh-teal-dark) 100%);
|
|
color: white;
|
|
padding: 2rem;
|
|
border-radius: 1rem 1rem 0 0;
|
|
text-align: center;
|
|
}
|
|
|
|
.login-body {
|
|
padding: 2.5rem;
|
|
}
|
|
|
|
.form-control:focus {
|
|
border-color: var(--kaauh-teal);
|
|
box-shadow: 0 0 0 0.2rem rgba(0, 99, 110, 0.25);
|
|
}
|
|
|
|
.btn-login {
|
|
background: linear-gradient(135deg, var(--kaauh-teal) 0%, var(--kaauh-teal-dark) 100%);
|
|
border: none;
|
|
color: white;
|
|
font-weight: 600;
|
|
padding: 0.75rem 2rem;
|
|
border-radius: 0.5rem;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.btn-login:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 8px 25px rgba(0, 99, 110, 0.3);
|
|
}
|
|
|
|
.input-group-text {
|
|
background-color: var(--kaauh-teal);
|
|
border-color: var(--kaauh-teal);
|
|
color: white;
|
|
}
|
|
|
|
.feature-icon {
|
|
width: 60px;
|
|
height: 60px;
|
|
background: linear-gradient(135deg, var(--kaauh-teal) 0%, var(--kaauh-teal-dark) 100%);
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: white;
|
|
font-size: 1.5rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.info-section {
|
|
background-color: #f8f9fa;
|
|
border-radius: 0.5rem;
|
|
padding: 1.5rem;
|
|
margin-top: 2rem;
|
|
}
|
|
|
|
.alert {
|
|
border-radius: 0.5rem;
|
|
border: none;
|
|
}
|
|
|
|
.alert-danger {
|
|
background-color: #f8d7da;
|
|
color: #721c24;
|
|
}
|
|
|
|
.alert-info {
|
|
background-color: #d1ecf1;
|
|
color: #0c5460;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="login-container">
|
|
<div class="login-card">
|
|
<!-- Login Header -->
|
|
<div class="login-header">
|
|
<div class="mb-3">
|
|
<i class="fas fa-building fa-3x"></i>
|
|
</div>
|
|
<h3 class="mb-2">{% trans "Agency Portal" %}</h3>
|
|
<p class="mb-0 opacity-75">
|
|
{% trans "Submit candidates for job assignments" %}
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Login Body -->
|
|
<div class="login-body">
|
|
<!-- Messages -->
|
|
|
|
|
|
<!-- Login Form -->
|
|
<form method="post" novalidate>
|
|
{% csrf_token %}
|
|
|
|
<!-- Access Token Field -->
|
|
<div class="mb-3">
|
|
<label for="{{ form.token.id_for_label }}" class="form-label fw-bold">
|
|
<i class="fas fa-key me-2"></i>
|
|
{% trans "Access Token" %}
|
|
</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text">
|
|
<i class="fas fa-lock"></i>
|
|
</span>
|
|
{{ form.token }}
|
|
</div>
|
|
{% if form.token.errors %}
|
|
<div class="text-danger small mt-1">
|
|
{% for error in form.token.errors %}{{ error }}{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
<small class="form-text text-muted">
|
|
{% trans "Enter the access token provided by the hiring organization" %}
|
|
</small>
|
|
</div>
|
|
|
|
<!-- Password Field -->
|
|
<div class="mb-4">
|
|
<label for="{{ form.password.id_for_label }}" class="form-label fw-bold">
|
|
<i class="fas fa-shield-alt me-2"></i>
|
|
{% trans "Password" %}
|
|
</label>
|
|
<div class="input-group">
|
|
<span class="input-group-text">
|
|
<i class="fas fa-key"></i>
|
|
</span>
|
|
{{ form.password }}
|
|
</div>
|
|
{% if form.password.errors %}
|
|
<div class="text-danger small mt-1">
|
|
{% for error in form.password.errors %}{{ error }}{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
<small class="form-text text-muted">
|
|
{% trans "Enter the password for this access token" %}
|
|
</small>
|
|
</div>
|
|
|
|
<!-- Submit Button -->
|
|
<div class="d-grid">
|
|
<button type="submit" class="btn btn-login btn-lg">
|
|
<i class="fas fa-sign-in-alt me-2"></i>
|
|
{% trans "Access Portal" %}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
|
|
<!-- Information Section -->
|
|
<div class="info-section">
|
|
<h6 class="fw-bold mb-3" style="color: var(--kaauh-teal-dark);">
|
|
<i class="fas fa-info-circle me-2"></i>
|
|
{% trans "Need Help?" %}
|
|
</h6>
|
|
|
|
<div class="row text-center">
|
|
<div class="col-6 mb-3">
|
|
<div class="feature-icon mx-auto">
|
|
<i class="fas fa-envelope"></i>
|
|
</div>
|
|
<h6 class="fw-bold">{% trans "Contact Support" %}</h6>
|
|
<small class="text-muted">
|
|
{% trans "Reach out to your hiring contact" %}
|
|
</small>
|
|
</div>
|
|
<div class="col-6 mb-3">
|
|
<div class="feature-icon mx-auto">
|
|
<i class="fas fa-question-circle"></i>
|
|
</div>
|
|
<h6 class="fw-bold">{% trans "Documentation" %}</h6>
|
|
<small class="text-muted">
|
|
{% trans "View user guides and tutorials" %}
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Security Notice -->
|
|
<div class="alert alert-info mt-3 mb-0">
|
|
<h6 class="alert-heading">
|
|
<i class="fas fa-shield-alt me-2"></i>
|
|
{% trans "Security Notice" %}
|
|
</h6>
|
|
<p class="mb-2 small">
|
|
{% trans "This portal is for authorized agency partners only. Access is monitored and logged." %}
|
|
</p>
|
|
<hr>
|
|
<p class="mb-0 small">
|
|
{% trans "If you believe you've received this link in error, please contact the hiring organization immediately." %}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block customJS %}
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Focus on access token field
|
|
const accessTokenField = document.getElementById('{{ form.token.id_for_label }}');
|
|
if (accessTokenField) {
|
|
accessTokenField.focus();
|
|
}
|
|
|
|
// Auto-format access token (remove spaces and convert to uppercase)
|
|
const accessTokenInput = document.getElementById('{{ form.token.id_for_label }}');
|
|
if (accessTokenInput) {
|
|
accessTokenInput.addEventListener('input', function(e) {
|
|
// Remove spaces and convert to uppercase
|
|
this.value = this.value.replace(/\s+/g, '');
|
|
});
|
|
}
|
|
|
|
// Show/hide password functionality
|
|
const passwordField = document.getElementById('{{ form.password.id_for_label }}');
|
|
const passwordToggle = document.createElement('button');
|
|
passwordToggle.type = 'button';
|
|
passwordToggle.className = 'btn btn-outline-secondary';
|
|
passwordToggle.innerHTML = '<i class="fas fa-eye"></i>';
|
|
passwordToggle.style.position = 'absolute';
|
|
passwordToggle.style.right = '10px';
|
|
passwordToggle.style.top = '50%';
|
|
passwordToggle.style.transform = 'translateY(-50%)';
|
|
passwordToggle.style.border = 'none';
|
|
passwordToggle.style.background = 'none';
|
|
passwordToggle.style.zIndex = '10';
|
|
|
|
if (passwordField && passwordField.parentElement) {
|
|
passwordField.parentElement.style.position = 'relative';
|
|
|
|
passwordToggle.addEventListener('click', function() {
|
|
const type = passwordField.getAttribute('type') === 'password' ? 'text' : 'password';
|
|
passwordField.setAttribute('type', type);
|
|
this.innerHTML = type === 'password' ? '<i class="fas fa-eye"></i>' : '<i class="fas fa-eye-slash"></i>';
|
|
});
|
|
|
|
passwordField.parentElement.appendChild(passwordToggle);
|
|
}
|
|
|
|
// Form validation
|
|
const form = document.querySelector('form');
|
|
if (form) {
|
|
form.addEventListener('submit', function(e) {
|
|
const accessToken = accessTokenInput.value.trim();
|
|
const password = passwordField.value.trim();
|
|
|
|
if (!accessToken) {
|
|
e.preventDefault();
|
|
showError('{% trans "Please enter your access token." %}');
|
|
accessTokenInput.focus();
|
|
return;
|
|
}
|
|
|
|
if (!password) {
|
|
e.preventDefault();
|
|
showError('{% trans "Please enter your password." %}');
|
|
passwordField.focus();
|
|
return;
|
|
}
|
|
});
|
|
}
|
|
|
|
function showError(message) {
|
|
// Remove existing alerts
|
|
const existingAlerts = document.querySelectorAll('.alert-danger');
|
|
existingAlerts.forEach(alert => alert.remove());
|
|
|
|
// Create new alert
|
|
const alertDiv = document.createElement('div');
|
|
alertDiv.className = 'alert alert-danger alert-dismissible fade show';
|
|
alertDiv.innerHTML = `
|
|
${message}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
`;
|
|
|
|
// Insert at the top of the login body
|
|
const loginBody = document.querySelector('.login-body');
|
|
loginBody.insertBefore(alertDiv, loginBody.firstChild);
|
|
|
|
// Auto-dismiss after 5 seconds
|
|
setTimeout(() => {
|
|
if (alertDiv.parentNode) {
|
|
alertDiv.remove();
|
|
}
|
|
}, 5000);
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|