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:
Generated
+90
-15
@@ -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 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)) import django; print('Django %s' % django.get_version()) sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS]) if 'setup' in dir(django): django.setup() 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)) import django; print('Django %s' % django.get_version()) sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS]) if 'setup' in dir(django): django.setup() 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 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 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 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 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 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 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 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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'
|
||||
|
||||
@@ -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">
|
||||
<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 -->
|
||||
|
||||
@@ -22,42 +22,84 @@
|
||||
</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 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>#}
|
||||
{# #}
|
||||
{# <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="p-6">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<div class="card-body">
|
||||
<div class="table-container">
|
||||
<table>
|
||||
<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>
|
||||
<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 class="divide-y divide-gray-200">
|
||||
<tbody>
|
||||
{% 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>{{ 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 %}
|
||||
@@ -65,6 +107,8 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
{% endblock content %}
|
||||
@@ -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>
|
||||
|
||||
@@ -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 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" }}#}
|
||||
|
||||
@@ -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 %}
|
||||
Reference in New Issue
Block a user