new changes.

main
nataly 12 months ago
parent 81d65b4236
commit 71108fe3ec

@ -0,0 +1,11 @@
from django.urls import path, include
from . import views
urlpatterns = [
# ADD
path('ticket/', views.customer_add_ticket, name='customeraddticket'),
path('customer/ticketupdate/<int:ticket_id>/', views.customer_add_ticket_update, name='customeraddticketupdate'),
path('ticketupdatereaction/<str:reaction_type>/<int:ticketupdate_id>/', views.customer_add_ticket_update_reaction, name='customeraddticketupdatereaction'),
]

@ -0,0 +1,175 @@
from django.shortcuts import render, get_object_or_404
from customercore.decorators import *
from customercore.models import *
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.conf import settings
@customer_login_required
def customer_add_ticket(request, *args, **kwargs):
customer_orders = Order.objects.filter(customer=request.user.customerprofile)
customer_orders_with_last_status = customer_orders.annotate(max_status_date=Max('orderstatus__date'))
customer_orders_completed = customer_orders_with_last_status.filter(orderstatus__status='Completed',orderstatus__date=F('max_status_date'))
customer_products = OrderItem.objects.filter(active__in=[True, None], item__type = 'Product', order__customer = request.user.customerprofile, order__in=customer_orders_completed )
customer_projects = Project.objects.filter(customer=request.user.customerprofile)
support_department = get_object_or_404(Department, name='Support')
if request.method == 'POST':
project = None
product = None
departments = [support_department]
regarding = 'General/Account/Billing'
if request.POST.get('project') and request.POST.get('regarding') == 'Project':
project = get_object_or_404(Project, id=request.POST.get('project'))
project_types = project.project_type.all()
departments = [project_type.department for project_type in project_types]
regarding = 'Project/Product'
elif request.POST.get('product') and request.POST.get('regarding') == 'Product':
product = get_object_or_404(Item, id=request.POST.get('product'))
departments = [product.item_type.department]
regarding = 'Project/Product'
ticket = Ticket(
status = 'Open',
customer = request.user.customerprofile,
title = request.POST.get('title'),
description = request.POST.get('description'),
regarding = regarding,
project = project,
product = product,
opened_by = request.user,
opened_date = datetime.now()
)
ticket.save()
ticket.departments.set(departments)
ticket_status = TicketStatus(
ticket = ticket,
status = 'Open',
added_by = request.user,
date_added = datetime.now()
)
ticket_status.save()
for file in request.FILES.getlist('files'):
ticket_attachment = TicketAttachment(
ticket=ticket,
file=file
)
ticket_attachment.save()
department_ids = [dept.id for dept in departments]
staff_profiles = StaffProfile.objects.filter(staff_position__department__id__in=department_ids, active=True)
print(staff_profiles)
for staff in staff_profiles:
subject = f"New Ticket Opened: {ticket.title}"
html_message = render_to_string('email_templates/new_ticket.html', {
'ticket': ticket,
'staff_first_name': staff.user.first_name
})
plain_message = strip_tags(html_message)
from_email = settings.DEFAULT_FROM_EMAIL
to_email = staff.user.email
send_mail(subject, plain_message, from_email, [to_email], html_message=html_message)
return redirect('customerticketdetails', ticket_number=ticket.ticket_number)
context = {
'customer_products': customer_products,
'customer_projects': customer_projects,
}
return render(request, 'add_templates/customer-add-ticket.html', context)
@customer_login_required
def customer_add_ticket_update(request, ticket_id):
ticket = get_object_or_404(Ticket, id=ticket_id)
if request.method == 'POST':
ticket_update = TicketUpdate(
ticket = ticket,
description = request.POST.get('description'),
added_by = request.user,
date_added = datetime.now(),
)
ticket_update.save()
for file in request.FILES.getlist('files'):
ticket_attachment = TicketAttachment(
ticket_update=ticket_update,
file=file
)
ticket_attachment.save()
if ticket.ticket_members.exists():
members_ids = ticket.ticket_members.values_list('id', flat=True)
staff_profiles = StaffProfile.objects.filter(id__in=members_ids)
else:
department_ids = ticket.departments.values_list('id', flat=True)
staff_profiles = StaffProfile.objects.filter(staff_position__department__id__in=department_ids, active=True)
for staff in staff_profiles:
subject = f"New Ticket Update: {ticket.title}"
html_message = render_to_string('email_templates/new_ticket_update.html', {
'ticket_update': ticket_update,
'staff_first_name': staff.user.first_name
})
plain_message = strip_tags(html_message)
from_email = settings.DEFAULT_FROM_EMAIL
to_email = staff.user.email
send_mail(subject, plain_message, from_email, [to_email], html_message=html_message)
return redirect('customerticketdetails', ticket_number=ticket.ticket_number)
context = {
'ticket': ticket,
}
return render(request, 'add_templates/customer-add-ticket.html', context)
@customer_login_required
def customer_add_ticket_update_reaction(request, reaction_type, ticketupdate_id):
ticket_update = get_object_or_404(TicketUpdate, id=ticketupdate_id)
existing_reaction = TicketUpdateReaction.objects.filter(ticket_update=ticket_update, customer=request.user).first()
if existing_reaction:
# If the existing reaction type is equal to the new reaction, delete it
if existing_reaction.reaction == reaction_type:
existing_reaction.delete()
else:
# If not, delete all previous reactions and add a new one
TicketUpdateReaction.objects.filter(ticket_update=ticket_update, customer=request.user).delete()
reaction = TicketUpdateReaction.objects.create(
ticket_update=ticket_update,
reaction=reaction_type,
customer=request.user
)
else:
# If there's no existing reaction, simply add the new one
reaction = TicketUpdateReaction.objects.create(
ticket_update=ticket_update,
reaction=reaction_type,
customer=request.user
)
return redirect('customerticketdetails', ticket_number=ticket_update.ticket.ticket_number)

@ -0,0 +1,23 @@
# Generated by Django 5.0.4 on 2024-05-22 12:17
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('customercore', '0016_rename_ticketstatusupdate_ticketstatus'),
('osinacore', '0081_status_task'),
]
operations = [
migrations.CreateModel(
name='TicketTask',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='osinacore.task')),
('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='customercore.ticketupdate')),
],
),
]

