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.
master
kikimor 8 months ago
parent 0eefaad424
commit 78d570ad4f

@ -5,26 +5,39 @@
</component> </component>
<component name="ChangeListManager"> <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."> <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/forms.css" afterDir="false" />
<change afterPath="$PROJECT_DIR$/static/styles/styles.css" afterDir="false" /> <change afterPath="$PROJECT_DIR$/templates/employee-base.html" afterDir="false" />
<change afterPath="$PROJECT_DIR$/templates/client-dashboard-original.html" afterDir="false" /> <change afterPath="$PROJECT_DIR$/templates/employee-dashboard-content.html" afterDir="false" />
<change afterPath="$PROJECT_DIR$/templates/landing-page.html" afterDir="false" /> <change afterPath="$PROJECT_DIR$/templates/employee-sidebar.html" afterDir="false" />
<change afterPath="$PROJECT_DIR$/users/forms.py" afterDir="false" /> <change afterPath="$PROJECT_DIR$/templates/recent.html" afterDir="false" />
<change afterPath="$PROJECT_DIR$/users/urls.py" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DepoT/settings.py" beforeDir="false" afterPath="$PROJECT_DIR$/DepoT/settings.py" afterDir="false" /> <change beforePath="$PROJECT_DIR$/accounts/admin.py" beforeDir="false" afterPath="$PROJECT_DIR$/accounts/admin.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/DepoT/urls.py" beforeDir="false" afterPath="$PROJECT_DIR$/DepoT/urls.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$/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> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" /> <option name="LAST_RESOLUTION" value="IGNORE" />
</component> </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"> <component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES"> <option name="RECENT_TEMPLATES">
<list> <list>
<option value="HTML File" />
<option value="Python Script" /> <option value="Python Script" />
<option value="CSS File" />
<option value="HTML File" />
</list> </list>
</option> </option>
</component> </component>
@ -48,17 +61,24 @@
"RunOnceActivity.ShowReadmeOnStart": "true", "RunOnceActivity.ShowReadmeOnStart": "true",
"django.template.preview.state": "SHOW_EDITOR_AND_PREVIEW", "django.template.preview.state": "SHOW_EDITOR_AND_PREVIEW",
"git-widget-placeholder": "master", "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.eslint": "true",
"node.js.detected.package.tslint": "true", "node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)", "node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)", "node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm", "nodejs_package_manager_path": "npm",
"vue.rearranger.settings.migration": "true" "vue.rearranger.settings.migration": "true"
},
"keyToStringList": {
"DatabaseDriversLRU": [
"postgresql"
]
} }
}]]></component> }]]></component>
<component name="RecentsManager"> <component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS"> <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\templates" />
<recent name="C:\dev_projects\python\Django\DepoT\static\styles" /> <recent name="C:\dev_projects\python\Django\DepoT\static\styles" />
</key> </key>
@ -106,7 +126,7 @@
<option name="number" value="Default" /> <option name="number" value="Default" />
<option name="presentableId" value="Default" /> <option name="presentableId" value="Default" />
<updated>1750784740296</updated> <updated>1750784740296</updated>
<workItem from="1750784741367" duration="29605000" /> <workItem from="1750784741367" duration="164972000" />
</task> </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."> <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" /> <option name="closed" value="true" />
@ -124,7 +144,55 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1750855273832</updated> <updated>1750855273832</updated>
</task> </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 /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
@ -138,11 +206,18 @@
<breakpoint-manager> <breakpoint-manager>
<breakpoints> <breakpoints>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line"> <line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/common/views.py</url> <url>file://$PROJECT_DIR$/containers/views.py</url>
<line>22</line> <line>35</line>
<option name="timeStamp" value="1" /> <option name="timeStamp" value="13" />
</line-breakpoint> </line-breakpoint>
</breakpoints> </breakpoints>
<default-breakpoints>
<breakpoint type="python-exception">
<properties notifyOnTerminate="true" exception="BaseException">
<option name="notifyOnTerminate" value="true" />
</properties>
</breakpoint>
</default-breakpoints>
</breakpoint-manager> </breakpoint-manager>
</component> </component>
</project> </project>

@ -12,13 +12,14 @@ class DepotUserAdmin(UserAdmin):
'company', 'company',
'line', 'line',
'company_permissions', 'company_permissions',
'new_field1', 'user_type',
'is_company_admin',
)}), )}),
) )
# Add fields to display in list view # 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 fields to the add form
add_fieldsets = UserAdmin.add_fieldsets + ( add_fieldsets = UserAdmin.add_fieldsets + (
@ -28,7 +29,6 @@ class DepotUserAdmin(UserAdmin):
'company', 'company',
'line', 'line',
'company_permissions', 'company_permissions',
'new_field1', 'user_type',
'is_company_admin',
)}), )}),
) )

