Skip to main content

Inactive Driver Feature — Changes Summary

Date: February 20, 2026


Overview

The inactive driver feature adds status (boolean) and inactive_at (date) columns to the drivers table, allowing drivers to be marked as active or inactive. Inactive drivers are hidden from assignment dropdowns, blocked from new task assignments, and prevented from logging into the mobile app.

Total files changed: 41 modified + 6 new files/directories


1. Database Migration

[NEW] database/migrations/2026_02_19_113248_add_status_to_drivers_table.php

  • Adds status (BOOLEAN, default 1) after line_color
  • Adds inactive_at (DATE, nullable) after status
  • Creates indexes on both columns

2. Model Layer

app/Driver.php

  • Imports: Added Carbon, Task, RunsheetRental
  • Fillable: Added 'status', 'inactive_at'
  • Casts: New $casts array — 'status' => 'boolean', 'inactive_at' => 'date:Y-m-d', 'licence_expired_date' => 'date:Y-m-d'
  • Default Attributes: 'status' => true
  • New Scopes:
    • scopeActive($query, $date = null) — filters active drivers; optionally includes drivers inactive after a given date
    • scopeInactive($query) — filters inactive drivers
  • New Helper Methods:
    • isActive(): bool — checks if status === true
    • wasActiveOn(string $date): bool — checks if driver was still active on a historical date

3. Repository Layer

app/Repositories/DriverRepository.php

  • New Methods:
    • canBeDeactivated(Driver $driver): bool — returns true if no blocking future tasks exist
    • getDeactivationErrors(Driver $driver): array — checks future direct tasks (via user_iddue_date) and future runsheet rental tasks (via driver_iddate)
    • deactivate(Driver $driver): bool — sets status = false, inactive_at = today, syncs User.status = 0, unassigns vehicle (within DB transaction)
    • activate(Driver $driver): bool — sets status = true, inactive_at = null, syncs User.status = 1 (within DB transaction)

4. Shared Trait

[NEW] app/Http/Controllers/Traits/ManagesDriverStatus.php

Shared trait used by both Admin\DriverController and Dashboard\DriverController.

  • Abstract methods (implemented per controller):
    • getDriverForStatusUpdate($id) — retrieves driver (with scoping)
    • authorizeDriverStatusUpdate(Request $request) — authorization check
  • Public endpoints:
    • activate(Request, DriverRepository, $id) — activates a driver (AJAX + redirect support)
    • deactivate(Request, DriverRepository, $id) — validates deactivation, then deactivates (AJAX + redirect support)
    • toggleStatus(Request, DriverRepository, $id) — AJAX-only toggle with validation

5. Middleware

[NEW] app/Http/Middleware/CheckDriverActive.php

  • Blocks inactive drivers from accessing api-driver and api-app routes
  • Returns 403 JSON response: "Your account is inactive. Please contact support."
  • Exempts the logout route

app/Http/Kernel.php

  • Registered as 'driver.active' in route middleware

app/Providers/RouteServiceProvider.php

  • Added 'driver.active' middleware to the driverApiRoutes() group

6. Controller Changes — By Endpoint

6.1 Admin\DriverController

EndpointMethodChanges
GET /admin/driversindex()Added ?status=active|inactive|all query filter; eager-loads user; passes $statusFilter and $repo to view
POST /admin/driversstore()Explicitly sets 'status' => true on new driver
GET /admin/drivers/{id}/editedit()Injects DriverRepository, passes $repo to view
PUT /admin/drivers/{id}update()Handles status change via $repo->canBeDeactivated() / $repo->deactivate() / $repo->activate()
POST /admin/drivers/{id}/activateactivate()Via ManagesDriverStatus trait
POST /admin/drivers/{id}/deactivatedeactivate()Via ManagesDriverStatus trait
PUT /admin/drivers/{id}/toggle-statustoggleStatus()Via ManagesDriverStatus trait

Trait implementation: getDriverForStatusUpdate() uses Driver::findOrFail($id). Authorization checks drivers-update permission.


6.2 Dashboard\DriverController

EndpointMethodChanges
GET /dashboard/driversindex()Added ?status=active|inactive|all query filter scoped by supplier; passes $statusFilter and $repo to view
GET /dashboard/drivers/{id}/editedit()Injects DriverRepository, passes $repo to view
POST /dashboard/drivers/{id}/activateactivate()Via ManagesDriverStatus trait
POST /dashboard/drivers/{id}/deactivatedeactivate()Via ManagesDriverStatus trait
POST /dashboard/drivers/{id}/toggle-statustoggleStatus()Via ManagesDriverStatus trait

Trait implementation: getDriverForStatusUpdate() scopes by supplier_id. Authorization defers to middleware.


6.3 Admin\TaskController

EndpointMethodChanges
GET /admin/tasks/createcreate()Driver dropdown now filters by ->active() scope
GET /admin/tasks/{task}/editedit()Driver dropdown includes active drivers + the currently assigned driver (even if inactive) via ->active()->orWhere('user_id', $task->user_id)
PUT /admin/tasks/{task}update()Validates that newly assigned driver (by driver_id or user_id) is active; throws exception if inactive
POST /admin/tasks/change-statuschangeStatus()Validates assigned driver is active before saving
POST /admin/tasks/move-multi-taskmoveMultiTask()Validates target driver is active; returns error if inactive
GET /admin/tasks/get-active-driversgetActiveDrivers()New endpoint — returns JSON list of active drivers (id, name, licence_class)

