From cc129bccac37bba952d5a2569fd73ed4f6d04c1e Mon Sep 17 00:00:00 2001 From: Kwesi Banson Jnr Date: Thu, 20 Aug 2026 19:08:31 +0000 Subject: [PATCH] added document vault and bug fixes on profile and staff members controllers --- app/Http/Controllers/DocumentsController.php | 88 ++-- .../Controllers/StaffMembersController.php | 10 + app/Models/DocumentType.php | 11 + app/Models/GeneralDocument.php | 5 + resources/views/documents/index.blade.php | 434 +++++++++--------- resources/views/staff/index.blade.php | 160 ++++++- routes/web.php | 9 +- 7 files changed, 456 insertions(+), 261 deletions(-) create mode 100644 app/Models/DocumentType.php diff --git a/app/Http/Controllers/DocumentsController.php b/app/Http/Controllers/DocumentsController.php index e4ce51c..d845c30 100644 --- a/app/Http/Controllers/DocumentsController.php +++ b/app/Http/Controllers/DocumentsController.php @@ -6,51 +6,79 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Log; +use App\Models\GeneralDocument; +use App\Models\StaffMember; +use App\Models; + class DocumentsController extends Controller { + public function index(Request $request) + { + $query = GeneralDocument::query(); + + // Optional filtering by category + if ($request->filled('category')) { + $query->where('category', $request->category); + } + + // Search by name or description + if ($request->filled('search')) { + $search = $request->search; + $query->where(function($q) use ($search) { + $q->where('name', 'like', "%{$search}%") + ->orWhere('description', 'like', "%{$search}%"); + }); + } + + $documents = $query->orderBy('created_at', 'desc')->paginate(12); + //todo remove this after we migrate from old GUI + $categories = GeneralDocument::select('category')->distinct()->whereNotNull('category')->pluck('category'); + $document_types = Models\DocumentType::orderBy('name', 'asc')->pluck('name'); + return view('documents.index', compact('documents', 'categories', 'document_types')); + } + public function store(Request $request) { - // 1. Validate the incoming request $request->validate([ - 'file' => 'required|file|max:10240', // 10MB - 'type' => 'required|string', + 'name' => 'required|string|max:191', + 'category' => 'nullable|string|max:45', + 'description' => 'nullable|string', + 'file' => 'required|file|mimes:pdf,jpg,jpeg,png,doc,docx,xls,xlsx|max:10240', // 10MB limit ]); - // 2. Store locally on your ERP server $file = $request->file('file'); - $originalName = $file->getClientOriginalName(); - $localPath = $file->storeAs('documents/' . date('Y/m'), $originalName, 'local'); + $filename = time() . '_' . preg_replace('/\s+/', '_', $file->getClientOriginalName()); + + // Store files in a 'documents' folder inside storage/app/public + $filePath = $file->storeAs('documents', $filename, 'public'); - // 3. Check if it needs to be pushed to Paperless-Ngx - // You can base this on the checkbox OR force it based on type (e.g., $request->type === 'contract') - if ($request->boolean('push_to_paperless')) { - $this->pushToPaperless($localPath, $originalName, $request->all()); - } + // Get current staff ID if applicable + $staff = StaffMember::where('email', auth()->user()->email)->first(); - return response()->json(['message' => 'Document saved successfully.']); + GeneralDocument::create([ + 'name' => $request->name, + 'description' => $request->description, + 'category' => $request->category, + 'filename' => $filePath, + 'file_extension' => $file->getClientOriginalExtension(), + 'uploaded_by' => $staff ? $staff->id : null, + ]); + + return response()->json(['success' => true, 'message' => 'Document uploaded successfully!']); } - public function storeTwo(Request $request) + public function destroy($id) { - // ... validation and local storage logic ... - $localPath = $file->storeAs('documents/' . date('Y/m'), $originalName, 'local'); + $document = GeneralDocument::findOrFail($id); - // Retrieve the actual Eloquent models based on the form input - $entity = MnoPartner::find($request->input('entity_id')); - $docType = DocumentType::where('slug', $request->input('type'))->first(); - - if ($request->boolean('push_to_paperless')) { - // Dispatch the job to the queue - PushDocumentToPaperless::dispatch( - $localPath, - $originalName, - $entity, - $docType, - $request->input('notes') - ); + // Delete actual physical file from storage + if ($document->filename && Storage::disk('public')->exists($document->filename)) { + Storage::disk('public')->delete($document->filename); } - return response()->json(['message' => 'Document saved and queued for archival.']); + $document->delete(); + + return response()->json(['success' => true, 'message' => 'Document deleted successfully!']); } private function pushToPaperless(string $localPath, string $fileName, array $metadata) @@ -72,7 +100,7 @@ class DocumentsController extends Controller ->post("{$paperlessUrl}/api/documents/post_document/", [ // Optional Paperless metadata fields 'title' => $metadata['notes'] ?? $fileName, - // You can map ERP tags to Paperless Tag IDs here + // mapping ERP tags to Paperless Tag IDs // 'tags' => [1, 4], // 'correspondent' => 2 ]); diff --git a/app/Http/Controllers/StaffMembersController.php b/app/Http/Controllers/StaffMembersController.php index 36c802e..c59f3d0 100644 --- a/app/Http/Controllers/StaffMembersController.php +++ b/app/Http/Controllers/StaffMembersController.php @@ -148,4 +148,14 @@ class StaffMembersController extends Controller return $upcomingStaff; } + public function showDetails($id) + { + $staff = StaffMember::with('dependents')->findOrFail($id); + + return response()->json([ + 'success' => true, + 'staff' => $staff, + 'dependents' => $staff->dependents + ]); + } } \ No newline at end of file diff --git a/app/Models/DocumentType.php b/app/Models/DocumentType.php new file mode 100644 index 0000000..ad05ef9 --- /dev/null +++ b/app/Models/DocumentType.php @@ -0,0 +1,11 @@ +belongsTo(StaffMember::class, 'uploaded_by', 'id'); + } } diff --git a/resources/views/documents/index.blade.php b/resources/views/documents/index.blade.php index 30de7d5..67c6acf 100644 --- a/resources/views/documents/index.blade.php +++ b/resources/views/documents/index.blade.php @@ -1,283 +1,259 @@ - - - - - - - Click ERP - - - - - +@extends('layouts.masterbeta') - + + -
-
-
- Document Vault -
-
- -
- -
-
-

Corporate Documents

-

Manage compliance files, MNO agreements, and client contracts.

+ +
+
+
+
+
+ + +
- -
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
File NameRelated EntityTypeSizeUploadedActions
- - MTN_SIP_Trunk_SLA_2026.pdf - MNO: MTNContract2.4 MBJun 15, 2026 - - - -
- - Telecel_Interconnect_Draft.docx - MNO: TelecelDraft850 KBJun 12, 2026 - - - -
+
+ +
+
+
-
-
+ + - + + @endpush @push('scripts') @@ -392,5 +476,79 @@ }); }); }); + + $(document).ready(function() { + const viewModal = new bootstrap.Modal(document.getElementById('viewStaffModal')); + + $('.btn-view-staff').on('click', function() { + const staffId = $(this).data('id'); + + // Reset fields to loading state + $('#viewStaffName').text('Loading...'); + $('#viewStaffDesignation').text(''); + $('#viewStaffEmail').text(''); + $('#viewStaffPhone').text(''); + $('#viewStaffCode').text(''); + $('#viewStaffPersonalEmail').text(''); + $('#viewStaffLocation').text(''); + $('#viewStaffLeaveBalance').text(''); + $('#viewStaffDependentsList').html('Loading...'); + + viewModal.show(); + + // Fetch staff details via AJAX + $.ajax({ + url: "{{ url('staff') }}/" + staffId + "/details", // Match your route endpoint + type: 'GET', + success: function(response) { + if (response.success) { + let staff = response.staff; + + $('#viewStaffName').text(staff.name); + $('#viewStaffDesignation').text(staff.designation || 'Staff Member'); + $('#viewStaffEmail').text(staff.email || 'N/A'); + $('#viewStaffPhone').text(staff.phone || 'N/A'); + $('#viewStaffCode').text(staff.staff_id || 'N/A'); + $('#viewStaffPersonalEmail').text(staff.personal_email || 'N/A'); + $('#viewStaffLocation').text(staff.location_country || 'N/A'); + $('#viewStaffLeaveBalance').text(staff.annual_leave_balance ?? 0); + + // Status Badge + let badgeClass = staff.status === 'ACTIVE' ? 'bg-success bg-opacity-10 text-success' : 'bg-warning bg-opacity-10 text-warning'; + $('#viewStaffStatusBadge').attr('class', `badge ${badgeClass} px-3 py-1`).text(staff.status); + + // Avatar setup + if (staff.profile_pic) { + $('#viewStaffAvatarContainer').html(``); + } else { + let initials = staff.name.split(' ').map(n => n[0]).join('').substring(0, 2).toUpperCase(); + $('#viewStaffAvatarContainer').html(`
${initials}
`); + } + + // Dependents Table population + let dependentsHtml = ''; + if (response.dependents && response.dependents.length > 0) { + response.dependents.forEach(dep => { + dependentsHtml += ` + + ${dep.fullname} + ${dep.relationship} + ${dep.phone || 'N/A'} + ${dep.medical_details || 'None'} + + `; + }); + } else { + dependentsHtml = `No emergency contacts found.`; + } + $('#viewStaffDependentsList').html(dependentsHtml); + } + }, + error: function() { + $('#viewStaffName').text('Error loading profile details.'); + } + }); + }); +}); @endpush \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 35d6a39..c44b3dc 100644 --- a/routes/web.php +++ b/routes/web.php @@ -37,10 +37,11 @@ Route::middleware(['auth'])->group(function () { Route::put('/mnos/{id}', [App\Http\Controllers\NetworkOperatorsController::class, 'update'])->name('mnos.update'); // Route::get('/staff', [App\Http\Controllers\StaffController::class, 'index'])->name('home'); + Route::get('/staff/{id}/details', [App\Http\Controllers\StaffMembersController::class, 'showDetails'])->name('staff.details'); Route::resource('staff', App\Http\Controllers\StaffMembersController::class)->except(['create', 'show', 'edit']); - Route::get('/documents', [App\Http\Controllers\DocumentsVaultController::class, 'index'])->name('documents.index'); + //Route::get('/documents', [App\Http\Controllers\DocumentsVaultController::class, 'index'])->name('documents.index'); // Route::get('/senderids', [App\Http\Controllers\SenderidsController::class, 'index']); Route::resource('senderids', App\Http\Controllers\SenderidsController::class)->except(['create', 'show', 'edit']); @@ -70,6 +71,12 @@ Route::middleware(['auth'])->group(function () { Route::put('/dependents/{id}', [App\Http\Controllers\ProfileController::class, 'updateDependent'])->name('dependent.update'); Route::delete('/dependents/{id}', [App\Http\Controllers\ProfileController::class, 'destroyDependent'])->name('dependent.destroy'); }); + + Route::prefix('documents')->name('documents.')->group(function () { + Route::get('/', [App\Http\Controllers\DocumentsController::class, 'index'])->name('index'); + Route::post('/store', [App\Http\Controllers\DocumentsController::class, 'store'])->name('store'); + Route::delete('/{id}', [App\Http\Controllers\DocumentsController::class, 'destroy'])->name('destroy'); + }); Route::get('/api/services', [App\Http\Controllers\ServicesController::class, 'getServicesJson']); Route::get('/api/countries', [App\Http\Controllers\HelperController::class, 'getCountriesJson']);