feat: Refactor dashboard data to public properties, update media handling, and fix analysis period logic.
This commit is contained in:
parent
acfa2977b3
commit
a9759f92c1
@ -69,6 +69,18 @@ class Analysis extends Component
|
||||
|
||||
public array $voucherUsageTrendChart = [];
|
||||
|
||||
public array $countingData = [];
|
||||
|
||||
public array $orders = [];
|
||||
|
||||
public array $expenses = [];
|
||||
|
||||
public array $topPerfumes = [];
|
||||
|
||||
public array $topProducts = [];
|
||||
|
||||
public array $topBottles = [];
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->outlets = auth()->user()->outlets()->get()->pluck('name', 'id')->toArray();
|
||||
@ -83,7 +95,7 @@ public function render(): View
|
||||
$range = $this->range;
|
||||
|
||||
$dateQuery = match ($period) {
|
||||
'7' => now()->subDays(1),
|
||||
'7' => now()->subDays(7),
|
||||
'30' => now()->subDays(30),
|
||||
'90' => now()->subDays(90),
|
||||
'365' => now()->subDays(365),
|
||||
@ -397,8 +409,9 @@ public function render(): View
|
||||
];
|
||||
|
||||
// 2. busiest hour
|
||||
$hourFunc = DB::getDriverName() === 'sqlite' ? "CAST(strftime('%H', created_at) AS INTEGER)" : 'HOUR(created_at)';
|
||||
$hourlySales = (clone $orderQuery)
|
||||
->select(DB::raw('HOUR(created_at) as hour'), DB::raw('count(*) as count'))
|
||||
->select(DB::raw("$hourFunc as hour"), DB::raw('count(*) as count'))
|
||||
->groupBy('hour')
|
||||
->orderBy('hour')
|
||||
->get()
|
||||
@ -484,8 +497,9 @@ public function render(): View
|
||||
];
|
||||
|
||||
// 7. Day of Week Sales
|
||||
$dayOfWeekFunc = DB::getDriverName() === 'sqlite' ? "(CAST(strftime('%w', created_at) AS INTEGER) + 1)" : 'DAYOFWEEK(created_at)';
|
||||
$dayOfWeekSales = (clone $orderQuery)
|
||||
->select(DB::raw('DAYOFWEEK(created_at) as day'), DB::raw('SUM(total) as revenue'))
|
||||
->select(DB::raw("$dayOfWeekFunc as day"), DB::raw('SUM(total) as revenue'))
|
||||
->groupBy('day')
|
||||
->get()
|
||||
->keyBy('day');
|
||||
@ -564,14 +578,15 @@ public function render(): View
|
||||
'data' => $trendDates->map(fn ($d) => (int) ($vouchersTrend->get($d)?->count ?? 0))->toArray(),
|
||||
];
|
||||
|
||||
$this->countingData = $countingData;
|
||||
$this->orders = array_values(array_filter($orders));
|
||||
$this->expenses = array_values(array_filter($expenses));
|
||||
$this->topPerfumes = $topPerfumes;
|
||||
$this->topProducts = $topProducts;
|
||||
$this->topBottles = $topBottles;
|
||||
|
||||
return view('livewire.studio.dashboard.analysis', [
|
||||
'pageTitle' => 'Analisa',
|
||||
'countingData' => $countingData,
|
||||
'orders' => $orders,
|
||||
'expenses' => $expenses,
|
||||
'topPerfumes' => $topPerfumes,
|
||||
'topProducts' => $topProducts,
|
||||
'topBottles' => $topBottles,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +40,8 @@ class Overview extends Component
|
||||
|
||||
public array $todayDiscountChart = [];
|
||||
|
||||
public array $stats = [];
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->outlets = auth()->user()->outlets()->get()->pluck('name', 'id')->toArray();
|
||||
@ -171,15 +173,17 @@ public function render(): View
|
||||
// --- Chart Data Logic ---
|
||||
|
||||
// 1. Hourly Sales Comparison (Today vs Yesterday)
|
||||
$hourFunc = DB::getDriverName() === 'sqlite' ? "CAST(strftime('%H', created_at) AS INTEGER)" : 'HOUR(created_at)';
|
||||
|
||||
$todayHourly = Order::whereDate('created_at', now())
|
||||
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
|
||||
->select(DB::raw('HOUR(created_at) as hour'), DB::raw('count(*) as count'))
|
||||
->select(DB::raw("$hourFunc as hour"), DB::raw('count(*) as count'))
|
||||
->groupBy('hour')
|
||||
->get()->keyBy('hour');
|
||||
|
||||
$yesterdayHourly = Order::whereDate('created_at', now()->yesterday())
|
||||
->when(! empty($outletIds), fn ($q) => $q->whereIn('outlet_id', $outletIds))
|
||||
->select(DB::raw('HOUR(created_at) as hour'), DB::raw('count(*) as count'))
|
||||
->select(DB::raw("$hourFunc as hour"), DB::raw('count(*) as count'))
|
||||
->groupBy('hour')
|
||||
->get()->keyBy('hour');
|
||||
|
||||
@ -282,7 +286,7 @@ public function render(): View
|
||||
'data' => [$withDiscount, $noDiscount],
|
||||
];
|
||||
|
||||
$stats = array_filter([
|
||||
$this->stats = array_values(array_filter([
|
||||
[
|
||||
'title' => 'Average Order Value (AOV)',
|
||||
'value' => formatCurrencyNumber($todayAov, 'Rp'),
|
||||
@ -418,10 +422,8 @@ public function render(): View
|
||||
: '∞%',
|
||||
'trendUp' => ($todayTopPerfume?->total_sold ?? 0) > ($yesterdayTopPerfume?->total_sold ?? 0),
|
||||
],
|
||||
]);
|
||||
]));
|
||||
|
||||
return view('livewire.studio.dashboard.overview', [
|
||||
'stats' => $stats,
|
||||
]);
|
||||
return view('livewire.studio.dashboard.overview');
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,12 +16,11 @@
|
||||
use Livewire\Attributes\On;
|
||||
use Livewire\Attributes\Title;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithFileUploads;
|
||||
|
||||
#[Title('Pengeluaran')]
|
||||
class Expense extends Component
|
||||
{
|
||||
use WithAuthorization, WithCloseModal, WithConfirmation, WithFileUploads, WithSubscribeNotification, WithToast, WithUpdatedData;
|
||||
use WithAuthorization, WithCloseModal, WithConfirmation, WithSubscribeNotification, WithToast, WithUpdatedData;
|
||||
|
||||
public ExpenseForm $form;
|
||||
|
||||
|
||||
@ -39,10 +39,14 @@ protected function syncMedia(array $newMedia, $model, string $collectionName): v
|
||||
protected function uploadMedia(array $mediaArray, $model, string $collectionName): void
|
||||
{
|
||||
foreach ($mediaArray as $file) {
|
||||
if (isset($file['path'])) {
|
||||
if (is_array($file) && isset($file['path'])) {
|
||||
$model->addMedia($file['path'])
|
||||
->preservingOriginal()
|
||||
->toMediaCollection($collectionName);
|
||||
} elseif ($file instanceof \Illuminate\Http\UploadedFile) {
|
||||
$model->addMedia($file->getRealPath())
|
||||
->preservingOriginal()
|
||||
->toMediaCollection($collectionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,10 +66,10 @@
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Analysis::class)
|
||||
// All period (default)
|
||||
->assertSet('orders.1.value', 'Rp150.000')
|
||||
->assertSet('orders.5.value', 'Rp150.000')
|
||||
// Last 7 days (only shows today's order)
|
||||
->set('period', '7')
|
||||
->assertSet('orders.1.value', 'Rp50.000');
|
||||
->assertSet('orders.5.value', 'Rp50.000');
|
||||
});
|
||||
|
||||
it('filters data by custom date range', function () {
|
||||
@ -89,7 +89,7 @@
|
||||
->test(Analysis::class)
|
||||
->set('range.start', '2024-01-01')
|
||||
->set('range.end', '2024-01-31')
|
||||
->assertSet('orders.1.value', 'Rp200.000');
|
||||
->assertSet('orders.5.value', 'Rp200.000');
|
||||
});
|
||||
|
||||
it('shows top performers correctly with aggregation', function () {
|
||||
|
||||
@ -48,10 +48,10 @@
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Overview::class)
|
||||
->assertSet('stats.0.value', 2) // Total Order Today
|
||||
->assertSet('stats.0.previous', 1) // Total Order Yesterday
|
||||
->assertSet('stats.1.value', 'Rp200.000') // Pendapatan Today (2 * 100k)
|
||||
->assertSet('stats.1.previous', 'Rp80.000'); // Pendapatan Yesterday (1 * 80k)
|
||||
->assertSet('stats.2.value', 2) // Total Order Today
|
||||
->assertSet('stats.2.previous', 1) // Total Order Yesterday
|
||||
->assertSet('stats.3.value', 'Rp200.000') // Pendapatan Today (2 * 100k)
|
||||
->assertSet('stats.3.previous', 'Rp80.000'); // Pendapatan Yesterday (1 * 80k)
|
||||
});
|
||||
|
||||
it('filters stats by selected outlets', function () {
|
||||
@ -66,13 +66,13 @@
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Overview::class)
|
||||
// No filter (shows both)
|
||||
->assertSet('stats.1.value', 'Rp150.000')
|
||||
->assertSet('stats.3.value', 'Rp150.000')
|
||||
// Filter by main outlet only
|
||||
->set('selectedOutletIds', [$this->outlet->id])
|
||||
->assertSet('stats.1.value', 'Rp100.000')
|
||||
->assertSet('stats.3.value', 'Rp100.000')
|
||||
// Filter by another outlet only
|
||||
->set('selectedOutletIds', [$anotherOutlet->id])
|
||||
->assertSet('stats.1.value', 'Rp50.000');
|
||||
->assertSet('stats.3.value', 'Rp50.000');
|
||||
});
|
||||
|
||||
it('shows top perfume correctly', function () {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user