@ -80,3 +80,9 @@ class TicketUpdateReaction(models.Model):
customer = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
reaction = models.CharField(max_length=50, choices=REACTION_CHOICES, null=True)
ticket_update = models.ForeignKey(TicketUpdate, on_delete=models.CASCADE)
class TicketTask(models.Model):
ticket = models.ForeignKey(TicketUpdate, on_delete=models.CASCADE)
task = models.ForeignKey(Task, on_delete=models.CASCADE)

@ -4,15 +4,11 @@ from . import views
urlpatterns = [
path('payment/', include('customercore.payment.urls')),
path('add/', include('customercore.add.urls')),
path('redirect-osimenu/', views.redirect_osimenu, name='redirectosimenu'),
path('redirect-osicard/', views.redirect_osicard, name='redirectosicard'),
# ADD
path('add/ticket/', views.customer_add_ticket, name='customeraddticket'),
path('customer/add/ticketupdate/<int:ticket_id>/', views.customer_add_ticket_update, name='customeraddticketupdate'),
# LISTING
path('my-invoices/', views.customer_invoices, name='customerinvoices'),
path('products/', views.all_products, name='products'),
@ -23,7 +19,6 @@ urlpatterns = [
# DETAILS
path('my-tickets/<int:ticket_number>/', views.customer_ticket_details, name='customerticketdetails'),
path('addticketupdatereaction/<str:reaction_type>/<int:ticketupdate_id>/', views.customer_add_ticket_update_reaction, name='customeraddticketupdatereaction'),
path('my-orders/<str:order_id>/', views.customer_order_details, name='customerorderdetails'),
path('my-projects/<str:project_id>/', views.customer_project_details, name='customerprojectdetails'),

@ -6,10 +6,7 @@ from .models import *
from django.db.models import Q
from django.http import Http404
from django.db.models import OuterRef, Subquery
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.conf import settings
# Create your views here.
@ -29,168 +26,6 @@ def redirect_osicard(request):
return redirect(url)
# ADD
@customer_login_required
def customer_add_ticket(request, *args, **kwargs):
customer_orders = Order.objects.filter(customer=request.user.customerprofile)
customer_orders_with_last_status = customer_orders.annotate(max_status_date=Max('orderstatus__date'))
customer_orders_completed = customer_orders_with_last_status.filter(orderstatus__status='Completed',orderstatus__date=F('max_status_date'))
customer_products = OrderItem.objects.filter(active__in=[True, None], item__type = 'Product', order__customer = request.user.customerprofile, order__in=customer_orders_completed )
customer_projects = Project.objects.filter(customer=request.user.customerprofile)
support_department = get_object_or_404(Department, name='Support')
if request.method == 'POST':
project = None
product = None
departments = [support_department]
regarding = 'General/Account/Billing'
if request.POST.get('project') and request.POST.get('regarding') == 'Project':
project = get_object_or_404(Project, id=request.POST.get('project'))
departments = [project.project_type.department]
regarding = 'Project/Product'
elif request.POST.get('product') and request.POST.get('regarding') == 'Product':
product = get_object_or_404(Item, id=request.POST.get('product'))
departments = [product.item_type.department]
regarding = 'Project/Product'
ticket = Ticket(
status = 'Open',
customer = request.user.customerprofile,
title = request.POST.get('title'),
description = request.POST.get('description'),
regarding = regarding,
project = project,
product = product,
opened_by = request.user,
opened_date = datetime.now()
)
ticket.save()
ticket.departments.set(departments)
ticket_status = TicketStatus(
ticket = ticket,
status = 'Open',
added_by = request.user,
date_added = datetime.now()
)
ticket_status.save()
for file in request.FILES.getlist('files'):
ticket_attachment = TicketAttachment(
ticket=ticket,
file=file
)
ticket_attachment.save()
department_ids = [dept.id for dept in departments]
staff_profiles = StaffProfile.objects.filter(staff_position__department__id__in=department_ids, active=True)
print(staff_profiles)
for staff in staff_profiles:
subject = f"New Ticket Opened: {ticket.title}"
html_message = render_to_string('email_templates/new_ticket.html', {
'ticket': ticket,
'staff_first_name': staff.user.first_name
})
plain_message = strip_tags(html_message)
from_email = settings.DEFAULT_FROM_EMAIL
to_email = staff.user.email
send_mail(subject, plain_message, from_email, [to_email], html_message=html_message)
return redirect('customerticketdetails', ticket_number=ticket.ticket_number)
context = {
'customer_products': customer_products,
'customer_projects': customer_projects,
}
return render(request, 'add_templates/customer-add-ticket.html', context)
@customer_login_required
def customer_add_ticket_update(request, ticket_id):
ticket = get_object_or_404(Ticket, id=ticket_id)
if request.method == 'POST':
ticket_update = TicketUpdate(
ticket = ticket,
description = request.POST.get('description'),
added_by = request.user,
date_added = datetime.now(),
)
ticket_update.save()
for file in request.FILES.getlist('files'):
ticket_attachment = TicketAttachment(
ticket_update=ticket_update,
file=file
)
ticket_attachment.save()
if ticket.ticket_members.exists():
members_ids = ticket.ticket_members.values_list('id', flat=True)
staff_profiles = StaffProfile.objects.filter(id__in=members_ids)
else:
department_ids = ticket.departments.values_list('id', flat=True)
staff_profiles = StaffProfile.objects.filter(staff_position__department__id__in=department_ids, active=True)
for staff in staff_profiles:
subject = f"New Ticket Update: {ticket.title}"
html_message = render_to_string('email_templates/new_ticket_update.html', {
'ticket_update': ticket_update,
'staff_first_name': staff.user.first_name
})
plain_message = strip_tags(html_message)
from_email = settings.DEFAULT_FROM_EMAIL
to_email = staff.user.email
send_mail(subject, plain_message, from_email, [to_email], html_message=html_message)
return redirect('customerticketdetails', ticket_number=ticket.ticket_number)
context = {
'ticket': ticket,
}
return render(request, 'add_templates/customer-add-ticket.html', context)
@customer_login_required
def customer_add_ticket_update_reaction(request, reaction_type, ticketupdate_id):
ticket_update = get_object_or_404(TicketUpdate, id=ticketupdate_id)
existing_reaction = TicketUpdateReaction.objects.filter(ticket_update=ticket_update, customer=request.user).first()
if existing_reaction:
# If the existing reaction type is equal to the new reaction, delete it
if existing_reaction.reaction == reaction_type:
existing_reaction.delete()
else:
# If not, delete all previous reactions and add a new one
TicketUpdateReaction.objects.filter(ticket_update=ticket_update, customer=request.user).delete()
reaction = TicketUpdateReaction.objects.create(
ticket_update=ticket_update,
reaction=reaction_type,
customer=request.user
)
else:
# If there's no existing reaction, simply add the new one
reaction = TicketUpdateReaction.objects.create(
ticket_update=ticket_update,
reaction=reaction_type,
customer=request.user
)
return redirect('customerticketdetails', ticket_number=ticket_update.ticket.ticket_number)
# LISTING
@customer_login_required
def customer_invoices(request, *args, **kwargs):
@ -356,35 +191,6 @@ def customer_ticket_details(request, ticket_number):
return render(request, 'details_templates/inner-customer-ticket.html', context)
@customer_login_required
def customer_add_ticket_update_reaction(request, reaction_type, ticketupdate_id):
ticket_update = get_object_or_404(TicketUpdate, id=ticketupdate_id)
existing_reaction = TicketUpdateReaction.objects.filter(ticket_update=ticket_update, customer=request.user).first()
if existing_reaction:
# If the existing reaction type is equal to the new reaction, delete it
if existing_reaction.reaction == reaction_type:
existing_reaction.delete()
else:
# If not, delete all previous reactions and add a new one
TicketUpdateReaction.objects.filter(ticket_update=ticket_update, customer=request.user).delete()
reaction = TicketUpdateReaction.objects.create(
ticket_update=ticket_update,
reaction=reaction_type,
customer=request.user
)
else:
# If there's no existing reaction, simply add the new one
reaction = TicketUpdateReaction.objects.create(
ticket_update=ticket_update,
reaction=reaction_type,
customer=request.user
)
return redirect('customerticketdetails', ticket_number=ticket_update.ticket.ticket_number)
# PRODUCTS

Binary file not shown.

@ -653,68 +653,73 @@ def add_reaction(request, status_id, emoji):
@staff_login_required
def add_ticket(request, customer_id):
customer= get_object_or_404(CustomerProfile, id=customer_id)
customer = get_object_or_404(CustomerProfile, id=customer_id)
customer_orders = Order.objects.filter(customer=customer)
customer_orders_with_last_status = customer_orders.annotate(max_status_date=Max('orderstatus__date'))
customer_orders_completed = customer_orders_with_last_status.filter(orderstatus__status='Completed',orderstatus__date=F('max_status_date'))
customer_products = OrderItem.objects.filter(active__in=[True, None], item__type = 'Product', order__customer = customer, order__in=customer_orders_completed)
customer_orders_completed = customer_orders_with_last_status.filter(orderstatus__status='Completed', orderstatus__date=F('max_status_date'))
customer_products = OrderItem.objects.filter(active__in=[True, None], item__type='Product', order__customer=customer, order__in=customer_orders_completed)
customer_projects = Project.objects.filter(customer=customer)
departments = Department.objects.all().order_by('name')
if request.method == 'POST':
project = None
product = None
if request.POST.get('department'):
department = get_object_or_404(Department, id=request.POST.get('department'))
department_ids = request.POST.getlist('departments') # Changed to get a list of department IDs
selected_departments = Department.objects.filter(id__in=department_ids)
regarding = 'General/Account/Billing'
if request.POST.get('project'):
project = get_object_or_404(Project, id=request.POST.get('project'))
if not department:
department = project.project_type.department
regarding = 'Project/Product'
elif request.POST.get('product'):
product = get_object_or_404(Item, id=request.POST.get('product'))
if not department:
department = project.project_type.department
regarding = 'Project/Product'
ticket = Ticket(
status = 'Open',
customer = customer,
title = request.POST.get('title'),
description = request.POST.get('description'),
regarding = regarding,
project = project,
product = product,
department = department,
opened_by = request.user,
opened_date = datetime.now()
status='Open',
customer=customer,
title=request.POST.get('title'),
description=request.POST.get('description'),
regarding=regarding,
project=project,
product=product,
opened_by=request.user,
opened_date=datetime.now()
)
ticket.save()
ticket_status_update = TicketUpdate(
ticket = ticket,
status = 'Open',
added_by = request.user,
date_added = datetime.now()
ticket.departments.set(selected_departments) # Assign multiple departments
ticket_status_update = TicketStatus(
ticket=ticket,
status='Open',
added_by=request.user,
date_added=datetime.now()
)
ticket_status_update.save()
for file in request.FILES.getlist('files'):
ticket_attachment = TicketAttachment(
ticket=ticket,
file=file
)
ticket_attachment.save()
return redirect('ticketdetails', ticket_number=ticket.ticket_number)
context = {
'customer_products' : customer_products,
'customer_projects' : customer_projects,
'customer_products': customer_products,
'customer_projects': customer_projects,
'customer': customer,
'departments' : departments
'departments': departments
}
return render(request, 'add_templates/add-ticket.html', context)
@staff_login_required
def add_ticket_update(request, ticket_id):
ticket = get_object_or_404(Ticket, id=ticket_id)

@ -131,13 +131,6 @@
</div>
</a>
<a href="{% url 'tickets' %}">
<div
class="w-full flex justify-start items-center gap-3 text-white border-b border-slate-600 py-2">
<p class="text-white">Tickets</p>
</div>
</a>
<a href="{% url 'my-notes' %}">
<div
class="w-full flex justify-start items-center gap-3 text-white border-b border-slate-600 py-2">
@ -154,7 +147,9 @@
</div>
<!-- SUPPORT DROPDOWN -->
<div class="w-full flex justify-between items-center border-b border-slate-600 py-3">
<div class="w-full menu-container">
<div
class="menuItem w-full flex justify-between items-center border-b border-slate-600 py-3 cursor-pointer">
<div class="w-full flex justify-start items-center gap-3">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-[25px] text-white">
<path stroke-linecap="round" stroke-linejoin="round" d="M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 0 1-.825-.242m9.345-8.334a2.126 2.126 0 0 0-.476-.095 48.64 48.64 0 0 0-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0 0 11.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155" />
@ -162,7 +157,19 @@
<p class="text-white">Support</p>
</div>
<div>
<i class="fa fa-angle-down" style="font-size: 20px; color: white;"></i>
<i class="angleDown fa fa-angle-down" style="font-size: 18px; color: white;"></i>
<i class="angleUp fa fa-angle-up"
style="font-size: 18px; color: white; display: none;"></i>
</div>
</div>
<div class="menuDropdownItems w-full h-fit p-3 hidden duration-300">
<a href="{% url 'tickets' %}">
<div
class="w-full flex justify-start items-center gap-3 text-white border-b border-slate-600 py-2">
<p class="text-white">Tickets</p>
</div>
</a>
</div>
</div>
@ -236,6 +243,15 @@
</div>
<div class="menuDropdownItems w-full h-fit p-3 hidden duration-300">
<a href="{% url 'departments' %}">
<div
class="w-full flex justify-start items-center gap-3 text-white border-b border-slate-600 py-2 cursor-pointer">
<p class="text-white">Departments</p>
</div>
</a>
<a href="{% url 'projecttypes' %}">
<div
class="w-full flex justify-start items-center gap-3 text-white border-b border-slate-600 py-2 cursor-pointer">
@ -272,6 +288,7 @@
</div>
</a>
<a href="{% url 'paymentmethods' %}">
<div
class="w-full flex justify-start items-center gap-3 text-white border-b border-slate-600 py-2 cursor-pointer">
@ -424,13 +441,6 @@
</div>
</a>
<a href="{% url 'tickets' %}">
<div
class="w-full flex justify-start items-center gap-3 text-white border-b border-slate-600 py-2">
<p class="text-white">My Tickets</p>
</div>
</a>
<a href="{% url 'my-notes' %}">
<div
class="w-full flex justify-start items-center gap-3 text-white border-b border-slate-600 py-2">
@ -446,7 +456,11 @@
</div>
</div>
<div class="w-full flex justify-between items-center border-b border-slate-600 py-3">
<!-- SUPPORT DROPDOWN -->
<div class="w-full menu-container">
<div
class="menuItem w-full flex justify-between items-center border-b border-slate-600 py-3 cursor-pointer">
<div class="w-full flex justify-start items-center gap-3">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-[25px] text-white">
<path stroke-linecap="round" stroke-linejoin="round" d="M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 0 1-.825-.242m9.345-8.334a2.126 2.126 0 0 0-.476-.095 48.64 48.64 0 0 0-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0 0 11.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155" />
@ -455,7 +469,18 @@
</div>
<div>
<i class="angleDown fa fa-angle-down" style="font-size: 18px; color: white;"></i>
<i class="angleUp fa fa-angle-up" style="font-size: 18px; color: white; display: none;"></i>
<i class="angleUp fa fa-angle-up"
style="font-size: 18px; color: white; display: none;"></i>
</div>
</div>
<div class="menuDropdownItems w-full h-fit p-3 hidden duration-300">
<a href="{% url 'tickets' %}">
<div
class="w-full flex justify-start items-center gap-3 text-white border-b border-slate-600 py-2">
<p class="text-white">Tickets</p>
</div>
</a>
</div>
</div>
@ -528,6 +553,15 @@
</div>
<div class="menuDropdownItems w-full h-fit p-3 hidden duration-300">
<a href="{% url 'departments' %}">
<div
class="w-full flex justify-start items-center gap-3 text-white border-b border-slate-600 py-2 cursor-pointer">
<p class="text-white">Departments</p>
</div>
</a>
<a href="{% url 'projecttypes' %}">
<div
class="w-full flex justify-start items-center gap-3 text-white border-b border-slate-600 py-2 cursor-pointer">

@ -2,6 +2,7 @@
{%load static%}
{% block content %}
<!-- IN THIS TASK FORM THE TASK BELONG ONLY TO A PROJECT AND THE USER MUST CHOOSE TO WHICH EPIC IT BELONGS -->
<div class="w-full px-5 s:px-9 mb-5">
@ -122,6 +123,7 @@
</div>
</div>
<div class="w-full flex justify-center items-center mt-3">
<button type="submit"
class="w-fit py-1 px-5 bg-osiblue rounded-md outline-none text-white border border-osiblue text-xl cursor-pointer hover:bg-white hover:text-osiblue duration-300">Save</button>
@ -131,6 +133,10 @@
</div>
<!-------------- JS SCRIPTS --------------->
<script type="text/javascript" src='{% static "js/upload-input-tag.js" %}'></script>

@ -2,6 +2,8 @@
{%load static%}
{% block content %}
<div class="w-full px-5 s:px-9 mb-5">
<div class="w-full h-full shadow-md rounded-md py-5 px-3 bg-white">
<h1 class="text-3xl text-secondosiblue text-center font-semibold">
@ -76,20 +78,23 @@
</div>
<div class="w-full">
<label class="text-gray-500">Attach Files:</label>
<div class="inbox-box border border-gray-300 w-full rounded-md px-3 mt-1">
<div class="flex items-center justify-between">
<input name="files" type="file" class="file-input" hidden multiple />
<span class="file-name text-gray-500 text-base focus:outline-none outline-none">Upload
Document(s)</span>
<label
class="file-label bg-transparent text-gray-500 border border-white h-14 cursor-pointer flex items-center">
<i class="fa fa-upload" style="font-size: 25px;"></i>
</label>
<div class="w-full border border-gray-300 rounded-md px-3 py-5 flex flex-col gap-3">
<div class="w-full flex justify-between items-center">
<div class="cursor-pointer">
<input class="w-full" type="file" name="files" hidden id="uploader" multiple="false">
<p class="text-gray-500 hover:text-secondosiblue duration-300 cursor-pointer">Upload Document</p>
</div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" color="#000000" fill="none">
<path d="M7 6.5H16.75C18.8567 6.5 19.91 6.5 20.6667 7.00559C20.9943 7.22447 21.2755 7.50572 21.4944 7.83329C21.9579 8.52694 21.9965 9.25981 21.9997 11M12 6.5L11.3666 5.23313C10.8418 4.18358 10.3622 3.12712 9.19926 2.69101C8.6899 2.5 8.10802 2.5 6.94427 2.5C5.1278 2.5 4.21956 2.5 3.53806 2.88032C3.05227 3.15142 2.65142 3.55227 2.38032 4.03806C2 4.71956 2 5.6278 2 7.44427V10.5C2 15.214 2 17.5711 3.46447 19.0355C4.8215 20.3926 6.94493 20.4921 11 20.4994H13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" />
<path d="M18.5 13.5L18.5 21.5M18.5 13.5C17.7998 13.5 16.4915 15.4943 16 16M18.5 13.5C19.2002 13.5 20.5085 15.4943 21 16" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</div>
</div>
<section class="progress-area"></section>
<section class="uploaded-area"></section>
</div>
<div class="w-full flex justify-center items-center mt-3">
<button type="submit"
class="w-fit py-1 px-5 bg-osiblue rounded-md outline-none text-white border border-osiblue text-xl cursor-pointer hover:bg-white hover:text-osiblue duration-300">Save</button>
@ -105,4 +110,6 @@
<script type="text/javascript" src='{% static "js/add-ticket.js" %}'></script>
<script type="text/javascript" src='{% static "js/uploader-bar.js" %}'></script>
{% endblock %}

@ -12,8 +12,14 @@
<div class="w-full xxlg1:w-[75%] bg-white h-fit rounded-md shadow-md p-5">
<div class="w-full h-fit flex flex-col gap-2 bg-gray-100 shadow-md rounded-md px-3 py-3">
<p class="text-secondosiblue text-[20px]">Ticket <span class="font-semibold">#{{ticket.ticket_number}}</span>
</p>
<div class="w-full flex justify-between items-center gap-3">
<p class="text-secondosiblue text-[20px]">Ticket <span class="font-semibold">#{{ticket.ticket_number}}</span></p>
<button class="px-3 py-2 bg-osiblue border border-osiblue text-white cursor-pointer duration-300 hover:bg-white hover:text-osiblue rounded-md">
Add Task
</button>
</div>
{% if last_ticket_status.status == 'Open' %}
@ -141,6 +147,121 @@
</div>
{% endfor %}
<div class="w-full mt-5">
<div
class=" bg-gray-200 rounded-t-md flex justify-between items-center text-white text-xl font-bold h-[50px]">
<div class="px-3">
<p class="text-secondosiblue uppercase font-bold">Task</p>
</div>
</div>
<div class="w-full flex flex-col gap-3">
{% if points %}
{% for point in points %}
<p class="pointId" data-point-id="{{ point.id }}" style="display: none;">{{ point.id }}</p>
<div class="w-full flex flex-col gap-1
{% if point.status == 'Completed' %}
bg-green-700
{% elif point.status == 'Working On' %}
bg-orange-500
{% elif point.status == 'Paused' %}
bg-red-500
{% else %}
bg-slate-700
{% endif %}
bg-opacity-50 rounded-md shadow-md p-3 mt-4">
<div class="w-full flex justify-between items-end pb-2 border-b border-gray-200">
<div class="w-[380px]">
{% if point.status == 'Completed' %}
<p class="text-white line-through">{{point.text}}</p>
{% else %}
<p class="text-white">{{point.text}}</p>
{% endif %}
</div>
<div class="flex justify-end items-center gap-2">
{% if point.status == 'Not Completed' or point.status == 'Paused' and not point.status == 'Completed' %}
<a href="{% url 'mark_point_working_on_task_page' point.id task.id %}">
<button
class="w-[40px] h-[40px] rounded-full bg-transparent shadow-md text-white border border-white flex justify-center items-center hover:scale-105 transition-transform duration-300"
id="startPointButton">
<i class="fa fa-play"></i>
</button>
</a>
{% endif %}
{% if point.status == 'Working On' and not point.status == 'Completed' %}
<a href="{% url 'mark_point_paused_task_page' point.id task.id %}">
<button
class="w-[40px] h-[40px] rounded-full bg-transparent shadow-md text-white border border-white justify-center items-center hover:scale-105 transition-transform duration-300"
id="pausePointButton">
<i class="fa fa-pause"></i>
</button>
</a>
{% endif %}
{% if not point.status == 'Completed' and not point.status == 'Paused' %}
<a href="{% url 'mark_point_completed_task_page' point.id task.id %}">
<button
class="w-[40px] h-[40px] rounded-full bg-transparent shadow-md text-white border border-white flex justify-center items-center hover:scale-105 transition-transform duration-300">
<i class="fa fa-check"></i>
</button>
</a>
{% endif %}
{% if point.status == 'Completed' %}
<button
class="w-[40px] h-[40px] rounded-full bg-transparent shadow-md text-white border border-white flex justify-center items-center opacity-30 cursor-default">
<i class="fa fa-check"></i>
</button>
{% endif %}
{% if not point.status == 'Completed' %}
<form method="post" action="{% url 'deletepointmodal' point.id task.id %}">
{% csrf_token %}
<button type="submit"
class="w-[40px] h-[40px] bg-transparent border border-white rounded-full text-white flex justify-center items-center shadow-md hover:scale-105 transition-transform duration-300">
<i class="fa fa-trash"></i>
</button>
</form>
{% endif %}
</div>
</div>
<div class="flex justify-between items-center gap-3 pt-2">
<div class="text-white text-sm">
<p>Total Time:
<span class="font-semibold pointTotalTime">
<span class="hours">{{ point.total_activity_time.0 }}</span> hours,
<span class="minutes">{{ point.total_activity_time.1 }}</span> minutes,
<span class="seconds">{{ point.total_activity_time.2 }}</span> seconds
</span>
</p>
</div>
<div class="w-fit py-1 px-2 bg-white text-secondosiblue text-xs rounded-md shadow-md">
{% if point.status == 'Completed' %}
<p class="text-green-700 opacity-50">Completed</p>
{% elif point.status == 'Working On' %}
<p class="text-orange-500 opacity-50">Working On</p>
{% elif point.status == 'Paused' %}
<p class="text-red-500 opacity-50">Paused</p>
{% else %}
<p class="text-secondosiblue opacity-50">Created</p>
{% endif %}
</div>
</div>
</div>
{% endfor %}
{% else %}
<div class="w-full flex justify-center items-center p-5 text-secondosiblue text-center">
<p>No Available Points</p>
</div>
{% endif %}
</div>
</div>
<!-- REPLYING SECTION -->
<form class="flex gap-3" method="POST" action="{% url 'addticketupdate' ticket.id %}"
enctype="multipart/form-data">

@ -25,7 +25,7 @@
<!-- TABLE HEADER -->
<div class="w-full rounded-md grid grid-cols-1 l:grid-cols-2">
<div
class="w-full flex flex-col justify-center items-center gap-2 border-r border-b border-gray-200 {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} rounded-t-md l:rounded-tr-none l:rounded-l-md text-base text-white text-center py-3 px-3">
class="w-full flex flex-col justify-center items-center gap-2 border-r border-b border-gray-200 {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} rounded-t-md l:rounded-tr-none l:rounded-l-md text-base text-white text-center py-3 px-3 bg-opacity-70">
<p>{{task.name}}</p>
<div class="w-full flex justify-center items-center gap-2">
@ -44,23 +44,23 @@
<div class="w-full grid grid-cols-2">
<div
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} py-3 px-3">
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} py-3 px-3 bg-opacity-70">
<p>{{task.status}}</p>
</div>
<div
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} py-3 px-3 rounded-none l:rounded-tr-md">
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} py-3 px-3 rounded-none l:rounded-tr-md bg-opacity-70">
<p>{{task.assigned_to.user.first_name}}
{{task.assigned_to.user.last_name}}</p>
</div>
<div
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} py-3 px-3 rounded-bl-md l:rounded-none">
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} py-3 px-3 rounded-bl-md l:rounded-none bg-opacity-70">
<p>{{task.start_date|date:"d-m-Y"}}</p>
</div>
<div
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} py-3 px-3 rounded-br-md">
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} py-3 px-3 rounded-br-md bg-opacity-70">
<p>{{task.end_date|date:"d-m-Y"}}</p>
</div>
</div>

