added dashboard view
This commit is contained in:
@@ -8,17 +8,23 @@ use Illuminate\View\View;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Carbon\Carbon;
|
||||
|
||||
// Explicitly import models for better readability and IDE support
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\UserActivity;
|
||||
use App\Models\StaffMember;
|
||||
use App\Models\NationalHoliday;
|
||||
use App\Models\DailyQuote;
|
||||
use App\Models\NetworkOps;
|
||||
use App\Models\LeaveRequest;
|
||||
use App\Models\GeneralDocument;
|
||||
|
||||
use App\Models\NetworkOperator;
|
||||
use App\Models\ShortCode;
|
||||
use App\Models\SenderId;
|
||||
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
public function index(): View
|
||||
public function indexOld(): View
|
||||
{
|
||||
// Grouped OR clauses inside a closure to prevent query bleeding
|
||||
$ussd_clients = Client::where(function ($query) {
|
||||
@@ -77,7 +83,113 @@ class DashboardController extends Controller
|
||||
'upcoming_hodidays' => $upcoming_hodidays
|
||||
]);
|
||||
}
|
||||
public function index()
|
||||
{
|
||||
// --- 1. TELECOM & CLIENT INSIGHTS (Top Section) ---
|
||||
$totalClients = Client::count();
|
||||
$activeClients = Client::where('status', 'Live')->count(); // Assuming you have a status column
|
||||
$activeNetworks = NetworkOperator::where('connection_status', 'ACTIVE')->count();
|
||||
$activeShortCodes = ShortCode::where('status', 'LIVE')->count();
|
||||
$totalSenderIds = SenderId::where('status', 'LIKE', 'APPROVED%')->count();
|
||||
|
||||
// Calculate a quick insight (e.g., percentage of active clients)
|
||||
$clientActiveRate = $totalClients > 0 ? round(($activeClients / $totalClients) * 100) : 0;
|
||||
|
||||
// --- 2. HR & INTERNAL METRICS (Bottom Section) ---
|
||||
$totalStaff = StaffMember::where('status', 'ACTIVE')->count();
|
||||
$pendingLeaves = LeaveRequest::where('status', 'PENDING')->count();
|
||||
$totalDocuments = GeneralDocument::count();
|
||||
$activeLeavesThisMonth = LeaveRequest::where('status', 'APPROVED')
|
||||
->whereMonth('start_date', Carbon::now()->month)
|
||||
->count();
|
||||
|
||||
$recentPendingLeaves = LeaveRequest::with('staff')->where('status', 'PENDING')->orderBy('created_at', 'desc')->take(5)->get();
|
||||
$recentDocuments = GeneralDocument::with('uploader')->orderBy('created_at', 'desc')->take(5)->get();
|
||||
|
||||
// Upcoming Birthdays
|
||||
$currentMonthDay = Carbon::now()->format('m-d');
|
||||
$futureMonthDay = Carbon::now()->addDays(30)->format('m-d');
|
||||
$upcomingBirthdays = StaffMember::where(function($query) use ($currentMonthDay, $futureMonthDay) {
|
||||
if ($currentMonthDay <= $futureMonthDay) {
|
||||
$query->whereBetween('dob', [$currentMonthDay, $futureMonthDay]);
|
||||
} else {
|
||||
$query->where('dob', '>=', $currentMonthDay)->orWhere('dob', '<=', $futureMonthDay);
|
||||
}
|
||||
})->orderBy('dob', 'asc')->take(5)->get();
|
||||
|
||||
return view('dashboard.index', compact(
|
||||
'totalClients', 'activeClients', 'activeNetworks', 'activeShortCodes', 'totalSenderIds', 'clientActiveRate',
|
||||
'totalStaff', 'pendingLeaves', 'totalDocuments', 'activeLeavesThisMonth',
|
||||
'recentPendingLeaves', 'recentDocuments', 'upcomingBirthdays'
|
||||
));
|
||||
}
|
||||
public function indexHr()
|
||||
{
|
||||
// 1. Key Metrics
|
||||
$totalStaff = StaffMember::where('status', 'ACTIVE')->count();
|
||||
$pendingLeaves = LeaveRequest::where('status', 'PENDING')->count();
|
||||
$totalDocuments = GeneralDocument::count();
|
||||
|
||||
// Approved leaves happening this month
|
||||
$activeLeavesThisMonth = LeaveRequest::where('status', 'APPROVED')
|
||||
->whereMonth('start_date', Carbon::now()->month)
|
||||
->count();
|
||||
|
||||
// 2. Pending Leave Requests for HR Action
|
||||
$recentPendingLeaves = LeaveRequest::with('staff')
|
||||
->where('status', 'PENDING')
|
||||
->orderBy('created_at', 'desc')
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
// 3. Recently Uploaded Documents
|
||||
$recentDocuments = GeneralDocument::with('uploader')
|
||||
->orderBy('created_at', 'desc')
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
// 4. Upcoming Birthdays (Using our MM-DD string format logic)
|
||||
$currentMonthDay = Carbon::now()->format('m-d');
|
||||
$futureMonthDay = Carbon::now()->addDays(30)->format('m-d');
|
||||
|
||||
if ($currentMonthDay <= $futureMonthDay) {
|
||||
$upcomingBirthdays = StaffMember::whereBetween('dob', [$currentMonthDay, $futureMonthDay])
|
||||
->orderBy('dob', 'asc')
|
||||
->take(5)
|
||||
->get();
|
||||
} else {
|
||||
$upcomingBirthdays = StaffMember::where(function($query) use ($currentMonthDay, $futureMonthDay) {
|
||||
$query->where('dob', '>=', $currentMonthDay)
|
||||
->orWhere('dob', '<=', $futureMonthDay);
|
||||
})
|
||||
->orderBy('dob', 'asc')
|
||||
->take(5)
|
||||
->get();
|
||||
}
|
||||
|
||||
$totalClients = Client::count(); // Or where('status', 'ACTIVE')
|
||||
$totalNetworks = NetworkOperator::count();
|
||||
|
||||
$recentClients = Client::orderBy('created_at', 'desc')->take(5)->get();
|
||||
$activeNetworks = NetworkOperator::where('connection_status', 'ACTIVE')->get();
|
||||
$activeShortCodes = ShortCode::where('status', 'ACTIVE')->get();
|
||||
$activeSenderIds = SenderId::where('status', 'ACTIVE')->get();
|
||||
return view('dashboard.index', compact(
|
||||
'totalStaff', 'pendingLeaves', 'totalDocuments', 'activeLeavesThisMonth',
|
||||
'recentPendingLeaves', 'recentDocuments', 'upcomingBirthdays',
|
||||
'totalClients', 'totalNetworks', 'recentClients', 'activeNetworks', 'activeShortCodes', 'activeSenderIds'
|
||||
));
|
||||
|
||||
return view('dashboard.index', compact(
|
||||
'totalStaff',
|
||||
'pendingLeaves',
|
||||
'totalDocuments',
|
||||
'activeLeavesThisMonth',
|
||||
'recentPendingLeaves',
|
||||
'recentDocuments',
|
||||
'upcomingBirthdays'
|
||||
));
|
||||
}
|
||||
public function getEvents(): JsonResponse
|
||||
{
|
||||
$event_arr = [
|
||||
|
||||
@@ -1,157 +1,209 @@
|
||||
@extends('layouts.master')
|
||||
@extends('layouts.masterbeta')
|
||||
|
||||
@section('title', 'Dashboard')
|
||||
@section('title', 'Click ERP - Dashboard')
|
||||
|
||||
@section('breadcrumbs')
|
||||
<span class="fw-bold text-dark" style="font-size: 0.95rem;"><i class="bi bi-speedometer2 me-2"></i> Main Dashboard</span>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="hero-banner p-4 mb-4">
|
||||
<h3>Dashboard</h3>
|
||||
</div>
|
||||
|
||||
<!-- <div class="row"> -->
|
||||
<!-- <div class="hero-banner p-4 mb-4 d-flex justify-content-between align-items-center">
|
||||
<div class="w-50">
|
||||
<h3 class="fw-bold mb-3">Base ERP Workstation <span class="badge bg-primary fs-6 align-middle ms-2" style="background-color: #5c4df0 !important;">ACTIVE</span></h3>
|
||||
<p class="text-secondary mb-0" style="font-size: 0.95rem; line-height: 1.6;">
|
||||
Welcome to Nexus-ERP base mockup. This screen loads aggregated statistics computed React state modifications (Customer Directory alterations, invoices creations, etc.) instantly.
|
||||
</p>
|
||||
<div class="mb-4 d-flex justify-content-between align-items-end">
|
||||
<div>
|
||||
<h4 class="fw-bold mb-1">Welcome back, {{ auth()->user()->name ?? 'Administrator' }}!</h4>
|
||||
<p class="text-secondary mb-0" style="font-size: 0.9rem;">Core business and operational activity summary</p>
|
||||
</div>
|
||||
<div class="d-flex gap-3">
|
||||
<button class="btn text-white fw-bold d-flex align-items-center px-4" style="background-color: #5c4df0; border-radius: 8px;" id="seedBtn">
|
||||
<i class="bi bi-stars me-2"></i> Seed Demo Records
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary text-white fw-bold d-flex align-items-center px-4" style="border-radius: 8px; border-color: #5a617a;">
|
||||
<i class="bi bi-plus-square me-2"></i> New Record Form
|
||||
</button>
|
||||
<div class="text-secondary small fw-bold">
|
||||
<i class="bi bi-calendar3 me-1"></i> {{ date('l, M d, Y') }}
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<!-- ========================================== -->
|
||||
<!-- SECTION 1: BUSINESS & TELECOM OPERATIONS -->
|
||||
<!-- ========================================== -->
|
||||
<h6 class="fw-bold text-secondary text-uppercase mb-3" style="font-size: 0.75rem; letter-spacing: 1px;">MNO & Client Insights</h6>
|
||||
|
||||
<div class="row g-4 mb-3">
|
||||
<!-- Client Insight -->
|
||||
<div class="col-md-3">
|
||||
<div class="content-card p-4 border-0 shadow-sm text-center h-100" style="background: linear-gradient(145deg, #ffffff, #f8f9fa);">
|
||||
<i class="bi bi-briefcase fs-1 text-primary mb-2 d-inline-block"></i>
|
||||
<h2 class="fw-bold text-dark mb-0">{{ $activeClients }}</h2>
|
||||
<div class="text-secondary fw-bold small mb-2" style="letter-spacing: 0.5px;">ACTIVE CLIENTS</div>
|
||||
<div class="badge bg-primary bg-opacity-10 text-primary border border-primary-subtle rounded-pill px-3">
|
||||
{{ $clientActiveRate }}% of Total Base
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Network Insight -->
|
||||
<div class="col-md-3">
|
||||
<div class="content-card p-4 border-0 shadow-sm text-center h-100" style="background: linear-gradient(145deg, #ffffff, #f8f9fa);">
|
||||
<i class="bi bi-hdd-network fs-1 text-success mb-2 d-inline-block"></i>
|
||||
<h2 class="fw-bold text-dark mb-0">{{ $activeNetworks }}</h2>
|
||||
<div class="text-secondary fw-bold small mb-2" style="letter-spacing: 0.5px;">MOBILE NETWORKS</div>
|
||||
<div class="text-success small fw-medium">Operational Status: Healthy</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- USSD Insight -->
|
||||
<div class="col-md-3">
|
||||
<div class="content-card p-4 border-0 shadow-sm text-center h-100" style="background: linear-gradient(145deg, #ffffff, #f8f9fa);">
|
||||
<i class="bi bi-hash fs-1 text-info mb-2 d-inline-block"></i>
|
||||
<h2 class="fw-bold text-dark mb-0">{{ $activeShortCodes }}</h2>
|
||||
<div class="text-secondary fw-bold small mb-2" style="letter-spacing: 0.5px;">PROVISIONED SHORT CODES</div>
|
||||
<div class="text-info small fw-medium">USSD | SMS | Voice</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sender ID Insight -->
|
||||
<div class="col-md-3">
|
||||
<div class="content-card p-4 border-0 shadow-sm text-center h-100" style="background: linear-gradient(145deg, #ffffff, #f8f9fa);">
|
||||
<i class="bi bi-broadcast-pin fs-1 text-danger mb-2 d-inline-block"></i>
|
||||
<h2 class="fw-bold text-dark mb-0">{{ $totalSenderIds }}</h2>
|
||||
<div class="text-secondary fw-bold small mb-2" style="letter-spacing: 0.5px;">APPROVED SENDER IDs</div>
|
||||
<div class="text-danger small fw-medium">Live traffic</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Written Summary -->
|
||||
<div class="alert alert-secondary border-0 shadow-sm d-flex align-items-center mb-5 bg-white text-dark py-3">
|
||||
<i class="bi bi-lightbulb-fill text-warning fs-4 me-3"></i>
|
||||
<div>
|
||||
<strong>Brief Summary:</strong> We are currently servicing <strong>{{ $activeClients }} active clients</strong> sending traffic through <strong>{{ $activeShortCodes }} USSD short codes</strong> and <strong>{{ $totalSenderIds }} SMS sender IDs</strong> across <strong>{{ $activeNetworks }} network operators</strong>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ========================================== -->
|
||||
<!-- SECTION 2: HR & INTERNAL OPERATIONS -->
|
||||
<!-- ========================================== -->
|
||||
<h6 class="fw-bold text-secondary text-uppercase mb-3" style="font-size: 0.75rem; letter-spacing: 1px;">Internal Administration</h6>
|
||||
|
||||
<div class="row g-4 mb-4">
|
||||
<div class="col-xl-3 col-md-6">
|
||||
<div class="card stat-card h-100 p-3 border-0">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="text-secondary fw-bold" style="font-size: 0.75rem; letter-spacing: 0.5px;">SMS Clients</div>
|
||||
<div class="stat-icon bg-success bg-opacity-10 text-success"><i class="bi bi-chat-dots"></i></div>
|
||||
</div>
|
||||
<h2 class="fw-bold mt-2 mb-3">150</h2>
|
||||
<div class="d-flex align-items-center mt-auto" style="font-size: 0.8rem;">
|
||||
<span class="text-success fw-bold"><i class="bi bi-arrow-up-right me-1"></i>+1.4%</span>
|
||||
<span class="text-secondary ms-2">quarter over quarter</span>
|
||||
<div class="col-md-3">
|
||||
<div class="content-card p-3 border-start border-4 border-0 shadow-sm" style="border-left-color: #5c4df0 !important;">
|
||||
<div class="text-secondary fw-bold mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">ACTIVE STAFF</div>
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<h3 class="fw-bold mb-0 text-dark">{{ $totalStaff }}</h3>
|
||||
<i class="bi bi-people fs-3 text-primary opacity-50"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6">
|
||||
<div class="card stat-card h-100 p-3 border-0">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="text-secondary fw-bold" style="font-size: 0.75rem; letter-spacing: 0.5px;">USSD Clients</div>
|
||||
<div class="stat-icon bg-primary bg-opacity-10 text-primary" style="color: #5c4df0 !important;"><i class="bi bi-phone"></i></div>
|
||||
</div>
|
||||
<h2 class="fw-bold mt-2 mb-3">50</h2>
|
||||
<div class="d-flex align-items-center justify-content-between mt-auto" style="font-size: 0.8rem;">
|
||||
<span class="text-primary fw-bold" style="color: #5c4df0 !important;">4 new clients</span>
|
||||
<span class="text-secondary">recent engagement result</span>
|
||||
<div class="col-md-3">
|
||||
<div class="content-card p-3 border-start border-4 border-0 shadow-sm" style="border-left-color: #f59e0b !important;">
|
||||
<div class="text-secondary fw-bold mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">PENDING LEAVES</div>
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<h3 class="fw-bold mb-0 text-dark">{{ $pendingLeaves }}</h3>
|
||||
<i class="bi bi-calendar-minus fs-3 text-warning opacity-50"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6">
|
||||
<div class="card stat-card h-100 p-3 border-0">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="text-secondary fw-bold" style="font-size: 0.75rem; letter-spacing: 0.5px;">Voice Clients</div>
|
||||
<div class="stat-icon bg-warning bg-opacity-10 text-warning"><i class="bi bi-megaphone"></i></div>
|
||||
</div>
|
||||
<h2 class="fw-bold mt-2 mb-3">10</h2>
|
||||
<div class="d-flex align-items-center mt-auto" style="font-size: 0.8rem;">
|
||||
<span class="text-warning fw-bold">Darwin System</span>
|
||||
<span class="text-secondary ms-3 lh-sm" style="font-size: 0.7rem;">Newly Acquired <br>client</span>
|
||||
<div class="col-md-3">
|
||||
<div class="content-card p-3 border-start border-4 border-0 shadow-sm" style="border-left-color: #10b981 !important;">
|
||||
<div class="text-secondary fw-bold mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">LEAVES THIS MONTH</div>
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<h3 class="fw-bold mb-0 text-dark">{{ $activeLeavesThisMonth }}</h3>
|
||||
<i class="bi bi-calendar-check fs-3 text-success opacity-50"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6">
|
||||
<div class="card stat-card h-100 p-3 border-0">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="text-secondary fw-bold" style="font-size: 0.75rem; letter-spacing: 0.5px;">Airtime Clients</div>
|
||||
<div class="stat-icon bg-danger bg-opacity-10 text-danger"><i class="bi bi-telephone-plus"></i></div>
|
||||
</div>
|
||||
<h2 class="fw-bold mt-2 mb-3">15</h2>
|
||||
<div class="d-flex align-items-center mt-auto" style="font-size: 0.8rem;">
|
||||
<span class="text-success fw-bold"><i class="bi bi-circle-fill me-1" style="font-size: 0.5rem;"></i>Healthy</span>
|
||||
<span class="text-secondary ms-3">Average bill secons: 3.5 mins</span>
|
||||
<div class="col-md-3">
|
||||
<div class="content-card p-3 border-start border-4 border-0 shadow-sm" style="border-left-color: #0ea5e9 !important;">
|
||||
<div class="text-secondary fw-bold mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">ARCHIVED DOCS</div>
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<h3 class="fw-bold mb-0 text-dark">{{ $totalDocuments }}</h3>
|
||||
<i class="bi bi-folder2-open fs-3 text-info opacity-50"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4">
|
||||
<!-- HR Lists Layout -->
|
||||
<div class="row g-4 mb-5">
|
||||
<!-- Left Column: Pending Leaves & Documents -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card stat-card border-0 p-4 h-100">
|
||||
<div class="d-flex justify-content-between align-items-start mb-4">
|
||||
<div>
|
||||
<h6 class="fw-bold mb-1">Revenue Projections Trend</h6>
|
||||
<p class="text-secondary mb-0" style="font-size: 0.85rem;">Demonstrating visual charts using pure responsive vector layouts</p>
|
||||
</div>
|
||||
<div class="d-flex gap-3" style="font-size: 0.85rem;">
|
||||
<span class="d-flex align-items-center"><i class="bi bi-circle-fill text-primary me-2" style="font-size: 0.5rem;"></i> Sales Target</span>
|
||||
<span class="d-flex align-items-center text-secondary"><i class="bi bi-circle-fill me-2" style="font-size: 0.5rem; color: #d1d5db;"></i> Prior Year</span>
|
||||
</div>
|
||||
<div class="content-card shadow-sm mb-4">
|
||||
<div class="p-3 border-bottom d-flex justify-content-between align-items-center bg-light bg-opacity-50">
|
||||
<h6 class="fw-bold mb-0"><i class="bi bi-clock-history me-2 text-warning"></i> Pending Leave Approvals</h6>
|
||||
<a href="{{ route('leave.index') }}" class="small text-decoration-none fw-bold" style="color: #5c4df0;">View All</a>
|
||||
</div>
|
||||
<div class="w-100 mt-auto position-relative" style="height: 200px;">
|
||||
<svg viewBox="0 0 800 200" class="w-100 h-100" preserveAspectRatio="none">
|
||||
<path d="M0,180 Q200,220 400,100 T800,20" fill="none" stroke="#e0e0e0" stroke-width="2" stroke-dasharray="5,5"/>
|
||||
<path d="M0,200 Q200,220 400,160 T800,0" fill="none" stroke="#5c4df0" stroke-width="4"/>
|
||||
<circle cx="400" cy="160" r="6" fill="#5c4df0" stroke="white" stroke-width="2"/>
|
||||
<circle cx="600" cy="50" r="6" fill="#5c4df0" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-custom mb-0 align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Staff Member</th>
|
||||
<th>Type</th>
|
||||
<th>Duration</th>
|
||||
<th class="text-end">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($recentPendingLeaves as $leave)
|
||||
<tr>
|
||||
<td><div class="fw-bold text-dark">{{ $leave->staff->name ?? 'Unknown' }}</div></td>
|
||||
<td><span class="badge bg-secondary bg-opacity-10 text-dark border">{{ $leave->leave_type }}</span></td>
|
||||
<td class="small text-secondary">{{ $leave->start_date->format('M d') }} - {{ $leave->end_date->format('M d') }}</td>
|
||||
<td class="text-end"><a href="{{ route('leave.index') }}" class="btn btn-sm btn-light text-primary border">Review</a></td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="4" class="text-center py-4 text-secondary">No pending leave requests.</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-card shadow-sm">
|
||||
<div class="p-3 border-bottom d-flex justify-content-between align-items-center bg-light bg-opacity-50">
|
||||
<h6 class="fw-bold mb-0"><i class="bi bi-file-earmark-arrow-up me-2 text-primary"></i> Recently Uploaded Documents</h6>
|
||||
<a href="{{ route('documents.index') }}" class="small text-decoration-none fw-bold" style="color: #5c4df0;">View Archive</a>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-custom mb-0 align-middle">
|
||||
<tbody>
|
||||
@forelse($recentDocuments as $doc)
|
||||
<tr>
|
||||
<td class="fw-bold text-dark w-50"><i class="bi bi-file-earmark-text text-primary me-2"></i>{{ $doc->name }}</td>
|
||||
<td><span class="badge bg-secondary bg-opacity-10 text-dark border">{{ $doc->category ?? 'General' }}</span></td>
|
||||
<td class="text-secondary small text-end">{{ $doc->created_at ? $doc->created_at->format('M d, Y') : 'N/A' }}</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="3" class="text-center py-4 text-secondary">No documents archived yet.</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Right Column: Upcoming Birthdays -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card stat-card border-0 p-4 h-100">
|
||||
<h6 class="fw-bold mb-1">Department Distribution</h6>
|
||||
<p class="text-secondary mb-4" style="font-size: 0.85rem;">Ratio of active records grouped by segment</p>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between align-items-center mb-1" style="font-size: 0.85rem;">
|
||||
<span class="fw-bold"><i class="bi bi-circle-fill me-2" style="font-size: 0.5rem; color: #5c4df0;"></i> Finance</span>
|
||||
<span class="text-secondary">1 (25%)</span>
|
||||
</div>
|
||||
<div class="progress progress-slim">
|
||||
<div class="progress-bar" role="progressbar" style="width: 25%; background-color: #5c4df0;" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<div class="content-card shadow-sm h-100">
|
||||
<div class="p-3 border-bottom bg-light bg-opacity-50">
|
||||
<h6 class="fw-bold mb-0"><i class="bi bi-cake2 me-2 text-danger"></i> Upcoming Birthdays</h6>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between align-items-center mb-1" style="font-size: 0.85rem;">
|
||||
<span class="fw-bold"><i class="bi bi-circle-fill me-2" style="font-size: 0.5rem; color: #10b981;"></i> Operations</span>
|
||||
<span class="text-secondary">1 (25%)</span>
|
||||
</div>
|
||||
<div class="progress progress-slim">
|
||||
<div class="progress-bar" role="progressbar" style="width: 25%; background-color: #10b981;" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between align-items-center mb-1" style="font-size: 0.85rem;">
|
||||
<span class="fw-bold"><i class="bi bi-circle-fill me-2" style="font-size: 0.5rem; color: #f59e0b;"></i> Sales</span>
|
||||
<span class="text-secondary">1 (25%)</span>
|
||||
</div>
|
||||
<div class="progress progress-slim">
|
||||
<div class="progress-bar" role="progressbar" style="width: 25%; background-color: #f59e0b;" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between align-items-center mb-1" style="font-size: 0.85rem;">
|
||||
<span class="fw-bold"><i class="bi bi-circle-fill me-2" style="font-size: 0.5rem; color: #ef4444;"></i> Marketing</span>
|
||||
<span class="text-secondary">0 (0%)</span>
|
||||
</div>
|
||||
<div class="progress progress-slim">
|
||||
<div class="progress-bar" role="progressbar" style="width: 0%; background-color: #ef4444;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<div class="p-3">
|
||||
@forelse($upcomingBirthdays as $staff)
|
||||
<div class="d-flex align-items-center mb-3 pb-3 border-bottom last-border-0">
|
||||
<div class="flex-grow-1">
|
||||
<h6 class="fw-bold mb-0 text-dark">{{ $staff->name }}</h6>
|
||||
<p class="text-secondary mb-0 small">{{ $staff->designation ?? 'Staff' }}</p>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<span class="badge bg-danger bg-opacity-10 text-danger border border-danger-subtle px-2 py-1 small">
|
||||
{{ $staff->dob ? date('M d', strtotime('2024-' . $staff->dob)) : '' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="text-center py-5 text-secondary small">
|
||||
<i class="bi bi-calendar-x fs-1 d-block mb-2 text-black-50 opacity-50"></i>
|
||||
No upcoming birthdays.
|
||||
</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@endsection
|
||||
206
resources/views/dashboard/index_hr.blade.php
Normal file
206
resources/views/dashboard/index_hr.blade.php
Normal file
@@ -0,0 +1,206 @@
|
||||
@extends('layouts.masterbeta')
|
||||
|
||||
@section('title', 'Click ERP - Dashboard')
|
||||
|
||||
@section('breadcrumbs')
|
||||
<span class="fw-bold text-dark" style="font-size: 0.95rem;"><i class="bi bi-speedometer2 me-2"></i> Dashboard Overview</span>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="mb-4">
|
||||
<h4 class="fw-bold mb-1">Welcome back, {{ auth()->user()->name ?? 'Administrator' }}!</h4>
|
||||
<p class="text-secondary mb-0" style="font-size: 0.9rem;">Here is a summary of operational activity across your organization.</p>
|
||||
</div>
|
||||
|
||||
<!-- ========================================== -->
|
||||
<!-- SECTION 1: HR & INTERNAL OPERATIONS -->
|
||||
<!-- ========================================== -->
|
||||
<h6 class="fw-bold text-secondary text-uppercase mb-3" style="font-size: 0.75rem; letter-spacing: 1px;">Internal Administration</h6>
|
||||
|
||||
<div class="row g-4 mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="content-card p-3 border-start border-4 border-0 shadow-sm" style="border-left-color: #5c4df0 !important;">
|
||||
<div class="text-secondary fw-bold mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">ACTIVE STAFF</div>
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<h3 class="fw-bold mb-0 text-dark">{{ $totalStaff }}</h3>
|
||||
<i class="bi bi-people fs-3 text-primary opacity-50"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="content-card p-3 border-start border-4 border-0 shadow-sm" style="border-left-color: #f59e0b !important;">
|
||||
<div class="text-secondary fw-bold mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">PENDING LEAVES</div>
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<h3 class="fw-bold mb-0 text-dark">{{ $pendingLeaves }}</h3>
|
||||
<i class="bi bi-calendar-minus fs-3 text-warning opacity-50"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="content-card p-3 border-start border-4 border-0 shadow-sm" style="border-left-color: #10b981 !important;">
|
||||
<div class="text-secondary fw-bold mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">LEAVES THIS MONTH</div>
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<h3 class="fw-bold mb-0 text-dark">{{ $activeLeavesThisMonth }}</h3>
|
||||
<i class="bi bi-calendar-check fs-3 text-success opacity-50"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="content-card p-3 border-start border-4 border-0 shadow-sm" style="border-left-color: #0ea5e9 !important;">
|
||||
<div class="text-secondary fw-bold mb-1" style="font-size: 0.7rem; letter-spacing: 0.5px;">ARCHIVED DOCS</div>
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<h3 class="fw-bold mb-0 text-dark">{{ $totalDocuments }}</h3>
|
||||
<i class="bi bi-folder2-open fs-3 text-info opacity-50"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4 mb-5">
|
||||
<div class="col-lg-8">
|
||||
<div class="content-card shadow-sm h-100">
|
||||
<div class="p-3 border-bottom d-flex justify-content-between align-items-center bg-light bg-opacity-50">
|
||||
<h6 class="fw-bold mb-0"><i class="bi bi-clock-history me-2 text-warning"></i> Pending Leave Approvals</h6>
|
||||
<a href="{{ route('leave.index') }}" class="small text-decoration-none fw-bold" style="color: #5c4df0;">View All</a>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-custom mb-0 align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Staff Member</th>
|
||||
<th>Type</th>
|
||||
<th>Duration</th>
|
||||
<th class="text-end">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($recentPendingLeaves as $leave)
|
||||
<tr>
|
||||
<td>
|
||||
<div class="fw-bold text-dark">{{ $leave->staff->name ?? 'Unknown' }}</div>
|
||||
</td>
|
||||
<td><span class="badge bg-secondary bg-opacity-10 text-dark border">{{ $leave->leave_type }}</span></td>
|
||||
<td class="small text-secondary">{{ $leave->start_date->format('M d') }} - {{ $leave->end_date->format('M d') }}</td>
|
||||
<td class="text-end">
|
||||
<a href="{{ route('leave.index') }}" class="btn btn-sm btn-light text-primary border">Review</a>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="4" class="text-center py-4 text-secondary">No pending leave requests.</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="content-card shadow-sm h-100">
|
||||
<div class="p-3 border-bottom bg-light bg-opacity-50">
|
||||
<h6 class="fw-bold mb-0"><i class="bi bi-cake2 me-2 text-danger"></i> Upcoming Birthdays</h6>
|
||||
</div>
|
||||
<div class="p-3">
|
||||
@forelse($upcomingBirthdays as $staff)
|
||||
<div class="d-flex align-items-center mb-3 pb-3 border-bottom last-border-0">
|
||||
<div class="flex-grow-1">
|
||||
<h6 class="fw-bold mb-0 text-dark">{{ $staff->name }}</h6>
|
||||
<p class="text-secondary mb-0 small">{{ $staff->designation ?? 'Staff' }}</p>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<span class="badge bg-danger bg-opacity-10 text-danger border border-danger-subtle px-2 py-1 small">
|
||||
{{ $staff->dob ? date('M d', strtotime('2024-' . $staff->dob)) : '' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@empty
|
||||
<div class="text-center py-4 text-secondary small">No upcoming birthdays.</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ========================================== -->
|
||||
<!-- SECTION 2: BUSINESS & TELECOM OPERATIONS -->
|
||||
<!-- ========================================== -->
|
||||
<h6 class="fw-bold text-secondary text-uppercase mb-3" style="font-size: 0.75rem; letter-spacing: 1px;">Telecom & Client Operations</h6>
|
||||
|
||||
<div class="row g-4">
|
||||
<!-- Clients & Networks Widget -->
|
||||
<div class="col-lg-6">
|
||||
<div class="content-card shadow-sm h-100">
|
||||
<div class="p-3 border-bottom bg-light bg-opacity-50 d-flex justify-content-between align-items-center">
|
||||
<h6 class="fw-bold mb-0"><i class="bi bi-briefcase me-2 text-primary"></i> Active Clients & Networks</h6>
|
||||
<span class="badge bg-primary rounded-pill">{{ $totalClients }} Clients</span>
|
||||
</div>
|
||||
<div class="p-3">
|
||||
<div class="mb-4">
|
||||
<h6 class="text-secondary small fw-bold mb-2">INTEGRATED NETWORKS</h6>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
@forelse($activeNetworks as $network)
|
||||
<span class="badge bg-light text-dark border px-3 py-2"><i class="bi bi-hdd-network me-1 text-success"></i> {{ $network->name }}</span>
|
||||
@empty
|
||||
<span class="text-secondary small">No networks configured.</span>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h6 class="text-secondary small fw-bold mb-2">RECENT CLIENTS</h6>
|
||||
<ul class="list-group list-group-flush border-top">
|
||||
@forelse($recentClients as $client)
|
||||
<li class="list-group-item px-0 d-flex justify-content-between align-items-center">
|
||||
<span class="fw-medium text-dark">{{ $client->name }}</span>
|
||||
<span class="badge bg-success bg-opacity-10 text-success">{{ $client->status ?? 'Active' }}</span>
|
||||
</li>
|
||||
@empty
|
||||
<li class="list-group-item px-0 text-secondary small">No clients found.</li>
|
||||
@endforelse
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Short Codes & Sender IDs Widget -->
|
||||
<div class="col-lg-6">
|
||||
<div class="content-card shadow-sm h-100">
|
||||
<div class="p-3 border-bottom bg-light bg-opacity-50">
|
||||
<h6 class="fw-bold mb-0"><i class="bi bi-broadcast-pin me-2 text-info"></i> Provisioning Overview</h6>
|
||||
</div>
|
||||
<div class="p-3">
|
||||
<!-- Short Codes -->
|
||||
<div class="mb-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<h6 class="text-secondary small fw-bold mb-0">ACTIVE SHORT CODES</h6>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
@forelse($activeShortCodes as $code)
|
||||
<span class="badge border border-info text-info bg-info bg-opacity-10 fs-6 px-3 py-2" style="letter-spacing: 1px;">
|
||||
*{{ $code->shortcode }}#
|
||||
</span>
|
||||
@empty
|
||||
<span class="text-secondary small">No active short codes.</span>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sender IDs -->
|
||||
<div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<h6 class="text-secondary small fw-bold mb-0">REGISTERED SENDER IDs</h6>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
@forelse($activeSenderIds as $sender)
|
||||
<span class="badge bg-secondary bg-opacity-10 text-dark border px-3 py-2 fs-6">
|
||||
{{ $sender->senderid }}
|
||||
</span>
|
||||
@empty
|
||||
<span class="text-secondary small">No sender IDs configured.</span>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -13,7 +13,8 @@ Auth::routes();
|
||||
|
||||
Route::middleware(['auth'])->group(function () {
|
||||
|
||||
Route::get('/', [App\Http\Controllers\DashboardController::class, 'index'])->name('home');
|
||||
|
||||
Route::get('/', [App\Http\Controllers\DashboardController::class, 'index'])->name('dashboard');
|
||||
Route::get('home', [App\Http\Controllers\DashboardController::class, 'index'])->name('home');
|
||||
#Clients
|
||||
Route::get('/clients/data', [App\Http\Controllers\ClientsController::class, 'fetchData'])->name('clients.data');
|
||||
|
||||
Reference in New Issue
Block a user