Sep 11 - Reupload the code

This commit is contained in:
2026-09-11 22:42:45 -04:00
commit d92cff81e5
130 changed files with 73508 additions and 0 deletions
+380
View File
@@ -0,0 +1,380 @@
{% extends "base_authenticated.html" %}
{% set page_title = "Add New Employee" %}
{% block title %}{{ page_title }}{% endblock %}
{% block extra_head %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/employees.css') }}">
<style>
.form-container {
max-width: 1400px;
margin: 0 auto;
background: #ffffff;
border-radius: 0.75rem;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
overflow: hidden;
}
/* UPDATE the .form-row to better utilize wider space: */
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
/* ADD new responsive breakpoints for better layout: */
@media (max-width: 1200px) {
.form-container {
max-width: 1000px;
}
.form-row {
gap: 1.5rem;
}
}
@media (max-width: 768px) {
.form-container {
max-width: 90%;
margin: 0 1rem;
}
.form-row {
grid-template-columns: 1fr;
gap: 1rem;
}
.form-actions {
flex-direction: column;
}
}
.form-header {
background: #f8fafc;
padding: 1.5rem;
border-bottom: 1px solid #e2e8f0;
position: relative;
}
.form-header::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, #10b981, #059669);
}
.form-header h2 {
display: flex;
align-items: center;
gap: 0.75rem;
font-size: 1.5rem;
font-weight: 600;
color: #0f172a;
margin: 0;
}
.form-header h2 i {
color: #10b981;
}
.form-body {
padding: 3rem;
}
.form-group {
margin-bottom: 2rem;
}
.form-group:last-child {
margin-bottom: 0;
}
.form-label {
display: block;
font-weight: 600;
color: #374151;
margin-bottom: 0.5rem;
font-size: 0.875rem;
}
.form-label.required::after {
content: " *";
color: #dc2626;
}
.form-input {
width: 70%;
padding: 1rem 1.25rem;
border: 2px solid #e2e8f0;
border-radius: 0.5rem;
font-size: 1rem;
transition: border-color 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
background: #ffffff;
}
.form-input:focus {
outline: none;
border-color: #10b981;
box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1);
}
.form-input.error {
border-color: #dc2626;
}
.form-input select {
cursor: pointer;
}
.form-input option {
padding: 0.5rem;
}
.form-help {
font-size: 0.875rem;
color: #6b7280;
margin-top: 0.25rem;
}
.form-actions {
display: flex;
gap: 1rem;
justify-content: flex-end;
padding-top: 1.5rem;
border-top: 1px solid #e2e8f0;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
@media (max-width: 640px) {
.form-row {
grid-template-columns: 1fr;
}
.form-actions {
flex-direction: column;
}
}
</style>
{% endblock %}
{% block content %}
<div class="employees-page">
<!-- Page Header -->
<div class="employees-header">
<div class="header-content">
<div class="header-navigation">
<a href="{{ url_for('employees.employees') }}" class="back-button">
<i class="fas fa-arrow-left"></i>
Back to Employees
</a>
</div>
<h1><i class="fas fa-user-plus"></i> Add New Employee</h1>
<p class="header-description">
Create a new employee record in the system
</p>
</div>
</div>
<!-- Form Container -->
<div class="form-container">
<div class="form-header">
<h2>
<i class="fas fa-user-plus"></i>
Employee Information
</h2>
</div>
<div class="form-body">
<form method="POST" id="createEmployeeForm">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<!-- Employee ID and Contract ID Row -->
<div class="form-row">
<div class="form-group">
<label for="employee_id" class="form-label required">Employee ID</label>
<input
type="number"
id="employee_id"
name="employee_id"
class="form-input"
required
min="1"
placeholder="Enter unique employee ID"
value="{{ request.form.get('employee_id', '') }}"
>
<div class="form-help">
Must be a unique numeric identifier
</div>
</div>
<div class="form-group">
<label for="contract_id" class="form-label">Project</label>
<select
id="contract_id"
name="contract_id"
class="form-input"
required
>
<option value="">-- Select Project --</option>
{% for project in projects %}
<option
value="{{ project.id }}"
{% if request.form.get('contract_id') == project.id|string or (not request.form.get('contract_id') and project.id == 1) %}selected{% endif %}
>
{{ project.name }}
</option>
{% endfor %}
</select>
<div class="form-help">
Select the project this employee will be assigned to
</div>
</div>
<!-- First Name and Last Name Row -->
<div class="form-row">
<div class="form-group">
<label for="first_name" class="form-label required">First Name</label>
<input
type="text"
id="first_name"
name="first_name"
class="form-input"
required
maxlength="50"
placeholder="Enter first name"
value="{{ request.form.get('first_name', '') }}"
>
</div>
<div class="form-group">
<label for="last_name" class="form-label required">Last Name</label>
<input
type="text"
id="last_name"
name="last_name"
class="form-input"
required
maxlength="50"
placeholder="Enter last name"
value="{{ request.form.get('last_name', '') }}"
>
</div>
</div>
<!-- Job Title -->
<div class="form-group">
<label for="title" class="form-label">Job Title</label>
<input
type="text"
id="title"
name="title"
class="form-input"
maxlength="20"
placeholder="Enter job title (optional)"
value="{{ request.form.get('title', '') }}"
>
<div class="form-help">
Optional field, maximum 20 characters
</div>
</div>
<!-- Form Actions -->
<div class="form-actions">
<a href="{{ url_for('employees.employees') }}" class="btn btn-secondary">
<i class="fas fa-times"></i>
Cancel
</a>
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i>
Create Employee
</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block extra_scripts %}
<script>
document.addEventListener('DOMContentLoaded', function() {
const form = document.getElementById('createEmployeeForm');
const employeeIdInput = document.getElementById('employee_id');
const firstNameInput = document.getElementById('first_name');
const lastNameInput = document.getElementById('last_name');
// Form validation
form.addEventListener('submit', function(e) {
let isValid = true;
// Clear previous error states
document.querySelectorAll('.form-input').forEach(input => {
input.classList.remove('error');
});
// Validate Employee ID
if (!employeeIdInput.value.trim()) {
employeeIdInput.classList.add('error');
isValid = false;
}
// Validate First Name
if (!firstNameInput.value.trim()) {
firstNameInput.classList.add('error');
isValid = false;
}
// Validate Last Name
if (!lastNameInput.value.trim()) {
lastNameInput.classList.add('error');
isValid = false;
}
if (!isValid) {
e.preventDefault();
alert('Please fill in all required fields.');
}
});
// Auto-capitalize names
[firstNameInput, lastNameInput].forEach(input => {
input.addEventListener('input', function() {
const words = this.value.split(' ');
const capitalizedWords = words.map(word => {
if (word.length > 0) {
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
}
return word;
});
this.value = capitalizedWords.join(' ');
});
});
// Employee ID validation
employeeIdInput.addEventListener('input', function() {
// Remove any non-numeric characters
this.value = this.value.replace(/[^0-9]/g, '');
// Remove leading zeros
if (this.value.length > 1) {
this.value = this.value.replace(/^0+/, '');
}
});
const contractIdSelect = document.getElementById('contract_id');
contractIdSelect.addEventListener('change', function() {
if (this.value) {
this.classList.remove('error');
}
});
});
</script>
{% endblock %}