401 lines
20 KiB
PHP
401 lines
20 KiB
PHP
@extends('layouts.masterbeta')
|
|
|
|
@section('title', 'Cick ERP - ' . $operator->name)
|
|
|
|
@section('breadcrumbs')
|
|
<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>
|
|
<a href="{{ route('mnos.index') }}" class="text-secondary text-decoration-none me-2" style="font-size: 0.95rem;">MNO Partners</a>
|
|
<i class="bi bi-chevron-right text-secondary me-2" style="font-size: 0.8rem;"></i>
|
|
<span class="fw-bold" style="font-size: 0.95rem;">{{ $operator->name }}</span>
|
|
@endsection
|
|
|
|
@section('content')
|
|
<!-- Header Section -->
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<div class="d-flex align-items-center">
|
|
<div class="avatar-circle bg-primary bg-opacity-10 text-primary fw-bold me-3 fs-4" style="width: 55px; height: 55px; border-radius: 50%; display: flex; align-items: center; justify-content: center;">
|
|
{{ strtoupper(substr($operator->name, 0, 2)) }}
|
|
</div>
|
|
<div>
|
|
<h3 class="fw-bold mb-1">{{ $operator->name }}</h3>
|
|
<p class="text-secondary mb-0" style="font-size: 0.9rem;">
|
|
<i class="bi bi-geo-alt me-1"></i> {{ $operator->country }} •
|
|
<span class="badge {{ $operator->connection_status == 'Online' ? 'bg-success' : 'bg-danger' }} ms-1">
|
|
{{ $operator->connection_status ?? 'Offline' }}
|
|
</span>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<a href="{{ route('mnos.index') }}" class="btn btn-outline-secondary btn-sm fw-bold">
|
|
<i class="bi bi-arrow-left me-1"></i> Back to List
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Overview Metrics Row -->
|
|
<div class="row g-4 mb-4">
|
|
<div class="col-xl-4 col-md-6">
|
|
<div class="content-card p-3 h-100 border-start border-4 border-primary">
|
|
<div class="text-secondary fw-bold mb-1" style="font-size: 0.75rem; letter-spacing: 0.5px;">CONNECTION TYPE</div>
|
|
<h5 class="fw-bold mb-0 text-dark">{{ $operator->connection_type ?? 'Standard Link' }}</h5>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-4 col-md-6">
|
|
<div class="content-card p-3 h-100 border-start border-4 border-success">
|
|
<div class="text-secondary fw-bold mb-1" style="font-size: 0.75rem; letter-spacing: 0.5px;">BUYING RATE</div>
|
|
<h5 class="fw-bold mb-0 text-dark">{{ $operator->buying_rate ? number_format($operator->buying_rate, 4) : '0.0000' }}</h5>
|
|
</div>
|
|
</div>
|
|
<div class="col-xl-4 col-md-6">
|
|
<div class="content-card p-3 h-100 border-start border-4 border-warning">
|
|
<div class="text-secondary fw-bold mb-1" style="font-size: 0.75rem; letter-spacing: 0.5px;">PAYMENT TERMS</div>
|
|
<h5 class="fw-bold mb-0 text-dark">{{ $operator->payment_terms ?? 'N/A' }}</h5>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Detailed Attributes Grid -->
|
|
<div class="row g-4">
|
|
<!-- Left Column: Carrier & Technical Meta -->
|
|
<div class="col-lg-8">
|
|
<div class="content-card p-4 mb-4">
|
|
<h5 class="fw-bold mb-3 text-secondary" style="font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.5px;">
|
|
<i class="bi bi-info-circle me-2 text-primary"></i> Carrier & Technical Configuration
|
|
</h5>
|
|
<hr class="text-muted opacity-25">
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<span class="text-muted small d-block">Operating Country</span>
|
|
<strong class="text-dark">{{ $operator->country }}</strong>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<span class="text-muted small d-block">Rate Type</span>
|
|
<strong class="text-dark">{{ $operator->rate_type ?? 'N/A' }}</strong>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<span class="text-muted small d-block">Account Manager</span>
|
|
<strong class="text-dark">{{ $operator->mno_account_manager ?? 'N/A' }}</strong>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<span class="text-muted small d-block">Direct Business</span>
|
|
<strong class="text-dark">{{ $operator->direct_business ?? 'YES' }}</strong>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Provisioned Services Badges -->
|
|
<div class="content-card p-4">
|
|
<h5 class="fw-bold mb-3 text-secondary" style="font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.5px;">
|
|
<i class="bi bi-layers me-2 text-primary"></i> Provisioned Services
|
|
</h5>
|
|
<hr class="text-muted opacity-25">
|
|
<div class="d-flex flex-wrap gap-2">
|
|
@if(is_array($operator->services) && count($operator->services) > 0)
|
|
@foreach($operator->services as $service)
|
|
<span class="badge bg-light text-primary border px-3 py-2" style="font-size: 0.85rem;">
|
|
<i class="bi bi-check-circle-fill me-1 text-success"></i> {{ is_numeric($service) ? App\Models\Service::find($service)->name ?? 'Service #'.$service : $service }}
|
|
</span>
|
|
@endforeach
|
|
@else
|
|
<span class="text-muted small">No specific services provisioned.</span>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right Column: Contacts & Support Channels -->
|
|
<div class="col-lg-4">
|
|
<div class="content-card p-4 mb-4">
|
|
<h5 class="fw-bold mb-3 text-secondary" style="font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.5px;">
|
|
<i class="bi bi-headset me-2 text-primary"></i> Support Contacts
|
|
</h5>
|
|
<hr class="text-muted opacity-25">
|
|
|
|
<div class="mb-3">
|
|
<span class="text-muted small d-block">Contact Person</span>
|
|
<strong class="text-dark">{{ $operator->contact_person ?? 'N/A' }}</strong>
|
|
</div>
|
|
<div class="mb-3">
|
|
<span class="text-muted small d-block">Direct Phone</span>
|
|
<strong class="text-dark">{{ $operator->contact_person_phone ?? 'N/A' }}</strong>
|
|
</div>
|
|
<div class="mb-3">
|
|
<span class="text-muted small d-block">Technical Support Lead</span>
|
|
<strong class="text-dark">{{ $operator->technical_support_person ?? 'N/A' }}</strong>
|
|
</div>
|
|
<div class="mb-3">
|
|
<span class="text-muted small d-block">Support MS Team</span>
|
|
<strong class="text-dark">{{ $operator->support_skype ?? 'N/A' }}</strong>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<span class="text-muted small d-block mb-1">Support Emails</span>
|
|
<div class="d-flex flex-wrap gap-1">
|
|
@if(is_array($operator->support_emails) && count($operator->support_emails) > 0)
|
|
@foreach($operator->support_emails as $email)
|
|
<span class="badge bg-secondary bg-opacity-10 text-dark border" style="font-size: 0.75rem;">{{ $email }}</span>
|
|
@endforeach
|
|
@else
|
|
<span class="text-muted small">None listed</span>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<span class="text-muted small d-block mb-1">Finance Emails</span>
|
|
<div class="d-flex flex-wrap gap-1">
|
|
@if(is_array($operator->finance_emails) && count($operator->finance_emails) > 0)
|
|
@foreach($operator->finance_emails as $email)
|
|
<span class="badge bg-secondary bg-opacity-10 text-dark border" style="font-size: 0.75rem;">{{ $email }}</span>
|
|
@endforeach
|
|
@else
|
|
<span class="text-muted small">None listed</span>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div> <!-- Close Support Contacts content-card -->
|
|
</div> <!-- Close Right Column (col-lg-4) -->
|
|
</div> <!-- Close the main row (row g-4) -->
|
|
<!-- Connections & Interconnect Details Section -->
|
|
<div class="content-card p-4 mb-4">
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<h5 class="fw-bold mb-0 text-secondary" style="font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.5px;">
|
|
<i class="bi bi-shield-lock me-2 text-primary"></i> Connection Endpoints (VPN / Whitelisted IPs & Domains)
|
|
</h5>
|
|
<button type="button" class="btn btn-sm text-white fw-bold" style="background-color: #5c4df0;" data-bs-toggle="modal" data-bs-target="#addConnectionModal">
|
|
<i class="bi bi-plus-lg me-1"></i> Add Connection Detail
|
|
</button>
|
|
</div>
|
|
<hr class="text-muted opacity-25">
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-custom align-middle mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th>Mode</th>
|
|
<th>Identifier (IP / Domain / VPN)</th>
|
|
<th>Port</th>
|
|
<th>Status</th>
|
|
<th>Notes</th>
|
|
<th class="text-end">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@forelse($operator->connectionDetails as $conn)
|
|
<tr>
|
|
<td>
|
|
<span class="badge bg-secondary bg-opacity-10 text-dark border">{{ $conn->connection_mode }}</span>
|
|
@if($conn->vpn_file_path)
|
|
<a href="{{ asset('storage/' . $conn->vpn_file_path) }}" target="_blank" class="d-block mt-1" style="font-size: 0.75rem;">
|
|
<i class="bi bi-paperclip"></i> View Form
|
|
</a>
|
|
@endif
|
|
</td>
|
|
<td><code>{{ $conn->identifier }}</code></td>
|
|
<td>{{ $conn->port ?? 'N/A' }}</td>
|
|
<td>
|
|
<span class="badge {{ $conn->status == 'Active' ? 'bg-success' : 'bg-warning' }} bg-opacity-10 text-success px-2 py-1">
|
|
{{ $conn->status }}
|
|
</span>
|
|
</td>
|
|
<td>{{ $conn->notes ?? '-' }}</td>
|
|
<td class="text-end">
|
|
<form action="{{ route('mnos.connections.destroy', $conn->id) }}" method="POST" class="d-inline">
|
|
@csrf
|
|
@method('DELETE')
|
|
<button type="submit" class="btn btn-sm btn-light text-danger" onclick="return confirm('Delete this connection detail?')">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="6" class="text-center text-secondary py-4">No specific VPN or IP whitelisting rules added yet.</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@endsection
|
|
@push('modals')
|
|
|
|
<!-- Add Connection Modal -->
|
|
<!-- Add Connection Modal -->
|
|
<div class="modal fade" id="addConnectionModal" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog modal-dialog-centered">
|
|
<div class="modal-content">
|
|
<div class="modal-header bg-light">
|
|
<h5 class="modal-title fw-bold">Add Interconnect Detail</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
|
|
<!-- Added ID to the form -->
|
|
<form id="addConnectionForm" action="{{ route('mnos.connections.store', $operator->id) }}" method="POST" enctype="multipart/form-data">
|
|
@csrf
|
|
<div class="modal-body p-4">
|
|
<!-- Alert container for AJAX errors -->
|
|
<div id="connectionModalAlert"></div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label text-secondary fw-semibold small">Connection Mode *</label>
|
|
<select name="connection_mode" id="connectionModeSelect" class="form-select" required>
|
|
<option value="Whitelisted IP">Whitelisted IP Address</option>
|
|
<option value="Domain">Domain / Hostname</option>
|
|
<option value="VPN Tunnel">VPN Tunnel Endpoint</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="mb-3" id="vpnFormContainer" style="display: none;">
|
|
<label class="form-label text-secondary fw-semibold small">Upload VPN Form (PDF, DOCX)</label>
|
|
<input type="file" name="vpn_file" id="vpnFileInput" class="form-control" accept=".pdf,.doc,.docx,.xlsx,.jpg,.png">
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label class="form-label text-secondary fw-semibold small">Identifier (IP / Domain / VPN Peer) *</label>
|
|
<input type="text" name="identifier" class="form-control" required placeholder="e.g. 196.200.15.22 or smpp.operator.com">
|
|
</div>
|
|
|
|
<div class="row g-3 mb-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label text-secondary fw-semibold small">Port</label>
|
|
<!-- Added type="number", min, and max -->
|
|
<input type="number" name="port" class="form-control" placeholder="e.g. 2775" min="1" max="65535">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label text-secondary fw-semibold small">Status</label>
|
|
<select name="status" class="form-select">
|
|
<option value="Active">Active</option>
|
|
<option value="Testing">Testing</option>
|
|
<option value="Disabled">Disabled</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label text-secondary fw-semibold small">Notes / Description</label>
|
|
<textarea name="notes" class="form-control" rows="2" placeholder="Optional context or routing details..."></textarea>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer bg-light">
|
|
<button type="button" class="btn btn-outline-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="submit" id="btnSubmitConnection" class="btn text-white btn-sm fw-bold px-4" style="background-color: #5c4df0;">Save Endpoint</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endpush
|
|
@push('scripts')
|
|
<script>
|
|
|
|
$(document).ready(function() {
|
|
console.log('foo bar')
|
|
$('#connectionModeSelect').on('change', function() {
|
|
if ($(this).val() === 'VPN Tunnel') {
|
|
$('#vpnFormContainer').slideDown();
|
|
} else {
|
|
$('#vpnFormContainer').slideUp();
|
|
$('#vpnFileInput').val(''); // Clear the file input if they switch away
|
|
}
|
|
});
|
|
});
|
|
$(document).ready(function() {
|
|
// Toggle VPN File input visibility
|
|
$('#connectionModeSelect').on('change', function() {
|
|
if ($(this).val() === 'VPN Tunnel') {
|
|
$('#vpnFormContainer').slideDown();
|
|
} else {
|
|
$('#vpnFormContainer').slideUp();
|
|
$('#vpnFileInput').val('');
|
|
}
|
|
});
|
|
|
|
// Handle AJAX Form Submission
|
|
$('#addConnectionForm').on('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
let $form = $(this);
|
|
let $submitBtn = $('#btnSubmitConnection');
|
|
let originalText = $submitBtn.html();
|
|
let $alertBox = $('#connectionModalAlert');
|
|
|
|
// Use FormData to handle the file upload payload
|
|
let formData = new FormData(this);
|
|
|
|
$submitBtn.html('<span class="spinner-border spinner-border-sm me-2"></span>Saving...').prop('disabled', true);
|
|
$alertBox.html('');
|
|
$form.find('.is-invalid').removeClass('is-invalid');
|
|
$form.find('.invalid-feedback').remove();
|
|
|
|
$.ajax({
|
|
url: $form.attr('action'),
|
|
type: 'POST',
|
|
data: formData,
|
|
processData: false, // Prevent jQuery from converting the data into a query string
|
|
contentType: false, // Prevent jQuery from overriding the multipart header
|
|
success: function(response) {
|
|
if (response.success) {
|
|
$('#addConnectionModal').modal('hide');
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'Success!',
|
|
text: response.message,
|
|
confirmButtonColor: '#5c4df0'
|
|
}).then(() => {
|
|
// Reload the page to reflect the new connection in the table
|
|
location.reload();
|
|
});
|
|
}
|
|
},
|
|
error: function(xhr) {
|
|
if (xhr.status === 422) {
|
|
let errors = xhr.responseJSON.errors;
|
|
|
|
$alertBox.html(`
|
|
<div class="alert alert-danger d-flex align-items-center py-2 px-3 small" role="alert">
|
|
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
|
<div>Please check the highlighted fields below.</div>
|
|
</div>
|
|
`);
|
|
|
|
// Highlight specific fields
|
|
$.each(errors, function(key, value) {
|
|
let $input = $form.find('[name="' + key + '"]');
|
|
if ($input.length) {
|
|
$input.addClass('is-invalid');
|
|
$input.parent().append('<div class="invalid-feedback d-block fw-medium small">' + value[0] + '</div>');
|
|
}
|
|
});
|
|
} else {
|
|
$alertBox.html(`
|
|
<div class="alert alert-danger d-flex align-items-center py-2 px-3 small" role="alert">
|
|
<i class="bi bi-x-circle-fill me-2"></i>
|
|
<div>An error occurred. Please try again.</div>
|
|
</div>
|
|
`);
|
|
}
|
|
},
|
|
complete: function() {
|
|
$submitBtn.html(originalText).prop('disabled', false);
|
|
}
|
|
});
|
|
});
|
|
|
|
// Reset the form when the modal is closed
|
|
$('#addConnectionModal').on('hidden.bs.modal', function () {
|
|
$('#addConnectionForm')[0].reset();
|
|
$('#vpnFormContainer').hide();
|
|
$('#connectionModalAlert').html('');
|
|
$('#addConnectionForm').find('.is-invalid').removeClass('is-invalid');
|
|
$('#addConnectionForm').find('.invalid-feedback').remove();
|
|
});
|
|
});
|
|
</script>
|
|
@endpush |