6.4 Dashboard\TaskController

EndpointMethodChanges
GET /dashboard/tasksindex()Driver filter dropdown scoped to ->active() for supplier
GET /dashboard/tasks/{task}/editedit()Driver dropdown includes active + currently assigned driver via ->active()->orWhere('user_id', $task->user_id)
PUT /dashboard/tasks/{task}update()Validates new driver assignment is active before saving
PUT /dashboard/tasks-assign/{task}assignTask()Validates driver is active before assignment

6.5 Admin\TaskRunsheetController

EndpointMethodChanges
GET /admin/task-runsheet/scheduleschedule()Filters drivers by ->active($date) scope; skips inactive drivers during day iteration via inactive_at check
GET /admin/task-runsheet/timesheettimesheet()Filters drivers by ->active($startDate)

6.6 Admin\RunsheetGroupController

EndpointMethodChanges
GET /admin/runsheet-groups/createcreate()Driver dropdown filtered by ->active()
GET /admin/runsheet-groups/{id}/editedit()Driver dropdown includes active + currently assigned driver via ->active()->orWhere('id', $runSheetGroup->driver_id)

6.7 Admin\RunsheetRentalController

EndpointMethodChanges
GET /admin/runsheet-rentalsindex()Driver dropdown filtered by ->active($date)
GET /admin/runsheet-rentals/createcreate()Driver dropdown filtered by ->active()
GET /admin/runsheet-rentals/{id}/editedit()Driver dropdown includes active + currently assigned driver via ->active()->orWhere('id', $runSheetRental->driver_id)

6.8 Admin\BinLogisticController

EndpointMethodChanges
GET /admin/bin-logisticindex()Driver list filtered by ->active($startDate)
POST /admin/bin-logistic/searchsearch()$all_drivers query filters by ->active($startDate) via whereHas('driver')

6.9 Admin\DriverTimesheetController

EndpointMethodChanges
GET /admin/driver/timesheetindex()Moved driver query after date calculation; filters by ->active($startDate)

6.10 Admin\TrackLocationController

EndpointMethodChanges
GET /admin/driver-timesheetdriverTimesheet()Filters drivers by ->active($date)
GET /admin/track-driverexportTrackLocation()Filters drivers by ->active($startDate)

6.11 Api\DriverController

EndpointMethodChanges
GET /api/driver-roomgetDriverRoom()Filters by Driver::active()
GET /api/driver-supplier-roomgetDriverSupplierRoom()Filters by ->active()
GET /api/driver-availabilitygetDriverAvailability()Filters by ->active($date) via whereHas('driver'); adds 'is_inactive' flag to response

6.12 ApiApp\RunsheetController

EndpointMethodChanges
POST /api-app/runsheet/staffrunsheetStaff()Changed Driver::get()Driver::active()->get()

7. Route Changes

routes/admin.php

  • Added: POST drivers/{id}/activate, POST drivers/{id}/deactivate, PUT drivers/{id}/toggle-status
  • Added: GET tasks/get-active-drivers

routes/dashboard.php

  • Added: POST drivers/{id}/activate, POST drivers/{id}/deactivate, POST drivers/{id}/toggle-status

routes/api-app.php

  • Added 'driver.active' middleware to the main API group

8. Vue Component Changes

resources/js/components/runsheets/Assign2.vue

  • Drag-and-drop: blocks assigning tasks to inactive drivers with SweetAlert warning
  • MoveMultiTask modal: passes active_driver_tasks (new computed) instead of all driver_tasks
  • Shows "Inactive" badge next to inactive driver names in the driver panel

resources/js/components/DriverAvailabilityOption.vue

  • isDisabled(): adds driver.is_inactive check
  • driverLabel(): shows "- Inactive" label for inactive drivers

resources/js/components/TrackMap.vue

  • Shows "Inactive" warning badge next to driver name when inactive_at is set

9. Blade View Changes

The following views were modified (primarily adding status badges, filter dropdowns, and activate/deactivate buttons):

ViewKey Changes
admin/driver/index.blade.phpStatus filter dropdown, status badge column, activate/deactivate buttons
admin/driver/edit.blade.phpStatus display + action buttons
admin/driver/timesheet.blade.phpAccommodates active driver filtering
admin/task/index.blade.phpDriver filter uses active drivers
admin/task/edit.blade.phpDriver dropdown shows active + assigned
admin/bin-logistic/index.blade.phpUses filtered active drivers
admin/bin-logistic/task-listing-list-view.blade.phpUses filtered $all_drivers
admin/runsheet-groups/index.blade.phpUses filtered active drivers
admin/runsheet-rentals/index.blade.phpUses filtered active drivers
admin/runsheet-rentals/form.blade.phpActive driver dropdown
admin/summary.blade.phpActive driver timesheet
dashboard/driver/index.blade.phpStatus filter, badges, action buttons
dashboard/driver/edit.blade.phpStatus display + action buttons
dashboard/task/index.blade.phpActive driver filter
dashboard/task/edit.blade.phpActive + assigned driver dropdown
dashboard/bin-logistic/task-listing-list-view.blade.phpUses filtered active drivers

[NEW] resources/views/dashboard/driver/partials/

  • New partial directory (likely for SweetAlert confirmation scripts)

10. Other Modified Files

FileChanges
app/Scopes/OrderByCreatedAtDesc.phpFormatting only
public/js/app.jsRebuilt with Vue component changes
public/mix-manifest.jsonUpdated asset hashes