sackey cbae4564b9
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
Add customer portal views for dashboard, estimates, invoices, vehicles, and work orders
- Implemented dashboard view with vehicle stats, active services, recent activity, and upcoming appointments.
- Created estimates view with filtering options and a list of service estimates.
- Developed invoices view to manage service invoices and payment history with filtering.
- Added vehicles view to display registered vehicles and their details.
- Built work orders view to track the progress of vehicle services with filtering and detailed information.
2025-08-08 09:56:26 +00:00

508 lines
18 KiB
PHP

<?php
namespace App\Livewire\Users;
use Livewire\Component;
use App\Models\User;
use App\Models\Role;
use App\Models\Permission;
use Illuminate\Support\Facades\Hash;
use Spatie\Activitylog\Models\Activity;
class Show extends Component
{
public User $user;
public $activeTab = 'profile';
public $showRoleModal = false;
public $showPermissionModal = false;
public $selectedRole = null;
public $selectedPermission = null;
public $showDeleteModal = false;
public $showImpersonateModal = false;
public $showActivityModal = false;
// User actions
public $confirmingAction = false;
public $pendingAction = '';
protected $queryString = ['activeTab'];
public function mount(User $user)
{
$this->user = $user->load(['roles.permissions', 'permissions', 'customer']);
}
public function render()
{
$userRoles = $this->user->roles()
->where('user_roles.is_active', true)
->where(function ($q) {
$q->whereNull('user_roles.expires_at')
->orWhere('user_roles.expires_at', '>', now());
})
->withPivot(['branch_code', 'assigned_at', 'expires_at'])
->get();
$userDirectPermissions = $this->user->permissions()
->where('user_permissions.granted', true)
->where(function ($q) {
$q->whereNull('user_permissions.expires_at')
->orWhere('user_permissions.expires_at', '>', now());
})
->withPivot(['branch_code', 'assigned_at', 'expires_at'])
->get();
$allPermissions = $this->user->getAllPermissions();
$permissionsByModule = $allPermissions->groupBy('module');
// Get role-based permissions
$rolePermissions = collect();
foreach ($userRoles as $role) {
$rolePermissions = $rolePermissions->merge($role->permissions);
}
$rolePermissions = $rolePermissions->unique('id');
// Get recent activity
$causedByUser = Activity::where('causer_id', $this->user->id)
->where('causer_type', User::class)
->latest()
->limit(10)
->get();
$performedOnUser = Activity::where('subject_id', $this->user->id)
->where('subject_type', User::class)
->latest()
->limit(10)
->get();
$recentActivity = $causedByUser->merge($performedOnUser)
->sortByDesc('created_at')
->take(20);
// Get user metrics
$metrics = $this->getUserMetrics();
// Get user's work orders, service orders, etc. (if applicable)
$workStats = $this->getUserWorkStats();
return view('livewire.users.show', [
'userRoles' => $userRoles,
'userDirectPermissions' => $userDirectPermissions,
'allPermissions' => $allPermissions,
'permissionsByModule' => $permissionsByModule,
'rolePermissions' => $rolePermissions,
'recentActivity' => $recentActivity,
'metrics' => $metrics,
'workStats' => $workStats,
]);
}
public function setActiveTab($tab)
{
$this->activeTab = $tab;
}
public function showRoleDetails($roleId)
{
$this->selectedRole = Role::with('permissions')->find($roleId);
$this->showRoleModal = true;
}
public function showPermissionDetails($permissionId)
{
$this->selectedPermission = Permission::find($permissionId);
$this->showPermissionModal = true;
}
public function closeModals()
{
$this->showRoleModal = false;
$this->showPermissionModal = false;
$this->showDeleteModal = false;
$this->showImpersonateModal = false;
$this->showActivityModal = false;
$this->selectedRole = null;
$this->selectedPermission = null;
}
public function removeRole($roleId)
{
try {
$this->user->roles()->detach($roleId);
$this->user->refresh();
// Log the action
activity()
->performedOn($this->user)
->causedBy(auth()->user())
->withProperties(['role_id' => $roleId])
->log('Role removed from user');
session()->flash('success', 'Role removed successfully.');
} catch (\Exception $e) {
session()->flash('error', 'Failed to remove role: ' . $e->getMessage());
}
}
public function removePermission($permissionId)
{
try {
$this->user->permissions()->detach($permissionId);
$this->user->refresh();
// Log the action
activity()
->performedOn($this->user)
->causedBy(auth()->user())
->withProperties(['permission_id' => $permissionId])
->log('Permission removed from user');
session()->flash('success', 'Permission removed successfully.');
} catch (\Exception $e) {
session()->flash('error', 'Failed to remove permission: ' . $e->getMessage());
}
}
public function toggleUserStatus()
{
if ($this->user->id === auth()->id()) {
session()->flash('error', 'You cannot change your own status.');
return;
}
try {
$newStatus = $this->user->status === 'active' ? 'inactive' : 'active';
$oldStatus = $this->user->status;
$this->user->update(['status' => $newStatus]);
// Log the action
activity()
->performedOn($this->user)
->causedBy(auth()->user())
->withProperties([
'old_status' => $oldStatus,
'new_status' => $newStatus,
])
->log('User status changed');
$statusText = $newStatus === 'active' ? 'activated' : 'deactivated';
session()->flash('success', "User {$statusText} successfully.");
} catch (\Exception $e) {
session()->flash('error', 'Failed to update status: ' . $e->getMessage());
}
}
public function suspendUser()
{
if ($this->user->id === auth()->id()) {
session()->flash('error', 'You cannot suspend your own account.');
return;
}
try {
$oldStatus = $this->user->status;
$this->user->update(['status' => 'suspended']);
// Log the action
activity()
->performedOn($this->user)
->causedBy(auth()->user())
->withProperties([
'old_status' => $oldStatus,
'new_status' => 'suspended',
])
->log('User suspended');
session()->flash('success', 'User suspended successfully.');
} catch (\Exception $e) {
session()->flash('error', 'Failed to suspend user: ' . $e->getMessage());
}
}
public function impersonateUser()
{
if ($this->user->id === auth()->id()) {
session()->flash('error', 'You cannot impersonate yourself.');
return;
}
if ($this->user->status !== 'active') {
session()->flash('error', 'Cannot impersonate inactive user.');
return;
}
try {
// Log the impersonation start
activity()
->performedOn($this->user)
->causedBy(auth()->user())
->log('Impersonation started');
// Store original user ID for returning later
session(['impersonate_original_user' => auth()->id()]);
auth()->loginUsingId($this->user->id);
session()->flash('success', 'Now impersonating ' . $this->user->name);
return redirect()->route('dashboard');
} catch (\Exception $e) {
session()->flash('error', 'Failed to impersonate user: ' . $e->getMessage());
}
}
public function sendPasswordReset()
{
try {
// Generate a secure temporary password
$tempPassword = $this->generateSecurePassword();
$this->user->update([
'password' => Hash::make($tempPassword),
'password_changed_at' => now(),
]);
// Log the action
activity()
->performedOn($this->user)
->causedBy(auth()->user())
->log('Password reset by admin');
// TODO: Send password reset email with new temporary password
// $this->user->notify(new PasswordResetByAdminNotification($tempPassword));
session()->flash('success', "Password reset successfully. New temporary password: {$tempPassword}");
} catch (\Exception $e) {
session()->flash('error', 'Failed to reset password: ' . $e->getMessage());
}
}
public function generateSecurePassword($length = 12)
{
$uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$lowercase = 'abcdefghijklmnopqrstuvwxyz';
$numbers = '0123456789';
$symbols = '!@#$%^&*()_+-=[]{}|;:,.<>?';
$password = '';
$password .= $uppercase[random_int(0, strlen($uppercase) - 1)];
$password .= $lowercase[random_int(0, strlen($lowercase) - 1)];
$password .= $numbers[random_int(0, strlen($numbers) - 1)];
$password .= $symbols[random_int(0, strlen($symbols) - 1)];
$allChars = $uppercase . $lowercase . $numbers . $symbols;
for ($i = 4; $i < $length; $i++) {
$password .= $allChars[random_int(0, strlen($allChars) - 1)];
}
return str_shuffle($password);
}
public function exportUserData()
{
try {
// Log the export request
activity()
->performedOn($this->user)
->causedBy(auth()->user())
->log('User data export requested');
// TODO: Implement user data export (GDPR compliance)
// This should include all user data, activity logs, etc.
session()->flash('success', 'User data export initiated. You will receive an email when ready.');
} catch (\Exception $e) {
session()->flash('error', 'Failed to export user data: ' . $e->getMessage());
}
}
public function deleteUser()
{
if ($this->user->id === auth()->id()) {
session()->flash('error', 'You cannot delete your own account.');
return;
}
try {
// Log before deletion
activity()
->performedOn($this->user)
->causedBy(auth()->user())
->withProperties([
'deleted_user_data' => [
'name' => $this->user->name,
'email' => $this->user->email,
'employee_id' => $this->user->employee_id,
]
])
->log('User deleted by admin');
$userName = $this->user->name;
$this->user->delete();
session()->flash('success', "User '{$userName}' deleted successfully.");
return redirect()->route('users.index');
} catch (\Exception $e) {
session()->flash('error', 'Failed to delete user: ' . $e->getMessage());
}
$this->showDeleteModal = false;
}
public function confirmDelete()
{
$this->showDeleteModal = true;
}
public function confirmImpersonate()
{
$this->showImpersonateModal = true;
}
public function getUserMetrics()
{
$totalPermissions = $this->user->getAllPermissions()->count();
$directPermissions = $this->user->permissions()
->where('user_permissions.granted', true)
->where(function ($q) {
$q->whereNull('user_permissions.expires_at')
->orWhere('user_permissions.expires_at', '>', now());
})
->count();
$activeRoles = $this->user->roles()
->where('user_roles.is_active', true)
->where(function ($q) {
$q->whereNull('user_roles.expires_at')
->orWhere('user_roles.expires_at', '>', now());
})
->count();
return [
'total_permissions' => $totalPermissions,
'direct_permissions' => $directPermissions,
'role_permissions' => $totalPermissions - $directPermissions,
'active_roles' => $activeRoles,
'days_since_created' => $this->user->created_at->diffInDays(now()),
'last_login' => $this->user->last_login_at ? $this->user->last_login_at->diffForHumans() : 'Never',
'password_age' => $this->user->password_changed_at ? $this->user->password_changed_at->diffInDays(now()) : null,
];
}
public function getUserWorkStats()
{
// Get work-related statistics for the user
$stats = [
'work_orders_assigned' => 0,
'work_orders_completed' => 0,
'service_orders_created' => 0,
'total_revenue_generated' => 0,
];
try {
// Work orders assigned to user (if technician)
if (\Schema::hasTable('work_orders')) {
$stats['work_orders_assigned'] = \DB::table('work_orders')
->where('assigned_technician_id', $this->user->id)
->count();
$stats['work_orders_completed'] = \DB::table('work_orders')
->where('assigned_technician_id', $this->user->id)
->where('status', 'completed')
->count();
}
// Service orders created by user (if service advisor)
if (\Schema::hasTable('service_orders')) {
$stats['service_orders_created'] = \DB::table('service_orders')
->where('created_by', $this->user->id)
->count();
$stats['total_revenue_generated'] = \DB::table('service_orders')
->where('created_by', $this->user->id)
->where('status', 'completed')
->sum('total_amount') ?? 0;
}
} catch (\Exception $e) {
// Tables might not exist, return default stats
}
return $stats;
}
public function getStatusBadgeClass($status)
{
return match($status) {
'active' => 'bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200',
'inactive' => 'bg-zinc-100 dark:bg-zinc-700 text-zinc-800 dark:text-zinc-200',
'suspended' => 'bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200',
default => 'bg-zinc-100 dark:bg-zinc-700 text-zinc-800 dark:text-zinc-200'
};
}
public function getRoleBadgeClass($roleName)
{
return match($roleName) {
'super_admin' => 'bg-gradient-to-r from-purple-500 to-pink-500 text-white',
'administrator' => 'bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200',
'manager' => 'bg-purple-100 dark:bg-purple-900 text-purple-800 dark:text-purple-200',
'service_manager' => 'bg-indigo-100 dark:bg-indigo-900 text-indigo-800 dark:text-indigo-200',
'technician' => 'bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200',
'senior_technician' => 'bg-emerald-100 dark:bg-emerald-900 text-emerald-800 dark:text-emerald-200',
'parts_clerk' => 'bg-amber-100 dark:bg-amber-900 text-amber-800 dark:text-amber-200',
'service_advisor' => 'bg-teal-100 dark:bg-teal-900 text-teal-800 dark:text-teal-200',
'receptionist' => 'bg-pink-100 dark:bg-pink-900 text-pink-800 dark:text-pink-200',
'cashier' => 'bg-orange-100 dark:bg-orange-900 text-orange-800 dark:text-orange-200',
'customer_portal' => 'bg-purple-100 dark:bg-purple-900 text-purple-800 dark:text-purple-200',
'customer' => 'bg-gray-100 dark:bg-gray-900 text-gray-800 dark:text-gray-200',
'viewer' => 'bg-zinc-100 dark:bg-zinc-700 text-zinc-800 dark:text-zinc-200',
default => 'bg-zinc-100 dark:bg-zinc-700 text-zinc-800 dark:text-zinc-200'
};
}
public function canPerformAction($action)
{
// Check if current user can perform certain actions on this user
$currentUser = auth()->user();
// Super admin can do anything
if ($currentUser->hasRole('super_admin')) {
return true;
}
// Can't perform actions on yourself (except view)
if ($currentUser->id === $this->user->id && $action !== 'view') {
return false;
}
// Check specific permissions based on action
return match($action) {
'edit' => $currentUser->can('users.edit'),
'delete' => $currentUser->can('users.delete'),
'impersonate' => $currentUser->can('users.impersonate'),
'reset_password' => $currentUser->can('users.reset-password'),
'manage_roles' => $currentUser->can('users.manage-roles'),
'view_activity' => $currentUser->can('users.view-activity'),
default => false,
};
}
public function getLastActivityDate()
{
$lastActivity = Activity::where('causer_id', $this->user->id)
->where('causer_type', User::class)
->latest()
->first();
return $lastActivity ? $lastActivity->created_at->diffForHumans() : 'No activity recorded';
}
public function getTotalLoginCount()
{
// This would require a login tracking system
return Activity::where('causer_id', $this->user->id)
->where('causer_type', User::class)
->where('description', 'like', '%login%')
->count();
}
}