2026-06-23 19:57:49 +01:00
|
|
|
{% extends "base.html" %}
|
|
|
|
|
|
|
|
|
|
{% block title %}{{ gettext('Student Details') }} - {{ student.full_name }}{% endblock %}
|
|
|
|
|
|
|
|
|
|
{% block content %}
|
2026-06-24 15:53:55 +01:00
|
|
|
<div class="space-y-6">
|
|
|
|
|
{# Breadcrumb #}
|
|
|
|
|
<nav class="flex" aria-label="Breadcrumb">
|
|
|
|
|
<ol class="flex items-center space-x-2">
|
|
|
|
|
<li>
|
|
|
|
|
<a href="{{ url_for('list_students') }}" class="text-cobalt-600 hover:text-cobalt-800">{{ gettext('Students') }}</a>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<svg class="w-4 h-4 text-gray-400" fill="currentColor" viewBox="0 0 20 20">
|
|
|
|
|
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
|
|
|
|
|
</svg>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
|
|
|
|
<span class="text-gray-500">{{ student.full_name }}</span>
|
|
|
|
|
</li>
|
|
|
|
|
</ol>
|
|
|
|
|
</nav>
|
|
|
|
|
|
|
|
|
|
{# Student Header #}
|
|
|
|
|
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
|
|
|
|
|
<div>
|
|
|
|
|
<h1 class="text-2xl font-bold text-gray-900">{{ student.full_name }}</h1>
|
|
|
|
|
<p class="text-gray-600 mt-1">{{ gettext('Student Details') }}</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex gap-2">
|
|
|
|
|
<a href="{{ url_for('edit_student', student_id=student.id) }}"
|
|
|
|
|
class="inline-flex items-center gap-2 px-4 py-2 bg-yellow-500 text-white rounded-lg hover:bg-yellow-600 transition-colors">
|
|
|
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>
|
|
|
|
|
</svg>
|
|
|
|
|
{{ gettext('Edit') }}
|
|
|
|
|
</a>
|
|
|
|
|
<a href="{{ url_for('delete_student', student_id=student.id) }}"
|
|
|
|
|
onclick="return confirm('{{ gettext('Are you sure you want to delete this student?') }}')"
|
|
|
|
|
class="inline-flex items-center gap-2 px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors">
|
|
|
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
|
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
|
|
|
|
</svg>
|
|
|
|
|
{{ gettext('Delete') }}
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{# Student Information and Assigned Devices #}
|
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
|
|
|
{# Student Information Card #}
|
|
|
|
|
<div class="bg-white rounded-lg shadow overflow-hidden">
|
|
|
|
|
<div class="bg-cobalt-600 px-6 py-4">
|
|
|
|
|
<h2 class="text-lg font-semibold text-white">{{ gettext('Student Information') }}</h2>
|
2026-06-23 19:57:49 +01:00
|
|
|
</div>
|
2026-06-24 15:53:55 +01:00
|
|
|
<div class="p-6">
|
|
|
|
|
<dl class="space-y-4">
|
|
|
|
|
<div class="flex flex-col sm:flex-row sm:items-center">
|
|
|
|
|
<dt class="text-sm font-medium text-gray-500 sm:w-1/3">{{ gettext('ID') }}:</dt>
|
|
|
|
|
<dd class="text-sm text-gray-900 sm:w-2/3">{{ student.id }}</dd>
|
2026-06-23 19:57:49 +01:00
|
|
|
</div>
|
2026-06-24 15:53:55 +01:00
|
|
|
<div class="flex flex-col sm:flex-row sm:items-center">
|
|
|
|
|
<dt class="text-sm font-medium text-gray-500 sm:w-1/3">{{ gettext('CIAL Code') }}:</dt>
|
|
|
|
|
<dd class="text-sm text-gray-900 sm:w-2/3">
|
|
|
|
|
<code class="bg-gray-100 px-2 py-1 rounded">{{ student.cial_code }}</code>
|
|
|
|
|
</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-col sm:flex-row sm:items-center">
|
|
|
|
|
<dt class="text-sm font-medium text-gray-500 sm:w-1/3">{{ gettext('NIF/NIE/Passport') }}:</dt>
|
|
|
|
|
<dd class="text-sm text-gray-900 sm:w-2/3">{{ student.nif_nie_passport or '-' }}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-col sm:flex-row sm:items-center">
|
|
|
|
|
<dt class="text-sm font-medium text-gray-500 sm:w-1/3">{{ gettext('Registration Number') }}:</dt>
|
|
|
|
|
<dd class="text-sm text-gray-900 sm:w-2/3">{{ student.registration_number or '-' }}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-col sm:flex-row sm:items-center">
|
|
|
|
|
<dt class="text-sm font-medium text-gray-500 sm:w-1/3">{{ gettext('File Number') }}:</dt>
|
|
|
|
|
<dd class="text-sm text-gray-900 sm:w-2/3">{{ student.file_number or '-' }}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-col sm:flex-row sm:items-center">
|
|
|
|
|
<dt class="text-sm font-medium text-gray-500 sm:w-1/3">{{ gettext('Order Number') }}:</dt>
|
|
|
|
|
<dd class="text-sm text-gray-900 sm:w-2/3">{{ student.order_number or '-' }}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-col sm:flex-row sm:items-center">
|
|
|
|
|
<dt class="text-sm font-medium text-gray-500 sm:w-1/3">{{ gettext('Full Name') }}:</dt>
|
|
|
|
|
<dd class="text-sm text-gray-900 sm:w-2/3">{{ student.full_name }}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-col sm:flex-row sm:items-center">
|
|
|
|
|
<dt class="text-sm font-medium text-gray-500 sm:w-1/3">{{ gettext('First Name') }}:</dt>
|
|
|
|
|
<dd class="text-sm text-gray-900 sm:w-2/3">{{ student.first_name }}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-col sm:flex-row sm:items-center">
|
|
|
|
|
<dt class="text-sm font-medium text-gray-500 sm:w-1/3">{{ gettext('Last Name') }}:</dt>
|
|
|
|
|
<dd class="text-sm text-gray-900 sm:w-2/3">{{ student.last_name }}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-col sm:flex-row sm:items-center">
|
|
|
|
|
<dt class="text-sm font-medium text-gray-500 sm:w-1/3">{{ gettext('Birth Date') }}:</dt>
|
|
|
|
|
<dd class="text-sm text-gray-900 sm:w-2/3">{{ student.birth_date or '-' }}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-col sm:flex-row sm:items-center">
|
|
|
|
|
<dt class="text-sm font-medium text-gray-500 sm:w-1/3">{{ gettext('Gender') }}:</dt>
|
|
|
|
|
<dd class="text-sm text-gray-900 sm:w-2/3">{{ student.gender or '-' }}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-col sm:flex-row sm:items-center">
|
|
|
|
|
<dt class="text-sm font-medium text-gray-500 sm:w-1/3">{{ gettext('Study Group') }}:</dt>
|
|
|
|
|
<dd class="text-sm text-gray-900 sm:w-2/3">{{ student.study_group or '-' }}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-col sm:flex-row sm:items-center">
|
|
|
|
|
<dt class="text-sm font-medium text-gray-500 sm:w-1/3">{{ gettext('Created') }}:</dt>
|
|
|
|
|
<dd class="text-sm text-gray-900 sm:w-2/3">{{ student.created_at }}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="flex flex-col sm:flex-row sm:items-center">
|
|
|
|
|
<dt class="text-sm font-medium text-gray-500 sm:w-1/3">{{ gettext('Updated') }}:</dt>
|
|
|
|
|
<dd class="text-sm text-gray-900 sm:w-2/3">{{ student.updated_at }}</dd>
|
|
|
|
|
</div>
|
|
|
|
|
</dl>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{# Assigned Devices Card #}
|
|
|
|
|
<div class="bg-white rounded-lg shadow overflow-hidden">
|
|
|
|
|
<div class="bg-green-600 px-6 py-4">
|
|
|
|
|
<h2 class="text-lg font-semibold text-white">{{ gettext('Assigned Devices') }}</h2>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="p-6">
|
|
|
|
|
{# Assigned Tablets #}
|
|
|
|
|
<h3 class="text-sm font-semibold text-gray-700 uppercase tracking-wider mb-3">{{ gettext('Tablets') }}</h3>
|
|
|
|
|
{% if assigned_tablets %}
|
|
|
|
|
<div class="space-y-3 mb-6">
|
|
|
|
|
{% for tablet in assigned_tablets %}
|
|
|
|
|
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
|
|
|
|
|
<div>
|
|
|
|
|
<div class="font-medium text-gray-900">{{ tablet.brand }} {{ tablet.model }}</div>
|
|
|
|
|
<div class="text-sm text-gray-500">
|
|
|
|
|
{{ gettext('Serial:') }} {{ tablet.serial_number }}
|
|
|
|
|
</div>
|
|
|
|
|
<div class="text-sm text-gray-500">
|
|
|
|
|
{{ gettext('Status:') }}
|
|
|
|
|
<span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium
|
|
|
|
|
{% if tablet.status == 'available' %}bg-green-100 text-green-800
|
|
|
|
|
{% elif tablet.status == 'loaned' %}bg-yellow-100 text-yellow-800
|
|
|
|
|
{% else %}bg-gray-100 text-gray-800{% endif %}">
|
|
|
|
|
{{ tablet.status }}
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
2026-06-23 19:57:49 +01:00
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-06-24 15:53:55 +01:00
|
|
|
{% endfor %}
|
2026-06-23 19:57:49 +01:00
|
|
|
</div>
|
2026-06-24 15:53:55 +01:00
|
|
|
{% else %}
|
|
|
|
|
<p class="text-gray-500 text-sm mb-6">{{ gettext('No tablets assigned.') }}</p>
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
|
|
{# Assigned Non-Loanable Devices #}
|
|
|
|
|
<h3 class="text-sm font-semibold text-gray-700 uppercase tracking-wider mb-3">{{ gettext('Non-Loanable Devices') }}</h3>
|
|
|
|
|
{% if assigned_devices %}
|
|
|
|
|
<div class="space-y-3">
|
|
|
|
|
{% for device in assigned_devices %}
|
|
|
|
|
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
|
|
|
|
|
<div>
|
|
|
|
|
<div class="font-medium text-gray-900">{{ device.brand }} {{ device.model }}</div>
|
|
|
|
|
<div class="text-sm text-gray-500">
|
|
|
|
|
{{ gettext('Serial:') }} {{ device.serial_number }}
|
|
|
|
|
</div>
|
|
|
|
|
<div class="text-sm text-gray-500">
|
|
|
|
|
{{ gettext('Type:') }} {{ device.device_type }}
|
|
|
|
|
</div>
|
2026-06-23 19:57:49 +01:00
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-06-24 15:53:55 +01:00
|
|
|
{% endfor %}
|
2026-06-23 19:57:49 +01:00
|
|
|
</div>
|
2026-06-24 15:53:55 +01:00
|
|
|
{% else %}
|
|
|
|
|
<p class="text-gray-500 text-sm">{{ gettext('No non-loanable devices assigned.') }}</p>
|
|
|
|
|
{% endif %}
|
2026-06-23 19:57:49 +01:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
{% endblock %}
|