@ -13,24 +13,26 @@
<div class="w-full bg-white h-fit rounded-md border border-gray-200">
<!-- TABLE HEADER -->
<div class="w-full h-[70px] rounded-t-md grid grid-cols-2">
<a href="{% url 'detailed-task' task.task_id %}" class="h-[70px]">
<div
class="flex justify-center items-center border-r border-b border-gray-200 px-3 {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} rounded-tl-md text-[17px] text-white text-center">
class="h-full flex justify-center items-center border-r border-b border-gray-200 px-3 {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} rounded-tl-md text-[17px] text-white text-center bg-opacity-70 hover:bg-opacity-100 duration-300">
<p>{{task.name}}</p>
</div>
</a>
<div class="grid grid-cols-3">
<div
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %}">
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} bg-opacity-70">
<p>{{task.status}}</p>
</div>
<div
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %}">
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} bg-opacity-70">
<p>{{task.start_date|date:"d-m-Y"}}</p>
</div>
<div
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} rounded-tr-md">
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} rounded-tr-md bg-opacity-70">
<p>{{task.end_date|date:"d-m-Y"}}</p>
</div>
</div>
@ -127,26 +129,29 @@
<div class="w-full h-fit bg-white p-3 rounded-md shadow-md mb-5">
<div class="border border-gray-200 rounded-t-md">
<div class="w-full rounded-t-md">
<a href="{% url 'detailed-task' task.task_id %}">
<div
class="text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} border-r border-gray-200 flex justify-center items-center text-center py-3 text-sm">
class="text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} border-r border-gray-200 rounded-t-md flex justify-center items-center text-center py-3 text-sm bg-opacity-70 hover:bg-opacity-100 duration-300">
<p>{{task.name}}</p>
</div>
</a>
</div>
<div class="grid grid-cols-3 border-t border-gray-200">
<div
class="text-white {% if task.status == 'Open' %} bg-secondosiblue {% endif %} {% if task.status == 'Working On' %} bg-yellow-500 {% endif %} {% if task.status == 'Closed' %} bg-green-700{% endif %} border-r border-gray-200 flex justify-center items-center text-center py-3 text-sm">
class="text-white {% if task.status == 'Open' %} bg-secondosiblue {% endif %} {% if task.status == 'Working On' %} bg-yellow-500 {% endif %} {% if task.status == 'Closed' %} bg-green-700{% endif %} border-r border-gray-200 flex justify-center items-center text-center py-3 text-sm bg-opacity-70">
<p>{{task.status}}</p>
</div>
<div
class="text-white {% if task.status == 'Open' %} bg-secondosiblue {% endif %} {% if task.status == 'Working On' %} bg-yellow-500 {% endif %} {% if task.status == 'Closed' %} bg-green-700{% endif %} border-r border-gray-200 flex justify-center items-center text-center py-3 text-sm">
class="text-white {% if task.status == 'Open' %} bg-secondosiblue {% endif %} {% if task.status == 'Working On' %} bg-yellow-500 {% endif %} {% if task.status == 'Closed' %} bg-green-700{% endif %} border-r border-gray-200 flex justify-center items-center text-center py-3 text-sm bg-opacity-70">
<p>{{task.start_date|date:"d-m-Y"}}</p>
</div>
<div
class="text-white {% if task.status == 'Open' %} bg-secondosiblue {% endif %} {% if task.status == 'Working On' %} bg-yellow-500 {% endif %} {% if task.status == 'Closed' %} bg-green-700{% endif %} border-r border-gray-200 flex justify-center items-center text-center py-3 text-sm">
class="text-white {% if task.status == 'Open' %} bg-secondosiblue {% endif %} {% if task.status == 'Working On' %} bg-yellow-500 {% endif %} {% if task.status == 'Closed' %} bg-green-700{% endif %} border-r border-gray-200 flex justify-center items-center text-center py-3 text-sm bg-opacity-70">
<p>{{task.end_date|date:"d-m-Y"}}</p>
</div>
</div>
@ -231,6 +236,100 @@
<p>No Available Tasks</p>
</div>
{% endif %}
<!-- TICKETS -->
<div class="w-full h-fit bg-white p-3 rounded-md shadow-md">
<h1 class="text-secondosiblue text-[25px]">Open Tickets</h1>
<div class="overflow-x-auto border border-gray-300 rounded-md mt-4" id="openTickets">
<table class="min-w-full divide-y">
<!-- TABLE HEADER -->
<thead class="bg-gray-50">
<tr>
<th scope="col"
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
Subject
</th>
<th scope="col"
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
Ticket ID
</th>
<th scope="col"
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase border-r border-gray-300 whitespace-nowrap">
Regarding
</th>
<th scope="col"
class="px-6 py-3 text-sm font-medium text-gray-500 border-r border-gray-300 uppercase whitespace-nowrap">
Last Updated
</th>
<th scope="col"
class="px-6 py-3 text-sm font-medium text-gray-500 border-r border-gray-300 uppercase whitespace-nowrap">
Updated By
</th>
<th scope="col"
class="px-6 py-3 text-sm font-medium text-gray-500 uppercase whitespace-nowrap">
Actions
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<tr>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
<p class="text-secondosiblue">Ticket Subject</p>
</td>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
<p class="text-secondosiblue">234233</p>
</td>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
<p class="text-secondosiblue">ggg</p>
</td>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
<p class="text-secondosiblue">20-2-234</p>
</td>
<td class="px-6 py-4 text-center text-sm border-r border-gray-300">
<p class="text-secondosiblue">20-2-234</p>
</td>
<td class="px-6 py-4 text-center text-sm">
<div class="flex justify-center items-center gap-3">
<button onclick="myFunction()">
<input type="text" class="hidden" value="https://osina.ositcom.com/my-tickets/{{ticket.ticket_number}}/" id="myInput">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-[16px] text-fifthosiblue hover:scale-110 duration-500 transition-transform">
<path stroke-linecap="round" stroke-linejoin="round" d="M7.217 10.907a2.25 2.25 0 1 0 0 2.186m0-2.186c.18.324.283.696.283 1.093s-.103.77-.283 1.093m0-2.186 9.566-5.314m-9.566 7.5 9.566 5.314m0 0a2.25 2.25 0 1 0 3.935 2.186 2.25 2.25 0 0 0-3.935-2.186Zm0-12.814a2.25 2.25 0 1 0 3.933-2.185 2.25 2.25 0 0 0-3.933 2.185Z" />
</svg>
</button>
<a href="">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"class="w-[18px] text-fifthosiblue hover:scale-110 duration-500 transition-transform">
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" />
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
</svg>
</a>
<a href="">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-[18px] text-fifthosiblue hover:scale-110 duration-500 transition-transform">
<path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
</svg>
</a>
<div class="cursor-pointer deleteTicketButton"
data-modal-url="">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-[18px] text-red-500 hover:scale-110 duration-500 transition-transform">
<path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
</svg>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>

