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)
|
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!']);
|
return response()->json(['message' => 'Note added successfully!']);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,5 +21,20 @@ class ClientNote extends Model
|
|||||||
public function created_by_info(){
|
public function created_by_info(){
|
||||||
return $this->hasOne('App\Models\SystemUser', 'id', 'auth_user_id');
|
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() {
|
$(document).ready(function() {
|
||||||
console.log('Client modals AJAX script loaded with SweetAlert.');
|
|
||||||
|
|
||||||
// Generic AJAX handler for standard forms (Shortcodes & Payments)
|
// Generic AJAX handler for standard forms (Shortcodes & Payments)
|
||||||
$(document).on('submit', '#shortcodeForm, #paymentForm, #noteForm', function(e) {
|
$(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
|
// Only fetch if options haven't been loaded yet
|
||||||
if ($select.children('option').length === 0) {
|
if ($select.children('option').length === 0) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: base_url + '/api/services', // Update route if needed
|
url: base_url + '/api/services',
|
||||||
type: 'GET',
|
type: 'GET',
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
$select.empty();
|
$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
|
// Clear Select2 values when modal is closed
|
||||||
$('#addPaymentModal').on('hidden.bs.modal', function () {
|
$('#addPaymentModal').on('hidden.bs.modal', function () {
|
||||||
$('#paymentServicesSelect').val(null).trigger('change');
|
$('#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 fade" id="addShortcodeModal" tabindex="-1" aria-labelledby="addShortcodeModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@@ -73,9 +73,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- ========================================== -->
|
<!-- ADD PAYMENT MODAL -->
|
||||||
<!-- 2. ADD PAYMENT MODAL -->
|
|
||||||
<!-- ========================================== -->
|
|
||||||
<div class="modal fade" id="addPaymentModal" tabindex="-1" aria-labelledby="addPaymentModalLabel" aria-hidden="true">
|
<div class="modal fade" id="addPaymentModal" tabindex="-1" aria-labelledby="addPaymentModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@@ -126,9 +125,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- ========================================== -->
|
<!-- UPLOAD DOCUMENT MODAL -->
|
||||||
<!-- 3. UPLOAD DOCUMENT MODAL (MULTI-FILE) -->
|
|
||||||
<!-- ========================================== -->
|
|
||||||
<div class="modal fade" id="uploadDocumentModal" tabindex="-1" aria-labelledby="uploadDocumentModalLabel" aria-hidden="true">
|
<div class="modal fade" id="uploadDocumentModal" tabindex="-1" aria-labelledby="uploadDocumentModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@@ -181,6 +179,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<!-- Client Note Modal -->
|
<!-- Client Note Modal -->
|
||||||
|
|
||||||
<div class="modal fade" id="addNoteModal" tabindex="-1" aria-labelledby="addNoteModalLabel" aria-hidden="true">
|
<div class="modal fade" id="addNoteModal" tabindex="-1" aria-labelledby="addNoteModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<form id="noteForm" action="{{ route('client-notes.store') }}" method="POST">
|
<form id="noteForm" action="{{ route('client-notes.store') }}" method="POST">
|
||||||
@@ -188,15 +187,24 @@
|
|||||||
<input type="hidden" name="client_id" value="{{ $showclient->id }}">
|
<input type="hidden" name="client_id" value="{{ $showclient->id }}">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<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>
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
<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>
|
<textarea name="note" class="form-control" rows="4" placeholder="Enter notes here..." required></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="modal-footer bg-light">
|
<div class="modal-footer bg-light">
|
||||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -347,6 +347,16 @@
|
|||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
@forelse($show_notes as $note)
|
@forelse($show_notes as $note)
|
||||||
<div class="list-group-item p-3 mb-2 border rounded shadow-sm">
|
<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>
|
<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;">
|
<div class="d-flex justify-content-between align-items-center text-muted" style="font-size: 0.8rem;">
|
||||||
<span>
|
<span>
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
<select class="form-select bg-white">
|
<select class="form-select bg-white">
|
||||||
<option value="">All Link Types</option>
|
<option value="">All Link Types</option>
|
||||||
<option value="vpn">IPsec VPN</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>
|
<option value="public">Whitelisted Public IP</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -154,14 +154,14 @@
|
|||||||
<span class="tech-badge">MNC: 02</span>
|
<span class="tech-badge">MNC: 02</span>
|
||||||
</td>
|
</td>
|
||||||
<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-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;">IP: 100.115.2.4</div>
|
<div class="text-secondary" style="font-size: 0.75rem;">Peer IP: 100.115.2.4</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="d-flex gap-1 flex-wrap">
|
<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;">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;">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>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -109,7 +109,7 @@
|
|||||||
<!-- Row 1 -->
|
<!-- Row 1 -->
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<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>
|
<div class="text-secondary mt-1" style="font-size: 0.75rem;">Created: May 12, 2026</div>
|
||||||
</td>
|
</td>
|
||||||
<td><span class="badge bg-dark bg-opacity-10 text-dark border">Internal System</span></td>
|
<td><span class="badge bg-dark bg-opacity-10 text-dark border">Internal System</span></td>
|
||||||
@@ -133,10 +133,10 @@
|
|||||||
<!-- Row 2 -->
|
<!-- Row 2 -->
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<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>
|
<div class="text-secondary mt-1" style="font-size: 0.75rem;">Created: Jun 02, 2026</div>
|
||||||
</td>
|
</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><span class="badge bg-secondary bg-opacity-10 text-secondary border">Alphanumeric</span></td>
|
||||||
<td>
|
<td>
|
||||||
<div class="d-flex gap-1 flex-wrap">
|
<div class="d-flex gap-1 flex-wrap">
|
||||||
|
|||||||
Reference in New Issue
Block a user