updated notes with services and updated sample texts on views
This commit is contained in:
@@ -704,9 +704,20 @@ class ClientsController extends Controller
|
||||
}
|
||||
public function storeNote(Request $request)
|
||||
{
|
||||
$request->validate(['note' => 'required|string', 'client_id' => 'required|exists:clients,id']);
|
||||
$request->validate([
|
||||
'note' => 'required|string',
|
||||
'client_id' => 'required|exists:clients,id',
|
||||
'services' => 'nullable|array',
|
||||
]);
|
||||
|
||||
\App\Models\ClientNote::create([
|
||||
'client_id' => $request->client_id,
|
||||
'user_id' => auth()->id(),
|
||||
'notes_body' => $request->note,
|
||||
'services' => $request->services,
|
||||
]);
|
||||
|
||||
|
||||
\App\Models\ClientNote::create($request->all());
|
||||
|
||||
return response()->json(['message' => 'Note added successfully!']);
|
||||
}
|
||||
|
||||
@@ -21,5 +21,20 @@ class ClientNote extends Model
|
||||
public function created_by_info(){
|
||||
return $this->hasOne('App\Models\SystemUser', 'id', 'auth_user_id');
|
||||
}
|
||||
protected $casts = [
|
||||
'services' => 'array',
|
||||
];
|
||||
|
||||
public function getServiceNamesAttribute()
|
||||
{
|
||||
if (empty($this->services) || !is_array($this->services)) {
|
||||
return collect();
|
||||
}
|
||||
return \App\Models\Service::whereIn('id', $this->services)->pluck('name');
|
||||
}
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(App\Models\User::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ document.addEventListener("DOMContentLoaded", function() {
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
console.log('Client modals AJAX script loaded with SweetAlert.');
|
||||
|
||||
|
||||
// Generic AJAX handler for standard forms (Shortcodes & Payments)
|
||||
$(document).on('submit', '#shortcodeForm, #paymentForm, #noteForm', function(e) {
|
||||
@@ -122,7 +122,7 @@ document.addEventListener("DOMContentLoaded", function() {
|
||||
// Only fetch if options haven't been loaded yet
|
||||
if ($select.children('option').length === 0) {
|
||||
$.ajax({
|
||||
url: base_url + '/api/services', // Update route if needed
|
||||
url: base_url + '/api/services',
|
||||
type: 'GET',
|
||||
success: function(data) {
|
||||
$select.empty();
|
||||
@@ -151,6 +151,40 @@ document.addEventListener("DOMContentLoaded", function() {
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize Select2 for Note Services when modal opens
|
||||
$('#addNoteModal').on('shown.bs.modal', function () {
|
||||
let $select = $('#noteServicesSelect');
|
||||
|
||||
if ($select.children('option').length === 0) {
|
||||
$.ajax({
|
||||
url: base_url + '/api/services',
|
||||
type: 'GET',
|
||||
success: function(data) {
|
||||
$select.empty();
|
||||
data.forEach(function(service) {
|
||||
$select.append(new Option(service.name, service.id, false, false));
|
||||
});
|
||||
|
||||
$select.select2({
|
||||
theme: 'bootstrap-5',
|
||||
dropdownParent: $('#addNoteModal'),
|
||||
placeholder: 'Search and select services...'
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$select.select2({
|
||||
theme: 'bootstrap-5',
|
||||
dropdownParent: $('#addNoteModal'),
|
||||
placeholder: 'Search and select services...'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Clear Select2 values when modal is closed
|
||||
$('#addNoteModal').on('hidden.bs.modal', function () {
|
||||
$('#noteServicesSelect').val(null).trigger('change');
|
||||
});
|
||||
// Clear Select2 values when modal is closed
|
||||
$('#addPaymentModal').on('hidden.bs.modal', function () {
|
||||
$('#paymentServicesSelect').val(null).trigger('change');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!-- ========================================== -->
|
||||
<!-- 1. ADD SHORT CODE MODAL -->
|
||||
<!-- ========================================== -->
|
||||
|
||||
<!-- SHORT CODE MODAL -->
|
||||
|
||||
<div class="modal fade" id="addShortcodeModal" tabindex="-1" aria-labelledby="addShortcodeModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
@@ -73,9 +73,8 @@
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ========================================== -->
|
||||
<!-- 2. ADD PAYMENT MODAL -->
|
||||
<!-- ========================================== -->
|
||||
<!-- ADD PAYMENT MODAL -->
|
||||
|
||||
<div class="modal fade" id="addPaymentModal" tabindex="-1" aria-labelledby="addPaymentModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
@@ -126,9 +125,8 @@
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ========================================== -->
|
||||
<!-- 3. UPLOAD DOCUMENT MODAL (MULTI-FILE) -->
|
||||
<!-- ========================================== -->
|
||||
<!-- UPLOAD DOCUMENT MODAL -->
|
||||
|
||||
<div class="modal fade" id="uploadDocumentModal" tabindex="-1" aria-labelledby="uploadDocumentModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
@@ -181,6 +179,7 @@
|
||||
|
||||
|
||||
<!-- Client Note Modal -->
|
||||
|
||||
<div class="modal fade" id="addNoteModal" tabindex="-1" aria-labelledby="addNoteModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<form id="noteForm" action="{{ route('client-notes.store') }}" method="POST">
|
||||
@@ -188,15 +187,24 @@
|
||||
<input type="hidden" name="client_id" value="{{ $showclient->id }}">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title fw-bold">Add Note</h5>
|
||||
<h5 class="modal-title fw-bold"><i class="bi bi-chat-square-text text-primary me-2"></i>Add Note</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<textarea name="note" class="form-control" rows="4" placeholder="Enter notes here..." required></textarea>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small fw-bold">Services</label>
|
||||
<select name="services[]" id="noteServicesSelect" class="form-select" multiple="multiple">
|
||||
<!-- Populated dynamically via AJAX -->
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small fw-bold">Note Details</label>
|
||||
<textarea name="note" class="form-control" rows="4" placeholder="Enter notes here..." required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm">Save Note</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm px-4">Save Note</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -347,6 +347,16 @@
|
||||
<div class="list-group">
|
||||
@forelse($show_notes as $note)
|
||||
<div class="list-group-item p-3 mb-2 border rounded shadow-sm">
|
||||
@php $noteServices = $note->service_names; @endphp
|
||||
@if($noteServices->count() > 0)
|
||||
<div class="d-flex flex-wrap gap-1 mb-2">
|
||||
@foreach($noteServices as $serviceName)
|
||||
<span class="badge bg-light text-primary border" style="font-size: 0.7rem;">
|
||||
{{ $serviceName }}
|
||||
</span>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
<p class="mb-2 text-dark">{{ $note->notes_body }}</p>
|
||||
<div class="d-flex justify-content-between align-items-center text-muted" style="font-size: 0.8rem;">
|
||||
<span>
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
<select class="form-select bg-white">
|
||||
<option value="">All Link Types</option>
|
||||
<option value="vpn">IPsec VPN</option>
|
||||
<option value="tailscale">Tailscale Mesh</option>
|
||||
<option value="tailscale">IPSec VPN Tunnel</option>
|
||||
<option value="public">Whitelisted Public IP</option>
|
||||
</select>
|
||||
</div>
|
||||
@@ -154,14 +154,14 @@
|
||||
<span class="tech-badge">MNC: 02</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="text-dark fw-semibold" style="font-size: 0.85rem;"><i class="bi bi-shuffle me-1 text-info"></i> Tailscale Node</div>
|
||||
<div class="text-secondary" style="font-size: 0.75rem;">IP: 100.115.2.4</div>
|
||||
<div class="text-dark fw-semibold" style="font-size: 0.85rem;"><i class="bi bi-shuffle me-1 text-info"></i> VPN Tunnel</div>
|
||||
<div class="text-secondary" style="font-size: 0.75rem;">Peer IP: 100.115.2.4</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex gap-1 flex-wrap">
|
||||
<span class="badge bg-secondary text-dark border bg-light" style="font-size: 0.65rem;">USSD</span>
|
||||
<span class="badge bg-secondary text-dark border bg-light" style="font-size: 0.65rem;">SMS Gateway</span>
|
||||
<span class="badge bg-secondary text-dark border bg-light" style="font-size: 0.65rem;">MoMo API</span>
|
||||
<span class="badge bg-secondary text-dark border bg-light" style="font-size: 0.65rem;">Payment API</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
<!-- Row 1 -->
|
||||
<tr>
|
||||
<td>
|
||||
<div class="sender-id-text fw-bold">NEXUS-OTP</div>
|
||||
<div class="sender-id-text fw-bold">ABSA-OTP</div>
|
||||
<div class="text-secondary mt-1" style="font-size: 0.75rem;">Created: May 12, 2026</div>
|
||||
</td>
|
||||
<td><span class="badge bg-dark bg-opacity-10 text-dark border">Internal System</span></td>
|
||||
@@ -133,10 +133,10 @@
|
||||
<!-- Row 2 -->
|
||||
<tr>
|
||||
<td>
|
||||
<div class="sender-id-text fw-bold">CLICKTECH</div>
|
||||
<div class="sender-id-text fw-bold">CLICKML</div>
|
||||
<div class="text-secondary mt-1" style="font-size: 0.75rem;">Created: Jun 02, 2026</div>
|
||||
</td>
|
||||
<td><span class="badge bg-info bg-opacity-10 text-info border border-info-subtle">Client: Click Tech</span></td>
|
||||
<td><span class="badge bg-info bg-opacity-10 text-info border border-info-subtle">Client: Abusua Solutions</span></td>
|
||||
<td><span class="badge bg-secondary bg-opacity-10 text-secondary border">Alphanumeric</span></td>
|
||||
<td>
|
||||
<div class="d-flex gap-1 flex-wrap">
|
||||
|
||||
Reference in New Issue
Block a user