@ -16,18 +16,25 @@ class RegisterForm(ModelForm):
password1 = CharField(label='Password', widget=PasswordInput) password1 = CharField(label='Password', widget=PasswordInput)
password2 = CharField(label='Confirm 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: class Meta:
model = get_user_model() 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): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.fields['password1'].widget.attrs.update({'autocomplete': 'new-password'}) self.fields['password1'].widget.attrs.update({'autocomplete': 'new-password'})
self.fields['password2'].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): def clean(self):
cleaned_data = super().clean() cleaned_data = super().clean()

@ -1,3 +1,4 @@
from django.contrib.auth.base_user import BaseUserManager
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.db import models from django.db import models
@ -13,11 +14,69 @@ class ClientPermission(models.Model):
('can_view_bookings', 'Can view bookings'), ('can_view_bookings', 'Can view bookings'),
('can_manage_company_users', 'Can manage company users'), ('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): def __str__(self):
return self.name 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 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) phone_number = models.CharField(max_length=15, blank=True, null=True)
email = models.EmailField(unique=True, blank=False, null=False) email = models.EmailField(unique=True, blank=False, null=False)
company = models.ForeignKey( company = models.ForeignKey(
@ -36,13 +95,14 @@ class DepotUser(AbstractUser):
) )
company_permissions = models.ManyToManyField('ClientPermission') company_permissions = models.ManyToManyField('ClientPermission')
new_field1 = models.BooleanField(default=False) employee_permissions = models.ManyToManyField('EmployeePermission', blank=True)
is_company_admin = models.BooleanField(default=False)
def has_company_perm(self, perm_codename): def has_company_perm(self, perm_codename):
if self.is_superuser: if self.is_superuser:
return True return True
return self.company_permissions.filter( return self.company_permissions.filter(codename=perm_codename).exists()
codename=perm_codename,
is_client_permission=self.company def has_employee_perm(self, perm_codename):
).exists() if self.is_superuser:
return True
return self.employee_permissions.filter(codename=perm_codename).exists()

@ -2,12 +2,17 @@ from django.contrib.auth import get_user_model
from django.contrib.auth.views import LoginView from django.contrib.auth.views import LoginView
from django.shortcuts import render from django.shortcuts import render
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView, FormView, ListView, UpdateView from django.views.generic import TemplateView, FormView, ListView, UpdateView
from accounts.forms import LoginForm, RegisterForm 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. # Create your views here.
class DepotLoginView(LoginView): class DepotLoginView(LoginView):
template_name = 'registration/login.html' template_name = 'registration/login.html'
# success_url = reverse_lazy('dashboard') # success_url = reverse_lazy('dashboard')
@ -15,19 +20,71 @@ class DepotLoginView(LoginView):
next_page = reverse_lazy('dashboard') 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' template_name = 'registration/register.html'
form_class = RegisterForm form_class = RegisterForm
# model = get_user_model() # model = get_user_model()
success_url = reverse_lazy('dashboard') 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): def form_valid(self, form):
# Create user from form data # Create user from form data
user = form.save(commit=False) 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.set_password(form.cleaned_data['password'])
user.save() user.save()
return super().form_valid(form) 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): class UserListView(ListView):
template_name = 'registration/register.html' template_name = 'registration/register.html'
# form_class = RegisterForm # form_class = RegisterForm

@ -1,10 +1,12 @@
from django.urls import path from django.urls import path, include
from common import views from common import views
urlpatterns = [ urlpatterns = [
path('', views.IndexView.as_view(), name='index'), path('', views.IndexView.as_view(), name='index'),
path('client/dashboard/', views.ClientDashboardView.as_view(), name='client_dashboard'), path('dashboard/', include([
path('barrier/dashboard/', views.BarrierDashboardView.as_view(), name='barrier_dashboard'), path('', views.DashboardRedirectView.as_view(), name='dashboard'),
path('client/', views.ClientDashboardView.as_view(), name='client_dashboard'),
path('dashboard/', views.DashboardRedirectView.as_view(), name='dashboard'), path('barrier/', views.BarrierDashboardView.as_view(), name='barrier_dashboard'),
path('employee/', views.EmployeeDashboardView.as_view(), name='employee_dashboard'),
]))
] ]

