HH/templates/projects/project_form.html
2026-07-05 14:49:45 +03:00

381 lines
14 KiB
HTML

{% extends "layouts/base.html" %}
{% load i18n %}{% get_current_language as LANG %}
{% block title %}{% if is_create %}{% trans "Create QI Project" %}{% else %}{% trans "Edit QI Project" %}{% endif %} - PX360{% endblock %}
{% block extra_css %}
<style>
.page-header-gradient {
background: linear-gradient(135deg, #005696 0%, #0069a8 50%, #007bbd 100%);
color: white;
padding: 1.5rem 2rem;
border-radius: 1rem;
margin-bottom: 1.5rem;
box-shadow: 0 10px 15px -3px rgba(0, 86, 150, 0.2);
}
.form-section {
background: #fff;
border: 2px solid #e2e8f0;
border-radius: 1rem;
padding: 1.5rem;
margin-bottom: 1.5rem;
transition: all 0.3s ease;
}
.form-section:hover {
border-color: #005696;
box-shadow: 0 4px 12px rgba(0, 86, 150, 0.1);
}
.form-label {
display: block;
font-size: 0.875rem;
font-weight: 600;
color: #1e293b;
margin-bottom: 0.5rem;
}
.form-control, .form-select {
width: 100%;
padding: 0.75rem 1rem;
border: 2px solid #e2e8f0;
border-radius: 0.75rem;
font-size: 0.875rem;
transition: all 0.2s ease;
}
.form-control:focus, .form-select:focus {
outline: none;
border-color: #005696;
box-shadow: 0 0 0 3px rgba(0, 86, 150, 0.1);
}
.hh-btn-primary {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1.5rem;
background: #005696;
color: white;
border-radius: 0.75rem;
font-weight: 600;
transition: all 0.2s ease;
border: none;
cursor: pointer;
}
.hh-btn-primary:hover {
background: #007bbd;
}
.hh-btn-secondary {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1.5rem;
background: white;
color: #64748b;
border: 2px solid #e2e8f0;
border-radius: 0.75rem;
font-weight: 600;
transition: all 0.2s ease;
}
.hh-btn-secondary:hover {
background: #f1f5f9;
border-color: #005696;
}
</style>
{% endblock %}
{% block content %}
<!-- Back Button -->
<div class="mb-6">
<a href="{% url 'projects:project_list' %}" class="inline-flex items-center gap-2 text-slate hover:text-navy transition">
<i data-lucide="arrow-left" class="w-4 h-4"></i>
<span class="text-sm font-medium">{% trans "Back to Projects" %}</span>
</a>
</div>
<!-- Header -->
<div class="page-header-gradient">
<div class="flex justify-between items-start">
<div>
<h1 class="text-2xl font-bold flex items-center gap-3">
<i data-lucide="kanban" class="w-6 h-6"></i>
{% if is_create %}{% trans "Create QI Project" %}{% else %}{% trans "Edit QI Project" %}{% endif %}
</h1>
<p class="text-sm mt-1 opacity-90">
{% if is_create %}
{% trans "Start a new quality improvement initiative" %}
{% else %}
{% trans "Update project details and settings" %}
{% endif %}
</p>
</div>
</div>
</div>
<!-- Form Section -->
<div class="form-section">
<h2 class="text-sm font-bold text-navy mb-4">{% trans "Project Information" %}</h2>
{% if template %}
<!-- Template Preview -->
<div class="mb-6 bg-blue-50 border border-blue-100 rounded-xl p-4">
<div class="flex items-start gap-3">
<i data-lucide="copy" class="w-5 h-5 text-blue mt-0.5"></i>
<div class="flex-1">
<h3 class="text-sm font-bold text-navy mb-1">
{% trans "Creating from Template:" %} {{ template.name }}
</h3>
{% if template.tasks.exists %}
<p class="text-xs text-slate mb-2">
{% trans "This template includes" %} {{ template.tasks.count }} {% trans "task(s) that will be copied to your new project." %}
</p>
<ul class="text-xs text-slate space-y-1">
{% for task in template.tasks.all|slice:":5" %}
<li class="flex items-center gap-2">
<i data-lucide="check" class="w-3 h-3 text-green-600"></i>
{{ task.title }}
</li>
{% endfor %}
{% if template.tasks.count > 5 %}
<li class="text-slate-500 italic">
{% trans "and" %} {{ template.tasks.count|add:"-5" }} {% trans "more..." %}
</li>
{% endif %}
</ul>
{% else %}
<p class="text-xs text-slate">{% trans "No predefined tasks in this template." %}</p>
{% endif %}
</div>
</div>
</div>
{% endif %}
<form method="post" novalidate>
{% csrf_token %}
{% if template %}
<input type="hidden" name="template_id" value="{{ template.pk }}">
{% endif %}
{% if related_model %}
<input type="hidden" name="related_model" value="{{ related_model }}">
{% endif %}
{% if related_id %}
<input type="hidden" name="related_id" value="{{ related_id }}">
{% endif %}
<div class="grid grid-cols-2 gap-6">
<!-- Project Name -->
<div>
<label for="{{ form.name.id_for_label }}" class="form-label">
{% trans "Project Name" %} <span class="text-red-500">*</span>
</label>
{{ form.name }}
{% if form.name.errors %}
<p class="text-red-500 text-xs mt-1">{{ form.name.errors.0 }}</p>
{% endif %}
</div>
<!-- Project Name (Arabic) -->
<div>
<label for="{{ form.name_ar.id_for_label }}" class="form-label">
{% trans "Project Name (Arabic)" %}
</label>
{{ form.name_ar }}
{% if form.name_ar.errors %}
<p class="text-red-500 text-xs mt-1">{{ form.name_ar.errors.0 }}</p>
{% endif %}
</div>
</div>
<!-- Description -->
<div class="mt-6">
<label for="{{ form.description.id_for_label }}" class="form-label">
{% trans "Description" %} <span class="text-red-500">*</span>
</label>
{{ form.description }}
{% if form.description.errors %}
<p class="text-red-500 text-xs mt-1">{{ form.description.errors.0 }}</p>
{% endif %}
<p class="text-xs text-slate mt-1">{% trans "Describe the project objectives and scope" %}</p>
</div>
<div class="grid grid-cols-2 gap-6 mt-6">
<!-- Hospital (hidden, auto-set) -->
{% if not form.hospital.is_hidden %}
<div>
<label for="{{ form.hospital.id_for_label }}" class="form-label">
{% trans "Hospital" %} <span class="text-red-500">*</span>
</label>
{{ form.hospital }}
{% if form.hospital.errors %}
<p class="text-red-500 text-xs mt-1">{{ form.hospital.errors.0 }}</p>
{% endif %}
</div>
{% else %}
{{ form.hospital }}
{% endif %}
<!-- Departments (multi-select) -->
<div class="md:col-span-2">
<label for="{{ form.departments.id_for_label }}" class="form-label">
{% trans "Departments" %}
</label>
{{ form.departments }}
{% if form.departments.errors %}
<p class="text-red-500 text-xs mt-1">{{ form.departments.errors.0 }}</p>
{% endif %}
<p class="text-xs text-slate mt-1">
{% trans "Select one or more departments. The team is auto-set from each department's champion and manager." %}
</p>
</div>
</div>
<div class="grid grid-cols-2 gap-6 mt-6">
<!-- Project Lead -->
<div>
<label for="{{ form.project_lead.id_for_label }}" class="form-label">
{% trans "Project Lead" %}
</label>
{{ form.project_lead }}
{% if form.project_lead.errors %}
<p class="text-red-500 text-xs mt-1">{{ form.project_lead.errors.0 }}</p>
{% endif %}
</div>
<!-- Status -->
<div>
<label for="{{ form.status.id_for_label }}" class="form-label">
{% trans "Status" %} <span class="text-red-500">*</span>
</label>
{{ form.status }}
{% if form.status.errors %}
<p class="text-red-500 text-xs mt-1">{{ form.status.errors.0 }}</p>
{% endif %}
</div>
</div>
<!-- Team (derived, read-only) -->
<div class="mt-6">
<label class="form-label">
{% trans "Team Members" %}
</label>
<p class="text-xs text-slate bg-blue-50 border border-blue-100 rounded-lg p-3">
<i data-lucide="users" class="w-3.5 h-3.5 inline -mt-0.5"></i>
{% blocktrans %}Team members are <strong>derived automatically</strong> from each selected department's champion and manager (plus the project lead). They cannot be edited directly.{% endblocktrans %}
</p>
</div>
<div class="grid grid-cols-2 gap-6 mt-6">
<!-- Start Date -->
<div>
<label for="{{ form.start_date.id_for_label }}" class="form-label">
{% trans "Start Date" %}
</label>
{{ form.start_date }}
{% if form.start_date.errors %}
<p class="text-red-500 text-xs mt-1">{{ form.start_date.errors.0 }}</p>
{% endif %}
</div>
<!-- Target Completion Date -->
<div>
<label for="{{ form.target_completion_date.id_for_label }}" class="form-label">
{% trans "Target Completion Date" %}
</label>
{{ form.target_completion_date }}
{% if form.target_completion_date.errors %}
<p class="text-red-500 text-xs mt-1">{{ form.target_completion_date.errors.0 }}</p>
{% endif %}
</div>
</div>
<!-- Outcome Description (only show for existing projects) -->
{% if not is_create %}
<div class="mt-6">
<label for="{{ form.outcome_description.id_for_label }}" class="form-label">
{% trans "Outcome Description" %}
</label>
{{ form.outcome_description }}
{% if form.outcome_description.errors %}
<p class="text-red-500 text-xs mt-1">{{ form.outcome_description.errors.0 }}</p>
{% endif %}
<p class="text-xs text-slate mt-1">{% trans "Document project outcomes and results" %}</p>
</div>
{% endif %}
<!-- Submit Buttons -->
<div class="flex items-center gap-3 mt-8 pt-6 border-t">
<button type="submit" class="hh-btn hh-btn-primary">
<i data-lucide="save" class="w-4 h-4"></i>
{% if is_create %}{% trans "Create Project" %}{% else %}{% trans "Save Changes" %}{% endif %}
</button>
<a href="{% url 'projects:project_list' %}" class="hh-btn hh-btn-secondary">
<i data-lucide="x" class="w-4 h-4"></i>
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
{% endblock %}
{% block extra_js %}
<script>
// Dynamic departments and project-lead filtering based on hospital selection.
// (team_members is derived server-side, so there is no widget to sync here.)
document.addEventListener('DOMContentLoaded', function() {
const hospitalSelect = document.getElementById('{{ form.hospital.id_for_label }}');
const departmentsSelect = document.getElementById('{{ form.departments.id_for_label }}');
const projectLeadSelect = document.getElementById('{{ form.project_lead.id_for_label }}');
function refreshDepartments(hospitalId) {
if (!departmentsSelect || !hospitalId) return;
fetch(`/api/organizations/hospitals/${hospitalId}/departments/`)
.then(r => r.json())
.then(data => {
// Preserve currently selected values (for edit form)
const previouslySelected = Array.from(departmentsSelect.selectedOptions || []).map(o => o.value);
departmentsSelect.innerHTML = '';
(data.departments || []).forEach(dept => {
const option = document.createElement('option');
option.value = dept.id;
option.textContent = {% if LANG == 'ar' %}dept.name_ar || dept.name{% else %}dept.name{% endif %};
if (previouslySelected.includes(String(dept.id))) {
option.selected = true;
}
departmentsSelect.appendChild(option);
});
});
}
function refreshProjectLead(hospitalId) {
if (!projectLeadSelect || !hospitalId) return;
fetch(`/api/organizations/hospitals/${hospitalId}/staff/`)
.then(r => r.json())
.then(data => {
const previouslySelected = projectLeadSelect.value;
projectLeadSelect.innerHTML = '<option value="">---------</option>';
(data.staff || []).forEach(staff => {
const option = document.createElement('option');
option.value = staff.id;
option.textContent = `${staff.first_name} ${staff.last_name}`;
if (String(staff.id) === String(previouslySelected)) {
option.selected = true;
}
projectLeadSelect.appendChild(option);
});
});
}
if (hospitalSelect) {
hospitalSelect.addEventListener('change', function() {
const hospitalId = this.value;
if (!hospitalId) return;
refreshDepartments(hospitalId);
refreshProjectLead(hospitalId);
});
}
});
</script>
{% endblock %}