HH/templates/dashboard/my_dashboard.html

448 lines
18 KiB
HTML

{% extends 'layouts/base.html' %}
{% load i18n %}
{% block title %}My Dashboard - PX360{% endblock %}
{% block page_title %}My Dashboard{% endblock %}
{% block content %}
<div class="container-fluid">
<!-- Summary Cards -->
<div class="row g-3 mb-4">
<!-- Total Items -->
<div class="col-lg-2 col-md-4 col-6">
<div class="card table-card border-primary">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<i class="bi bi-inbox fs-2 text-primary"></i>
</div>
<div class="flex-grow-1 ms-3">
<h3 class="mb-0">{{ total_stats.total }}</h3>
<p class="mb-0 text-muted small">Total Items</p>
</div>
</div>
</div>
</div>
</div>
<!-- Open -->
<div class="col-lg-2 col-md-4 col-6">
<div class="card table-card border-warning">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<i class="bi bi-envelope-open fs-2 text-warning"></i>
</div>
<div class="flex-grow-1 ms-3">
<h3 class="mb-0">{{ total_stats.open }}</h3>
<p class="mb-0 text-muted small">Open</p>
</div>
</div>
</div>
</div>
</div>
<!-- In Progress -->
<div class="col-lg-2 col-md-4 col-6">
<div class="card table-card border-info">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<i class="bi bi-hourglass-split fs-2 text-info"></i>
</div>
<div class="flex-grow-1 ms-3">
<h3 class="mb-0">{{ total_stats.in_progress }}</h3>
<p class="mb-0 text-muted small">In Progress</p>
</div>
</div>
</div>
</div>
</div>
<!-- Resolved -->
<div class="col-lg-2 col-md-4 col-6">
<div class="card table-card border-success">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<i class="bi bi-check-circle fs-2 text-success"></i>
</div>
<div class="flex-grow-1 ms-3">
<h3 class="mb-0">{{ total_stats.resolved }}</h3>
<p class="mb-0 text-muted small">Resolved</p>
</div>
</div>
</div>
</div>
</div>
<!-- Closed -->
<div class="col-lg-2 col-md-4 col-6">
<div class="card table-card border-secondary">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<i class="bi bi-x-circle fs-2 text-secondary"></i>
</div>
<div class="flex-grow-1 ms-3">
<h3 class="mb-0">{{ total_stats.closed }}</h3>
<p class="mb-0 text-muted small">Closed</p>
</div>
</div>
</div>
</div>
</div>
<!-- Overdue -->
<div class="col-lg-2 col-md-4 col-6">
<div class="card table-card border-danger">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="flex-shrink-0">
<i class="bi bi-exclamation-triangle fs-2 text-danger"></i>
</div>
<div class="flex-grow-1 ms-3">
<h3 class="mb-0">{{ total_stats.overdue }}</h3>
<p class="mb-0 text-muted small">Overdue</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Chart Row -->
<div class="row g-3 mb-4">
<div class="col-12">
<div class="card table-card">
<div class="card-header">
<h5 class="mb-0"><i class="bi bi-graph-up me-2"></i>{% trans "Completion Trend (Last 30 Days)" %}</h5>
</div>
<div class="card-body">
<div id="completionTrendChart"></div>
</div>
</div>
</div>
</div>
<!-- Filter Bar -->
<div class="card table-card mb-4">
<div class="card-body">
<form method="GET" class="row g-3">
<div class="col-md-3">
<label class="form-label">Date Range</label>
<select name="date_range" class="form-select">
<option value="7" {% if date_range == 7 %}selected{% endif %}>Last 7 days</option>
<option value="30" {% if date_range == 30 %}selected{% endif %}>Last 30 days</option>
<option value="90" {% if date_range == 90 %}selected{% endif %}>Last 90 days</option>
<option value="-1" {% if date_range == -1 %}selected{% endif %}>All time</option>
</select>
</div>
<div class="col-md-3">
<label class="form-label">Search</label>
<input type="text" name="search" class="form-control" value="{{ search_query }}" placeholder="Search...">
</div>
<div class="col-md-2">
<label class="form-label">Status</label>
<select name="status" class="form-select">
<option value="">All</option>
<option value="open" {% if status_filter == 'open' %}selected{% endif %}>Open</option>
<option value="in_progress" {% if status_filter == 'in_progress' %}selected{% endif %}>In Progress</option>
<option value="resolved" {% if status_filter == 'resolved' %}selected{% endif %}>Resolved</option>
<option value="closed" {% if status_filter == 'closed' %}selected{% endif %}>Closed</option>
</select>
</div>
<div class="col-md-2">
<label class="form-label">Priority/Severity</label>
<select name="priority" class="form-select">
<option value="">All</option>
<option value="low" {% if priority_filter == 'low' %}selected{% endif %}>Low</option>
<option value="medium" {% if priority_filter == 'medium' %}selected{% endif %}>Medium</option>
<option value="high" {% if priority_filter == 'high' %}selected{% endif %}>High</option>
<option value="critical" {% if priority_filter == 'critical' %}selected{% endif %}>Critical</option>
</select>
</div>
<div class="col-md-2 d-flex align-items-end">
<button type="submit" class="btn btn-primary w-100">
<i class="bi bi-filter"></i> Apply Filters
</button>
</div>
</form>
</div>
</div>
<!-- Tabs -->
<ul class="nav nav-tabs mb-4" id="dashboardTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link {% if active_tab == 'complaints' %}active{% endif %}"
data-bs-toggle="tab" data-bs-target="#complaints-tab" type="button">
<i class="bi bi-exclamation-triangle"></i>
Complaints <span class="badge bg-danger ms-1">{{ stats.complaints.total }}</span>
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link {% if active_tab == 'inquiries' %}active{% endif %}"
data-bs-toggle="tab" data-bs-target="#inquiries-tab" type="button">
<i class="bi bi-question-circle"></i>
Inquiries <span class="badge bg-info ms-1">{{ stats.inquiries.total }}</span>
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link {% if active_tab == 'observations' %}active{% endif %}"
data-bs-toggle="tab" data-bs-target="#observations-tab" type="button">
<i class="bi bi-eye"></i>
Observations <span class="badge bg-warning ms-1">{{ stats.observations.total }}</span>
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link {% if active_tab == 'actions' %}active{% endif %}"
data-bs-toggle="tab" data-bs-target="#actions-tab" type="button">
<i class="bi bi-clipboard-check"></i>
PX Actions <span class="badge bg-primary ms-1">{{ stats.actions.total }}</span>
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link {% if active_tab == 'tasks' %}active{% endif %}"
data-bs-toggle="tab" data-bs-target="#tasks-tab" type="button">
<i class="bi bi-list-task"></i>
Tasks <span class="badge bg-secondary ms-1">{{ stats.tasks.total }}</span>
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link {% if active_tab == 'feedback' %}active{% endif %}"
data-bs-toggle="tab" data-bs-target="#feedback-tab" type="button">
<i class="bi bi-chat-dots"></i>
Feedback <span class="badge bg-success ms-1">{{ stats.feedback.total }}</span>
</button>
</li>
</ul>
<!-- Tab Content -->
<div class="tab-content">
<!-- Complaints Tab -->
<div class="tab-pane fade {% if active_tab == 'complaints' %}show active{% endif %}" id="complaints-tab">
{% include 'dashboard/partials/complaints_table.html' with data=paginated_data.complaints stats=stats.complaints %}
</div>
<!-- Inquiries Tab -->
<div class="tab-pane fade {% if active_tab == 'inquiries' %}show active{% endif %}" id="inquiries-tab">
{% include 'dashboard/partials/inquiries_table.html' with data=paginated_data.inquiries stats=stats.inquiries %}
</div>
<!-- Observations Tab -->
<div class="tab-pane fade {% if active_tab == 'observations' %}show active{% endif %}" id="observations-tab">
{% include 'dashboard/partials/observations_table.html' with data=paginated_data.observations stats=stats.observations %}
</div>
<!-- Actions Tab -->
<div class="tab-pane fade {% if active_tab == 'actions' %}show active{% endif %}" id="actions-tab">
{% include 'dashboard/partials/actions_table.html' with data=paginated_data.actions stats=stats.actions %}
</div>
<!-- Tasks Tab -->
<div class="tab-pane fade {% if active_tab == 'tasks' %}show active{% endif %}" id="tasks-tab">
{% include 'dashboard/partials/tasks_table.html' with data=paginated_data.tasks stats=stats.tasks %}
</div>
<!-- Feedback Tab -->
<div class="tab-pane fade {% if active_tab == 'feedback' %}show active{% endif %}" id="feedback-tab">
{% include 'dashboard/partials/feedback_table.html' with data=paginated_data.feedback stats=stats.feedback %}
</div>
</div>
</div>
<!-- Bulk Action Modal -->
<div class="modal fade" id="bulkActionModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Bulk Action</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<input type="hidden" id="bulkActionTab">
<div class="mb-3">
<label class="form-label">Select Action</label>
<select id="bulkActionType" class="form-select">
<option value="bulk_status">Change Status</option>
<option value="bulk_assign">Assign to User</option>
</select>
</div>
<div class="mb-3" id="bulkStatusContainer">
<label class="form-label">New Status</label>
<select id="bulkStatus" class="form-select">
<option value="open">Open</option>
<option value="in_progress">In Progress</option>
<option value="resolved">Resolved</option>
<option value="closed">Closed</option>
</select>
</div>
<div class="mb-3 d-none" id="bulkAssignContainer">
<label class="form-label">Assign To</label>
<select id="bulkAssignUser" class="form-select">
<!-- Users will be loaded dynamically -->
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="executeBulkAction">Execute</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
// Completion Trend Chart
const chartElement = document.getElementById('completionTrendChart');
if (chartElement) {
const completionData = {{ chart_data.completion_trend|safe }};
var options = {
series: [{
name: 'Completed Items',
data: completionData.data
}],
chart: {
type: 'bar',
height: 350,
toolbar: {
show: false
}
},
plotOptions: {
bar: {
borderRadius: 4,
columnWidth: '60%'
}
},
colors: ['#22c55e'],
xaxis: {
categories: completionData.labels,
labels: {
style: {
fontSize: '12px'
}
}
},
yaxis: {
min: 0,
forceNiceScale: true,
labels: {
style: {
fontSize: '12px'
}
}
},
grid: {
borderColor: '#e7e7e7',
strokeDashArray: 5
},
tooltip: {
theme: 'light'
},
dataLabels: {
enabled: false
}
};
var chart = new ApexCharts(chartElement, options);
chart.render();
}
// Bulk action handling
const bulkActionModal = new bootstrap.Modal(document.getElementById('bulkActionModal'));
let selectedItems = [];
document.querySelectorAll('.bulk-checkbox').forEach(checkbox => {
checkbox.addEventListener('change', function() {
if (this.checked) {
if (!selectedItems.includes(this.value)) {
selectedItems.push(this.value);
}
} else {
selectedItems = selectedItems.filter(id => id !== this.value);
}
updateBulkActionButtons();
});
});
function updateBulkActionButtons() {
const buttons = document.querySelectorAll('.bulk-action-btn');
buttons.forEach(btn => {
btn.disabled = selectedItems.length === 0;
});
}
document.querySelectorAll('.bulk-action-btn').forEach(btn => {
btn.addEventListener('click', function() {
const tab = this.dataset.tab;
document.getElementById('bulkActionTab').value = tab;
bulkActionModal.show();
});
});
document.getElementById('bulkActionType').addEventListener('change', function() {
if (this.value === 'bulk_status') {
document.getElementById('bulkStatusContainer').classList.remove('d-none');
document.getElementById('bulkAssignContainer').classList.add('d-none');
} else if (this.value === 'bulk_assign') {
document.getElementById('bulkStatusContainer').classList.add('d-none');
document.getElementById('bulkAssignContainer').classList.remove('d-none');
// Load users dynamically
// This is a placeholder - you'd fetch users from an API endpoint
}
});
document.getElementById('executeBulkAction').addEventListener('click', function() {
const tab = document.getElementById('bulkActionTab').value;
const actionType = document.getElementById('bulkActionType').value;
let data = {
action: actionType,
tab: tab,
item_ids: selectedItems
};
if (actionType === 'bulk_status') {
data.new_status = document.getElementById('bulkStatus').value;
} else if (actionType === 'bulk_assign') {
data.user_id = document.getElementById('bulkAssignUser').value;
}
fetch('{% url "dashboard:bulk_action" %}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(result => {
if (result.success) {
alert(`Successfully processed ${result.updated_count} items`);
location.reload();
} else {
alert('Error: ' + result.error);
}
})
.catch(error => {
alert('Error: ' + error.message);
});
});
// Tab switching preserves filters
document.querySelectorAll('[data-bs-toggle="tab"]').forEach(tab => {
tab.addEventListener('shown.bs.tab', function(e) {
const targetTab = e.target.getAttribute('data-bs-target').replace('-tab', '').replace('#', '');
const url = new URL(window.location);
url.searchParams.set('tab', targetTab);
window.history.pushState({}, '', url);
});
});
</script>
{% endblock %}