{% extends 'base.html.twig' %}
{% block title %}Applications{% endblock %}
{% block content %}
<!-- Page Header -->
<div class="d-flex align-items-center justify-content-between mb-3">
<div class="d-flex align-items-center">
<div class="bg-primary bg-opacity-10 rounded d-flex align-items-center justify-content-center me-3" style="width: 40px; height: 40px;">
<i data-lucide="file-text" class="text-primary" style="width: 20px; height: 20px;"></i>
</div>
<div>
<h4 class="mb-0 fw-semibold">Applications</h4>
<span class="text-muted small">{{ applications.totalItemCount }} total applications</span>
</div>
</div>
<div class="d-flex gap-2">
<button type="button" class="btn btn-outline-primary btn-sm" data-bs-toggle="modal" data-bs-target="#exportApplicationModal">
<i data-lucide="download" style="width: 14px; height: 14px;" class="me-1"></i> Export
</button>
<button type="button" class="btn btn-outline-primary btn-sm" data-bs-toggle="modal" data-bs-target="#exportHistoryModal">
<i data-lucide="clock" style="width: 14px; height: 14px;" class="me-1"></i> Export History
</button>
{% if not is_granted('ROLE_READ_ONLY') %}
<a href="{{ path('application_create') }}" class="btn btn-primary btn-sm">
<i data-lucide="plus" style="width: 14px; height: 14px;" class="me-1"></i> New Application
</a>
{% endif %}
</div>
</div>
<!-- Filters -->
{% include 'application/_partials/filters.html.twig' %}
<!-- Applications Table -->
<div class="card">
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-sm table-hover mb-0">
<thead class="bg-light">
<tr class="small">
<th class="border-0" style="width: 25%;">Company</th>
<th class="border-0">MCC</th>
<th class="border-0">Instance</th>
<th class="border-0">Created</th>
<th class="border-0" style="width: 28%;">Products & Status</th>
<th class="border-0 text-center">Type</th>
</tr>
</thead>
<tbody>
{% for application in applications.items %}
{% set firstProduct = application.product_statuses is defined and application.product_statuses|length > 0 ? application.product_statuses|first : null %}
{% set rowUrl = application.app_token and firstProduct ? path('application_view', {token: application.app_token, product: firstProduct.product_name|default('')|lower|replace({' ': '-', '_': '-'})}) : '#' %}
<tr style="cursor: pointer;" onclick="window.location='{{ rowUrl }}';">
<td>
<div class="d-flex align-items-center text-decoration-none text-reset">
<div class="flex-shrink-0 me-2">
<div class="bg-secondary bg-opacity-10 rounded d-flex align-items-center justify-content-center" style="width: 32px; height: 32px;">
<i data-lucide="building-2" class="text-secondary" style="width: 16px; height: 16px;"></i>
</div>
</div>
<div class="min-width-0">
<div class="fw-medium small text-truncate">{{ application.comp_legal_name|default('-') }}</div>
{% if application.comp_uic|default('') %}
<code class="small text-muted">{{ application.comp_uic }}</code>
{% endif %}
</div>
</div>
</td>
<td>
<span class="small">{{ application.ba_mcc|default('-') }}</span>
</td>
<td>
<span class="badge bg-light text-dark">{{ application.app_instance|instance }}</span>
</td>
<td>
<span class="small text-muted">
{{ application.app_created_at|date('d/m/Y H:i') }}
</span>
</td>
<td>
{% if application.product_statuses is defined and application.product_statuses|length > 0 %}
<div class="d-flex flex-wrap gap-1">
{% for productStatus in application.product_statuses %}
{% set productName = productStatus.product_name|default('') %}
{% set status = productStatus.status|default('') %}
{% set statusColor = status == 'approved' ? 'success' : (status == 'rejected' or status == 'declined' ? 'danger' : (status == 'pending' or status == 'under_review' or status == 'in_review' ? 'warning' : 'secondary')) %}
{% set productSlug = productName|lower|replace({' ': '-', '_': '-'}) %}
{% set productUrl = application.app_token ? path('application_view', {token: application.app_token, product: productSlug}) : '#' %}
<a href="{{ productUrl }}" class="text-decoration-none" onclick="event.stopPropagation();">
<span class="badge bg-{{ statusColor }}-subtle text-{{ statusColor }}" style="font-size: 10px;">
{{ productName|upper }}
{% if status %}
<span class="opacity-75">• {{ status|replace({'_': ' '})|title }}</span>
{% endif %}
</span>
</a>
{% endfor %}
</div>
{% else %}
<span class="text-muted small">-</span>
{% endif %}
</td>
<td class="text-center">
{% if application.app_channel is defined %}
{% if application.app_channel == 'api' %}
<span class="badge bg-info-subtle text-info" data-bs-toggle="tooltip" title="Submitted via API">
<i data-lucide="zap" style="width: 10px; height: 10px;" class="me-1"></i>Auto
</span>
{% elseif application.app_channel == 'admin' %}
<span class="badge bg-primary-subtle text-primary" data-bs-toggle="tooltip" title="Created manually">
<i data-lucide="user" style="width: 10px; height: 10px;" class="me-1"></i>Manual
</span>
{% else %}
<span class="badge bg-secondary-subtle text-secondary">Unknown</span>
{% endif %}
{% else %}
<span class="badge bg-secondary-subtle text-secondary">-</span>
{% endif %}
</td>
</tr>
{% else %}
<tr>
<td colspan="7" class="text-center py-5 text-muted">
<i data-lucide="file-x" class="mb-2" style="width: 32px; height: 32px;"></i>
<p class="mb-0">No applications found</p>
<p class="small">Try adjusting your filters</p>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% if applications.totalItemCount > 0 %}
<div class="card-footer py-2 bg-light">
{{ knp_pagination_render(applications) }}
</div>
{% endif %}
</div>
{% embed 'application/modals/_export-application-modal.html.twig' %}
{% block export_modal_js %}{% endblock %}
{% endembed %}
{% embed 'export/_export-history-modal.html.twig' %}
{% block export_history_js %}{% endblock %}
{% endembed %}
{% endblock %}
{% block css %}
{{ parent() }}
<style>
#advancedFilters {
display: none;
}
#advancedFilters.show {
display: block;
}
</style>
{% endblock %}
{% block js %}
{{ parent() }}
<script>
$(document).ready(function() {
// Initialize Lucide icons
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
// Handle advanced filters toggle manually
var toggleBtn = document.getElementById('toggleAdvancedFilters');
var advancedFilters = document.getElementById('advancedFilters');
if (toggleBtn && advancedFilters) {
toggleBtn.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
if (advancedFilters.classList.contains('show')) {
advancedFilters.classList.remove('show');
toggleBtn.setAttribute('aria-expanded', 'false');
} else {
advancedFilters.classList.add('show');
toggleBtn.setAttribute('aria-expanded', 'true');
}
});
}
// Initialize flatpickr for date fields
if (typeof flatpickr !== 'undefined') {
var $fromInput = $('input[name*="createdAtFrom"]');
var $toInput = $('input[name*="createdAtTo"]');
if ($fromInput.length && $toInput.length) {
var fromPicker = flatpickr($fromInput[0], {
dateFormat: 'Y-m-d',
altInput: true,
altFormat: 'd/m/Y',
allowInput: true,
onChange: function() {
var date = this.selectedDates[0] || null;
toPicker.set('minDate', date);
}
});
var toPicker = flatpickr($toInput[0], {
dateFormat: 'Y-m-d',
altInput: true,
altFormat: 'd/m/Y',
allowInput: true,
onChange: function() {
if (this.selectedDates[0] && fromPicker.selectedDates[0] && this.selectedDates[0] < fromPicker.selectedDates[0]) {
this.setDate(null);
alert('End date cannot be before start date');
}
}
});
$fromInput.on('input', function() {
setTimeout(function() {
var date = fromPicker.parseDate($fromInput.val(), 'Y-m-d');
toPicker.set('minDate', date && !isNaN(date.getTime()) ? date : null);
}, 100);
});
} else {
flatpickr('.flatpickr-date', { dateFormat: 'Y-m-d', altInput: true, altFormat: 'd/m/Y', allowInput: true });
}
}
// Initialize Bootstrap tooltips
$('[data-bs-toggle="tooltip"]').each(function() {
new bootstrap.Tooltip(this);
});
});
</script>
{% embed 'application/modals/_export-application-modal.html.twig' %}
{% block export_modal_html %}{% endblock %}
{% block export_modal_js %}{{ parent() }}{% endblock %}
{% endembed %}
{% embed 'export/_export-history-modal.html.twig' %}
{% block export_history_html %}{{ parent() }}{% endblock %}
{% block export_history_js %}{{ parent() }}{% endblock %}
{% endembed %}
{% endblock %}