@ -2,6 +2,11 @@ from django.urls import reverse_lazy
from django.views.generic import TemplateView, RedirectView from django.views.generic import TemplateView, RedirectView
from django.shortcuts import render 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. # Create your views here.
class IndexView(TemplateView): class IndexView(TemplateView):
@ -21,12 +26,16 @@ class DashboardRedirectView(RedirectView):
def get_redirect_url(self, *args, **kwargs): def get_redirect_url(self, *args, **kwargs):
# if self.request.user.is_authenticated: # 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') 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') 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') 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') return reverse_lazy('index')
@ -47,10 +56,26 @@ class BarrierDashboardView(TemplateView):
'description': 'This is the client dashboard page.', 'description': 'This is the client dashboard page.',
} }
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
return render(request, self.template_name, self.extra_context) 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): # class ClientPreinfoView(TemplateView):
# template_name = 'client-preinfo-content.html' # template_name = 'client-preinfo-content.html'

@ -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;
}

@ -6,6 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Line Operator Dashboard | Container Depot</title> <title>Line Operator Dashboard | Container Depot</title>
<script src="https://cdn.tailwindcss.com"></script> <script src="https://cdn.tailwindcss.com"></script>
<style> <style>
body { body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
@ -57,6 +58,7 @@
to { opacity: 1; transform: translateY(0); } to { opacity: 1; transform: translateY(0); }
} }
</style> </style>
<link rel="stylesheet" href="{% static 'styles/forms.css' %}">
</head> </head>
<body class="flex h-screen overflow-hidden"> <body class="flex h-screen overflow-hidden">
<!-- Sidebar --> <!-- Sidebar -->

@ -22,49 +22,93 @@
</div> </div>
</div> </div>
<div class="mt-6 bg-white rounded-lg shadow"> {# <div class="mt-6 bg-white rounded-lg shadow">#}
<div class="px-6 py-4 border-b border-gray-200"> {# <div class="px-6 py-4 border-b border-gray-200">#}
<h3 class="text-lg font-semibold text-gray-800">Recent Preinfo Submissions</h3> {# <h3 class="text-lg font-semibold text-gray-800">Recent Preinfo Submissions</h3>#}
</div> {# </div>#}
<div class="p-6"> {# <div class="p-6">#}
<div class="overflow-x-auto"> {# <div class="overflow-x-auto">#}
<table class="min-w-full divide-y divide-gray-200"> {# <table class="min-w-full divide-y divide-gray-200">#}
<thead> {# <thead>#}
<tr> {# <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">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">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">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">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">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">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">Status</th>#}
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th> {# <th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>#}
</tr> {# </tr>#}
</thead> {# </thead>#}
<tbody class="divide-y divide-gray-200"> {# <tbody class="divide-y divide-gray-200">#}
{% for booking in recent %} {# {% for booking in recent %}#}
<tr> {# <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.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 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_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.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.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 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> </div>
{% endblock content %} {% endblock content %}

@ -32,14 +32,17 @@
Reports Reports
</a> </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> <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"> <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="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" /> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg> </svg>
Settings Settings
</a> </a>
{% endif %}
</nav> </nav>
<div class="p-4 border-t border-blue-700"> <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-sm font-medium">{{ request.user }}</p>
<p class="text-xs text-blue-300">{{ request.user.company }}</p> <p class="text-xs text-blue-300">{{ request.user.company }}</p>
</div> </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"> <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" /> <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> </svg>

@ -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>

@ -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 %}

@ -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>

@ -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>

@ -5,7 +5,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Container Depot Management System</title> <title>Container Depot Management System</title>
<link rel="stylesheet" href="{% static '/css/styles.css' %}"/> <link rel="stylesheet" href="{% static '/styles/styles.css' %}"/>
</head> </head>
<body> <body>
{# {{ title|default:"Container Depot Management System" }} {{ description|default:"Login to the Container Depot Management System" }}#} {# {{ title|default:"Container Depot Management System" }} {{ description|default:"Login to the Container Depot Management System" }}#}

@ -1,14 +1,55 @@
<!DOCTYPE html> {% extends 'client-base.html' %}
<html lang="en"> {% block content %}
<head>
<meta charset="UTF-8">
<title>Register User</title>
</head>
<body>
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
{{ form.as_p }} {{ form }}
<button type="submit">Register</button> <button type="submit">Register</button>
</form> </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 %}
Loading…
Cancel
Save