@ -54,24 +54,26 @@
<div class="w-full bg-white h-fit rounded-md border border-gray-200">
<!-- TABLE HEADER -->
<div class="w-full h-[70px] rounded-t-md grid grid-cols-2">
<a href="{% url 'detailed-task' task.task_id %}" class="h-[70px]">
<div
class="flex justify-center items-center border-r border-b border-gray-200 px-3 {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} rounded-tl-md text-[17px] text-white text-center">
class="flex h-full justify-center items-center border-r border-b border-gray-200 px-3 {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} rounded-tl-md text-[17px] text-white text-center bg-opacity-70 hover:bg-opacity-100 duration-300">
<p>{{task.name}}</p>
</div>
</a>
<div class="grid grid-cols-3">
<div
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %}">
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} bg-opacity-70">
<p>{{task.status}}</p>
</div>
<div
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %}">
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} bg-opacity-70">
<p>{{task.start_date|date:"d-m-Y"}}</p>
</div>
<div
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} rounded-tr-md">
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} rounded-tr-md bg-opacity-70">
<p>{{task.end_date|date:"d-m-Y"}}</p>
</div>
</div>
@ -168,26 +170,28 @@
<div class="w-full h-fit bg-white p-3 rounded-md shadow-md mb-5">
<div class="border border-gray-200 rounded-t-md">
<div class="w-full rounded-t-md">
<a href="{% url 'detailed-task' task.task_id %}">
<div
class="text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} border-r border-gray-200 flex justify-center items-center text-center py-3 text-sm">
class="text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} border-r border-gray-200 flex justify-center items-center text-center py-3 text-sm bg-opacity-70 rounded-t-md hover:bg-opacity-100 duration-300">
<p>{{task.name}}</p>
</div>
</a>
</div>
<div class="grid grid-cols-3 border-t border-gray-200">
<div
class="text-white {% if task.status == 'Open' %} bg-secondosiblue {% endif %} {% if task.status == 'Working On' %} bg-yellow-500 {% endif %} {% if task.status == 'Closed' %} bg-green-700{% endif %} border-r border-gray-200 flex justify-center items-center text-center py-3 text-sm">
class="text-white {% if task.status == 'Open' %} bg-secondosiblue {% endif %} {% if task.status == 'Working On' %} bg-yellow-500 {% endif %} {% if task.status == 'Closed' %} bg-green-700{% endif %} border-r border-gray-200 flex justify-center items-center text-center py-3 text-sm bg-opacity-70">
<p>{{task.status}}</p>
</div>
<div
class="text-white {% if task.status == 'Open' %} bg-secondosiblue {% endif %} {% if task.status == 'Working On' %} bg-yellow-500 {% endif %} {% if task.status == 'Closed' %} bg-green-700{% endif %} border-r border-gray-200 flex justify-center items-center text-center py-3 text-sm">
class="text-white {% if task.status == 'Open' %} bg-secondosiblue {% endif %} {% if task.status == 'Working On' %} bg-yellow-500 {% endif %} {% if task.status == 'Closed' %} bg-green-700{% endif %} border-r border-gray-200 flex justify-center items-center text-center py-3 text-sm bg-opacity-70">
<p>{{task.start_date|date:"d-m-Y"}}</p>
</div>
<div
class="text-white {% if task.status == 'Open' %} bg-secondosiblue {% endif %} {% if task.status == 'Working On' %} bg-yellow-500 {% endif %} {% if task.status == 'Closed' %} bg-green-700{% endif %} border-r border-gray-200 flex justify-center items-center text-center py-3 text-sm">
class="text-white {% if task.status == 'Open' %} bg-secondosiblue {% endif %} {% if task.status == 'Working On' %} bg-yellow-500 {% endif %} {% if task.status == 'Closed' %} bg-green-700{% endif %} border-r border-gray-200 flex justify-center items-center text-center py-3 text-sm bg-opacity-70">
<p>{{task.end_date|date:"d-m-Y"}}</p>
</div>
</div>

