Files
Kol-Manager/app/Services/DashboardService.php
I-Fun 22f03ccca7 Add contract management and invoice settings pages
- Created a new Blade view for managing brand contracts with forms for adding and editing contracts, including client and category selection.
- Implemented success message notifications for contract actions.
- Added a new Blade view for invoice settings, allowing customization of invoice number format, header branding, and default values for new invoices.
- Introduced a new PDF view for generating rate cards with customizable styles based on user profile settings.
- Developed a profile management page for rate cards, enabling users to update their identity, appearance, and visibility settings.
2026-04-01 21:47:34 +07:00

146 lines
5.4 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace App\Services;
use App\Models\BrandContract;
use App\Models\Client;
use App\Models\ClientCategory;
use App\Models\ContentBrief;
use App\Models\Event;
use App\Models\Invoice;
use App\Models\MediaFile;
use App\Models\SocialStat;
use Illuminate\Support\Collection;
final class DashboardService
{
public function getStats(): array
{
return [
'total_clients' => Client::count(),
'active_clients' => Client::where('status', 'active')->count(),
'upcoming_events' => Event::upcoming(24 * 90)->count(), // 3 months
'pending_invoices' => Invoice::where('status', 'sent')->count(),
'total_revenue' => Invoice::where('status', 'paid')->sum('total'),
'content_in_progress' => ContentBrief::whereNotIn('status', ['posted', 'archived'])->count(),
'total_categories' => ClientCategory::whereNull('parent_id')->count(),
'total_subcategories' => ClientCategory::whereNotNull('parent_id')->count(),
'total_files' => MediaFile::count(),
'active_contracts' => BrandContract::where('is_active', true)->where('end_date', '>=', today())->count(),
'total_contracts' => BrandContract::count(),
];
}
/**
* Combined today's activities: events (today or ongoing), invoices due, content targets.
*/
public function getTodayActivities(): Collection
{
$activities = collect();
// Events starting today OR currently ongoing (started before today, ends today or later)
$events = Event::with('client')
->where(function ($q) {
$q->whereDate('start_time', today())
->orWhere(function ($q2) {
$q2->whereDate('start_time', '<', today())
->where(function ($q3) {
$q3->whereDate('end_time', '>=', today())
->orWhereNull('end_time');
})
->whereNotIn('status', ['completed', 'cancelled']);
});
})
->orderBy('start_time')
->limit(15)
->get();
foreach ($events as $e) {
$timeLabel = $e->is_all_day
? 'All day'
: ($e->start_time->format('H:i') . ($e->end_time ? ' – ' . $e->end_time->format('H:i') : ''));
$activities->push([
'type' => 'event',
'icon' => '📅',
'title' => $e->title,
'subtitle' => $timeLabel . ($e->client ? ' · ' . $e->client->name : ''),
'label' => $e->event_type,
'badge' => $e->status->label(),
'badge_class' => $e->status->badgeClass(),
'color' => $e->color ?? '#FFB7C5',
'priority' => $e->is_priority,
'sort_key' => $e->start_time->timestamp,
]);
}
// Invoices due today (not yet paid or cancelled)
$invoices = Invoice::with('client')
->whereDate('due_date', today())
->whereNotIn('status', ['paid', 'cancelled'])
->get();
foreach ($invoices as $inv) {
$activities->push([
'type' => 'invoice',
'icon' => '🧾',
'title' => $inv->title ?? $inv->invoice_number,
'subtitle' => ($inv->client?->name ?? 'No client') . ' · ' . ($inv->formatted_total ?? ''),
'label' => 'Invoice Due',
'badge' => $inv->status->label(),
'badge_class' => $inv->status->badgeClass(),
'color' => '#FDFD96',
'priority' => false,
'sort_key' => today()->setTime(23, 59, 0)->timestamp,
]);
}
// Content briefs with target date today (not posted/archived)
$content = ContentBrief::with('client')
->whereDate('target_date', today())
->whereNotIn('status', ['posted', 'archived'])
->get();
foreach ($content as $c) {
$activities->push([
'type' => 'content',
'icon' => $c->platform_icon,
'title' => $c->title,
'subtitle' => ucfirst($c->platform) . ($c->client ? ' · ' . $c->client->name : ''),
'label' => 'Content Target',
'badge' => $c->status->label(),
'badge_class' => 'badge-ghost',
'color' => '#E8D5F5',
'priority' => false,
'sort_key' => today()->setTime(12, 0, 0)->timestamp,
]);
}
return $activities->sortBy('sort_key')->values();
}
public function getAlertCount(): int
{
return Event::upcoming(24)->count();
}
public function getLatestInvoices(): Collection
{
return Invoice::with('client')
->latest()
->limit(5)
->get();
}
public function getSocialStats(): Collection
{
return SocialStat::whereIn('id', function ($query): void {
$query->selectRaw('MAX(id)')
->from('social_stats')
->groupBy('platform');
})->get();
}
}