added document vault and bug fixes on profile and staff members controllers
This commit is contained in:
@@ -6,51 +6,79 @@ use Illuminate\Http\Request;
|
|||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use App\Models\GeneralDocument;
|
||||||
|
use App\Models\StaffMember;
|
||||||
|
use App\Models;
|
||||||
|
|
||||||
|
|
||||||
class DocumentsController extends Controller
|
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)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
// 1. Validate the incoming request
|
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'file' => 'required|file|max:10240', // 10MB
|
'name' => 'required|string|max:191',
|
||||||
'type' => 'required|string',
|
'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');
|
$file = $request->file('file');
|
||||||
$originalName = $file->getClientOriginalName();
|
$filename = time() . '_' . preg_replace('/\s+/', '_', $file->getClientOriginalName());
|
||||||
$localPath = $file->storeAs('documents/' . date('Y/m'), $originalName, 'local');
|
|
||||||
|
|
||||||
// 3. Check if it needs to be pushed to Paperless-Ngx
|
// Store files in a 'documents' folder inside storage/app/public
|
||||||
// You can base this on the checkbox OR force it based on type (e.g., $request->type === 'contract')
|
$filePath = $file->storeAs('documents', $filename, 'public');
|
||||||
if ($request->boolean('push_to_paperless')) {
|
|
||||||
$this->pushToPaperless($localPath, $originalName, $request->all());
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json(['message' => 'Document saved successfully.']);
|
// Get current staff ID if applicable
|
||||||
|
$staff = StaffMember::where('email', auth()->user()->email)->first();
|
||||||
|
|
||||||
|
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 ...
|
$document = GeneralDocument::findOrFail($id);
|
||||||
$localPath = $file->storeAs('documents/' . date('Y/m'), $originalName, 'local');
|
|
||||||
|
|
||||||
// Retrieve the actual Eloquent models based on the form input
|
// Delete actual physical file from storage
|
||||||
$entity = MnoPartner::find($request->input('entity_id'));
|
if ($document->filename && Storage::disk('public')->exists($document->filename)) {
|
||||||
$docType = DocumentType::where('slug', $request->input('type'))->first();
|
Storage::disk('public')->delete($document->filename);
|
||||||
|
|
||||||
if ($request->boolean('push_to_paperless')) {
|
|
||||||
// Dispatch the job to the queue
|
|
||||||
PushDocumentToPaperless::dispatch(
|
|
||||||
$localPath,
|
|
||||||
$originalName,
|
|
||||||
$entity,
|
|
||||||
$docType,
|
|
||||||
$request->input('notes')
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
private function pushToPaperless(string $localPath, string $fileName, array $metadata)
|
||||||
@@ -72,7 +100,7 @@ class DocumentsController extends Controller
|
|||||||
->post("{$paperlessUrl}/api/documents/post_document/", [
|
->post("{$paperlessUrl}/api/documents/post_document/", [
|
||||||
// Optional Paperless metadata fields
|
// Optional Paperless metadata fields
|
||||||
'title' => $metadata['notes'] ?? $fileName,
|
'title' => $metadata['notes'] ?? $fileName,
|
||||||
// You can map ERP tags to Paperless Tag IDs here
|
// mapping ERP tags to Paperless Tag IDs
|
||||||
// 'tags' => [1, 4],
|
// 'tags' => [1, 4],
|
||||||
// 'correspondent' => 2
|
// 'correspondent' => 2
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -148,4 +148,14 @@ class StaffMembersController extends Controller
|
|||||||
|
|
||||||
return $upcomingStaff;
|
return $upcomingStaff;
|
||||||
}
|
}
|
||||||
|
public function showDetails($id)
|
||||||
|
{
|
||||||
|
$staff = StaffMember::with('dependents')->findOrFail($id);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'staff' => $staff,
|
||||||
|
'dependents' => $staff->dependents
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
11
app/Models/DocumentType.php
Normal file
11
app/Models/DocumentType.php
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class DocumentType extends Model
|
||||||
|
{
|
||||||
|
protected $guarded = array('id');
|
||||||
|
public $table = "document_types";
|
||||||
|
}
|
||||||
@@ -7,4 +7,9 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
class GeneralDocument extends Model
|
class GeneralDocument extends Model
|
||||||
{
|
{
|
||||||
protected $guarded = array('id');
|
protected $guarded = array('id');
|
||||||
|
|
||||||
|
public function uploader()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(StaffMember::class, 'uploaded_by', 'id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,283 +1,259 @@
|
|||||||
<!DOCTYPE html>
|
@extends('layouts.masterbeta')
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
|
||||||
<title>Click ERP</title>
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
|
|
||||||
<style>
|
|
||||||
body { background-color: #f8f9fc; }
|
|
||||||
|
|
||||||
/* Sidebar & Topbar (Inherited from Base Design) */
|
@section('title', 'Click ERP - Document Vault')
|
||||||
#sidebar { width: 260px; background-color: #111425; position: fixed; height: 100vh; overflow-y: auto; z-index: 1000; }
|
|
||||||
.sidebar-brand { color: #fff; padding: 1.5rem 1.25rem; font-weight: 700; }
|
|
||||||
.sidebar-brand-icon { background: #5c4df0; padding: 0.5rem; border-radius: 8px; margin-right: 10px; }
|
|
||||||
.sidebar-nav-item { color: #8a90a5; text-decoration: none; padding: 0.75rem 1.25rem; display: block; border-radius: 8px; margin: 0.2rem 1rem; font-size: 0.9rem; }
|
|
||||||
.sidebar-nav-item:hover, .sidebar-nav-item.active { background-color: #5c4df0; color: #fff; }
|
|
||||||
.sidebar-heading { color: #5a617a; font-size: 0.75rem; text-transform: uppercase; padding: 1rem 1.25rem 0.5rem; font-weight: 600; }
|
|
||||||
|
|
||||||
#main-content { margin-left: 260px; min-height: 100vh; }
|
@section('breadcrumbs')
|
||||||
.topbar { background: #fff; height: 70px; border-bottom: 1px solid #eaedf1; padding: 0 1.5rem; }
|
<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>
|
||||||
/* Cards & Tables */
|
|
||||||
.content-card { background: #fff; border: 1px solid #eaedf1; border-radius: 12px; box-shadow: 0 2px 4px rgba(0,0,0,0.02); }
|
|
||||||
.table-custom th { background-color: #f8f9fc; color: #5a617a; font-weight: 600; font-size: 0.8rem; text-transform: uppercase; border-bottom: 2px solid #eaedf1; padding: 1rem; }
|
|
||||||
.table-custom td { padding: 1rem; vertical-align: middle; font-size: 0.9rem; border-bottom: 1px solid #eaedf1; }
|
|
||||||
|
|
||||||
/* Modal Customization */
|
|
||||||
.modal-content { border-radius: 12px; border: none; box-shadow: 0 10px 30px rgba(0,0,0,0.1); }
|
|
||||||
.modal-header { border-bottom: 1px solid #eaedf1; background-color: #f8f9fc; border-radius: 12px 12px 0 0; }
|
|
||||||
.modal-footer { border-top: 1px solid #eaedf1; }
|
|
||||||
.form-control:focus, .form-select:focus { border-color: #5c4df0; box-shadow: 0 0 0 0.25rem rgba(92, 77, 240, 0.25); }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<aside id="sidebar">
|
|
||||||
<div class="sidebar-brand d-flex align-items-center">
|
|
||||||
<span class="sidebar-brand-icon"><i class="bi bi-buildings"></i></span>
|
|
||||||
<div>
|
|
||||||
<div class="mb-0 fs-6">NEXUS <span class="badge bg-secondary ms-1" style="font-size: 0.6rem;">ERP</span></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="sidebar-heading mt-2">Core Entities</div>
|
|
||||||
<a href="#" class="sidebar-nav-item"><i class="bi bi-person-badge me-2"></i> Staff Directory</a>
|
|
||||||
<a href="#" class="sidebar-nav-item"><i class="bi bi-people me-2"></i> Clients</a>
|
|
||||||
<a href="#" class="sidebar-nav-item"><i class="bi bi-broadcast-pin me-2"></i> MNO Partners</a>
|
|
||||||
<div class="sidebar-heading mt-2">Resources</div>
|
|
||||||
<a href="#" class="sidebar-nav-item active"><i class="bi bi-folder2-open me-2"></i> Document Vault</a>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
<main id="main-content">
|
|
||||||
<header class="topbar d-flex justify-content-between align-items-center">
|
|
||||||
<div class="d-flex align-items-center">
|
|
||||||
<span class="fw-bold" style="font-size: 0.95rem;">Document Vault</span>
|
<span class="fw-bold" style="font-size: 0.95rem;">Document Vault</span>
|
||||||
</div>
|
@endsection
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="container-fluid p-4">
|
|
||||||
|
|
||||||
|
@section('content')
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
<div>
|
<div>
|
||||||
<h4 class="fw-bold mb-1">Corporate Documents</h4>
|
<h4 class="fw-bold mb-1">Document Vault</h4>
|
||||||
<p class="text-secondary mb-0" style="font-size: 0.9rem;">Manage compliance files, MNO agreements, and client contracts.</p>
|
<p class="text-secondary mb-0" style="font-size: 0.9rem;">Store, manage, and share company or staff documents securely.</p>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn text-white fw-bold d-flex align-items-center" style="background-color: #5c4df0; border-radius: 8px;" id="btnOpenUploadModal">
|
<button class="btn text-white fw-bold d-flex align-items-center" style="background-color: #5c4df0; border-radius: 8px;" id="btnOpenUploadModal">
|
||||||
<i class="bi bi-cloud-upload me-2"></i> Upload Document
|
<i class="bi bi-upload me-2"></i> Upload Document
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="content-card">
|
<!-- Filters & Search -->
|
||||||
|
<div class="content-card mb-4 p-3 shadow-sm">
|
||||||
|
<form action="{{ route('documents.index') }}" method="GET">
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-text bg-white border-end-0 text-secondary"><i class="bi bi-search"></i></span>
|
||||||
|
<input type="text" name="search" value="{{ request('search') }}" class="form-control bg-white border-start-0 ps-0" placeholder="Search by document name or description...">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<select name="category" class="form-select bg-white" onchange="this.form.submit()">
|
||||||
|
<option value="">Category: All</option>
|
||||||
|
@foreach($categories as $cat)
|
||||||
|
<option value="{{ $cat }}" {{ request('category') == $cat ? 'selected' : '' }}>{{ $cat }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<button type="submit" class="btn text-white w-100" style="background-color: #5c4df0;">
|
||||||
|
<i class="bi bi-funnel me-1"></i> Filter
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Documents Grid / Table -->
|
||||||
|
<div class="content-card shadow-sm">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-custom table-hover mb-0">
|
<table class="table table-custom table-hover mb-0 align-middle">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>File Name</th>
|
<th>Document Name</th>
|
||||||
<th>Related Entity</th>
|
<th>Category</th>
|
||||||
<th>Type</th>
|
<th>Description</th>
|
||||||
<th>Size</th>
|
<th>Format</th>
|
||||||
<th>Uploaded</th>
|
<th>Uploaded</th>
|
||||||
<th class="text-end">Actions</th>
|
<th class="text-end">Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@forelse($documents as $doc)
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<i class="bi bi-file-earmark-pdf text-danger me-2"></i>
|
<div class="fw-bold text-dark d-flex align-items-center">
|
||||||
<span class="fw-bold text-dark">MTN_SIP_Trunk_SLA_2026.pdf</span>
|
<i class="bi bi-file-earmark-text text-primary me-2 fs-5"></i>
|
||||||
|
{{ $doc->name }}
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td><span class="badge bg-dark bg-opacity-10 text-dark">MNO: MTN</span></td>
|
|
||||||
<td>Contract</td>
|
|
||||||
<td class="text-secondary">2.4 MB</td>
|
|
||||||
<td class="text-secondary">Jun 15, 2026</td>
|
|
||||||
<td class="text-end">
|
|
||||||
<button class="btn btn-sm btn-light text-primary me-1"><i class="bi bi-download"></i></button>
|
|
||||||
<button class="btn btn-sm btn-light text-secondary me-1 btn-edit-doc" data-id="1" data-filename="MTN_SIP_Trunk_SLA_2026.pdf" data-entity="mno_mtn" data-type="contract"><i class="bi bi-pencil"></i></button>
|
|
||||||
<button class="btn btn-sm btn-light text-danger"><i class="bi bi-trash"></i></button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
<td>
|
||||||
<i class="bi bi-file-earmark-word text-primary me-2"></i>
|
@if($doc->category)
|
||||||
<span class="fw-bold text-dark">Telecel_Interconnect_Draft.docx</span>
|
<span class="badge bg-secondary bg-opacity-10 text-dark border">{{ $doc->category }}</span>
|
||||||
|
@else
|
||||||
|
<span class="text-secondary small">Uncategorized</span>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="text-secondary small text-truncate d-inline-block" style="max-width: 250px;" title="{{ $doc->description }}">
|
||||||
|
{{ $doc->description ?? 'No description provided.' }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="text-uppercase fw-bold text-secondary" style="font-size: 0.75rem;">{{ $doc->file_extension }}</span>
|
||||||
|
</td>
|
||||||
|
<td class="text-secondary small">
|
||||||
|
<div>{{ $doc->created_at ? $doc->created_at->format('M d, Y') : 'N/A' }}</div>
|
||||||
</td>
|
</td>
|
||||||
<td><span class="badge bg-dark bg-opacity-10 text-dark">MNO: Telecel</span></td>
|
|
||||||
<td>Draft</td>
|
|
||||||
<td class="text-secondary">850 KB</td>
|
|
||||||
<td class="text-secondary">Jun 12, 2026</td>
|
|
||||||
<td class="text-end">
|
<td class="text-end">
|
||||||
<button class="btn btn-sm btn-light text-primary me-1"><i class="bi bi-download"></i></button>
|
<a href="{{ asset('public/storage/' . $doc->filename) }}" target="_blank" class="btn btn-sm btn-light text-primary me-1" title="View / Download">
|
||||||
<button class="btn btn-sm btn-light text-secondary me-1 btn-edit-doc" data-id="2" data-filename="Telecel_Interconnect_Draft.docx" data-entity="mno_telecel" data-type="draft"><i class="bi bi-pencil"></i></button>
|
<i class="bi bi-download"></i>
|
||||||
<button class="btn btn-sm btn-light text-danger"><i class="bi bi-trash"></i></button>
|
</a>
|
||||||
|
{{--
|
||||||
|
<button class="btn btn-sm btn-light text-danger btn-delete-doc" data-id="{{ $doc->id }}" title="Delete">
|
||||||
|
<i class="bi bi-trash"></i>
|
||||||
|
</button>
|
||||||
|
--}}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@empty
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="text-center py-4 text-secondary">No documents found in the Vault.</td>
|
||||||
|
</tr>
|
||||||
|
@endforelse
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="p-3 border-top">
|
||||||
|
{{ $documents->links('pagination::bootstrap-5') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
@endsection
|
||||||
|
|
||||||
<div class="modal fade" id="documentModal" tabindex="-1" aria-hidden="true">
|
@push('modals')
|
||||||
|
<!-- UPLOAD DOCUMENT MODAL -->
|
||||||
|
<div class="modal fade" id="uploadDocModal" tabindex="-1" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header bg-light">
|
||||||
<h5 class="modal-title fw-bold" id="documentModalTitle">Upload New Document</h5>
|
<h5 class="modal-title fw-bold">Upload Document</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form id="documentForm" enctype="multipart/form-data">
|
<form id="uploadDocForm" enctype="multipart/form-data">
|
||||||
|
@csrf
|
||||||
<div class="modal-body p-4">
|
<div class="modal-body p-4">
|
||||||
<input type="hidden" id="docId" name="id">
|
<div id="uploadModalAlert"></div>
|
||||||
<input type="hidden" id="docMethod" name="_method" value="POST">
|
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label text-secondary fw-semibold" style="font-size: 0.85rem;">Select File</label>
|
<label class="form-label text-secondary fw-semibold small">Document Name *</label>
|
||||||
<input class="form-control" type="file" id="docFile" name="file">
|
<input type="text" class="form-control" name="name" required placeholder="e.g. Employee Handbook 2026">
|
||||||
<div class="form-text" id="fileHelpText">Max size: 10MB. Allowed: PDF, DOCX, PNG, JPG.</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row g-3 mb-3">
|
<div class="mb-3">
|
||||||
<div class="col-md-6">
|
<label class="form-label text-secondary fw-semibold small">Category</label>
|
||||||
<label class="form-label text-secondary fw-semibold" style="font-size: 0.85rem;">Document Type</label>
|
<!-- <input type="text" class="form-control" name="category" placeholder="e.g. Policy, Contract, Template"> -->
|
||||||
<select class="form-select" id="docType" name="type" required>
|
<select name="client_id" id="modal_client_id" class="form-select select2-field">
|
||||||
<option value="" selected disabled>Select...</option>
|
<option value="">Category</option>
|
||||||
<option value="contract">SLA / Contract</option>
|
@foreach($document_types as $type)
|
||||||
<option value="draft">Draft Proposal</option>
|
<option value="{{ $type }}">{{ $type }}</option>
|
||||||
<option value="identity">KYC / Identity</option>
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
|
||||||
<label class="form-label text-secondary fw-semibold" style="font-size: 0.85rem;">Related Entity</label>
|
|
||||||
<select class="form-select" id="docEntity" name="entity_id">
|
<div class="mb-3">
|
||||||
<option value="">General (None)</option>
|
<label class="form-label text-secondary fw-semibold small">Description</label>
|
||||||
<optgroup label="Mobile Network Operators">
|
<textarea class="form-control" name="description" rows="2" placeholder="Brief details about this file..."></textarea>
|
||||||
<option value="mno_mtn">MTN</option>
|
</div>
|
||||||
<option value="mno_telecel">Telecel</option>
|
|
||||||
<option value="mno_at">AT</option>
|
<div class="mb-3">
|
||||||
</optgroup>
|
<label class="form-label text-secondary fw-semibold small">Select File * (Max: 10MB)</label>
|
||||||
<optgroup label="Clients">
|
<input type="file" class="form-control" name="file" required accept=".pdf,.jpg,.jpeg,.png,.doc,.docx,.xls,.xlsx">
|
||||||
<option value="client_1">Click Tech Corp</option>
|
|
||||||
</optgroup>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-2">
|
|
||||||
<label class="form-label text-secondary fw-semibold" style="font-size: 0.85rem;">Description</label>
|
|
||||||
<textarea class="form-control" id="docNotes" name="notes" rows="2" placeholder="Optional notes..."></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer bg-light">
|
<div class="modal-footer bg-light">
|
||||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
<button type="button" class="btn btn-outline-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
|
||||||
<button type="submit" class="btn text-white fw-bold px-4" style="background-color: #5c4df0;" id="btnSubmitDoc">
|
<button type="submit" id="btnSubmitDoc" class="btn text-white btn-sm fw-bold px-4" style="background-color: #5c4df0;">Upload File</button>
|
||||||
Upload File
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@endpush
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
@push('scripts')
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
// Setup CSRF token for all AJAX requests
|
const uploadModal = new bootstrap.Modal(document.getElementById('uploadDocModal'));
|
||||||
$.ajaxSetup({
|
const $form = $('#uploadDocForm');
|
||||||
headers: {
|
|
||||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const docModal = new bootstrap.Modal(document.getElementById('documentModal'));
|
|
||||||
const $form = $('#documentForm');
|
|
||||||
|
|
||||||
// --- OPEN MODAL FOR CREATE ---
|
|
||||||
$('#btnOpenUploadModal').on('click', function() {
|
$('#btnOpenUploadModal').on('click', function() {
|
||||||
$form[0].reset(); // Clear previous data
|
|
||||||
$('#docId').val('');
|
|
||||||
$('#docMethod').val('POST');
|
|
||||||
|
|
||||||
$('#documentModalTitle').text('Upload New Document');
|
|
||||||
$('#btnSubmitDoc').html('<i class="bi bi-cloud-upload me-2"></i>Upload File');
|
|
||||||
$('#docFile').prop('required', true); // File is mandatory for upload
|
|
||||||
$('#fileHelpText').text('Max size: 10MB. Allowed: PDF, DOCX, PNG, JPG.');
|
|
||||||
|
|
||||||
docModal.show();
|
|
||||||
});
|
|
||||||
|
|
||||||
// --- OPEN MODAL FOR EDIT ---
|
|
||||||
$('.btn-edit-doc').on('click', function() {
|
|
||||||
const id = $(this).data('id');
|
|
||||||
const filename = $(this).data('filename');
|
|
||||||
const entity = $(this).data('entity');
|
|
||||||
const type = $(this).data('type');
|
|
||||||
|
|
||||||
$form[0].reset();
|
$form[0].reset();
|
||||||
$('#docId').val(id);
|
$('#uploadModalAlert').html('');
|
||||||
$('#docMethod').val('PUT'); // Set to PUT for backend routing
|
uploadModal.show();
|
||||||
|
|
||||||
// Populate existing data
|
|
||||||
$('#docType').val(type);
|
|
||||||
$('#docEntity').val(entity);
|
|
||||||
|
|
||||||
$('#documentModalTitle').text('Edit Document Info');
|
|
||||||
$('#btnSubmitDoc').html('<i class="bi bi-save me-2"></i>Save Changes');
|
|
||||||
$('#docFile').prop('required', false); // File is optional when editing
|
|
||||||
$('#fileHelpText').text('Leave file input blank to keep existing file: ' + filename);
|
|
||||||
|
|
||||||
docModal.show();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- HANDLE FORM SUBMISSION VIA AJAX ---
|
// Handle AJAX Upload
|
||||||
$form.on('submit', function(e) {
|
$form.on('submit', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const $btn = $('#btnSubmitDoc');
|
const $btn = $('#btnSubmitDoc');
|
||||||
const originalText = $btn.html();
|
const originalText = $btn.html();
|
||||||
|
|
||||||
$btn.html('<span class="spinner-border spinner-border-sm me-2"></span> Processing...');
|
$btn.html('<span class="spinner-border spinner-border-sm me-2"></span> Uploading...');
|
||||||
$btn.prop('disabled', true);
|
$btn.prop('disabled', true);
|
||||||
|
|
||||||
// Use FormData to handle the multipart/form-data payload natively
|
|
||||||
let formData = new FormData(this);
|
let formData = new FormData(this);
|
||||||
let isEdit = $('#docId').val() !== '';
|
|
||||||
let ajaxUrl = isEdit ? '/api/documents/' + $('#docId').val() : '/api/documents';
|
|
||||||
|
|
||||||
// Simulating the AJAX call
|
|
||||||
setTimeout(() => {
|
|
||||||
console.log('Submitted Payload:', Object.fromEntries(formData));
|
|
||||||
|
|
||||||
$btn.html(originalText);
|
|
||||||
$btn.prop('disabled', false);
|
|
||||||
docModal.hide();
|
|
||||||
|
|
||||||
// Here you would normally trigger a toast notification or reload the data table
|
|
||||||
alert(isEdit ? 'Document metadata updated successfully!' : 'File uploaded successfully!');
|
|
||||||
}, 1200);
|
|
||||||
|
|
||||||
/* // Actual AJAX Call Structure:
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: ajaxUrl,
|
url: "{{ route('documents.store') }}",
|
||||||
type: 'POST', // Always POST for FormData, pass _method=PUT in data for edits
|
type: 'POST',
|
||||||
data: formData,
|
data: formData,
|
||||||
processData: false, // Prevent jQuery from processing the data
|
processData: false,
|
||||||
contentType: false, // Prevent jQuery from setting contentType
|
contentType: false,
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
docModal.hide();
|
if (response.success) {
|
||||||
// Refresh DataTables or UI
|
uploadModal.hide();
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'success',
|
||||||
|
title: 'Uploaded!',
|
||||||
|
text: response.message,
|
||||||
|
confirmButtonColor: '#5c4df0'
|
||||||
|
}).then(() => location.reload());
|
||||||
|
}
|
||||||
},
|
},
|
||||||
error: function(xhr) {
|
error: function(xhr) {
|
||||||
|
let msg = xhr.responseJSON?.message || 'Failed to upload document. Check file size/type.';
|
||||||
|
$('#uploadModalAlert').html(`
|
||||||
|
<div class="alert alert-danger py-2 px-3 small" role="alert">
|
||||||
|
<i class="bi bi-exclamation-triangle-fill me-2"></i> ${msg}
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
$btn.html(originalText).prop('disabled', false);
|
$btn.html(originalText).prop('disabled', false);
|
||||||
// Handle validation errors
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
*/
|
});
|
||||||
|
|
||||||
|
// Handle Delete Document
|
||||||
|
$('.btn-delete-doc').on('click', function() {
|
||||||
|
const docId = $(this).data('id');
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Delete Document?',
|
||||||
|
text: "This file will be permanently removed from storage.",
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonColor: '#ef4444',
|
||||||
|
cancelButtonColor: '#6c757d',
|
||||||
|
confirmButtonText: 'Yes, delete it!'
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
$.ajax({
|
||||||
|
url: "{{ url('documents') }}/" + docId,
|
||||||
|
type: 'POST',
|
||||||
|
data: {
|
||||||
|
_token: '{{ csrf_token() }}',
|
||||||
|
_method: 'DELETE'
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'success',
|
||||||
|
title: 'Deleted!',
|
||||||
|
text: response.message,
|
||||||
|
confirmButtonColor: '#5c4df0'
|
||||||
|
}).then(() => location.reload());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
@endpush
|
||||||
</html>
|
|
||||||
@@ -128,7 +128,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="d-flex gap-2 mt-auto pt-2 border-top">
|
<div class="d-flex gap-2 mt-auto pt-2 border-top">
|
||||||
<button class="btn btn-sm btn-light text-primary flex-grow-1 fw-semibold btn-edit-staff"
|
<button class="btn btn-sm btn-light text-success flex-grow-1 btn-view-staff"
|
||||||
|
data-id="{{ $staff->id }}"
|
||||||
|
title="View Profile Details">
|
||||||
|
<i class="bi bi-eye"></i> View
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-sm btn-light text-primary me-1 fw-semibold btn-edit-staff"
|
||||||
data-id="{{ $staff->id }}"
|
data-id="{{ $staff->id }}"
|
||||||
data-name="{{ $staff->name }}"
|
data-name="{{ $staff->name }}"
|
||||||
data-email="{{ $staff->email }}"
|
data-email="{{ $staff->email }}"
|
||||||
@@ -141,6 +146,7 @@
|
|||||||
<i class="bi bi-pencil me-1"></i> Edit
|
<i class="bi bi-pencil me-1"></i> Edit
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{{--
|
||||||
<form action="{{ route('staff.destroy', $staff->id) }}" method="POST" class="flex-grow-1 m-0">
|
<form action="{{ route('staff.destroy', $staff->id) }}" method="POST" class="flex-grow-1 m-0">
|
||||||
@csrf
|
@csrf
|
||||||
@method('DELETE')
|
@method('DELETE')
|
||||||
@@ -148,6 +154,7 @@
|
|||||||
<i class="bi bi-trash me-1"></i> Delete
|
<i class="bi bi-trash me-1"></i> Delete
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
--}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -256,6 +263,83 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- VIEW STAFF PROFILE MODAL -->
|
||||||
|
<div class="modal fade" id="viewStaffModal" tabindex="-1" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header bg-light">
|
||||||
|
<h5 class="modal-title fw-bold" id="viewStaffTitle">Staff Profile Details</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body p-4">
|
||||||
|
<!-- Basic Info Header -->
|
||||||
|
<div class="d-flex align-items-center mb-4 pb-3 border-bottom">
|
||||||
|
<div id="viewStaffAvatarContainer" class="me-3">
|
||||||
|
<!-- Dynamic Avatar inserted via JS -->
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4 class="fw-bold mb-1 text-dark" id="viewStaffName">---</h4>
|
||||||
|
<p class="text-secondary mb-1 small" id="viewStaffDesignation">---</p>
|
||||||
|
<span id="viewStaffStatusBadge" class="badge">---</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Info Grid -->
|
||||||
|
<div class="row g-3 mb-4">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="text-secondary small fw-semibold">WORK EMAIL</div>
|
||||||
|
<div class="fw-medium text-dark small" id="viewStaffEmail">---</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="text-secondary small fw-semibold">PHONE NUMBER</div>
|
||||||
|
<div class="fw-medium text-dark small" id="viewStaffPhone">---</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="text-secondary small fw-semibold">STAFF ID</div>
|
||||||
|
<div class="fw-medium text-dark small" id="viewStaffCode">---</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="text-secondary small fw-semibold">PERSONAL EMAIL</div>
|
||||||
|
<div class="fw-medium text-dark small" id="viewStaffPersonalEmail">---</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="text-secondary small fw-semibold">LOCATION / COUNTRY</div>
|
||||||
|
<div class="fw-medium text-dark small" id="viewStaffLocation">---</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>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Emergency Contacts Table Section -->
|
||||||
|
<h6 class="fw-bold text-dark mb-3"><i class="bi bi-shield-exclamation me-2 text-danger"></i>Emergency Contacts & Dependents</h6>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-bordered table-sm align-middle mb-0">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>Full Name</th>
|
||||||
|
<th>Relationship</th>
|
||||||
|
<th>Phone</th>
|
||||||
|
<th>Medical Details</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="viewStaffDependentsList">
|
||||||
|
<tr>
|
||||||
|
<td colspan="4" class="text-center text-secondary py-3">Loading emergency contacts...</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer bg-light">
|
||||||
|
<button type="button" class="btn btn-outline-secondary btn-sm" data-bs-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
@push('scripts')
|
@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('<tr><td colspan="4" class="text-center text-secondary py-3">Loading...</td></tr>');
|
||||||
|
|
||||||
|
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(`<img src="{{ asset('public/storage') }}/${staff.profile_pic}" class="rounded-circle border" style="width: 70px; height: 70px; object-fit: cover;">`);
|
||||||
|
} else {
|
||||||
|
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>`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dependents Table population
|
||||||
|
let dependentsHtml = '';
|
||||||
|
if (response.dependents && response.dependents.length > 0) {
|
||||||
|
response.dependents.forEach(dep => {
|
||||||
|
dependentsHtml += `
|
||||||
|
<tr>
|
||||||
|
<td class="fw-bold">${dep.fullname}</td>
|
||||||
|
<td><span class="badge bg-secondary bg-opacity-10 text-dark border">${dep.relationship}</span></td>
|
||||||
|
<td>${dep.phone || 'N/A'}</td>
|
||||||
|
<td class="text-secondary">${dep.medical_details || 'None'}</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
dependentsHtml = `<tr><td colspan="4" class="text-center text-secondary py-3">No emergency contacts found.</td></tr>`;
|
||||||
|
}
|
||||||
|
$('#viewStaffDependentsList').html(dependentsHtml);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
$('#viewStaffName').text('Error loading profile details.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
@endpush
|
@endpush
|
||||||
@@ -37,10 +37,11 @@ Route::middleware(['auth'])->group(function () {
|
|||||||
Route::put('/mnos/{id}', [App\Http\Controllers\NetworkOperatorsController::class, 'update'])->name('mnos.update');
|
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', [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::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::get('/senderids', [App\Http\Controllers\SenderidsController::class, 'index']);
|
||||||
Route::resource('senderids', App\Http\Controllers\SenderidsController::class)->except(['create', 'show', 'edit']);
|
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::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::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/services', [App\Http\Controllers\ServicesController::class, 'getServicesJson']);
|
||||||
Route::get('/api/countries', [App\Http\Controllers\HelperController::class, 'getCountriesJson']);
|
Route::get('/api/countries', [App\Http\Controllers\HelperController::class, 'getCountriesJson']);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user