@ -5,7 +5,7 @@
<!-- TABLE HEADER -->
<div class="w-full rounded-md grid grid-cols-1 l:grid-cols-2">
<div
class="w-full flex flex-col justify-center items-center gap-2 border-r border-b border-gray-200 {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} rounded-t-md l:rounded-tr-none l:rounded-l-md text-base text-white text-center py-3 px-3">
class="w-full flex flex-col justify-center items-center gap-2 border-r border-b border-gray-200 {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} rounded-t-md l:rounded-tr-none l:rounded-l-md text-base text-white text-center py-3 px-3 bg-opacity-70">
<p>{{task.name}}</p>
<div class="w-full flex justify-center items-center gap-2">
@ -25,23 +25,23 @@
<div class="w-full grid grid-cols-2">
<div
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} py-3 px-3">
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} py-3 px-3 bg-opacity-70">
<p>{{task.status}}</p>
</div>
<div
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} py-3 px-3 rounded-none l:rounded-tr-md">
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} py-3 px-3 rounded-none l:rounded-tr-md bg-opacity-70">
<p>{{task.assigned_to.user.first_name}}
{{task.assigned_to.user.last_name}}</p>
</div>
<div
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} py-3 px-3 rounded-bl-md l:rounded-none">
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} py-3 px-3 rounded-bl-md l:rounded-none bg-opacity-70">
<p>{{task.start_date|date:"d-m-Y"}}</p>
</div>
<div
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} py-3 px-3 rounded-br-md">
class="flex justify-center items-center border-r border-b border-gray-200 text-white {% if task.status == 'Open' %}bg-secondosiblue{% endif %} {% if task.status == 'Working On' %}bg-yellow-500{% endif %} {% if task.status == 'Closed' %}bg-green-700{% endif %} py-3 px-3 rounded-br-md bg-opacity-70">
<p>{{task.end_date|date:"d-m-Y"}}</p>
</div>
</div>

