diff --git a/app/Http/Controllers/ClientsController.php b/app/Http/Controllers/ClientsController.php index 8ba6489..46fdaeb 100644 --- a/app/Http/Controllers/ClientsController.php +++ b/app/Http/Controllers/ClientsController.php @@ -134,6 +134,8 @@ class ClientsController extends Controller // dump($change_account_mgr_permission); $change_account_mgr_permission = $this->hasAnyAccess([$change_account_mgr_permission]) ? 'YES' : 'NO'; // dd($change_account_mgr_permission); + + // dd($showclient); return view('clients.show', [ 'page_title' => 'Client Profile', 'showclient' => $showclient, @@ -390,7 +392,39 @@ class ClientsController extends Controller return redirect('clients'); } + public function getClientJson($id) + { + $client = \App\Models\Client::findOrFail($id); + return response()->json($client); + } + public function update(Request $request, $id) + { + $client = \App\Models\Client::findOrFail($id); + + $client->update([ + 'name' => $request->name, + 'email' => $request->email, + 'phone' => $request->phone, + 'contact_person' => $request->contact_person, + 'company_type' => $request->company_type, + 'contract_type' => $request->contract_type, + 'industry' => $request->industry, + 'status' => $request->status, + 'currency' => $request->currency, + 'country' => $request->country, + // Arrays handled by model casts + 'services' => $request->services, + 'message_types' => $request->message_types, + 'connections' => $request->connections, + 'support_phones' => $request->support_phones, + 'support_emails' => $request->support_emails, + 'rate_emails' => $request->rate_emails, + 'support_skype' => $request->support_skype, + ]); + + return response()->json(['message' => 'Client updated successfully!']); + } public function storeFiles(AddFilesRequest $request){ diff --git a/app/Http/Controllers/NetworkOperatorsControlle.php b/app/Http/Controllers/NetworkOperatorsControlle.php deleted file mode 100644 index 5f29cc7..0000000 --- a/app/Http/Controllers/NetworkOperatorsControlle.php +++ /dev/null @@ -1,16 +0,0 @@ - 'Dashboard' - ]; - return view('network_operators.index', $data); - } -} diff --git a/app/Http/Controllers/NetworkOperatorsController.php b/app/Http/Controllers/NetworkOperatorsController.php new file mode 100644 index 0000000..7d6ee85 --- /dev/null +++ b/app/Http/Controllers/NetworkOperatorsController.php @@ -0,0 +1,115 @@ +filled('search')) { + $search = $request->input('search'); + $query->where('name', 'like', "%{$search}%") + ->orWhere('contact_person_email', 'like', "%{$search}%") + ->orWhere('support_phones', 'like', "%{$search}%"); + } + + if ($request->filled('country')) { + $query->where('country', $request->input('country')); + } + + if ($request->filled('connection_status')) { + $query->where('connection_status', 'like', "%{$request->input('connection_status')}%"); + } + + // Paginate instead of getting all records at once (e.g., 10 per page) + $operators = $query->latest('id')->paginate(10)->withQueryString(); + + // dd($operators); + + $totalActive = NetworkOperator::where('connection_status', 'Active')->count(); + $totalSipLinks = NetworkOperator::where('connection_type', 'like', '%VPN%')->count(); + $totalOperators = NetworkOperator::count(); + + return view('network_operators.index', compact('operators', 'totalActive', 'totalSipLinks', 'totalOperators')); + } + + public function store(Request $request) + { + $request->validate([ + 'name' => 'required|string|max:200', + 'country' => 'required|string', + ]); + + NetworkOperator::create([ + 'name' => $request->name, + 'country' => $request->country, + 'connection_status' => $request->connection_status ?? 'Online', + 'contact_person' => $request->contact_person, + 'contact_person_phone' => $request->contact_person_phone, + 'contact_person_email' => $request->contact_person_email, + 'technical_support_person' => $request->technical_support_person, + 'support_skype' => $request->support_skype, + 'mno_account_manager' => $request->mno_account_manager, + 'services' => $request->services, + 'support_emails' => $request->support_emails, + 'finance_emails' => $request->finance_emails, + 'buying_rate' => $request->buying_rate ?? 0, + 'rate_type' => $request->rate_type, + 'payment_terms' => $request->payment_terms, + 'connection_type' => $request->connection_type, + ]); + + return response()->json(['message' => 'MNO Partner created successfully!']); + } + + public function update(Request $request, $id) + { + $operator = NetworkOperator::findOrFail($id); + + $request->validate([ + 'name' => 'required|string|max:200', + 'country' => 'required|string', + ]); + + $operator->update([ + 'name' => $request->name, + 'country' => $request->country, + 'connection_status' => $request->connection_status, + 'contact_person' => $request->contact_person, + 'contact_person_phone' => $request->contact_person_phone, + 'contact_person_email' => $request->contact_person_email, + 'technical_support_person' => $request->technical_support_person, + 'support_skype' => $request->support_skype, + 'mno_account_manager' => $request->mno_account_manager, + 'services' => $request->services, + 'support_emails' => $request->support_emails, + 'finance_emails' => $request->finance_emails, + 'buying_rate' => $request->buying_rate, + 'rate_type' => $request->rate_type, + 'payment_terms' => $request->payment_terms, + 'connection_type' => $request->connection_type, + ]); + + return response()->json(['message' => 'MNO Partner updated successfully!']); + } + + // Fetch single record JSON for editing modal + public function getJson($id) + { + $operator = NetworkOperator::findOrFail($id); + return response()->json($operator); + } + public function show($id) + { + $operator = NetworkOperator::findOrFail($id); + return view('network_operators.show', compact('operator')); + } + + +} \ No newline at end of file diff --git a/app/Http/Controllers/ProjectStatusesController.php b/app/Http/Controllers/ProjectStatusesController.php deleted file mode 100644 index 9d33b16..0000000 --- a/app/Http/Controllers/ProjectStatusesController.php +++ /dev/null @@ -1,69 +0,0 @@ -id; - // dd($user_id); - $result = Models\ProjectStatus::with('project') - ->where('assignee_id', $user_id) - ->orderBy('project_id', 'DESC') - ->get(); - $data = [ - 'page_title' => 'Projects Status List', - 'project_statuses' => $result - ]; - return view('project_status.index', $data); - } - public function add_status($id){ - $result = Models\Project::with('statusInfo')->where('id', $id)->firstOrFail(); - $data = [ - 'page_title' => 'Projects Status Update', - 'project' => $result - ]; - // dd($data); - return view('project_status.add_status', $data); - } - public function create() { - - return view('project_status.create'); - } - - public function store(Request $request) { - // Save a new post - $this->validate($request, [ - 'description' => 'required', - 'status' => 'required', - 'project_id' => 'required', - 'assignee_id' => 'required' - ]); - $project_status_arr = $request->except('_token'); - $result = Models\ProjectStatus::create($project_status_arr); - Session::flash('success_message', 'Project status added successfully!'); - - return redirect(url('projects')); - } - - public function show($id) { - // Show a specific post - } - - public function edit($id) { - // Show form to edit a post - } - - public function update(Request $request, $id) { - // Update a specific post - return redirect(url('project-status')); - } - - public function destroy($id) { - // Delete a specific post - } -} diff --git a/app/Http/Controllers/ProjectsController.php b/app/Http/Controllers/ProjectsController.php deleted file mode 100644 index 715b2e0..0000000 --- a/app/Http/Controllers/ProjectsController.php +++ /dev/null @@ -1,86 +0,0 @@ -id; - // dd($user_id); - $result = Models\Project::where('user_id', $user_id)->get(); - $data = [ - 'page_title' => 'Projects List', - 'projects' => $result - ]; - return view('projects.index', $data); - } - public function create() { - // Show form to create a new post - return view('projects.create'); - } - - public function store(Request $request) { - // Save a new post - $this->validate($request, [ - 'name' => 'required', - 'description'=> 'required', - 'dependancy' => 'sometimes', - 'status' => 'required', - ]); - $project_arr = $request->except('_token'); - $result = Models\Project::create($project_arr); - Session::flash('success_message', 'Project created successfully!'); - return redirect(url('projects')); - } - - public function show($id) { - // Show a specific post - $user_id = \Auth::user()->id; - $result = Models\Project::with('statusInfo')->where('id', $id)->firstOrFail(); - $data = [ - 'page_title' => 'Projects Details', - 'project' => $result - ]; - // dump($data); - return view('projects.show', $data); - } - - public function edit($id) { - // Show form to edit a post - $user_id = \Auth::user()->id; - $result = Models\Project::with('statusInfo')->where('id', $id)->firstOrFail(); - $data = [ - 'page_title' => 'Projects Update', - 'project' => $result - ]; - return view('projects.edit', $data); - } - - public function update(Request $request, $id) { - // Update a specific post - $this->validate($request, [ - 'name' => 'required', - 'description'=> 'required', - 'dependancy' => 'sometimes', - 'status' => 'required', - ]); - - $project = Models\Project::findOrFail($id); - - $project->name = $request->name; - $project->description = $request->description; - $project->dependancy = $request->dependancy; - $project->status = $request->status; - $result = $project->save(); - Session::flash('success_message', 'Project details updated successfully!'); - return redirect(url('projects')); - } - - public function destroy($id) { - // Delete a specific post - } -} diff --git a/app/Models/Client.php b/app/Models/Client.php index 3be8606..1b818a8 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -51,4 +51,14 @@ class Client extends Model } return $service_name_arr; } + + protected $casts = [ + 'connections' => 'array', + 'message_types' => 'array', + 'services' => 'array', + 'support_emails' => 'array', + 'rate_emails' => 'array', + 'support_skype' => 'array', + 'support_phones' => 'array', + ]; } diff --git a/app/Models/NetworkOps.php b/app/Models/NetworkOperator.php similarity index 78% rename from app/Models/NetworkOps.php rename to app/Models/NetworkOperator.php index 7ac1e5a..71901e8 100755 --- a/app/Models/NetworkOps.php +++ b/app/Models/NetworkOperator.php @@ -5,11 +5,17 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Casts\Attribute; -class NetworkOps extends Model +class NetworkOperator extends Model { protected $guarded = array('id'); public $table = "network_operators"; - + + protected $casts = [ + 'services' => 'array', + 'support_emails' => 'array', + 'finance_emails' => 'array', + 'bind_specifics' => 'array', + ]; public function account_manager_info(){ return $this->hasOne('App\Models\StaffMember', 'id', 'account_manager_id'); } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index fd52d92..9993f98 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -4,6 +4,7 @@ namespace App\Providers; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\URL; +use Illuminate\Pagination\Paginator; class AppServiceProvider extends ServiceProvider { @@ -23,5 +24,6 @@ class AppServiceProvider extends ServiceProvider if (config('app.env') === 'production') { URL::forceScheme('https'); } + Paginator::useBootstrapFive(); } } diff --git a/public/assets/js/client-show-modal.js b/public/assets/js/client-show-modal.js index c81c614..490457f 100644 --- a/public/assets/js/client-show-modal.js +++ b/public/assets/js/client-show-modal.js @@ -249,5 +249,134 @@ document.addEventListener("DOMContentLoaded", function() { `); }); + + // 1. Populate Edit Client Modal when opened + $(document).on('click', '[data-bs-target="#editClientModal"]', function() { + let clientId = $(this).data('client-id'); + let $form = $('#editClientForm'); + + $form.attr('action', base_url + '/clients/' + clientId); + + // Fetch Services first, then Client data + $.ajax({ + url: base_url + '/api/services', + type: 'GET', + success: function(services) { + let $servicesSelect = $('#edit_services'); + $servicesSelect.empty(); + services.forEach(function(s) { + $servicesSelect.append(new Option(s.name, s.id)); + }); + + // Now fetch client details + $.ajax({ + url: base_url + '/clients/' + clientId + '/json', + type: 'GET', + success: function(client) { + $('#edit_name').val(client.name); + $('#edit_email').val(client.email); + $('#edit_phone').val(client.phone); + $('#edit_contact_person').val(client.contact_person); + $('#edit_company_type').val(client.company_type); + $('#edit_contract_type').val(client.contract_type); + $('#edit_industry').val(client.industry); + $('#edit_status').val(client.status); + $('#edit_currency').val(client.currency); + $('#edit_country').val(client.country); + + // Helper function to set values for Select2 multi-select tags fields + function setSelect2Values(selector, values) { + let $el = $(selector); + $el.val(null).trigger('change'); + if (values && Array.isArray(values)) { + values.forEach(function(val) { + if ($el.find("option[value='" + val + "']").length === 0) { + $el.append(new Option(val, val, true, true)); + } + }); + $el.val(values).trigger('change'); + } + } + + setSelect2Values('#edit_services', client.services); + setSelect2Values('#edit_message_types', client.message_types); + setSelect2Values('#edit_connections', client.connections); + setSelect2Values('#edit_support_phones', client.support_phones); + setSelect2Values('#edit_support_emails', client.support_emails); + setSelect2Values('#edit_rate_emails', client.rate_emails); + setSelect2Values('#edit_support_skype', client.support_skype); + } + }); + } + }); + }); + + // Initialize Select2 with tags option enabled for all multi-select fields inside edit modal + $('#editClientModal').on('shown.bs.modal', function () { + $('#editClientModal .select2-tags').each(function() { + if (!$(this).hasClass("select2-hidden-accessible")) { + $(this).select2({ + theme: 'bootstrap-5', + dropdownParent: $('#editClientModal'), + tags: true, // Allows typing custom entries for emails, phones, etc. + tokenSeparators: [',', ' '], + placeholder: 'Select or type and hit enter...' + }); + } + }); + }); + + // Clean up Select2 when modal closes + $('#editClientModal').on('hidden.bs.modal', function () { + $('#editClientModal .select2-tags').val(null).trigger('change'); + }); + + // Submit Edit Client Form via AJAX + $(document).on('submit', '#editClientForm', function(e) { + e.preventDefault(); // Hard stop on native form post + + let $form = $(this); + let $submitBtn = $form.find('button[type="submit"]'); + let originalBtnText = $submitBtn.text(); + + $submitBtn.prop('disabled', true).text('Updating...'); + + $.ajax({ + url: $form.attr('action'), + type: 'POST', // Spoofed as PUT via hidden input + data: $form.serialize(), + headers: { + 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') + }, + success: function(response) { + $('#editClientModal').modal('hide'); + + Swal.fire({ + icon: 'success', + title: 'Updated!', + text: response.message || 'Client updated successfully.', + confirmButtonColor: '#0d6efd' + }).then(() => { + location.reload(); + }); + }, + error: function(xhr) { + let errors = xhr.responseJSON?.errors; + let errorMsg = 'Something went wrong. Please check your inputs.'; + if (errors) { + errorMsg = Object.values(errors).flat().join('\n'); + } + + Swal.fire({ + icon: 'error', + title: 'Validation Error', + text: errorMsg, + confirmButtonColor: '#dc3545' + }); + + $submitBtn.prop('disabled', false).text(originalBtnText); + } + }); + }); }); }); \ No newline at end of file diff --git a/public/assets/js/mno_index.js b/public/assets/js/mno_index.js new file mode 100644 index 0000000..ef1e643 --- /dev/null +++ b/public/assets/js/mno_index.js @@ -0,0 +1,183 @@ +$(document).ready(function() { + const mnoModal = new bootstrap.Modal(document.getElementById('mnoModal')); + const $form = $('#mnoForm'); + + + function loadServicesAndOpen(callback) { + $.ajax({ + url: base_url + '/api/services', + type: 'GET', + success: function(services) { + let $servicesSelect = $('#mnoServices'); + $servicesSelect.empty(); + services.forEach(function(s) { + $servicesSelect.append(new Option(s.name, s.id)); + }); + if (typeof callback === 'function') callback(); + } + }); + } + + function setSelect2Values(selector, values) { + let $el = $(selector); + $el.val(null).trigger('change'); + if (values && Array.isArray(values)) { + values.forEach(function(val) { + if ($el.find("option[value='" + val + "']").length === 0) { + // If it's a free-form tag not in the base options, append it + $el.append(new Option(val, val, true, true)); + } + }); + $el.val(values).trigger('change'); + } + } + + // --- OPEN MODAL FOR CREATE --- + $('#btnOpenMnoModal').on('click', function(e) { + e.preventDefault(); // Prevent any default anchor/button jump + + $form[0].reset(); + $('#mnoId').val(''); + $('#methodField').html(''); + $form.attr('action', "{{ route('mnos.store') }}"); + $('#mnoModalTitle').text('Add New MNO'); + $('#btnSubmitMno').html('Save Gateway Profile'); + + // Clear all multi-selects first + $('#mnoServices, #mnoSupportEmails, #mnoFinanceEmails').val(null).trigger('change'); + + // Fetch services and then open the modal directly + $.ajax({ + url: base_url + '/api/services', + type: 'GET', + success: function(services) { + let $servicesSelect = $('#mnoServices'); + $servicesSelect.empty(); + services.forEach(function(s) { + $servicesSelect.append(new Option(s.name, s.id)); + }); + $servicesSelect.trigger('change'); + + // Open modal safely once data is ready + mnoModal.show(); + }, + error: function() { + // Fallback: open modal even if service fetch fails + mnoModal.show(); + } + }); + }); + + // --- OPEN MODAL FOR EDIT --- + $(document).on('click', '.btn-edit-mno', function() { + const mnoId = $(this).data('id'); + + $form[0].reset(); + $('#methodField').html(''); + $form.attr('action', base_url + '/mnos/' + mnoId); + $('#mnoModalTitle').text('Modify MNO Profile'); + $('#btnSubmitMno').html('Apply Changes'); + + loadServicesAndOpen(function() { + $.ajax({ + url: base_url + '/mnos/' + mnoId + '/json', + type: 'GET', + success: function(mno) { + $('#mnoId').val(mno.id); + $('#mnoName').val(mno.name); + $('#mnoCountry').val(mno.country); + $('#mnoConnectionStatus').val(mno.connection_status); + $('#mnoContactPerson').val(mno.contact_person); + $('#mnoContactPhone').val(mno.contact_person_phone); + $('#mnoContactEmail').val(mno.contact_person_email); + $('#mnoTechSupport').val(mno.technical_support_person); + $('#mnoSupportSkype').val(mno.support_skype); + $('#mnoAccountManager').val(mno.mno_account_manager); + $('#mnoBuyingRate').val(mno.buying_rate); + $('#mnoRateType').val(mno.rate_type); + $('#mnoPaymentTerms').val(mno.payment_terms); + $('#mnoConnectionType').val(mno.connection_type); + + // Populate Select2 fields with existing records + setSelect2Values('#mnoServices', mno.services); + setSelect2Values('#mnoSupportEmails', mno.support_emails); + setSelect2Values('#mnoFinanceEmails', mno.finance_emails); + + mnoModal.show(); + }, + error: function() { + Swal.fire('Error', 'Could not fetch MNO details.', 'error'); + } + }); + }); + }); + + // --- INITIALIZE SELECT2 TAGS ON MODAL SHOWN --- + $('#mnoModal').on('shown.bs.modal', function () { + // Initialize Database-driven services multi-select (no custom tags allowed) + if (!$('#mnoServices').hasClass("select2-hidden-accessible")) { + $('#mnoServices').select2({ + theme: 'bootstrap-5', + dropdownParent: $('#mnoModal'), + placeholder: 'Select services...' + }); + } + + // Initialize Email fields with custom tagging enabled (allows typing custom emails) + $('#mnoModal .select2-tags').each(function() { + if (!$(this).hasClass("select2-hidden-accessible")) { + $(this).select2({ + theme: 'bootstrap-5', + dropdownParent: $('#mnoModal'), + tags: true, + tokenSeparators: [',', ' '], + placeholder: 'Type email and press enter...' + }); + } + }); + }); + + // --- AJAX FORM SUBMISSION --- + $form.on('submit', function(e) { + e.preventDefault(); + const $btn = $('#btnSubmitMno'); + const originalText = $btn.html(); + + $btn.html(' Saving...'); + $btn.prop('disabled', true); + + $.ajax({ + url: $form.attr('action'), + type: 'POST', + data: $form.serialize(), + headers: { + 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') + }, + success: function(response) { + mnoModal.hide(); + Swal.fire({ + icon: 'success', + title: 'Success!', + text: response.message || 'Saved successfully.', + confirmButtonColor: '#5c4df0' + }).then(() => { + location.reload(); + }); + }, + error: function(xhr) { + let errors = xhr.responseJSON?.errors; + let errorMsg = 'Validation failed. Please check inputs.'; + if (errors) { + errorMsg = Object.values(errors).flat().join('\n'); + } + Swal.fire({ + icon: 'error', + title: 'Error', + text: errorMsg, + confirmButtonColor: '#dc3545' + }); + $btn.html(originalText).prop('disabled', false); + } + }); + }); +}); diff --git a/resources/views/clients/partials/edit-modal.blade.php b/resources/views/clients/partials/edit-modal.blade.php new file mode 100644 index 0000000..8df6364 --- /dev/null +++ b/resources/views/clients/partials/edit-modal.blade.php @@ -0,0 +1,103 @@ + \ No newline at end of file diff --git a/resources/views/clients/show.blade.php b/resources/views/clients/show.blade.php index a56d799..fe84152 100644 --- a/resources/views/clients/show.blade.php +++ b/resources/views/clients/show.blade.php @@ -38,9 +38,8 @@
- -
@@ -129,11 +128,9 @@
Subscribed Services
- @php - $services = json_decode($showclient->services, true) ?? []; - @endphp - @if(count($services) > 0) - @foreach($services as $service) + + @if(count($showclient->services) > 0) + @foreach($showclient->services as $service) {{ $service }} @endforeach @else @@ -156,16 +153,15 @@
Message Types
- @php - $msgTypes = json_decode($showclient->message_types, true) ?? []; - @endphp - @if(count($msgTypes) > 0) - @foreach($msgTypes as $type) + @if($showclient->message_types !== null) + @if(count($showclient->message_types) > 0) + @foreach($showclient->message_types as $type) {{ $type }} @endforeach @else N/A @endif + @endif
@@ -250,11 +246,11 @@
- + @php - function renderBadges($jsonString, $type = 'email') { - $items = json_decode($jsonString, true) ?? []; - if(count($items) === 0) return 'N/A'; + function renderBadges($items, $type = 'email') { + if(gettype($items) == 'string') return ''.$items.''; + elseif(count($items) === 0) return 'N/A'; $html = ''; foreach($items as $item) { $icon = $type == 'email' ? 'bi-envelope' : 'bi-telephone'; @@ -263,27 +259,43 @@ return $html; } @endphp - +
Finance Emails
-
{!! renderBadges($showclient->finance_email, 'email') !!}
+ @if($showclient->finance_email == null) + N/A + @else +
{!! renderBadges($showclient->finance_email, 'email') !!}
+ @endif
-
Support Emails
-
{!! renderBadges($showclient->support_emails, 'email') !!}
+ @if($showclient->support_emails == null) + N/A + @else +
{!! renderBadges($showclient->support_emails, 'email') !!}
+ @endif
-
Rate Emails
-
{!! renderBadges($showclient->rate_emails, 'email') !!}
+ @if($showclient->rate_emails == null) + N/A + @else +
{!! renderBadges($showclient->rate_emails, 'email') !!}
+ @endif
Support Phones
-
{!! renderBadges($showclient->support_phones, 'phone') !!}
+ @if($showclient->support_phones == null) + N/A + @else +
{!! renderBadges($showclient->support_phones, 'phone') !!}
+ @endif
+ +
@@ -440,6 +452,7 @@ @foreach($recent_payments as $payment) + {{ $payment->invoice_number ?? 'N/A' }} @@ -459,6 +472,7 @@ - @endif + {{ $payment->invoice_amount }} {{ $payment->invoice_date ? \Carbon\Carbon::parse($payment->invoice_date)->format('d M Y') : 'N/A' }} {{ $payment->invoice_status ?? 'Pending' }} @@ -558,9 +572,12 @@ @include('clients.partials.shortcode-payment-docs-modal') +@include('clients.partials.edit-modal') @endsection @push('scripts') -@endpush \ No newline at end of file +@endpush + +0546907824 \ No newline at end of file diff --git a/resources/views/network_operators/index.blade.php b/resources/views/network_operators/index.blade.php index 4bf4185..a2d892a 100644 --- a/resources/views/network_operators/index.blade.php +++ b/resources/views/network_operators/index.blade.php @@ -22,65 +22,56 @@

Mobile Network Operators (MNO)

-

Manage telecommunications carrier connections, signaling links, and gateways.

+

Manage MNO details, connections and others

+
-
+
ACTIVE CONNECTIONS
-

4 100% Up

+

{{ $totalActive }} Online

-
+
-
PROVISIONED SHORTCODES
-

12

+
VPN LINKS
+

{{ $totalSipLinks }} Links

-
+
-
TOTAL SIP TRUNKS
-

6 Links

-
-
-
-
-
AGGREGATED DAILY VOL
-

142.8k hits

+
REGISTERED MNO PARTNERS
+

{{ $totalOperators }}

-
+
- +
- + @include('network_operators.partials.countries')
- + + + +
-
+
@@ -89,251 +80,87 @@ Operator Country - Network Codes - Infrastructure Links - Capabilities - Link Status + Connection Type + Services + Status Actions - - -
-
MTN
-
-
MTN Ghana
-
Scancom PLC
+ @forelse($operators as $operator) + + +
+
+ {{ strtoupper(substr($operator->name, 0, 2)) }} +
+
+
{{ $operator->name }}
+
{{ $operator->contact_person ?? 'N/A' }}
+
-
- - Ghana (GH) - - MCC: 620 - MNC: 01 - - -
IPsec VPN Tunnel
-
Gateway: 172.16.42.1
- - -
- USSD - SMS Gateway - SIP Trunk - MoMo API -
- - - - - Online - - - - - - - - - -
-
TL
-
-
Telecel Ghana
-
Telecel Group
+ + {{ $operator->country }} + +
{{ $operator->connection_type ?? 'N/A' }}
+ + +
+ @if(is_array($operator->services)) + @foreach($operator->services as $service) + {{ strtoupper($service) }} + @endforeach + @else + None + @endif
-
- - Ghana (GH) - - MCC: 620 - MNC: 02 - - -
VPN Tunnel
-
Peer IP: 100.115.2.4
- - -
- USSD - SMS Gateway - Payment API -
- - - - - Online - - - - - - - + + + + + + {{ $operator->connection_status ?? 'N/A' }} + + + + +
+ + + + +
+ + + @empty + + No MNO partners found. + + @endforelse -
+ + @if($operators->hasPages()) +
+
+ Showing {{ $operators->firstItem() }} to {{ $operators->lastItem() }} of {{ $operators->total() }} MNO partners +
+
+ {{ $operators->links() }} +
+
+ @endif +
+
@endsection @push('modals') - + @include('network_operators.partials.mno_modals') @endpush @push('scripts') - + @endpush \ No newline at end of file diff --git a/resources/views/network_operators/partials/countries.blade.php b/resources/views/network_operators/partials/countries.blade.php new file mode 100644 index 0000000..8b1821f --- /dev/null +++ b/resources/views/network_operators/partials/countries.blade.php @@ -0,0 +1,58 @@ + + \ No newline at end of file diff --git a/resources/views/network_operators/partials/mno_modals.blade.php b/resources/views/network_operators/partials/mno_modals.blade.php new file mode 100644 index 0000000..63f7800 --- /dev/null +++ b/resources/views/network_operators/partials/mno_modals.blade.php @@ -0,0 +1,165 @@ + \ No newline at end of file diff --git a/resources/views/network_operators/show.blade.php b/resources/views/network_operators/show.blade.php new file mode 100644 index 0000000..3772099 --- /dev/null +++ b/resources/views/network_operators/show.blade.php @@ -0,0 +1,161 @@ +@extends('layouts.masterbeta') + +@section('title', 'Cick ERP - ' . $operator->name) + +@section('breadcrumbs') + + + MNO Partners + + {{ $operator->name }} +@endsection + +@section('content') + +
+
+
+ {{ strtoupper(substr($operator->name, 0, 2)) }} +
+
+

{{ $operator->name }}

+

+ {{ $operator->country }} • + + {{ $operator->connection_status ?? 'Offline' }} + +

+
+
+ +
+ + +
+
+
+
CONNECTION TYPE
+
{{ $operator->connection_type ?? 'Standard Link' }}
+
+
+
+
+
BUYING RATE
+
{{ $operator->buying_rate ? number_format($operator->buying_rate, 4) : '0.0000' }}
+
+
+
+
+
PAYMENT TERMS
+
{{ $operator->payment_terms ?? 'N/A' }}
+
+
+
+ + +
+ +
+
+
+ Carrier & Technical Configuration +
+
+
+
+ Operating Country + {{ $operator->country }} +
+
+ Rate Type + {{ $operator->rate_type ?? 'N/A' }} +
+
+ Account Manager + {{ $operator->mno_account_manager ?? 'N/A' }} +
+
+ Direct Business + {{ $operator->direct_business ?? 'YES' }} +
+
+
+ + +
+
+ Provisioned Services +
+
+
+ @if(is_array($operator->services) && count($operator->services) > 0) + @foreach($operator->services as $service) + + {{ is_numeric($service) ? App\Models\Service::find($service)->name ?? 'Service #'.$service : $service }} + + @endforeach + @else + No specific services provisioned. + @endif +
+
+
+ + +
+
+
+ Support Contacts +
+
+ +
+ Contact Person + {{ $operator->contact_person ?? 'N/A' }} +
+
+ Direct Phone + {{ $operator->contact_person_phone ?? 'N/A' }} +
+
+ Technical Support Lead + {{ $operator->technical_support_person ?? 'N/A' }} +
+
+ Support MS Team + {{ $operator->support_skype ?? 'N/A' }} +
+ +
+ Support Emails +
+ @if(is_array($operator->support_emails) && count($operator->support_emails) > 0) + @foreach($operator->support_emails as $email) + {{ $email }} + @endforeach + @else + None listed + @endif +
+
+ +
+ Finance Emails +
+ @if(is_array($operator->finance_emails) && count($operator->finance_emails) > 0) + @foreach($operator->finance_emails as $email) + {{ $email }} + @endforeach + @else + None listed + @endif +
+
+
+
+
+@endsection \ No newline at end of file diff --git a/resources/views/vendor/pagination/bootstrap-4.blade.php b/resources/views/vendor/pagination/bootstrap-4.blade.php new file mode 100644 index 0000000..63c6f56 --- /dev/null +++ b/resources/views/vendor/pagination/bootstrap-4.blade.php @@ -0,0 +1,46 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/resources/views/vendor/pagination/bootstrap-5.blade.php b/resources/views/vendor/pagination/bootstrap-5.blade.php new file mode 100644 index 0000000..94db613 --- /dev/null +++ b/resources/views/vendor/pagination/bootstrap-5.blade.php @@ -0,0 +1,80 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/resources/views/vendor/pagination/default.blade.php b/resources/views/vendor/pagination/default.blade.php new file mode 100644 index 0000000..0db70b5 --- /dev/null +++ b/resources/views/vendor/pagination/default.blade.php @@ -0,0 +1,46 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/resources/views/vendor/pagination/semantic-ui.blade.php b/resources/views/vendor/pagination/semantic-ui.blade.php new file mode 100644 index 0000000..ef0dbb1 --- /dev/null +++ b/resources/views/vendor/pagination/semantic-ui.blade.php @@ -0,0 +1,36 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/resources/views/vendor/pagination/simple-bootstrap-4.blade.php b/resources/views/vendor/pagination/simple-bootstrap-4.blade.php new file mode 100644 index 0000000..4bb4917 --- /dev/null +++ b/resources/views/vendor/pagination/simple-bootstrap-4.blade.php @@ -0,0 +1,27 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/resources/views/vendor/pagination/simple-bootstrap-5.blade.php b/resources/views/vendor/pagination/simple-bootstrap-5.blade.php new file mode 100644 index 0000000..a89005e --- /dev/null +++ b/resources/views/vendor/pagination/simple-bootstrap-5.blade.php @@ -0,0 +1,29 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/resources/views/vendor/pagination/simple-default.blade.php b/resources/views/vendor/pagination/simple-default.blade.php new file mode 100644 index 0000000..36bdbc1 --- /dev/null +++ b/resources/views/vendor/pagination/simple-default.blade.php @@ -0,0 +1,19 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/resources/views/vendor/pagination/simple-tailwind.blade.php b/resources/views/vendor/pagination/simple-tailwind.blade.php new file mode 100644 index 0000000..ea02400 --- /dev/null +++ b/resources/views/vendor/pagination/simple-tailwind.blade.php @@ -0,0 +1,25 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/resources/views/vendor/pagination/tailwind.blade.php b/resources/views/vendor/pagination/tailwind.blade.php new file mode 100644 index 0000000..aee2ad2 --- /dev/null +++ b/resources/views/vendor/pagination/tailwind.blade.php @@ -0,0 +1,106 @@ +@if ($paginator->hasPages()) + +@endif diff --git a/routes/web.php b/routes/web.php index 7c1dc93..649cf46 100644 --- a/routes/web.php +++ b/routes/web.php @@ -14,32 +14,28 @@ Route::middleware(['auth'])->group(function () { Route::get('/', [App\Http\Controllers\DashboardController::class, 'index'])->name('home'); Route::get('home', [App\Http\Controllers\DashboardController::class, 'index'])->name('home'); - - // Route::get('/clients', [App\Http\Controllers\ClientsController::class, 'index'])->name('clients.index'); + #Clients Route::get('/clients/data', [App\Http\Controllers\ClientsController::class, 'fetchData'])->name('clients.data'); Route::get('/clients/export', [App\Http\Controllers\ClientController::class, 'export'])->name('clients.export'); - - // {{ route('shortcodes.store') }} - // {{ route('client-payments.store') }} - // {{ route('client-files.store') }} - // Route::post('/shortcodes', [App\Http\Controllers\ShortCodesController::class, 'store'])->name('shortcodes.store'); + Route::get('/clients/{id}/json', [App\Http\Controllers\ClientsController::class, 'getClientJson']); + Route::put('/clients/{id}', [App\Http\Controllers\ClientsController::class, 'update'])->name('clients.update'); Route::post('/clients/shortcodes-store', [App\Http\Controllers\ClientsController::class, 'shortcodeStore'])->name('shortcodes.store'); Route::post('/clients/payments-store', [App\Http\Controllers\ClientsController::class, 'paymentsStore'])->name('client-payments.store'); Route::post('/clients/files-store', [App\Http\Controllers\ClientsController::class, 'storeDocument'])->name('client-files.store'); - Route::post('/clients/notes-store', [App\Http\Controllers\ClientsController::class, 'storeNote'])->name('client-notes.store'); - - - Route::get('/client-files/download/{id}', [App\Http\Controllers\ClientsController::class, 'clientFiledownload'])->name('client-files.download'); Route::resource('clients', App\Http\Controllers\ClientsController::class); - + #MNOs mnos.store + Route::get('/mnos/{id}', [App\Http\Controllers\NetworkOperatorsController::class, 'show'])->name('mnos.show'); + Route::get('/mnos', [App\Http\Controllers\NetworkOperatorsController::class, 'index'])->name('mnos.index'); + Route::post('/mnos', [App\Http\Controllers\NetworkOperatorsController::class, 'store'])->name('mnos.store'); + Route::get('/mnos/{id}/json', [App\Http\Controllers\NetworkOperatorsController::class, 'getJson']); + 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('/mnos', [App\Http\Controllers\NetworkOperatorsControlle::class, 'index'])->name('mnos.index'); Route::get('/documents', [App\Http\Controllers\DocumentsVaultController::class, 'index'])->name('documents.index'); Route::get('/senderids', [App\Http\Controllers\SenderidsController::class, 'index']); diff --git a/scratch.md b/scratch.md new file mode 100644 index 0000000..865e0c5 --- /dev/null +++ b/scratch.md @@ -0,0 +1,87 @@ +`name` varchar(200) NOT NULL DEFAULT '', + `country` varchar(200) NOT NULL DEFAULT '', + `contact_person` varchar(191) DEFAULT NULL, + `contact_person_phone` varchar(25) DEFAULT NULL, + `contact_person_email` varchar(191) DEFAULT NULL, + + `support_emails` text DEFAULT NULL, + `finance_emails` text DEFAULT NULL, + `support_skype` text DEFAULT NULL, + + `technical_support_person` varchar(191) DEFAULT NULL, + `services` text DEFAULT NULL, + `buying_rate` decimal(10,4) DEFAULT 0.0000, + `rate_type` varchar(20) DEFAULT NULL, + `payment_terms` varchar(20) DEFAULT NULL, + `sliding_rate_file` text DEFAULT NULL, + `connection_status` varchar(70) DEFAULT NULL, + `connection_type` text DEFAULT NULL, + `integration_type` text DEFAULT NULL, + `bind_specifics` text DEFAULT NULL, + `account_manager_id` int(11) DEFAULT NULL, + `mno_account_manager` varchar(191) DEFAULT NULL, + `contract_auto_renew` varchar(15) DEFAULT NULL, + `contract_validity` varchar(191) DEFAULT NULL, + `direct_business` varchar(10) DEFAULT 'YES', + + @php + function renderBadges($jsonString, $type = 'email') { + $items = json_decode($jsonString, true) ?? []; + if(count($items) === 0) return 'N/A'; + $html = ''; + foreach($items as $item) { + $icon = $type == 'email' ? 'bi-envelope' : 'bi-telephone'; + $html .= ''.$item.''; + } + return $html; + } + @endphp + +@php + $services = json_decode($showclient->services, true) ?? []; +@endphp + +@php + $msgTypes = json_decode($showclient->message_types, true) ?? []; +@endphp + +{!! renderBadges($showclient->finance_email, 'email') !!} +
{!! renderBadges($showclient->finance_email, 'email') !!}
+ {!! renderBadges($showclient->support_emails, 'email') !!}
+
{!! renderBadges($showclient->rate_emails, 'email') !!}
+
{!! renderBadges($showclient->support_phones, 'phone') !!}
+ + + +
+
Finance Emails
+ @if($showclient->finance_email !== null || $showclient->finance_email !== "") +
finance_email) ?>
+
{!! renderBadges($showclient->finance_email, 'email') !!}
+ @endif +
+ +
+
Support Emails
+ @if($showclient->support_emails !== null) +
{!! renderBadges($showclient->support_emails, 'email') !!}
+
support_emails) ?>
+ @endif +
+ +
+
Rate Emails
+ @if($showclient->rate_emails !== null) +
rate_emails) ?>
+
{!! renderBadges($showclient->rate_emails, 'email') !!}
+ @endif +
+ +
+
Support Phones
+ @if($showclient->support_phones !== null) +
support_phones) ?>
+
{!! renderBadges($showclient->support_phones, 'phone') !!}
+ @endif +
+ \ No newline at end of file