@extends('layout.app')
@php
use Carbon\Carbon;
@endphp
{{-- Critical: hide cx-overlay modals in
to prevent FOUC on page load --}}
@push('styles')
@endpush
@section('content')
@php
$r = $list->first();
// Reseller name + type (resolved from reseller_id)
$resellerName = $r->reseller_name ?? null;
$isOwnReseller = $r->reseller_type === 'own';
$isClosed = !empty($r->deleted_at);
// Address line
$addressParts = array_filter([
$r->flat_no ?? null,
$r && $r->road_no ? 'Road ' . $r->road_no : null,
$r->building_name ?? null,
$r->block_sector ?? null,
checkSettings('area') == 'enable' ? $r->area ?? null : null,
]);
$addressLine = count($addressParts) ? implode(', ', $addressParts) : '';
// Google-map link from stored lat/long
$mapLink =
$r && $r->client_latitude && $r->client_longitude
? 'https://maps.google.com/?q=' . $r->client_latitude . ',' . $r->client_longitude
: null;
// Balance: customer_accounts.dueAmount ( > 0 => Due, < 0 => Advance )
$due = (float) ($r->dueAmount ?? 0);
// Expiry + days remaining
$expDate = $r && $r->expire_date ? Carbon::parse($r->expire_date) : null;
$daysLeft = $expDate ? Carbon::today()->diffInDays($expDate->copy()->startOfDay(), false) : null;
// Status badge mapping (clients_status: active | expired | deactive | disable)
$statusMap = [
'active' => ['hero' => 'cx-sb-active', 'tag' => 'cx-tag-active', 'label' => 'Active'],
'expired' => ['hero' => 'cx-sb-expired', 'tag' => 'cx-tag-expired', 'label' => 'Expired'],
'deactive' => ['hero' => 'cx-sb-deact', 'tag' => 'cx-tag-deact', 'label' => 'Deactivated'],
'disable' => ['hero' => 'cx-sb-closed', 'tag' => 'cx-tag-closed', 'label' => 'Disabled'],
];
$st = $statusMap[$r->clients_status ?? ''] ?? [
'hero' => 'cx-sb-closed',
'tag' => 'cx-tag-closed',
'label' => ucfirst($r->clients_status ?? ''),
];
// Seed values only — the live status is fetched by cxLoadLiveInfo() after
// render, which replaces the connection bar, buttons and session details.
// isLive, not activeClientInfo — the latter also carries the last known
// session for an offline client, which would read as online here.
$isOnline = empty($error) && !empty($isLive);
$onlineIp = $activeClientInfo['address'] ?? ($r->ip_address ?? null);
// Contact number normalised for tel/sms/whatsapp links
$contact = $r->contact_no ?? '';
$contactDigits = preg_replace('/\D+/', '', $contact);
$waNumber = $contactDigits
? (substr($contactDigits, 0, 2) === '88'
? $contactDigits
: '88' . $contactDigits)
: '';
@endphp
{{-- ══════════════════ HERO ══════════════════ --}}
{{ strtoupper(substr($r->clients_name ?? 'U', 0, 1)) }}
{{ $r->clients_name ?? '' }}
{{ $st['label'] }}
{{ $r->userid ?? '' }}
@can('show-mother-package')
Package - {{ $r->package_name ?? '' }}
@endcan
Pop - {{ $r->popname ?? '' }}
Exp. Date - {{ $expDate ? $expDate->format('d M Y') : 'N/A' }}
Reseller - {{ $resellerName ?? 'N/A' }}
Call
@can('single-customer-sms-send')
SMS
@endcan
WhatsApp
@if ($mapLink)
View on Map
@endif
@if (!$isClosed)
@if ($isOwnReseller)
@can('money-receipt-entry')
Pay Now
@endcan
@else
@can('customer-recharge')
@if (($r->client_approval ?? '') == 'approved')
Recharge
@endif
@endcan
@endif
@endif
{{-- ONU power, up here where it is seen without scrolling. Reads the
same value as the ONU Information card below; the two are kept in
step by the refresh handler, which writes both.
A click jumps to the power history graph, but only when there is a
graph to jump to: onu_info_log off means onu_info_logs is never
written, and show-connection-information is what renders the card
at all. Without both it stays a plain reading. --}}
@if (globalPermission('onu_information_laser'))
@can('onu_information_laser')
@isset($onuInfo->laser)
@if (globalPermission('onu_info_log') && auth()->user()->can('show-connection-information'))
ONU Power:
{{ $onuInfo->laser }}
@else
ONU Power:
{{ $onuInfo->laser }}
@endif
@endisset
@endcan
@endif
{{-- ══════════════════ QUICK ACTIONS BAR ══════════════════ --}}
@if (!$isClosed)
Edit
Create Ticket
@if ($isOwnReseller)
@can('money-receipt-entry')
Payment
@endcan
@else
@can('customer-recharge')
@if (($r->client_approval ?? '') == 'approved')
Recharge
@endif
@endcan
@endif
@if ($isOwnReseller)
Invoice
PDF
@endif
@if (checkSettings('show-traffice') == 'enable' && ($r->client_approval ?? '') != 'pending')
Live
Traffic
@endif
@if ($isOwnReseller)
@can('money-receipt-entry')
Pay History
@endcan
@else
@if (auth()->user()->can('reseller-balance-log-report') || auth()->user()->can('sub-reseller-balance-log-report'))
Recharge History
@endif
@endif
@can('single-customer-sms-send')
Send SMS
@endcan
{{-- Others dropdown --}}
Others
@else
{{-- Closed client: show read-only history buttons only --}}
@if ($isOwnReseller)
Invoice PDF
@can('money-receipt-entry')
Pay History
@endcan
@else
@if (auth()->user()->can('reseller-balance-log-report') || auth()->user()->can('sub-reseller-balance-log-report'))
Recharge History
@endif
@endif
@endif
{{-- ══════════════════ THREE-COLUMN GRID ══════════════════ --}}
@can('show-service-information')
{{-- CARD 1 · CUSTOMER INFORMATION --}}
CID
{{ $r->id ?? '' }}
@if (!$r->isStatic)
Username
{{ $r->userid ?? '' }}
@else
IP Address
{{ $r->ip_address ?? '' }}
@if (!empty($r->ip_address))
@endif
@endif
@if (checkSettings('customer_code') == 'enable')
Customer Code
{{ $r->customer_code ?? '' }}
@endif
@if (!$r->isStatic)
Password
•••••
@endif
Contact
{{ $contact }}
@if (!$isClosed)
@can('single-customer-sms-send')
@endcan
@endif
@can('show-address-information')
Address
{{ $addressLine }}
@if ($mapLink)
@endif
Area
{{-- $r is a joined stdClass (DB::table), so clientsinfo.area is flat on $r --}}
{{ $r->area ?? 'N/A' }}
@endcan
Reseller
{{ $resellerName ?? 'N/A' }}
POP Name
{{ $r->popname ?? '' }}
@if (!$isClosed)
@can('pop_change_on_client_edit')
@endcan
@endif
Billing Date
{{ $r->billing_cycle ?? '' }} of month
@if ($isOwnReseller)
Balance
@if ($due > 0)
{{ number_format($due, 2) }} BDT (Due)
@elseif ($due < 0)
{{ number_format(abs($due), 2) }} BDT (Advance)
@else
0.00 BDT
@endif
@if (!$isClosed)
@if ($isOwnReseller)
@can('money-receipt-entry')
@endcan
@else
@can('customer-recharge')
@if (($r->client_approval ?? '') == 'approved')
@endif
@endcan
@endif
@can('add_other_bill')
@if ($isOwnReseller)
@endif
@endcan
@endif
@endif
Package
@if ($r->sub_package_name && $r->subreseller == 'yes')
@can('show-sub-package')
{{ $r->sub_package_name }}
@endcan
@else
@can('show-mother-package')
{{ $r->package_name ?? '' }}
@endcan
@endif
@if (!$isClosed)
@can('changePackage')
@endcan
@endif
Expiry Date
{{ $expDate ? $expDate->format('Y-m-d') : '' }}
@if (!is_null($daysLeft))
@if ($daysLeft > 7)
{{ $daysLeft }}d left
@elseif ($daysLeft >= 0)
{{ $daysLeft }}d left
@else
{{ abs($daysLeft) }}d overdue
@endif
@endif
@if (!$isClosed)
@can('change-expire-date')
@endcan
@endif
Extended
{{ $r->payment_dadeline ?? '0' }} days
@if (!$isClosed)
@can('extend-temporary-dedline')
@if ($isOwnReseller)
@endif
@endcan
@endif
Status
{{ $st['label'] }}
@endcan
@can('show-connection-information')
{{-- CARD 2 · CONNECTION STATUS --}}
Connection Status
@if ($r->ignoreMKCheck == 0)
Sync
Mikrotik
@else
Ignore MK ✅
@endif
@php $mkIp = optional(optional($clientUser->pop)->nas)->nasname; @endphp
@if ($mkIp)
MikroTik:
{{ $mkIp }}
@endif
{{ $isOnline ? 'Online' : 'Offline' }}
@if ($isOnline && $onlineIp)
{{ $onlineIp }}
@else
@endif
@can('onlineUserDisconnection')
@endcan
Perm. Discount
{{ number_format((float) ($r->parmanent_discount ?? 0), 2) }}
BDT
@if (!$isClosed && checkSettings('parmanent-discount') == 'enable' && $isOwnReseller)
@if (auth()->user()->can('parmanent-discount'))
@endif
@endif
@if (checkSettings('free_client') == 'enable')
Free Client
@if (!empty($r->is_free))
Yes
@else
No
@endif
@if (!$isClosed)
@can('add-free-client')
@endcan
@endif
@endif
@if (checkSettings('single_client_billing_type') == 'enable')
Billing Type
{{ $r->billing_type ? ucfirst($r->billing_type) : 'N/A' }}
@if (!$isClosed && auth()->user()->can('single_client_billing_type'))
@endif
@endif
@if (!$isClosed)
{{-- Both states render; cxLoadLiveInfo() shows whichever matches the live status. --}}
Remote Login
Remote Login
Ping Test
@endif
@endcan
@can('show-personal-information')
{{-- CARD 3 · OTHER DETAILS --}}
NID
{{ $r->national_id ?? '' }}
@if (!empty($r->national_id))
@endif
Father Name {{ $r->father_name ?? '' }}
Date of Birth {{ $r->dob ?? null ? date('d-M-Y', strtotime($r->dob)) : '' }}
Remote User
{{ $r->remote_access_username ?? '' }}
@if (!empty($r->remote_access_username))
@endif
Remote Pass
{{ $r->remote_access_password ?? '' }}
@if (!empty($r->remote_access_password))
@endif
Created {{ $r->created_at ?? null ? date('d-M-Y h:i:s A', strtotime($r->created_at)) : '' }}
Joining Date {{ $r->joinDate ?? null ? date('d-M-Y', strtotime($r->joinDate)) : '' }}
Created By {{ optional(\App\Models\User::find($r->created_by ?? 0))->name ?? '' }}
@if (!auth()->user()->hasRole(['Reseller Admin', 'Sub Reseller', 'Sub Reseller Technician']))
Marketed By {{ $r->marketing_employee_name ?? '' }}
@endif
Referenced By {{ $previousClientReferenceText ?? '' }}
OTC Amount {{ number_format((float) ($r->otc ?? 0), 2) }}
BDT
@endcan
{{-- /.cx-grid --}}
{{-- ══════════════════ SESSION & ONU ROW ══════════════════ --}}
@php
// Whether the ONU card will render. It decides how much room is left
// for Login Attempts below: with ONU present that card is alone on
// its own row and spans both columns, otherwise it fills the empty
// cell next to Session Details.
$hasOnuCard =
globalPermission('onu_information_laser') &&
auth()->user()->can('onu_information_laser') &&
isset($onuInfo->laser);
@endphp
{{-- SESSION DETAILS --}}
@if (checkSettings('show-traffice') == 'enable' && ($r->client_approval ?? '') != 'pending')
@php
// Seeded from the DB; the live values arrive via cxLoadLiveInfo().
$clientMac = $r->mac ?? null;
@endphp
Last
Link Up
…
Last Logout
…
Duration
…
Client MAC
{{ $clientMac ?? '…' }}
Vendor
…
@endif
{{-- ONU INFORMATION --}}
@if (globalPermission('onu_information_laser'))
@can('onu_information_laser')
@isset($onuInfo->laser)
@php
$onuMac = !empty($onuInfo->mac)
? strtoupper(implode(':', str_split($onuInfo->mac, 2)))
: null;
@endphp
OLT {{ $onuInfo->oltaddress ?? '-' }} —
"{{ $onuInfo->oltName ?? '-' }}"
ONU Id {{ $onuInfo->onuid ?? '-' }}
Power (Laser)
{{ $onuInfo->laser ?? '-' }}
Last Update {{ isset($onuInfo->updated_at) ? \Carbon\Carbon::parse($onuInfo->updated_at)->format('d-m-Y h:i A') : '-' }}
PON ID, Vlan {{ $onuInfo->interface ?? '-' }}, {{ $onuInfo->Vlan ?? '-' }}
Device MAC
{{ $onuMac ?? '-' }}
@if ($onuMac)
@endif
@endisset
@endcan
@endif
{{-- RADIUS LOGIN ATTEMPTS --}}
{{-- Last in this two-column grid: with no ONU card it fills the cell
beside Session Details, and when ONU is present it drops to its
own row and spans the full width rather than leaving half of it
empty. Filled by cxLoadLoginAttempts() after render, and left
hidden on an API-only install, where radpostauth is never written. --}}
@can('show-connection-information')
@endcan
{{-- /.cx-grid-onu --}}
{{-- ══════════════════ ONU POWER HISTORY ══════════════════ --}}
{{-- Full width below Login Attempts. Filled by cxLoadOnuPower() after
render, and left hidden unless the onu_info_log setting is on —
onu_info_logs is only written while it is. --}}
@can('show-connection-information')
ONU Power History
Last 24 hours
Last 3 days
Last 7 days
Last 15 days
Last 30 days
Last 90 days
No readings recorded for this period.
{{-- The fixed height is required: with maintainAspectRatio
false, Chart.js sizes the canvas from its parent, and an
auto-height parent grows a little on every redraw. --}}
@endcan
{{-- ══════════════════ DOCUMENTS ══════════════════ --}}
@if (checkSettings('pictureUpload') == 'enable')
@if ($r->bill_generate == 'yes' || checkSettings('file_up_for_own_other') == 'enable')
@php
$s3 = checkSettings('store_image_to_s3') == 'enable';
$cxDocs = [
[
'key' => 'customer_profile_picture',
'label' => 'Profile Picture',
'folder' => 'customer_profile_picture',
],
['key' => 'customer_agrement', 'label' => 'Agreement', 'folder' => 'customer_agrement'],
['key' => 'profilePicture', 'label' => 'Picture', 'folder' => 'profilePicture'],
['key' => 'picture', 'label' => 'Building Photo', 'folder' => 'picture'],
['key' => 'client_door', 'label' => 'Flat Door', 'folder' => 'client_door'],
['key' => 'onu_router_info', 'label' => 'ONU / Router', 'folder' => 'onu_router_info'],
];
if (checkSettings('national_id_picture') == 'enable') {
$cxDocs[] = ['key' => 'nid_image', 'label' => 'National ID', 'folder' => 'nationalId'];
}
@endphp
@foreach ($cxDocs as $doc)
@php
$fileName = $r->{$doc['key']} ?? null;
$fileUrl = null;
if ($fileName) {
$fileUrl = $s3
? \Illuminate\Support\Facades\Storage::disk('s3')->url(
$doc['folder'] . '/' . $fileName,
)
: asset('storage/' . $doc['folder'] . '/' . $fileName);
}
@endphp
@endforeach
@endif
@endif
{{-- ══════════════════ MODALS ══════════════════ --}}
{{-- PAYMENT --}}
{{-- CREATE TICKET --}}
Create Support
Ticket
Subject
Category
Connection Issue
Billing Issue
Speed Problem
Equipment
Other
Priority
Low
Medium
High
Critical
Description
Assign To
Auto-assign
Karim
Rahim
{{-- CHANGE PACKAGE --}}
{{-- EDIT HISTORY --}}
Edit History
{{ $r->userid }}
{{-- AUTO DEACTIVE DATE --}}
@can('change_auto_deactive_date')
@endcan
{{-- CHANGE STATUS --}}
Change Account
Status
@if ($r->deleted_at)
@can('customer-reactivate')
Restore
@endcan
@else
@canany(['id-enable', 'customer-reactivate'])
clients_status === 'active') style="display:none" @endif>
Active
@endcanany
@can('id-disable')
clients_status === 'disable') style="display:none" @endif>
Disable
@endcan
@can('customer-deactivated')
clients_status === 'deactive') style="display:none" @endif>
Deactivated
@endcan
@can('customer-delete')
Closed
@endcan
@endif
{{-- LIVE TRAFFIC --}}
Live Traffic
Username:
{{ $r->userid }}
Waiting…
{{-- PAYMENT HISTORY --}}
Payment History
Date
Amount
Method
Recorded By
2026-05-12
700 BDT
bKash
Admin
2026-04-12
700 BDT
Cash
Karim
2026-03-12
700 BDT
Nagad
Admin
2026-02-12
1200 BDT
Cash
Rahim
2026-01-12
700 BDT
bKash
Admin
{{-- SESSIONS --}}
Session
Details
IP Address
Started
Duration
Status
172.0.0.1
2026-06-03 08:14
14h 32m
Online
172.0.0.1
2026-06-02 09:00
23h 14m
Ended
172.0.0.1
2026-06-01 07:45
22h 50m
Ended
{{-- EXPIRE DATE EXTEND --}}
{{-- CHANGE EXTENDED DATE --}}
{{-- ADD BILL --}}
Add Custom Bill
Bill Amount (BDT)
Bill Type
— Select Type —
Other
Description
{{-- CHANGE DISCOUNT --}}
{{-- FREE CLIENT --}}
Free Client
Current status: {{ !empty($r->is_free) ? 'Free' : 'Paid' }}
Yes — Free
No — Paid
{{-- BILLING TYPE --}}
Billing
Type
Current: {{ $r->billing_type === 'day_to_day' ? 'Date2Date' : ($r->billing_type === 'monthly' ? 'Monthly' : 'N/A') }}
Date2Date
Monthly
{{-- BILL CYCLE CHANGE --}}
@can('changeBillCycle')
@endcan
{{-- EXPIRE DATE CHANGE --}}
@can('change-expire-date')
@endcan
{{-- CHANGE POP --}}
Change
POP
Select POP
— Select POP —
@foreach ($pop as $p)
id == $r->pop_id ? 'selected' : '' }}>
{{ $p->popname }}
@endforeach
{{-- CHANGE CONTACT --}}
{{-- PAYMENT LOG --}}
{{-- ══════════════════ DOCUMENT PREVIEW MODAL ══════════════════ --}}
@push('styles')
@endpush
{{-- ══════════════════ PING TEST MODAL ══════════════════ --}}
@push('styles')
@endpush
{{-- Loading state --}}
{{-- Result state (hidden until data arrives) --}}
{{-- Status banner --}}
{{-- Stats grid --}}
{{-- Individual packets table --}}
Seq #
Host
Time (ms)
Status
{{-- Error state --}}
{{-- ══════════════════ SMS MODAL (Bootstrap 4) ══════════════════ --}}
@push('styles')
@endpush
@push('styles')
@endpush
{{-- ══════════════════ EDIT MODAL ══════════════════ --}}
{{-- ══════════════════ CREATE TICKET MODAL ══════════════════ --}}
@push('styles')
@endpush
{{-- ══════════════════ PAY HISTORY MODAL ══════════════════ --}}
@push('styles')
@endpush
{{-- TOAST CONTAINER --}}
{{-- /.cx-page --}}
@endsection
@section('ajax')