emile 1 month ago
parent 71e722b0d1
commit a1ebd69efc

Binary file not shown.

@ -0,0 +1,117 @@
{% extends "main.html" %}
{% load static %}
{% block content %}
<link href="https://cdn.jsdelivr.net/npm/tom-select@2.4.3/dist/css/tom-select.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/tom-select@2.4.3/dist/js/tom-select.complete.min.js"></script>
<div class="h-fit w-full flex flex-col items gap-5 rounded-xl bg-gray-50 shadow-md p-5">
<div class="flex flex-row gap-3 justify-between items-center">
<h1 class="text-2xl text-secondosiblue text-center font-semibold">Projects Dashboard</h1>
</div>
<form method="get" id="filter-form">
<div class="w-full flex flex-col gap-10 justify-center items-center">
<div class="flex flex-col lg:flex-row w-full justify-center items-center gap-5">
<div class="w-full max-w-[300px] flex flex-row gap-2 items-center">
<p>From:</p>
<input name="start_date" id="start-date" type="date"
value="{{ start_date }}"
class="w-full border rounded-md outline-none focus:border-primary p-2" />
</div>
<div class="w-full max-w-[300px] flex flex-row gap-2 items-center">
<p>To:</p>
<input name="end_date" id="end-date" type="date"
value="{{ end_date }}"
class="w-full border rounded-md outline-none focus:border-primary p-2" />
</div>
</div>
<div class="w-full flex flex-row flex-wrap gap-5">
<div class="w-full flex flex-1 flex-col items-center">
<p class="font-medium text-secondary">Projects</p>
<select name="projects" id="projects" class="w-full h-full rounded-md z-10 confirm-exit-input" multiple>
{% for project in projects %}
<option value="{{ project.id }}"
{% if project.id in selected_projects %}selected{% endif %}>
{{ project.name }}
</option>
{% endfor %}
</select>
</div>
<div class="w-full flex-1 flex flex-col items-center">
<p class="font-medium text-secondary">Staff</p>
<select name="staff" id="staff" class="w-full h-full rounded-md z-10 confirm-exit-input" multiple>
{% for staff in staffs %}
<option value="{{ staff.id }}"
{% if staff.id in selected_staff %}selected{% endif %}>
{{ staff.user.first_name }} {{ staff.user.last_name }}
</option>
{% endfor %}
</select>
</div>
</div>
<button type="submit" class="bg-primary text-white px-4 py-2 rounded-md">
Apply Filters
</button>
</div>
</form>
<div class="w-full flex flex-col gap-10 justify-center items-center">
<table class="table-auto w-full">
<thead>
<tr>
<th class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">Project</th>
<th class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">Status</th>
<th class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">Date</th>
<th class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">Staff</th>
</tr>
</thead>
<tbody id="status-table-body">
{% for task in tasks %}
<tr>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">{{ task.project.name }}</td>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">{{ task.status }}</td>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">{{ task.start_date }}</td>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">{{ task.assigned_to.user.first_name }} {{ task.assigned_to.user.last_name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Initialize TomSelect for Projects
new TomSelect('#projects', {
create: false,
sortField: 'text',
onChange: function() {
document.getElementById('filter-form').submit();
}
});
// Initialize TomSelect for Staff
new TomSelect('#staff', {
create: false,
sortField: 'text',
onChange: function() {
document.getElementById('filter-form').submit();
}
});
// Submit form when date changes
document.getElementById('start-date').addEventListener('change', function() {
document.getElementById('filter-form').submit();
});
document.getElementById('end-date').addEventListener('change', function() {
document.getElementById('filter-form').submit();
});
});
</script>
{% endblock content %}

@ -91,6 +91,7 @@ urlpatterns = [
path('fetch_epics/', views.fetch_epics, name='fetch_epics'), path('fetch_epics/', views.fetch_epics, name='fetch_epics'),
path('projects/status/<str:status>/', views.fetch_projects_by_status, name='projects_by_status'), path('projects/status/<str:status>/', views.fetch_projects_by_status, name='projects_by_status'),
path('all-projects/', views.fetch_projects_by_status, name='all_projects'), path('all-projects/', views.fetch_projects_by_status, name='all_projects'),
path('projects-dashboard/', views.projects_dashboard, name='projects_dashboard'),
] ]

