Add IntelliJ IDEA project configuration files

This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.
This commit is contained in:
2025-07-03 18:43:27 +03:00
parent 0eefaad424
commit 78d570ad4f
17 changed files with 1022 additions and 95 deletions
+90 -15
View File
@@ -5,26 +5,39 @@
</component>
<component name="ChangeListManager">
<list default="true" id="7410a44d-51b9-408b-85ad-4fa46776b372" name="Changes" comment="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<change afterPath="$PROJECT_DIR$/common/urls.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/static/styles/styles.css" afterDir="false" />
<change afterPath="$PROJECT_DIR$/templates/client-dashboard-original.html" afterDir="false" />
<change afterPath="$PROJECT_DIR$/templates/landing-page.html" afterDir="false" />
<change afterPath="$PROJECT_DIR$/users/forms.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/users/urls.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DepoT/settings.py" beforeDir="false" afterPath="$PROJECT_DIR$/DepoT/settings.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DepoT/urls.py" beforeDir="false" afterPath="$PROJECT_DIR$/DepoT/urls.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/static/styles/forms.css" afterDir="false" />
<change afterPath="$PROJECT_DIR$/templates/employee-base.html" afterDir="false" />
<change afterPath="$PROJECT_DIR$/templates/employee-dashboard-content.html" afterDir="false" />
<change afterPath="$PROJECT_DIR$/templates/employee-sidebar.html" afterDir="false" />
<change afterPath="$PROJECT_DIR$/templates/recent.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/accounts/admin.py" beforeDir="false" afterPath="$PROJECT_DIR$/accounts/admin.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/accounts/forms.py" beforeDir="false" afterPath="$PROJECT_DIR$/accounts/forms.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/accounts/models.py" beforeDir="false" afterPath="$PROJECT_DIR$/accounts/models.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/accounts/views.py" beforeDir="false" afterPath="$PROJECT_DIR$/accounts/views.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/common/urls.py" beforeDir="false" afterPath="$PROJECT_DIR$/common/urls.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/common/views.py" beforeDir="false" afterPath="$PROJECT_DIR$/common/views.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/client-base.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/client-base.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/client-booking-content.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/client-booking-content.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/client-sidebar.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/client-sidebar.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/registration/login.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/registration/login.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/templates/registration/register.html" beforeDir="false" afterPath="$PROJECT_DIR$/templates/registration/register.html" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="ChangesViewManager" show_ignored="true" />
<component name="DjangoConsoleOptions" custom-start-script="import sys; print('Python %s on %s' % (sys.version, sys.platform))&#10;import django; print('Django %s' % django.get_version())&#10;sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS])&#10;if 'setup' in dir(django): django.setup()&#10;import django_manage_shell; django_manage_shell.run(PROJECT_ROOT)">
<option name="myCustomStartScript" value="import sys; print('Python %s on %s' % (sys.version, sys.platform))&#10;import django; print('Django %s' % django.get_version())&#10;sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS])&#10;if 'setup' in dir(django): django.setup()&#10;import django_manage_shell; django_manage_shell.run(PROJECT_ROOT)" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="HTML File" />
<option value="Python Script" />
<option value="CSS File" />
<option value="HTML File" />
</list>
</option>
</component>
@@ -48,17 +61,24 @@
"RunOnceActivity.ShowReadmeOnStart": "true",
"django.template.preview.state": "SHOW_EDITOR_AND_PREVIEW",
"git-widget-placeholder": "master",
"last_opened_file_path": "C:/dev_projects/python/Django/DepoT/templates",
"last_opened_file_path": "C:/dev_projects/python/Django/DepoT/templates/registration",
"list.type.of.created.stylesheet": "CSS",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"vue.rearranger.settings.migration": "true"
},
"keyToStringList": {
"DatabaseDriversLRU": [
"postgresql"
]
}
}]]></component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="C:\dev_projects\python\Django\DepoT\templates\registration" />
<recent name="C:\dev_projects\python\Django\DepoT\templates" />
<recent name="C:\dev_projects\python\Django\DepoT\static\styles" />
</key>
@@ -106,7 +126,7 @@
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1750784740296</updated>
<workItem from="1750784741367" duration="29605000" />
<workItem from="1750784741367" duration="164972000" />
</task>
<task id="LOCAL-00001" summary="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<option name="closed" value="true" />
@@ -124,7 +144,55 @@
<option name="project" value="LOCAL" />
<updated>1750855273832</updated>
</task>
<option name="localTasksCounter" value="3" />
<task id="LOCAL-00003" summary="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<option name="closed" value="true" />
<created>1750942491703</created>
<option name="number" value="00003" />
<option name="presentableId" value="LOCAL-00003" />
<option name="project" value="LOCAL" />
<updated>1750942491703</updated>
</task>
<task id="LOCAL-00004" summary="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<option name="closed" value="true" />
<created>1750942543055</created>
<option name="number" value="00004" />
<option name="presentableId" value="LOCAL-00004" />
<option name="project" value="LOCAL" />
<updated>1750942543055</updated>
</task>
<task id="LOCAL-00005" summary="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<option name="closed" value="true" />
<created>1750942560128</created>
<option name="number" value="00005" />
<option name="presentableId" value="LOCAL-00005" />
<option name="project" value="LOCAL" />
<updated>1750942560128</updated>
</task>
<task id="LOCAL-00006" summary="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<option name="closed" value="true" />
<created>1751295996186</created>
<option name="number" value="00006" />
<option name="presentableId" value="LOCAL-00006" />
<option name="project" value="LOCAL" />
<updated>1751295996186</updated>
</task>
<task id="LOCAL-00007" summary="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<option name="closed" value="true" />
<created>1751359397230</created>
<option name="number" value="00007" />
<option name="presentableId" value="LOCAL-00007" />
<option name="project" value="LOCAL" />
<updated>1751359397230</updated>
</task>
<task id="LOCAL-00008" summary="Add IntelliJ IDEA project configuration files&#10;&#10;This commit adds IntelliJ IDEA-specific configuration files for the project, including module setup, version control integration, inspection profiles, and workspace settings. These files facilitate development environment configuration for contributors using IntelliJ IDEA.">
<option name="closed" value="true" />
<created>1751443902965</created>
<option name="number" value="00008" />
<option name="presentableId" value="LOCAL-00008" />
<option name="project" value="LOCAL" />
<updated>1751443902965</updated>
</task>
<option name="localTasksCounter" value="9" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
@@ -138,11 +206,18 @@
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/common/views.py</url>
<line>22</line>
<option name="timeStamp" value="1" />
<url>file://$PROJECT_DIR$/containers/views.py</url>
<line>35</line>
<option name="timeStamp" value="13" />
</line-breakpoint>
</breakpoints>
<default-breakpoints>
<breakpoint type="python-exception">
<properties notifyOnTerminate="true" exception="BaseException">
<option name="notifyOnTerminate" value="true" />
</properties>
</breakpoint>
</default-breakpoints>
</breakpoint-manager>
</component>
</project>
+5 -5
View File
@@ -12,13 +12,14 @@ class DepotUserAdmin(UserAdmin):
'company',
'line',
'company_permissions',
'new_field1',
'is_company_admin',
'user_type',
)}),
)
# Add fields to display in list view
list_display = UserAdmin.list_display + ('phone_number', 'company', 'line', 'is_company_admin')
list_display = ('username', 'email', 'user_type', 'company', 'line', 'is_active', 'is_staff', 'is_superuser')
search_fields = ('username', 'email')
list_filter = ('user_type', 'is_active', 'is_staff', 'is_superuser')
# Add fields to the add form
add_fieldsets = UserAdmin.add_fieldsets + (
@@ -28,7 +29,6 @@ class DepotUserAdmin(UserAdmin):
'company',
'line',
'company_permissions',
'new_field1',
'is_company_admin',
'user_type',
)}),
)
+9 -2
View File
@@ -16,18 +16,25 @@ class RegisterForm(ModelForm):
password1 = CharField(label='Password', widget=PasswordInput)
password2 = CharField(label='Confirm Password', widget=PasswordInput)
field_order = ['username', 'email', 'password1', 'password2', 'phone_number', 'line', 'company_permissions']
field_order = ['username', 'email', 'password1', 'password2', 'phone_number', 'company', 'line', 'user_type', 'company_permissions', 'employee_permissions', 'is_active']
class Meta:
model = get_user_model()
fields = ['username', 'email', 'password1', 'password2', 'phone_number', 'line', 'company_permissions']
fields = ['username', 'email', 'password1', 'password2', 'phone_number', 'company', 'line', 'user_type', 'company_permissions', 'employee_permissions', 'is_active']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['password1'].widget.attrs.update({'autocomplete': 'new-password'})
self.fields['password2'].widget.attrs.update({'autocomplete': 'new-password'})
self.fields['user_type'].widget.attrs['disabled'] = True
self.fields['company_permissions'].widget.attrs['disabled'] = True
self.fields['employee_permissions'].widget.attrs['disabled'] = True
if self.data.get('user_type') in ( 'EM', 'BS'):
self.fields['company_permissions'].required = False
if self.data.get('user_type') in ('CL', 'CA', 'BS'):
self.fields['company_permissions'].required = False
def clean(self):
cleaned_data = super().clean()
+66 -6
View File
@@ -1,3 +1,4 @@
from django.contrib.auth.base_user import BaseUserManager
from django.contrib.auth.models import AbstractUser
from django.db import models
@@ -13,11 +14,69 @@ class ClientPermission(models.Model):
('can_view_bookings', 'Can view bookings'),
('can_manage_company_users', 'Can manage company users'),
)
def __str__(self):
return self.name
class EmployeePermission(models.Model):
codename = models.CharField(max_length=100, default='')
name = models.CharField(max_length=255, default='')
class Meta:
managed = True
default_permissions = ()
permissions = (
('can_manage_containers', 'Can manage containers'),
('can_view_reports', 'Can view reports'),
('can_handle_operations', 'Can handle operations'),
)
def __str__(self):
return self.name
class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError('Users must have an email address')
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password=None, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
extra_fields.setdefault('user_type', 'AD') # Set user_type to admin
if extra_fields.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self.create_user(email, password, **extra_fields)
class DepotUser(AbstractUser):
class UserType(models.TextChoices):
BARRIER_STAFF = 'BS', 'Barrier Staff'
COMPANY_ADMIN = 'CA', 'Company Admin'
EMPLOYEE = 'EM', 'Employee'
CLIENT = 'CL', 'Client',
ADMIN = 'AD', 'Admin'
objects = CustomUserManager()
user_type = models.CharField(
max_length=2,
choices=UserType.choices,
default=UserType.CLIENT
)
phone_number = models.CharField(max_length=15, blank=True, null=True)
email = models.EmailField(unique=True, blank=False, null=False)
company = models.ForeignKey(
@@ -36,13 +95,14 @@ class DepotUser(AbstractUser):
)
company_permissions = models.ManyToManyField('ClientPermission')
new_field1 = models.BooleanField(default=False)
is_company_admin = models.BooleanField(default=False)
employee_permissions = models.ManyToManyField('EmployeePermission', blank=True)
def has_company_perm(self, perm_codename):
if self.is_superuser:
return True
return self.company_permissions.filter(
codename=perm_codename,
is_client_permission=self.company
).exists()
return self.company_permissions.filter(codename=perm_codename).exists()
def has_employee_perm(self, perm_codename):
if self.is_superuser:
return True
return self.employee_permissions.filter(codename=perm_codename).exists()
+59 -2
View File
@@ -2,12 +2,17 @@ from django.contrib.auth import get_user_model
from django.contrib.auth.views import LoginView
from django.shortcuts import render
from django.urls import reverse_lazy
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView, FormView, ListView, UpdateView
from accounts.forms import LoginForm, RegisterForm
from accounts.models import DepotUser
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.mixins import AccessMixin
# Create your views here.
class DepotLoginView(LoginView):
template_name = 'registration/login.html'
# success_url = reverse_lazy('dashboard')
@@ -15,19 +20,71 @@ class DepotLoginView(LoginView):
next_page = reverse_lazy('dashboard')
class RegisterView(FormView):
def is_company_admin(user):
return user.is_authenticated and user.is_company_admin
@method_decorator(login_required, name='dispatch')
class RegisterView(AccessMixin, FormView):
template_name = 'registration/register.html'
form_class = RegisterForm
# model = get_user_model()
success_url = reverse_lazy('dashboard')
def dispatch(self, request, *args, **kwargs):
user: DepotUser = request.user
if not (user.is_superuser or user.user_type == DepotUser.UserType.COMPANY_ADMIN):
return self.handle_no_permission()
return super().dispatch(request, *args, **kwargs)
def form_valid(self, form):
# Create user from form data
user = form.save(commit=False)
user_type = form.cleaned_data['user_type']
# Clear irrelevant permissions based on user type
if user_type == DepotUser.UserType.CLIENT:
user.employee_permissions.clear()
elif user_type == DepotUser.UserType.EMPLOYEE:
user.company_permissions.clear()
# user.set_password(form.cleaned_data['password'])
user.save()
return super().form_valid(form)
def get_form(self, form_class = None):
form = super().get_form(form_class)
user: DepotUser = self.request.user
if user.is_superuser:
# Superuser can manage all permissions and user types
form.fields['user_type'].widget.attrs['disabled'] = False
form.fields['company_permissions'].widget.attrs['disabled'] = False
form.fields['employee_permissions'].widget.attrs['disabled'] = False
# Show relevant permissions based on selected user type
if form.initial.get('user_type') == DepotUser.UserType.CLIENT:
form.fields['employee_permissions'].widget.attrs['disabled'] = True
elif form.initial.get('user_type') == DepotUser.UserType.EMPLOYEE:
form.fields['company_permissions'].widget.attrs['disabled'] = True
elif user.user_type == DepotUser.UserType.COMPANY_ADMIN:
form.fields['company'].queryset = form.fields['company'].queryset.filter(pk=user.company.pk)
form.fields['company'].initial = user.company
form.fields['company'].widget.readonly = True # form.fields['line'].widget.attrs['disabled'] = True
form.fields['line'].queryset = form.fields['line'].queryset.filter(company=user.company.pk)
form.fields['user_type'].choices = [
(DepotUser.UserType.CLIENT, 'Client')
]
form.fields['user_type'].initial = DepotUser.UserType.CLIENT
form.fields['company_permissions'].widget.attrs['disabled'] = False
form.fields['employee_permissions'].widget.attrs['disabled'] = True
return form
class UserListView(ListView):
template_name = 'registration/register.html'
# form_class = RegisterForm
+7 -5
View File
@@ -1,10 +1,12 @@
from django.urls import path
from django.urls import path, include
from common import views
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('client/dashboard/', views.ClientDashboardView.as_view(), name='client_dashboard'),
path('barrier/dashboard/', views.BarrierDashboardView.as_view(), name='barrier_dashboard'),
path('dashboard/', views.DashboardRedirectView.as_view(), name='dashboard'),
path('dashboard/', include([
path('', views.DashboardRedirectView.as_view(), name='dashboard'),
path('client/', views.ClientDashboardView.as_view(), name='client_dashboard'),
path('barrier/', views.BarrierDashboardView.as_view(), name='barrier_dashboard'),
path('employee/', views.EmployeeDashboardView.as_view(), name='employee_dashboard'),
]))
]
+28 -3
View File
@@ -2,6 +2,11 @@ from django.urls import reverse_lazy
from django.views.generic import TemplateView, RedirectView
from django.shortcuts import render
from accounts.models import DepotUser
from booking.models import Booking
from containers.models import Container
from preinfo.models import Preinfo
# Create your views here.
class IndexView(TemplateView):
@@ -21,12 +26,16 @@ class DashboardRedirectView(RedirectView):
def get_redirect_url(self, *args, **kwargs):
# if self.request.user.is_authenticated:
if self.request.user.username == 'client':
if self.request.user.user_type == DepotUser.UserType.COMPANY_ADMIN:
return reverse_lazy('client_dashboard')
elif self.request.user.username == 'clientadmin':
elif self.request.user.user_type == DepotUser.UserType.CLIENT:
return reverse_lazy('client_dashboard')
elif self.request.user.username == 'barrier':
elif self.request.user.user_type == DepotUser.UserType.BARRIER_STAFF:
return reverse_lazy('barrier_dashboard')
elif self.request.user.user_type == DepotUser.UserType.EMPLOYEE:
return reverse_lazy('employee_dashboard')
elif self.request.user.user_type == DepotUser.UserType.ADMIN:
return reverse_lazy('employee_dashboard')
return reverse_lazy('index')
@@ -47,10 +56,26 @@ class BarrierDashboardView(TemplateView):
'description': 'This is the client dashboard page.',
}
def get(self, request, *args, **kwargs):
return render(request, self.template_name, self.extra_context)
class EmployeeDashboardView(TemplateView):
template_name = 'employee-dashboard-content.html'
extra_context = {
'title': 'Employee Dashboard',
'description': 'This is the depot employee dashboard page.',
}
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
containers = Container.objects.filter(expedited=False).count()
preinfos = Preinfo.objects.filter(received=False).count()
bookings = Booking.objects.filter(status='active').count()
context['containers'] = containers
context['preinfos'] = preinfos
context['bookings'] = bookings
return context
# class ClientPreinfoView(TemplateView):
# template_name = 'client-preinfo-content.html'
+149
View File
@@ -0,0 +1,149 @@
/* Basic form styling */
form {
max-width: 600px;
margin: 20px auto;
padding: 20px;
}
/* Label styling */
label {
display: block;
margin-bottom: 2px;
font-weight: 500;
color: #a57d52;
}
/* Input field styling */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="date"],
input[type="number"],
select,
textarea {
width: 100%;
padding: 8px;
margin-bottom: 10px;
border: 1px solid #a57d52;
border-radius: 4px;
box-sizing: border-box;
}
/* Submit button styling */
button[type="submit"] {
background-color: #a57d52;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
/*margin-top: 20px;*/
}
button[type="submit"]:hover {
background-color: #a67744;
}
/* Error messages */
.errorlist {
color: #dc3545;
list-style: none;
padding: 0;
margin: 5px 0;
font-size: 0.9em;
}
/* Help text */
.helptext {
color: #666;
font-size: 0.9em;
margin-bottom: 10px;
display: block;
}
.card {
margin-top: 24px;
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}
.card-header {
padding: 16px 24px;
border-bottom: 1px solid #ddd;
}
.card-header h3 {
margin: 0;
font-size: 18px;
font-weight: bold;
color: #333;
}
.card-body {
padding: 24px;
}
.table-container {
overflow-x: auto;
}
table {
width: 100%;
border-collapse: collapse;
}
thead {
background-color: #f9f9f9;
}
th, td {
padding: 12px 16px;
text-align: left;
font-size: 14px;
}
th {
font-weight: bold;
text-transform: uppercase;
color: #666;
border-bottom: 1px solid #ddd;
}
tbody tr {
border-bottom: 1px solid #eee;
}
.status {
display: inline-block;
padding: 4px 8px;
font-size: 12px;
font-weight: bold;
border-radius: 12px;
background-color: #e0f0ff;
color: #0066cc;
}
.actions button {
background: none;
border: none;
color: #0066cc;
font-size: 14px;
cursor: pointer;
margin-right: 10px;
}
.actions button:hover {
color: #004999;
}
.actions button:last-child {
color: #cc0000;
margin-right: 0;
}
.actions button:last-child:hover {
color: #990000;
}
+2
View File
@@ -6,6 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Line Operator Dashboard | Container Depot</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
@@ -57,6 +58,7 @@
to { opacity: 1; transform: translateY(0); }
}
</style>
<link rel="stylesheet" href="{% static 'styles/forms.css' %}">
</head>
<body class="flex h-screen overflow-hidden">
<!-- Sidebar -->
+86 -42
View File
@@ -22,49 +22,93 @@
</div>
</div>
<div class="mt-6 bg-white rounded-lg shadow">
<div class="px-6 py-4 border-b border-gray-200">
<h3 class="text-lg font-semibold text-gray-800">Recent Preinfo Submissions</h3>
</div>
<div class="p-6">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead>
<tr>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Booking №</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Container №</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Container count</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Containers left</th>
{# <div class="mt-6 bg-white rounded-lg shadow">#}
{# <div class="px-6 py-4 border-b border-gray-200">#}
{# <h3 class="text-lg font-semibold text-gray-800">Recent Preinfo Submissions</h3>#}
{# </div>#}
{# <div class="p-6">#}
{# <div class="overflow-x-auto">#}
{# <table class="min-w-full divide-y divide-gray-200">#}
{# <thead>#}
{# <tr>#}
{# <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Booking №</th>#}
{# <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Container №</th>#}
{# <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>#}
{# <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Container count</th>#}
{# <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Containers left</th>#}
{# <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Vehicles</th>#}
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Vehicles</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
{% for booking in recent %}
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">{{ booking.number }}</td>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">{{ booking.container_number }}</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">{{ booking.container_type }}</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">{{ booking.container_count }}</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">{{ booking.containers_left }}</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">{{ booking.vehicles_left }}</td>
{# <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Vehicles</th>#}
{# <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>#}
{# <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>#}
{# </tr>#}
{# </thead>#}
{# <tbody class="divide-y divide-gray-200">#}
{# {% for booking in recent %}#}
{# <tr>#}
{# <td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">{{ booking.number }}</td>#}
{# <td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">{{ booking.container_number }}</td>#}
{# <td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">{{ booking.container_type }}</td>#}
{# <td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">{{ booking.container_count }}</td>#}
{# <td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">{{ booking.containers_left }}</td>#}
{# <td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">{{ booking.vehicles_left }}</td>#}
{# #}
{# <td class="px-4 py-3 whitespace-nowrap">#}
{# <span class="px-2 py-1 text-xs font-semibold rounded-full bg-blue-100 text-blue-800">{{ booking.status }}</span>#}
{# </td>#}
{# <td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">#}
{# <button class="text-blue-600 hover:text-blue-800 mr-3">Edit</button>#}
{# <button class="text-red-600 hover:text-red-800">Cancel</button>#}
{# </td>#}
{# </tr>#}
{# {% endfor %}#}
{# </tbody>#}
{# </table>#}
{# </div>#}
{# </div>#}
{# </div>#}
<div class="card">
<div class="card-header">
<h3>Recent Preinfo Submissions</h3>
</div>
<div class="card-body">
<div class="table-container">
<table>
<thead>
<tr>
<th>Booking №</th>
<th>Container №</th>
<th>Type</th>
<th>Container count</th>
<th>Containers left</th>
<th>Vehicles</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for booking in recent %}
<tr>
<td>{{ booking.number }}</td>
<td>{{ booking.container_number }}</td>
<td>{{ booking.container_type }}</td>
<td>{{ booking.container_count }}</td>
<td>{{ booking.containers_left }}</td>
<td>{{ booking.vehicles_left }}</td>
<td><span class="status">{{ booking.status }}</span></td>
<td class="actions">
<button>Edit</button>
<button>Cancel</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-blue-100 text-blue-800">{{ booking.status }}</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">
<button class="text-blue-600 hover:text-blue-800 mr-3">Edit</button>
<button class="text-red-600 hover:text-red-800">Cancel</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endblock content %}
+5 -2
View File
@@ -32,14 +32,17 @@
Reports
</a>
{% if request.user.UserType.COMPANY_ADMIN %}
<div class="px-4 py-2 mt-6 text-xs text-blue-300 uppercase tracking-wider">Account</div>
<a href="#" class="nav-item flex items-center px-6 py-3 text-white">
<a href="{% url 'register' %}" class="nav-item flex items-center px-6 py-3 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Settings
</a>
{% endif %}
</nav>
<div class="p-4 border-t border-blue-700">
@@ -51,7 +54,7 @@
<p class="text-sm font-medium">{{ request.user }}</p>
<p class="text-xs text-blue-300">{{ request.user.company }}</p>
</div>
<a href="{% url 'relogin' %}" class="ml-auto text-white" >
<a href="{% url 'login' %}" class="ml-auto text-white" >
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
</svg>
+196
View File
@@ -0,0 +1,196 @@
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Employee Dashboard | Container Depot</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f5f7fa;
}
.sidebar {
background: linear-gradient(180deg, #0f4c81 0%, #1a6baf 100%);
transition: all 0.3s;
}
.content-area {
transition: all 0.3s;
}
.nav-item {
transition: all 0.2s;
}
.nav-item:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.nav-item.active {
background-color: rgba(255, 255, 255, 0.2);
border-left: 4px solid white;
}
.card {
transition: all 0.3s;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.tab {
transition: all 0.2s;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
animation: fadeIn 0.5s ease-in-out;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.form-section {
animation: slideIn 0.5s ease-in-out;
}
@keyframes slideIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
<link rel="stylesheet" href="{% static 'styles/forms.css' %}">
</head>
<body class="flex h-screen overflow-hidden">
<!-- Sidebar -->
{% include 'employee-sidebar.html' %}
<!-- Main Content -->
<main class="content-area flex-1 overflow-y-auto">
<!-- Top Navigation -->
<header class="bg-white shadow-sm">
<div class="flex items-center justify-between px-6 py-4">
<div class="flex items-center">
<h2 class="text-xl font-semibold text-gray-800">Dashboard</h2>
</div>
<div class="flex items-center space-x-4">
<button class="text-gray-500 hover:text-gray-700">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
</svg>
</button>
<button class="text-gray-500 hover:text-gray-700">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</button>
</div>
</div>
</header>
<!-- Dashboard Content -->
<div class="p-6">
{% block content %}
{# {% include 'client-dashboard-content.html' %}#}
{# {% include 'client-preinfo-content.html' %}#}
{# {% include 'client-orders-content.html' %}#}
{% endblock content %}
</div>
</main>
{# <script>#}
{# // Tab Navigation#}
{# const dashboardContent = document.getElementById('dashboardContent');#}
{# const preinfoContent = document.getElementById('preinfoContent');#}
{# const ordersContent = document.getElementById('ordersContent');#}
{# #}
{# const preinfoNav = document.getElementById('preinfoNav');#}
{# const ordersNav = document.getElementById('ordersNav');#}
{# #}
{# preinfoNav.addEventListener('click', function(e) {#}
{# e.preventDefault();#}
{# #}
{# // Update content visibility#}
{# dashboardContent.classList.remove('active');#}
{# preinfoContent.classList.add('active');#}
{# ordersContent.classList.remove('active');#}
{# #}
{# // Update navigation styling#}
{# document.querySelector('.nav-item.active').classList.remove('active');#}
{# preinfoNav.classList.add('active');#}
{# #}
{# // Update header title#}
{# document.querySelector('header h2').textContent = 'Container Preinfo';#}
{# });#}
{# #}
{# ordersNav.addEventListener('click', function(e) {#}
{# e.preventDefault();#}
{# #}
{# // Update content visibility#}
{# dashboardContent.classList.remove('active');#}
{# preinfoContent.classList.remove('active');#}
{# ordersContent.classList.add('active');#}
{# #}
{# // Update navigation styling#}
{# document.querySelector('.nav-item.active').classList.remove('active');#}
{# ordersNav.classList.add('active');#}
{# #}
{# // Update header title#}
{# document.querySelector('header h2').textContent = 'Expedition Orders';#}
{# });#}
{# #}
{# // Damage checkbox toggle#}
{# const damageCheck = document.getElementById('damageCheck');#}
{# const damageDetails = document.getElementById('damageDetails');#}
{# #}
{# damageCheck.addEventListener('change', function() {#}
{# if (this.checked) {#}
{# damageDetails.classList.remove('hidden');#}
{# } else {#}
{# damageDetails.classList.add('hidden');#}
{# }#}
{# });#}
{# #}
{# // Order type toggle#}
{# const specificContainer = document.getElementById('specificContainer');#}
{# const anyContainer = document.getElementById('anyContainer');#}
{# const specificContainerFields = document.getElementById('specificContainerFields');#}
{# const anyContainerFields = document.getElementById('anyContainerFields');#}
{# #}
{# specificContainer.addEventListener('change', function() {#}
{# if (this.checked) {#}
{# specificContainerFields.classList.remove('hidden');#}
{# anyContainerFields.classList.add('hidden');#}
{# }#}
{# });#}
{# #}
{# anyContainer.addEventListener('change', function() {#}
{# if (this.checked) {#}
{# specificContainerFields.classList.add('hidden');#}
{# anyContainerFields.classList.remove('hidden');#}
{# }#}
{# });#}
{# #}
{# // Form submissions#}
{# document.getElementById('preinfoForm').addEventListener('submit', function(e) {#}
{# e.preventDefault();#}
{# #}
{# // In a real app, this would send data to the server#}
{# alert('Preinfo submitted successfully!');#}
{# this.reset();#}
{# });#}
{# #}
{# document.getElementById('orderForm').addEventListener('submit', function(e) {#}
{# e.preventDefault();#}
{# #}
{# // In a real app, this would send data to the server#}
{# alert('Expedition order submitted successfully!');#}
{# this.reset();#}
{# });#}
{# #}
{# // Add more container button#}
{# document.getElementById('addMoreContainer').addEventListener('click', function() {#}
{# alert('In a real app, this would add fields for another container');#}
{# });#}
{# </script>#}
{#<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'947f86ac452d3130',t:'MTc0ODYyMTY4Mi4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>#}
</body>
</html>
+162
View File
@@ -0,0 +1,162 @@
{% extends 'employee-base.html' %}
{% block content %}
<div id="dashboardContent" class="tab-content active">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
<div class="card bg-white rounded-lg shadow p-6">
<div class="flex items-center">
<div class="p-3 rounded-full bg-blue-100 text-blue-600">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
</svg>
</div>
<div class="ml-4">
<h3 class="text-lg font-semibold text-gray-700">Active Containers</h3>
<p class="text-3xl font-bold text-gray-900">{{ containers }}</p>
<p class="text-sm text-green-600">+3 since last week</p>
</div>
</div>
</div>
<div class="card bg-white rounded-lg shadow p-6">
<div class="flex items-center">
<div class="p-3 rounded-full bg-green-100 text-green-600">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<div class="ml-4">
<h3 class="text-lg font-semibold text-gray-700">Preinfo Sent</h3>
<p class="text-3xl font-bold text-gray-900">{{ preinfos }}</p>
<p class="text-sm text-green-600">+5 since last week</p>
</div>
</div>
</div>
<div class="card bg-white rounded-lg shadow p-6">
<div class="flex items-center">
<div class="p-3 rounded-full bg-orange-100 text-orange-600">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" />
</svg>
</div>
<div class="ml-4">
<h3 class="text-lg font-semibold text-gray-700">Bookings</h3>
<p class="text-3xl font-bold text-gray-900">{{ bookings }}</p>
<p class="text-sm text-orange-600">2 require attention</p>
</div>
</div>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div class="bg-white rounded-lg shadow">
<div class="px-6 py-4 border-b border-gray-200">
<h3 class="text-lg font-semibold text-gray-800">Recent Container Activity</h3>
</div>
<div class="p-6">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead>
<tr>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Container</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">MSCU1234567</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">40HC</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-green-100 text-green-800">Received</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">2023-06-15</td>
</tr>
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">MSCU7654321</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">20DV</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-blue-100 text-blue-800">Preinfo</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">2023-06-14</td>
</tr>
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">MSCU2468135</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">40DV</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-orange-100 text-orange-800">Order</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">2023-06-13</td>
</tr>
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">MSCU1357924</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">20RF</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-red-100 text-red-800">Expedited</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">2023-06-12</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow">
<div class="px-6 py-4 border-b border-gray-200">
<h3 class="text-lg font-semibold text-gray-800">Payment Status</h3>
</div>
<div class="p-6">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead>
<tr>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Invoice</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Amount</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Due Date</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">INV-2023-0042</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">$1,250.00</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-green-100 text-green-800">Paid</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">2023-06-10</td>
</tr>
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">INV-2023-0041</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">$875.50</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-yellow-100 text-yellow-800">Pending</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">2023-06-20</td>
</tr>
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">INV-2023-0040</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">$2,100.00</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-red-100 text-red-800">Overdue</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">2023-06-05</td>
</tr>
<tr>
<td class="px-4 py-3 whitespace-nowrap text-sm font-medium text-gray-900">INV-2023-0039</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">$950.25</td>
<td class="px-4 py-3 whitespace-nowrap">
<span class="px-2 py-1 text-xs font-semibold rounded-full bg-green-100 text-green-800">Paid</span>
</td>
<td class="px-4 py-3 whitespace-nowrap text-sm text-gray-700">2023-05-28</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
+64
View File
@@ -0,0 +1,64 @@
{% load static %}
<aside class="sidebar w-64 h-full text-white flex flex-col">
<div class="p-5 border-b border-blue-700">
<h1 class="text-xl font-bold">Container Depot</h1>
<p class="text-sm text-blue-200">Employee Portal</p>
</div>
<nav class="flex-grow py-4">
<div class="px-4 py-2 text-xs text-blue-300 uppercase tracking-wider">Main</div>
<a href="{% url 'dashboard' %}" class="nav-item active flex items-center px-6 py-3 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
</svg>
Dashboard
</a>
<a href="{% url 'client_preinfo' %}" id="preinfoNav" class="nav-item flex items-center px-6 py-3 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
</svg>
Container Preinfo
</a>
<a href="{% url 'client_booking' %}" id="ordersNav" class="nav-item flex items-center px-6 py-3 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" />
</svg>
Bookings
</a>
<a href="#" class="nav-item flex items-center px-6 py-3 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
Reports
</a>
{% if request.user.UserType.ADMIN %}
<div class="px-4 py-2 mt-6 text-xs text-blue-300 uppercase tracking-wider">Account</div>
<a href="{% url 'register' %}" class="nav-item flex items-center px-6 py-3 text-white">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Settings
</a>
{% endif %}
</nav>
<div class="p-4 border-t border-blue-700">
<div class="flex items-center">
<div class="w-10 h-10 rounded-full bg-blue-500 flex items-center justify-center text-white font-bold">
LO
</div>
<div class="ml-3">
<p class="text-sm font-medium">{{ request.user }}</p>
<p class="text-xs text-blue-300">{{ request.user.company }}</p>
</div>
<a href="{% url 'login' %}" class="ml-auto text-white" >
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
</svg>
</a>
</div>
</div>
</aside>
+40
View File
@@ -0,0 +1,40 @@
<div class="card">
<div class="card-header">
<h3>Recent Preinfo Submissions</h3>
</div>
<div class="card-body">
<div class="table-container">
<table>
<thead>
<tr>
<th>Booking №</th>
<th>Container №</th>
<th>Type</th>
<th>Container count</th>
<th>Containers left</th>
<th>Vehicles</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for booking in recent %}
<tr>
<td>{{ booking.number }}</td>
<td>{{ booking.container_number }}</td>
<td>{{ booking.container_type }}</td>
<td>{{ booking.container_count }}</td>
<td>{{ booking.containers_left }}</td>
<td>{{ booking.vehicles_left }}</td>
<td><span class="status">{{ booking.status }}</span></td>
<td class="actions">
<button>Edit</button>
<button>Cancel</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
+1 -1
View File
@@ -5,7 +5,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Container Depot Management System</title>
<link rel="stylesheet" href="{% static '/css/styles.css' %}"/>
<link rel="stylesheet" href="{% static '/styles/styles.css' %}"/>
</head>
<body>
{# {{ title|default:"Container Depot Management System" }} {{ description|default:"Login to the Container Depot Management System" }}#}
+51 -10
View File
@@ -1,14 +1,55 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Register User</title>
</head>
<body>
{% extends 'client-base.html' %}
{% block content %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
{{ form }}
<button type="submit">Register</button>
</form>
</body>
</html>
<script>
document.addEventListener('DOMContentLoaded', function() {
const userTypeSelect = document.getElementById('id_user_type');
const companyPerms = document.getElementById('id_company_permissions');
const employeePerms = document.getElementById('id_employee_permissions');
function handleUserTypeChange(select) {
console.log('User type changed to:', userTypeSelect.value); // Add this line
// {#if (!userTypeSelect || !companyPerms || !employeePerms) return;#}
const isSuperuser = {{ user.is_superuser|yesno:"true,false" }};
const isCompanyAdmin = ('{{ user.user_type }}' === 'CA');
// Remove disabled attribute first
companyPerms.removeAttribute('disabled');
employeePerms.removeAttribute('disabled');
switch(userTypeSelect.value) {
case 'CL': // Client
companyPerms.disabled = false;
employeePerms.disabled = true;
break;
case 'EM': // Employee
companyPerms.disabled = true;
employeePerms.disabled = false;
break;
default:
companyPerms.disabled = true;
employeePerms.disabled = true;
break;
}
companyPerms.parentElement.hidden = companyPerms.disabled;
employeePerms.parentElement.hidden = employeePerms.disabled;
}
// Add change event listener
if (userTypeSelect) {
userTypeSelect.addEventListener('change', handleUserTypeChange);
// Initial call to set up the form correctly
handleUserTypeChange();
}
});
</script>
{% endblock content %}