New Changes.

main
nataly 12 months ago
parent 039e092cee
commit e7b5200fc0

@ -12,7 +12,6 @@ from weasyprint import HTML, CSS
@staff_login_required
def add_product(request, *args, **kwargs):
item_types = ProjectType.objects.all().order_by('name')
@ -214,6 +213,7 @@ def add_payment_comment_modal(request):
def add_invoice_pdf(request, order_id):
order = get_object_or_404(Order, id=order_id)
@ -334,3 +334,8 @@ def add_payment_pdf(request, order_id):

Binary file not shown.

@ -456,7 +456,7 @@
<div class="w-full h-full flex flex-col justify-between items-center">
<div class="w-full flex justify-between items-center">
<p class="text-[22px] text-secondosiblue font-poppinsBold uppercase">Projects</p>
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 625.51 595.28" class="w-[60px]">
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 625.51 595.28" class="w-[55px]">
<defs>
<style>
.cls-1 {
@ -495,7 +495,7 @@
<div class="w-full h-full flex flex-col justify-between items-center">
<div class="w-full flex justify-between items-center">
<p class="text-[22px] text-secondosiblue font-poppinsBold uppercase">Tickets</p>
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 625.51 595.28" class="w-[60px]">
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 625.51 595.28" class="w-[55px]">
<defs>
<style>
.cls-1 {

@ -89,15 +89,12 @@
<!-- PROJECT MANAGER -->
<div>
<p class="text-gray-500 text-xl">Project Manager:</p>
<div
class="w-fit flex justify-start items-center gap-1 px-9 py-3 bg-gray-100 rounded-md shadow-md mt-2">
<div class="w-fit flex justify-start items-center gap-1 px-9 py-3 bg-gray-100 rounded-md shadow-md mt-2">
<div class="w-[50px] h-[50px] rounded-full bg-white">
{% if project.manager.image %}
<img src="{{project.manager.image.url}}"
class="w-full h-full rounded-full object-cover">
<img src="{{project.manager.image.url}}" class="w-full h-full rounded-full object-cover">
{% else %}
<img src="{% static 'images/default-user.png' %}"
class="w-full h-full rounded-full object-cover">
<img src="{% static 'images/default-user.png' %}" class="w-full h-full rounded-full object-cover">
{% endif %}
</div>
@ -116,8 +113,7 @@
<div class="flex justify-start items-center gap-1">
<div class="w-[50px] h-[50px] rounded-full bg-white">
{% if member.image %}
<img src="{{member.image.url}}"
class="w-full h-full rounded-full object-cover">
<img src="{{member.image.url}}" class="w-full h-full rounded-full object-cover">
{% else %}
<img src="{% static 'images/default-user.png' %}"
class="w-full h-full rounded-full object-cover">
@ -421,6 +417,7 @@
</div>
</div>
<!-- NOTES -->
<div class="w-full mt-5">
<div

@ -1,5 +1,20 @@
{% load static %}
<div class="w-full flex justify-center items-center p-5 hidden" id="epicLoader">
<div role="status">
<svg aria-hidden="true" class="w-12 h-12 text-gray-200 animate-spin dark:text-gray-600 fill-osiblue"
viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor" />
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill" />
</svg>
</div>
</div>
<div
class="flex flex-col md:flex-row justify-between items-center gap-3 bg-gray-100 border border-gray-100 text-white py-2 px-3 rounded-md shadow-md">
<div>

@ -21,12 +21,13 @@
</button>
</div>
<select name="" id=""
class="border border-gray-300 p-2 rounded-md outline-none w-full md:w-[160px] text-gray-500 h-[40px]">
<option value="" disabled selected>Status</option>
<option value="">Open</option>
<option value="">Working On</option>
<option value="">Closed</option>
<select name="" id="statusesSelectTag"
class="border border-gray-300 p-2 rounded-md outline-none w-full md:w-[250px] text-gray-500 h-[40px]">
<option value="All">All</option>
<option value="Pending">Pending</option>
<option value="In Progress" selected>In Progress</option>
<option value="Completed">Completed</option>
<option value="Cancelled">Cancelled</option>
</select>
</div>
<div class="w-full md:w-fit">
@ -40,8 +41,22 @@
</div>
<div class="w-full flex justify-center items-center p-5 hidden" id="projectLoader">
<div role="status">
<svg aria-hidden="true" class="w-12 h-12 text-gray-400 animate-spin dark:text-gray-600 fill-osiblue"
viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor" />
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill" />
</svg>
</div>
</div>
<div class="w-full flex flex-col gap-5 mt-5">
<!-- ALL PROJECTS -->
<div class="w-full flex flex-col gap-5 mt-3 hidden" id="allProjectsContainer">
{% for project in projects %}
<div class="w-full h-fit bg-white rounded-md shadow-md p-3 projectContainer">
<p id="projectId" class="hidden">{{project.id}}</p>
@ -79,7 +94,8 @@
d="M6 6.878V6a2.25 2.25 0 0 1 2.25-2.25h7.5A2.25 2.25 0 0 1 18 6v.878m-12 0c.235-.083.487-.128.75-.128h10.5c.263 0 .515.045.75.128m-12 0A2.25 2.25 0 0 0 4.5 9v.878m13.5-3A2.25 2.25 0 0 1 19.5 9v.878m0 0a2.246 2.246 0 0 0-.75-.128H5.25c-.263 0-.515.045-.75.128m15 0A2.25 2.25 0 0 1 21 12v6a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 18v-6c0-.98.626-1.813 1.5-2.122" />
</svg>
<p class="text-secondosiblue"><span class="font-poppinsBold">{{project.open_user_tasks_count}}</span> Open {% if project.open_user_tasks_count == 1 %} Task {% else %} Tasks {% endif %}</p>
<p class="text-secondosiblue"><span
class="font-poppinsBold">{{project.open_user_tasks_count}}</span> Open {% if project.open_user_tasks_count == 1 %} Task {% else %} Tasks {% endif %}</p>
</div>
@ -100,15 +116,15 @@
</div>
<!-- Action Buttons -->
<div class="w-full border-t border-b l:border-b-0 border-gray-200 grid grid-cols-1 s:grid-cols-3">
<div
class="w-full border-t border-b l:border-b-0 border-gray-200 grid grid-cols-1 s:grid-cols-3">
<a href="{% url 'detailed-project' project.project_id %}"
class="p-3 border-b s:border-b-0 border-r-0 s:border-r border-gray-200 text-base bg-gray-50 text-secondosiblue flex justify-center items-center">View</a>
<a href="{% url 'editproject' project.project_id %}"
class="p-3 text-base bg-gray-50 border-b s:border-b-0 border-r-0 s:border-r border-gray-200 text-secondosiblue flex justify-center items-center">Edit</a>
<button
class="p-3 text-base bg-gray-50 text-secondosiblue deleteProjectButton"
<button class="p-3 text-base bg-gray-50 text-secondosiblue deleteProjectButton"
data-modal-url="{% url 'deleteprojectmodal' project.id %}">Delete</button>
</div>
</div>
@ -119,8 +135,8 @@
{% with last_note=project.note_set.last %}
<div class="w-full h-full flex flex-col gap-3 justify-center items-center p-3">
<p class="text-secondosiblue break-all whitespace-pre-wrap">{{ last_note.text }}</p>
<div
class="w-[30px] h-[30px] rounded-full shadow-md p-1 flex justify-center items-center bg-gray-100 cursor-pointer hover:scale-105 duration-300 addProjectNoteButton" data-modal-url="{% url 'addprojectnotemodal' project.project_id %}">
<div class="w-[30px] h-[30px] rounded-full shadow-md p-1 flex justify-center items-center bg-gray-100 cursor-pointer hover:scale-105 duration-300 addProjectNoteButton"
data-modal-url="{% url 'addprojectnotemodal' project.project_id %}">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3"
stroke="currentColor" class="w-6 h-6 text-secondosiblue">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
@ -131,8 +147,114 @@
{% else %}
<div class="w-full h-full flex flex-col justify-center items-center gap-3 p-3">
<p class="text-secondosiblue">No Recent Note</p>
<div class="w-[30px] h-[30px] rounded-full shadow-md p-1 flex justify-center items-center bg-gray-100 cursor-pointer hover:scale-105 duration-300 addProjectNoteButton"
data-modal-url="{% url 'addprojectnotemodal' project.project_id %}">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3"
stroke="currentColor" class="w-6 h-6 text-secondosiblue">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
</svg>
</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<!-- IN PROGRESS PROJECTS -->
<div class="w-full flex flex-col gap-5 mt-3" id="inProgressProjectsContainer">
{% for project in in_progress_projects %}
<div
class="w-full h-fit bg-white rounded-md shadow-md p-3 projectContainer">
<p id="projectId" class="hidden">{{project.id}}</p>
<p class="hidden startDate">{{project.start_date}}</p>
<p class="hidden endDate">{{project.end_date}}</p>
<div class="w-full bg-white h-fit rounded-md border border-gray-200">
<div class="w-full px-5 py-5 bg-orange-500 flex justify-center items-center text-center text-white rounded-t-md text-[17px] s:text-[20px]">
<p>{{project.name}}</p>
</div>
<!-- Progress Bar -->
<div class="w-full h-[8px] bg-gray-100 mainBar">
<div class="h-full progressBar">
</div>
</div>
<div class="w-full grid grid-cols-1 l:grid-cols-2">
<!-- Left Section -->
<div class="flex flex-col justify-between">
<!-- Details -->
<div class="w-full flex flex-col gap-3 p-5">
<div class="w-full flex justify-start items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor" class="w-6 h-6 text-secondosiblue">
<path stroke-linecap="round" stroke-linejoin="round"
d="M6 6.878V6a2.25 2.25 0 0 1 2.25-2.25h7.5A2.25 2.25 0 0 1 18 6v.878m-12 0c.235-.083.487-.128.75-.128h10.5c.263 0 .515.045.75.128m-12 0A2.25 2.25 0 0 0 4.5 9v.878m13.5-3A2.25 2.25 0 0 1 19.5 9v.878m0 0a2.246 2.246 0 0 0-.75-.128H5.25c-.263 0-.515.045-.75.128m15 0A2.25 2.25 0 0 1 21 12v6a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 18v-6c0-.98.626-1.813 1.5-2.122" />
</svg>
<p class="text-secondosiblue"><span
class="font-poppinsBold">{{project.open_user_tasks_count}}</span> Open {% if project.open_user_tasks_count == 1 %} Task {% else %} Tasks {% endif %}</p>
</div>
<div class="w-full flex justify-start items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke-width="1.5" stroke="currentColor" class="w-6 h-6 text-secondosiblue">
<path stroke-linecap="round" stroke-linejoin="round"
d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
</svg>
<p class="text-secondosiblue">Total Time: <span
class="font-poppinsBold">{{project.total_time_worked_hours}}hr
{{project.total_time_worked_minutes}}min
{{project.total_time_worked_seconds}}sec</span>
</p>
</div>
</div>
<!-- Action Buttons -->
<div
class="w-[30px] h-[30px] rounded-full shadow-md p-1 flex justify-center items-center bg-gray-100 cursor-pointer hover:scale-105 duration-300 addProjectNoteButton" data-modal-url="{% url 'addprojectnotemodal' project.project_id %}">
class="w-full border-t border-b l:border-b-0 border-gray-200 grid grid-cols-1 s:grid-cols-3">
<a href="{% url 'detailed-project' project.project_id %}"
class="p-3 border-b s:border-b-0 border-r-0 s:border-r border-gray-200 text-base bg-gray-50 text-secondosiblue flex justify-center items-center">View</a>
<a href="{% url 'editproject' project.project_id %}"
class="p-3 text-base bg-gray-50 border-b s:border-b-0 border-r-0 s:border-r border-gray-200 text-secondosiblue flex justify-center items-center">Edit</a>
<button class="p-3 text-base bg-gray-50 text-secondosiblue deleteProjectButton"
data-modal-url="{% url 'deleteprojectmodal' project.id %}">Delete</button>
</div>
</div>
<!-- Right Section - Recent Notes -->
<div class="w-full border-l-none l:border-l border-gray-200">
{% if project.note_set.exists %}
{% with last_note=project.note_set.last %}
<div class="w-full h-full flex flex-col gap-3 justify-center items-center p-3">
<p class="text-secondosiblue break-all whitespace-pre-wrap">{{ last_note.text }}</p>
<div class="w-[30px] h-[30px] rounded-full shadow-md p-1 flex justify-center items-center bg-gray-100 cursor-pointer hover:scale-105 duration-300 addProjectNoteButton"
data-modal-url="{% url 'addprojectnotemodal' project.project_id %}">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3"
stroke="currentColor" class="w-6 h-6 text-secondosiblue">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
</svg>
</div>
</div>
{% endwith %}
{% else %}
<div class="w-full h-full flex flex-col justify-center items-center gap-3 p-3">
<p class="text-secondosiblue">No Recent Note</p>
<div class="w-[30px] h-[30px] rounded-full shadow-md p-1 flex justify-center items-center bg-gray-100 cursor-pointer hover:scale-105 duration-300 addProjectNoteButton"
data-modal-url="{% url 'addprojectnotemodal' project.project_id %}">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3"
stroke="currentColor" class="w-6 h-6 text-secondosiblue">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
@ -147,7 +269,14 @@
</div>
{% endfor %}
</div>
<!-- PROJECTS BY STATUS -->
<div class="w-full flex flex-col gap-5 mt-3" id="projectsByStatusContainer">
</div>
</div>
<!-- POPUP MODAL -->
@ -163,6 +292,8 @@
<script type="text/javascript" src='{% static "js/pop-modals.js" %}'></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!---------------------- JS SCRIPTS -------------------->
@ -170,4 +301,7 @@
<script type="text/javascript" src='{% static "js/calculate-all-projects-time.js" %}'></script>
<script type="text/javascript" src='{% static "js/projects-filtering.js" %}'></script>
{% endblock content %}

@ -0,0 +1,97 @@
{% load static %}
{% for project in projects %}
<div class="w-full h-fit bg-white rounded-md shadow-md p-3 projectContainer">
<p id="projectId" class="hidden">{{project.id}}</p>
<div class="w-full bg-white h-fit rounded-md border border-gray-200">
<div class="w-full px-5 py-5 {% if project.projectstatus_set.all.last.status == 'Completed' %}bg-green-700{% endif %}
{% if project.projectstatus_set.all.last.status == 'Cancelled' %}bg-red-500{% endif %}
{% if project.projectstatus_set.all.last.status == 'In Progress' %}bg-orange-500{% endif %}
{% if project.projectstatus_set.all.last.status == 'Pending' %}bg-yellow-500{% endif %}
flex justify-center items-center text-center text-white rounded-t-md text-[17px] s:text-[20px]">
<p>{{project.name}}</p>
</div>
<div class="w-full grid grid-cols-1 l:grid-cols-2">
<!-- Left Section -->
<div class="flex flex-col justify-between">
<!-- Details -->
<div class="w-full flex flex-col gap-3 p-5">
<div class="w-full flex justify-start items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="w-6 h-6 text-secondosiblue">
<path stroke-linecap="round" stroke-linejoin="round"
d="M6 6.878V6a2.25 2.25 0 0 1 2.25-2.25h7.5A2.25 2.25 0 0 1 18 6v.878m-12 0c.235-.083.487-.128.75-.128h10.5c.263 0 .515.045.75.128m-12 0A2.25 2.25 0 0 0 4.5 9v.878m13.5-3A2.25 2.25 0 0 1 19.5 9v.878m0 0a2.246 2.246 0 0 0-.75-.128H5.25c-.263 0-.515.045-.75.128m15 0A2.25 2.25 0 0 1 21 12v6a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 18v-6c0-.98.626-1.813 1.5-2.122" />
</svg>
<p class="text-secondosiblue"><span
class="font-poppinsBold">{{project.open_user_tasks_count}}</span> Open
{% if project.open_user_tasks_count == 1 %} Task {% else %} Tasks {% endif %}</p>
</div>
<div class="w-full flex justify-start items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="w-6 h-6 text-secondosiblue">
<path stroke-linecap="round" stroke-linejoin="round"
d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
</svg>
<p class="text-secondosiblue">Total Time: <span
class="font-poppinsBold">{{project.total_time_worked_hours}}hr
{{project.total_time_worked_minutes}}min
{{project.total_time_worked_seconds}}sec</span>
</p>
</div>
</div>
<!-- Action Buttons -->
<div class="w-full border-t border-b l:border-b-0 border-gray-200 grid grid-cols-1 s:grid-cols-3">
<a href="{% url 'detailed-project' project.project_id %}"
class="p-3 border-b s:border-b-0 border-r-0 s:border-r border-gray-200 text-base bg-gray-50 text-secondosiblue flex justify-center items-center">View</a>
<a href="{% url 'editproject' project.project_id %}"
class="p-3 text-base bg-gray-50 border-b s:border-b-0 border-r-0 s:border-r border-gray-200 text-secondosiblue flex justify-center items-center">Edit</a>
<button class="p-3 text-base bg-gray-50 text-secondosiblue deleteProjectButton"
data-modal-url="{% url 'deleteprojectmodal' project.id %}">Delete</button>
</div>
</div>
<!-- Right Section - Recent Notes -->
<div class="w-full border-l-none l:border-l border-gray-200">
{% if project.note_set.exists %}
{% with last_note=project.note_set.last %}
<div class="w-full h-full flex flex-col gap-3 justify-center items-center p-3">
<p class="text-secondosiblue break-all whitespace-pre-wrap">{{ last_note.text }}</p>
<div class="w-[30px] h-[30px] rounded-full shadow-md p-1 flex justify-center items-center bg-gray-100 cursor-pointer hover:scale-105 duration-300 addProjectNoteButton"
data-modal-url="{% url 'addprojectnotemodal' project.project_id %}">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3"
stroke="currentColor" class="w-6 h-6 text-secondosiblue">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
</svg>
</div>
</div>
{% endwith %}
{% else %}
<div class="w-full h-full flex flex-col justify-center items-center gap-3 p-3">
<p class="text-secondosiblue">No Recent Note</p>
<div class="w-[30px] h-[30px] rounded-full shadow-md p-1 flex justify-center items-center bg-gray-100 cursor-pointer hover:scale-105 duration-300 addProjectNoteButton"
data-modal-url="{% url 'addprojectnotemodal' project.project_id %}">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3"
stroke="currentColor" class="w-6 h-6 text-secondosiblue">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
</svg>
</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}

@ -80,6 +80,7 @@ urlpatterns = [
path('getupdatedactivities/', views.get_latest_activities, name='getupdatedactivities'),
path('recent-activities-page/', views.recent_activities_page, name='recentactivitiespage'),
path('fetch_epics/', views.fetch_epics, name='fetch_epics'),
path('projects/status/<str:status>/', views.fetch_projects_by_status, name='projects_by_status'),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

@ -21,6 +21,7 @@ from django.conf import settings
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from customercore .models import *
from django.db.models import Max
def login_with_email(request, email, key):
@ -269,6 +270,8 @@ def staffs(request):
@staff_login_required
def my_projects(request, *args, **kwargs):
user = request.user
@ -282,7 +285,14 @@ def my_projects(request, *args, **kwargs):
Q(manager=user.staffprofile) | Q(members=user.staffprofile)
).distinct().order_by('-project_id')
# Fetch projects with their last status as "In Progress"
in_progress_projects = []
for project in projects:
last_status = project.projectstatus_set.aggregate(last_status=Max('date', filter=Q(status='In Progress')))
if last_status['last_status']:
in_progress_projects.append(project)
for project in in_progress_projects:
total_time_seconds = 0
# Modify task queryset based on user role
if user.is_superuser:
@ -307,18 +317,18 @@ def my_projects(request, *args, **kwargs):
else:
open_user_tasks_count = Task.objects.filter(project=project, assigned_to=user.staffprofile).exclude(status='Closed').count()
project.open_user_tasks_count = open_user_tasks_count
context = {
'projects': projects,
'in_progress_projects': in_progress_projects, # Add in-progress projects to context
}
return render(request, 'listing_pages/projects.html', context)
@staff_login_required
def my_tasks(request, *args, **kwargs):
if request.user.is_superuser:
@ -825,3 +835,39 @@ def reset_password(request, uidb64, token):
return render(request, 'forgot-password-confirmation.html')
else:
return HttpResponse('Activation link is invalid!')
def fetch_projects_by_status(request, status):
projects = Project.objects.filter(projectstatus__status=status)
for project in projects:
total_time_seconds = 0
open_user_tasks_count = 0
# Modify task queryset based on user role
if request.user.is_superuser:
tasks = project.task_set.all()
open_user_tasks_count = Task.objects.filter(project=project).exclude(status='Closed').count()
else:
tasks = project.task_set.filter(assigned_to=request.user.staffprofile)
open_user_tasks_count = Task.objects.filter(project=project, assigned_to=request.user.staffprofile).exclude(status='Closed').count()
for task in tasks:
total_time_hours, total_time_minutes, total_time_seconds_task = task.total_task_time()
total_time_seconds += (total_time_hours * 3600) + (total_time_minutes * 60) + total_time_seconds_task
total_time_hours = total_time_seconds // 3600
total_time_minutes = (total_time_seconds % 3600) // 60
total_time_seconds = total_time_seconds % 60
project.total_time_worked_hours = total_time_hours
project.total_time_worked_minutes = total_time_minutes
project.total_time_worked_seconds = total_time_seconds
project.open_user_tasks_count = open_user_tasks_count
context = {
'projects': projects,
'status': status,
}
return render(request, 'projects-by-status.html', context)

@ -628,6 +628,18 @@ video {
}
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
.pointer-events-none {
pointer-events: none;
}
@ -1068,10 +1080,18 @@ video {
height: 1.5rem;
}
.h-7 {
height: 1.75rem;
}
.h-8 {
height: 2rem;
}
.h-9 {
height: 2.25rem;
}
.h-\[100px\] {
height: 100px;
}
@ -1120,6 +1140,10 @@ video {
height: 210px;
}
.h-\[250px\] {
height: 250px;
}
.h-\[25px\] {
height: 25px;
}
@ -1210,36 +1234,8 @@ video {
height: 100vh;
}
.h-\[5px\] {
height: 5px;
}
.h-9 {
height: 2.25rem;
}
.h-\[300px\] {
height: 300px;
}
.h-\[250px\] {
height: 250px;
}
.h-\[3\] {
height: 3;
}
.h-7 {
height: 1.75rem;
}
.h-\[65px\] {
height: 65px;
}
.h-\[\] {
height: ;
.h-12 {
height: 3rem;
}
.max-h-\[50px\] {
@ -1286,6 +1282,10 @@ video {
width: 1.5rem;
}
.w-7 {
width: 1.75rem;
}
.w-8 {
width: 2rem;
}
@ -1338,6 +1338,10 @@ video {
width: 22px;
}
.w-\[240px\] {
width: 240px;
}
.w-\[25\%\] {
width: 25%;
}
@ -1443,32 +1447,8 @@ video {
width: 100%;
}
.w-\[80px\] {
width: 80px;
}
.w-7 {
width: 1.75rem;
}
.w-\[550px\] {
width: 550px;
}
.w-\[65px\] {
width: 65px;
}
.w-\[200px\] {
width: 200px;
}
.w-\[230px\] {
width: 230px;
}
.w-\[240px\] {
width: 240px;
.w-12 {
width: 3rem;
}
.min-w-full {
@ -1895,6 +1875,11 @@ video {
border-right-width: 1px;
}
.border-y {
border-top-width: 1px;
border-bottom-width: 1px;
}
.border-b {
border-bottom-width: 1px;
}
@ -2224,6 +2209,11 @@ video {
background-color: rgb(249 168 212 / var(--tw-bg-opacity));
}
.bg-pink-700 {
--tw-bg-opacity: 1;
background-color: rgb(190 24 93 / var(--tw-bg-opacity));
}
.bg-purple-200 {
--tw-bg-opacity: 1;
background-color: rgb(233 213 255 / var(--tw-bg-opacity));
@ -2303,6 +2293,11 @@ video {
background-color: rgb(254 240 138 / var(--tw-bg-opacity));
}
.bg-yellow-300 {
--tw-bg-opacity: 1;
background-color: rgb(253 224 71 / var(--tw-bg-opacity));
}
.bg-yellow-400 {
--tw-bg-opacity: 1;
background-color: rgb(250 204 21 / var(--tw-bg-opacity));
@ -2318,16 +2313,6 @@ video {
background-color: rgb(202 138 4 / var(--tw-bg-opacity));
}
.bg-pink-700 {
--tw-bg-opacity: 1;
background-color: rgb(190 24 93 / var(--tw-bg-opacity));
}
.bg-yellow-300 {
--tw-bg-opacity: 1;
background-color: rgb(253 224 71 / var(--tw-bg-opacity));
}
.bg-opacity-10 {
--tw-bg-opacity: 0.1;
}
@ -2482,6 +2467,10 @@ video {
fill: #374a7a;
}
.fill-blue-600 {
fill: #2563eb;
}
.stroke-black {
stroke: #000;
}
@ -2491,6 +2480,10 @@ video {
object-fit: cover;
}
.p-0 {
padding: 0px;
}
.p-1 {
padding: 0.25rem;
}
@ -2523,10 +2516,6 @@ video {
padding: 2.25rem;
}
.p-0 {
padding: 0px;
}
.px-0 {
padding-left: 0px;
padding-right: 0px;
@ -2648,6 +2637,10 @@ video {
padding-bottom: 1.5rem;
}
.pb-9 {
padding-bottom: 2.25rem;
}
.pb-\[50px\] {
padding-bottom: 50px;
}
@ -2680,10 +2673,6 @@ video {
padding-top: 2.25rem;
}
.pb-9 {
padding-bottom: 2.25rem;
}
.text-left {
text-align: left;
}
@ -2949,10 +2938,6 @@ video {
color: rgb(234 179 8 / var(--tw-text-opacity));
}
.text-\[xl\] {
color: xl;
}
.underline {
text-decoration-line: underline;
}
@ -3349,10 +3334,9 @@ video {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.hover\:scale-100:hover {
--tw-scale-x: 1;
--tw-scale-y: 1;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
.hover\:bg-gray-100:hover {
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
}
.hover\:bg-gray-50:hover {
@ -3379,11 +3363,6 @@ video {
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.hover\:bg-gray-100:hover {
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
}
.hover\:bg-opacity-60:hover {
--tw-bg-opacity: 0.6;
}
@ -3575,18 +3554,10 @@ video {
flex-direction: row;
}
.s\:items-center {
align-items: center;
}
.s\:justify-end {
justify-content: flex-end;
}
.s\:justify-between {
justify-content: space-between;
}
.s\:gap-0 {
gap: 0px;
}
@ -3692,6 +3663,10 @@ video {
width: fit-content;
}
.md\:w-\[250px\] {
width: 250px;
}
.md\:grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
@ -3937,10 +3912,6 @@ video {
}
@media (min-width: 1600px) {
.xll\:mt-1 {
margin-top: 0.25rem;
}
.xll\:flex {
display: flex;
}
@ -3961,10 +3932,6 @@ video {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.xll\:rounded-none {
border-radius: 0px;
}
.xll\:text-left {
text-align: left;
}

@ -1,40 +1,42 @@
// OPEN TASKS
function fetchOpenTasks() {
var projectId = $('#projectId').text().trim();
$('#epicLoader').removeClass('hidden');
$.ajax({
url: '/open_tasks_for_project/' + projectId + '/',
method: 'GET',
success: function (data) {
// console.log('Success:', data);
$('#epicRelatedTasksContainer').empty();
$('#epicLoader').addClass('hidden');
$('#epicRelatedTasksContainer').html(data);
console.log('Updated Container:', $('#epicRelatedTasksContainer').html());
},
error: function (error) {
console.error('Error fetching open tasks:', error);
$('#epicLoader').addClass('hidden');
}
});
}
// To load to display open tasks by default
$(document).ready(function () {
fetchOpenTasks();
});
// Click event handler for the "All Open Tasks" link
$('.openTasks').on('click', function () {
// Remove the selectedEpic class from all epic titles
$('.epicTitle').removeClass('selectedEpic');
$('.openTasks').removeClass('selectedEpic');
// Add the selectedEpic class to the "All Open Tasks" link
$(this).addClass('selectedEpic');
fetchOpenTasks();
});
// Click event handler for the epic titles
// TASKS BY EPIC
$('.epicTitle').on('click', function () {
// Remove the selectedEpic class from all epic titles
$('.epicTitle').removeClass('selectedEpic');
$('.openTasks').removeClass('selectedEpic');
@ -42,16 +44,19 @@ $('.epicTitle').on('click', function () {
$(this).addClass('selectedEpic');
$('#epicLoader').removeClass('hidden');
$.ajax({
url: '/get_tasks/' + epicId + '/',
method: 'GET',
success: function (data) {
// console.log('Success:', data);
$('#epicRelatedTasksContainer').empty();
$('#epicLoader').addClass('hidden');
$('#epicRelatedTasksContainer').html(data);
console.log('Updated Container:', $('#epicRelatedTasksContainer').html());
},
error: function (error) {
console.error('Error fetching tasks:', error);
$('#epicLoader').addClass('hidden');
}
});
});

@ -0,0 +1,37 @@
document.addEventListener('DOMContentLoaded', function () {
const inProgressProjectsContainer = document.getElementById('inProgressProjectsContainer');
const projectsByStatusContainer = document.getElementById('projectsByStatusContainer');
const allProjectsContainer = document.getElementById('allProjectsContainer');
const projectLoader = document.getElementById('projectLoader');
var statusesSelectTag = document.getElementById('statusesSelectTag');
statusesSelectTag.addEventListener('change', function () {
var selectedStatus = statusesSelectTag.value;
projectLoader.classList.remove('hidden');
inProgressProjectsContainer.classList.add('hidden');
projectsByStatusContainer.classList.add('hidden');
allProjectsContainer.classList.add('hidden');
// Check if "All" is selected
if (selectedStatus === 'All') {
allProjectsContainer.classList.remove('hidden');
projectLoader.classList.add('hidden');
// Check if "Pending" is selected
} else if (selectedStatus === 'Pending') {
inProgressProjectsContainer.classList.remove('hidden');
projectLoader.classList.add('hidden');
} else {
fetch('/projects/status/' + selectedStatus + '/')
.then(response => response.text())
.then(data => {
projectsByStatusContainer.classList.remove('hidden');
$(projectsByStatusContainer).html(data);
projectLoader.classList.add('hidden');
})
.catch(error => console.error('Error:', error));
}
});
});
Loading…
Cancel
Save