@ -1024,6 +1024,14 @@ video {
margin-top: 80px;
}
.ml-2 {
margin-left: 0.5rem;
}
.mr-2 {
margin-right: 0.5rem;
}
.block {
display: block;
}
@ -1807,6 +1815,10 @@ video {
border-radius: 0.75rem;
}
.rounded-lg {
border-radius: 0.5rem;
}
.rounded-b-md {
border-bottom-right-radius: 0.375rem;
border-bottom-left-radius: 0.375rem;
@ -3456,6 +3468,10 @@ video {
--tw-bg-opacity: 0.6;
}
.hover\:bg-opacity-100:hover {
--tw-bg-opacity: 1;
}
.hover\:p-2:hover {
padding: 0.5rem;
}

@ -0,0 +1,80 @@
document.addEventListener("DOMContentLoaded", () => {
const fileInput = document.querySelector("#uploader");
const progressArea = document.querySelector(".progress-area");
const uploadedArea = document.querySelector(".uploaded-area");
const uploadTrigger = fileInput.closest('div').querySelector('p');
// Add event listener to the upload trigger element
uploadTrigger.addEventListener("click", () => {
fileInput.click();
});
fileInput.onchange = ({ target }) => {
let file = target.files[0];
if (file) {
let fileName = file.name;
if (fileName.length >= 12) {
let splitName = fileName.split('.');
fileName = splitName[0].substring(0, 13) + "... ." + splitName[1];
}
// Clear previous progress and uploaded file information
progressArea.innerHTML = "";
uploadedArea.innerHTML = "";
uploadFile(fileName, file);
}
};
function uploadFile(name, file) {
let xhr = new XMLHttpRequest();
xhr.open("POST", "upload"); // Change URL to your upload endpoint
xhr.upload.addEventListener("progress", ({ loaded, total }) => {
let fileLoaded = Math.floor((loaded / total) * 100);
let fileTotal = Math.floor(total / 1000);
let fileSize;
(fileTotal < 1024) ? fileSize = fileTotal + " KB" : fileSize = (loaded / (1024 * 1024)).toFixed(2) + " MB";
let progressHTML = `<li class="flex items-center mb-4">
<i class="fas fa-file-alt text-blue-500 mr-2"></i>
<div class="flex-grow">
<div class="flex justify-between text-gray-500">
<span>${name} Uploading</span>
<span>${fileLoaded}%</span>
</div>
<div class="bg-gray-300 h-2 rounded-lg mt-1">
<div class="bg-secondosiblue h-2 rounded-lg" style="width: ${fileLoaded}%"></div>
</div>
</div>
</li>`;
uploadedArea.classList.add("onprogress");
progressArea.innerHTML = progressHTML;
if (loaded === total) {
progressArea.innerHTML = "";
let uploadedHTML = `<div class="w-full px-3 py-3 bg-secondosiblue bg-opacity-70 rounded-md flex justify-between items-center gap-3 mt-3">
<div class="flex justify-start items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="text-white h-6 w-6" color="#000000" fill="none">
<path d="M16 17L9 17" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
<path d="M16 13L13 13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
<path d="M20.5 14C20.5 17.7712 20.5 19.6569 19.2552 20.8284C18.0104 22 16.0069 22 12 22H11.2273C7.96607 22 6.33546 22 5.20307 21.2022C4.87862 20.9736 4.59058 20.7025 4.3477 20.3971C3.5 19.3313 3.5 17.7966 3.5 14.7273V12.1818C3.5 9.21865 3.5 7.73706 3.96894 6.55375C4.72281 4.65142 6.31714 3.15088 8.33836 2.44135C9.59563 2 11.1698 2 14.3182 2C16.1173 2 17.0168 2 17.7352 2.2522C18.8902 2.65765 19.8012 3.5151 20.232 4.60214C20.5 5.27832 20.5 6.12494 20.5 7.81818V14Z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round" />
<path d="M3.5 12C3.5 10.1591 4.99238 8.66667 6.83333 8.66667C7.49912 8.66667 8.28404 8.78333 8.93137 8.60988C9.50652 8.45576 9.95576 8.00652 10.1099 7.43136C10.2833 6.78404 10.1667 5.99912 10.1667 5.33333C10.1667 3.49238 11.6591 2 13.5 2" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
</svg>
<p class="text-white">${name}</p>
</div>
<div class="flex justify-end items-center gap-2">
<p class="text-white">${fileSize}</p>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="text-white h-6 w-6" fill="none">
<path d="M5 14.5C5 14.5 6.5 14.5 8.5 18C8.5 18 14.0588 8.83333 19 7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</div>
</div>`;
uploadedArea.classList.remove("onprogress");
uploadedArea.innerHTML = uploadedHTML;
}
});
let formData = new FormData();
formData.append('file', file);
xhr.send(formData);
}
});
Loading…
Cancel
Save