user roles, bug fixes

This commit is contained in:
Kwesi Banson
2026-10-13 14:29:40 +00:00
parent 40162f3080
commit 8428d94abd
14 changed files with 366 additions and 9 deletions

View File

@@ -255,4 +255,42 @@
</form>
</div>
</div>
</div>
<!-- Add Note Modal -->
<div class="modal fade" id="addNoteModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header bg-light border-bottom-0">
<h5 class="modal-title fw-bold">Add Internal Note</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form id="addNoteForm" action="{{ route('mnos.notes.store', $operator->id) }}" method="POST">
@csrf
<div class="modal-body p-4">
<div id="noteModalAlert"></div>
<div class="mb-3">
<label class="form-label text-secondary fw-semibold small">Related Service / Topic (Optional)</label>
<select name="services" id="note_services" class="form-select" style="width: 100%;">
<option value=""></option>
@foreach($allServices as $svc)
<option value="{{ $svc->name }}">{{ $svc->name }}</option>
@endforeach
</select>
</div>
<div class="mb-3">
<label class="form-label text-secondary fw-semibold small">Note Detail *</label>
<textarea name="notes_body" class="form-control" rows="4" required placeholder="Log call notes, updates, or instructions here..."></textarea>
</div>
</div>
<div class="modal-footer bg-light border-top-0">
<button type="button" class="btn btn-outline-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
<button type="submit" id="btnSubmitNote" class="btn text-white btn-sm fw-bold px-4" style="background-color: #5c4df0;">Save Note</button>
</div>
</form>
</div>
</div>
</div>

View File