@ -893,10 +893,6 @@ def addressbookdetails(request, addressbook_id):
@staff_login_required @staff_login_required
def prospecting_lists(request): def prospecting_lists(request):
Country.objects.get_or_create(name='Lebanon') Country.objects.get_or_create(name='Lebanon')
Group.objects.get_or_create(name='Test Group 1')
Group.objects.get_or_create(name='Test Group 2')
Group.objects.get_or_create(name='Test Group 3')
Group.objects.get_or_create(name='Test Group 4')
query = request.GET.get('q', '') query = request.GET.get('q', '')
lists = ProspectingList.objects.all() lists = ProspectingList.objects.all()
@ -910,3 +906,55 @@ def prospecting_lists(request):
'lists': lists, 'lists': lists,
} }
return render(request, 'listing_pages/prospecting-lists.html', context) return render(request, 'listing_pages/prospecting-lists.html', context)
from django.utils.dateparse import parse_date
from django.shortcuts import render
@staff_login_required
def projects_dashboard(request):
# Get all projects and staff for the dropdowns
all_projects = Project.objects.all()
all_staff = StaffProfile.objects.all()
# Initialize variables
selected_project_ids = []
selected_staff_ids = []
start_date = None
end_date = None
# Get filter parameters from GET request
if request.method == 'GET':
selected_project_ids = request.GET.getlist('projects', [])
selected_staff_ids = request.GET.getlist('staff', [])
start_date_str = request.GET.get('start_date', '')
end_date_str = request.GET.get('end_date', '')
# Parse dates
start_date = parse_date(start_date_str) if start_date_str else None
end_date = parse_date(end_date_str) if end_date_str else None
# Filter tasks based on parameters
tasks = Task.objects.all()
if selected_project_ids:
tasks = tasks.filter(project__id__in=selected_project_ids)
if selected_staff_ids:
tasks = tasks.filter(assigned_to__id__in=selected_staff_ids)
if start_date and end_date:
tasks = tasks.filter(end_date__range=[start_date, end_date])
context = {
'projects': all_projects,
'staffs': all_staff, # Changed from 'staff' to match your template
'tasks': tasks,
'selected_projects': [int(id) for id in selected_project_ids if id],
'selected_staff': [int(id) for id in selected_staff_ids if id],
'start_date': start_date_str if start_date else '',
'end_date': end_date_str if end_date else '',
}
return render(request, "projects-dashboard.html", context)

@ -1473,6 +1473,10 @@ video {
max-width: 48rem; max-width: 48rem;
} }
.max-w-\[300px\] {
max-width: 300px;
}
.max-w-\[80\%\] { .max-w-\[80\%\] {
max-width: 80%; max-width: 80%;
} }
@ -1501,6 +1505,10 @@ video {
flex-grow: 0; flex-grow: 0;
} }
.table-auto {
table-layout: auto;
}
.border-collapse { .border-collapse {
border-collapse: collapse; border-collapse: collapse;
} }
@ -1619,6 +1627,10 @@ video {
resize: both; resize: both;
} }
.list-inside {
list-style-position: inside;
}
.list-disc { .list-disc {
list-style-type: disc; list-style-type: disc;
} }
@ -1753,6 +1765,10 @@ video {
align-self: flex-end; align-self: flex-end;
} }
.self-center {
align-self: center;
}
.justify-self-end { .justify-self-end {
justify-self: end; justify-self: end;
} }
@ -1819,6 +1835,10 @@ video {
border-radius: 0px; border-radius: 0px;
} }
.rounded-xl {
border-radius: 0.75rem;
}
.rounded-b-md { .rounded-b-md {
border-bottom-right-radius: 0.375rem; border-bottom-right-radius: 0.375rem;
border-bottom-left-radius: 0.375rem; border-bottom-left-radius: 0.375rem;
@ -3791,6 +3811,10 @@ video {
width: 480px; width: 480px;
} }
.lg\:flex-row {
flex-direction: row;
}
.lg\:text-\[48px\] { .lg\:text-\[48px\] {
font-size: 48px; font-size: 48px;
} }

@ -0,0 +1,61 @@
document.addEventListener('DOMContentLoaded', function () {
// Initialize TomSelect for Projects
new TomSelect('#projects', {
create: false, // Disable creating new options
sortField: 'text',
onChange: function(values) {
updateTasks(); // Update tasks on value change
}
});
// Initialize TomSelect for Staff
new TomSelect('#staff', {
create: false,
sortField: 'text',
onChange: function(values) {
updateTasks(); // Update tasks on value change
}
});
// Update tasks based on filters
function updateTasks() {
const projectIds = Array.from(document.getElementById('projects').selectedOptions).map(option => option.value);
const staffIds = Array.from(document.getElementById('staff').selectedOptions).map(option => option.value);
const startDate = document.getElementById('start-date').value;
const endDate = document.getElementById('end-date').value;
// Construct the query parameters without brackets around the projectIds
let queryParams = `?projects=${projectIds.join(',')}&staff=${staffIds.join(',')}&start_date=${startDate}&end_date=${endDate}`;
// Perform AJAX request
fetch(`/projects-dashboard/${queryParams}`, {
method: 'GET',
headers: {
'X-Requested-With': 'XMLHttpRequest',
},
})
.then(response => response.json())
.then(data => {
// Update table body with new data
const tbody = document.getElementById('status-table-body');
tbody.innerHTML = ''; // Clear the existing table rows
data.tasks_data.forEach(task => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td>${task.project_name}</td>
<td>${task.status}</td>
<td>${task.start_date}</td>
<td>${task.staff}</td>
`;
tbody.appendChild(tr);
});
})
.catch(error => {
console.error('Error updating tasks:', error);
});
}
// Trigger update when date range changes
document.getElementById('start-date').addEventListener('change', updateTasks);
document.getElementById('end-date').addEventListener('change', updateTasks);
});
Loading…
Cancel
Save