@@ -1,7 +1,31 @@
@extends('layouts.masterbeta')
@section('title', 'Cick ERP - ' . $operator->name)
@push('styles')
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<style>
/* Keep your existing styles here... */
/* Select2 Bootstrap 5 / Custom tweaks */
.select2-container .select2-selection--single {
height: 38px;
border: 1px solid #dee2e6;
border-radius: 0.375rem;
display: flex;
align-items: center;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
height: 36px;
}
.network-badge { font-size: 0.65rem; padding: 0.2rem 0.4rem; border-radius: 4px; border: 1px solid #e2e8f0; font-weight: 600; display: inline-flex; align-items: center; gap: 3px; }
.net-approved { background-color: rgba(16, 185, 129, 0.1); color: #10b981; border-color: rgba(16, 185, 129, 0.2); }
.net-pending { background-color: rgba(245, 158, 11, 0.1); color: #f59e0b; border-color: rgba(245, 158, 11, 0.2); }
.net-rejected { background-color: rgba(239, 68, 68, 0.1); color: #ef4444; border-color: rgba(239, 68, 68, 0.2); }
.sender-id-text { font-family: monospace; font-size: 1.1rem; letter-spacing: 1px; color: #111425; }
</style>
@endpush
@section('breadcrumbs')
<a href="{{ url('/') }}" class="text-secondary text-decoration-none"><i class="bi bi-house me-2"></i></a>
<i class="bi bi-chevron-right text-secondary me-2" style="font-size: 0.8rem;"></i>
@@ -303,6 +327,44 @@
</tbody>
</table>
</div>
<!-- Notes Section -->
<div class="content-card p-4 mb-4">
<div class="d-flex justify-content-between align-items-center mb-3">
<h5 class="fw-bold mb-0 text-secondary" style="font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.5px;">
<i class="bi bi-journal-text me-2 text-primary"></i> Internal Notes & Activity
</h5>
<button type="button" class="btn btn-sm text-white fw-bold" style="background-color: #5c4df0;" data-bs-toggle="modal" data-bs-target="#addNoteModal">
<i class="bi bi-plus-lg me-1"></i> Add Note
</button>
</div>
<hr class="text-muted opacity-25">
<div class="mt-3">
@forelse($operator->notes as $note)
<div class="border-bottom pb-3 mb-3">
<div class="d-flex justify-content-between align-items-start">
<div>
<span class="fw-bold text-dark">{{ $note->user->name ?? 'System User' }}</span>
<span class="text-secondary small ms-2"><i class="bi bi-clock me-1"></i>{{ $note->created_at->format('d M Y, h:i A') }}</span>
@if($note->services)
<span class="badge bg-light text-primary border ms-2">{{ $note->services }}</span>
@endif
</div>
<form action="{{ route('mnos.notes.destroy', $note->id) }}" method="POST" class="d-inline">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-sm btn-light text-danger border-0 p-1" onclick="return confirm('Delete this note?')">
<i class="bi bi-trash"></i>
</button>
</form>
</div>
<div class="text-dark mt-2" style="font-size: 0.9rem; white-space: pre-wrap;">{{ $note->notes_body }}</div>
</div>
@empty
<div class="text-center text-secondary py-4">No notes added yet.</div>
@endforelse
</div>
</div>
</div>
</div>
</div>
@@ -317,6 +379,7 @@
const baseUrl = "{{ url('/') }}";
const operatorId = "{{ $operator->id }}";
</script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script src="{{ asset('public/assets/js/mno-show.js') }}"></script>

View File

@@ -149,7 +149,8 @@
data-department_id="{{ $staff->department_id }}"
data-location_country="{{ $staff->location_country }}"
data-status="{{ $staff->status }}"
data-pic="{{ $staff->profile_pic ? asset('public/storage/' . $staff->profile_pic) : '' }}">
data-pic="{{ $staff->profile_pic ? asset('public/storage/' . $staff->profile_pic) : '' }}"
data-roles="{{ $staff->roles->pluck('id')->toJson() }}">
<i class="bi bi-pencil me-1"></i> Edit
</button>
@@ -258,6 +259,16 @@
<option value="INACTIVE">Inactive</option>
</select>
</div>
<!-- Insert this directly after the Status col-md-4 block -->
<div class="col-12 mt-3 pt-3 border-top">
<label class="form-label text-secondary fw-semibold small">System Roles & Permissions</label>
<select class="form-select" id="staffRoles" name="roles[]" multiple="multiple">
@foreach($systemRoles as $role)
<option value="{{ $role->id }}">{{ $role->label }}</option>
@endforeach
</select>
<div class="form-text text-muted" style="font-size: 0.75rem;">Leave blank for standard employee access.</div>
</div>
</div>
</div>
<div class="modal-footer bg-light">
@@ -318,6 +329,19 @@
<div class="text-secondary small fw-semibold">ANNUAL LEAVE BALANCE</div>
<div class="fw-medium text-dark small"><span id="viewStaffLeaveBalance">0</span> Days</div>
</div>
<div class="col-md-4">
<div class="text-secondary small fw-semibold">ANNUAL LEAVE BALANCE</div>
<div class="fw-medium text-dark small"><span id="viewStaffLeaveBalance">0</span> Days</div>
</div>
<!-- NEW ROLES SECTION -->
<div class="col-12 mt-3 pt-3 border-top">
<div class="text-secondary small fw-semibold mb-2">SYSTEM ROLES</div>
<div id="viewStaffRoles" class="d-flex flex-wrap gap-1">
<span class="text-muted small">Loading...</span>
</div>
</div>
<!-- END ROLES SECTION -->
</div>
<!-- Emergency Contacts Table Section -->
@@ -423,6 +447,12 @@
width: '100%',
dropdownParent: $('#staffModal')
});
$('#staffRoles').select2({
placeholder: "Select applicable roles...",
allowClear: true,
width: '100%',
dropdownParent: $('#staffModal')
});
// Handle Photo Preview
$('#staffPhoto').on('change', function(e) {
@@ -441,7 +471,7 @@
$('#staffId').val('');
$('#avatarPreview').html('<i class="bi bi-person text-secondary"></i>');
$('#staffCountry').val(null).trigger('change');
$('#staffRoles').val(null).trigger('change');
$('#staffModalTitle').text('Add New Employee');
$('#btnSubmitStaff').html('<i class="bi bi-save me-2"></i>Save Employee');
staffModal.show();
@@ -460,6 +490,7 @@
$('#staffPhone').val(data.phone);
$('#staffDept').val(data.department_id);
$('#staffCountry').val(data.location_country).trigger('change');
$('#staffRoles').val(data.roles).trigger('change');
$('#staffStatus').val(data.status);
if (data.pic) {
@@ -559,7 +590,7 @@
$('#viewStaffLocation').text('');
$('#viewStaffLeaveBalance').text('');
$('#viewStaffDependentsList').html('<tr><td colspan="4" class="text-center text-secondary py-3">Loading...</td></tr>');
$('#viewStaffRoles').html('<span class="text-muted small">Loading...</span>');
viewModal.show();
// Fetch staff details via AJAX
@@ -590,6 +621,15 @@
let initials = staff.name.split(' ').map(n => n[0]).join('').substring(0, 2).toUpperCase();
$('#viewStaffAvatarContainer').html(`<div class="rounded-circle bg-light text-primary fw-bold d-flex align-items-center justify-content-center border" style="width: 70px; height: 70px; font-size: 1.5rem;">${initials}</div>`);
}
let rolesHtml = '';
if (staff.roles && staff.roles.length > 0) {
staff.roles.forEach(role => {
rolesHtml += `<span class="badge bg-primary bg-opacity-10 text-primary border border-primary-subtle px-2 py-1">${role.label}</span>`;
});
} else {
rolesHtml = `<span class="text-muted small fst-italic">Standard Employee Access</span>`;
}
$('#viewStaffRoles').html(rolesHtml);
// Dependents Table population
let dependentsHtml = '';