feat: Add tooltips and hover effects to dashboard cards and stats for improved user experience, and include a description for the outlet statistic.
This commit is contained in:
parent
6477684540
commit
3b289588f2
@ -83,11 +83,15 @@ class Analysis extends Component
|
|||||||
|
|
||||||
public function mount(): void
|
public function mount(): void
|
||||||
{
|
{
|
||||||
$this->outlets = auth()->user()->outlets()->get()->pluck('name', 'id')->toArray();
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
$this->outlets = $user->outlets()->get()->pluck('name', 'id')->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
{
|
{
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
$outletIds = $this->selectedOutletIds;
|
$outletIds = $this->selectedOutletIds;
|
||||||
$period = $this->period;
|
$period = $this->period;
|
||||||
$range = $this->range;
|
$range = $this->range;
|
||||||
@ -119,6 +123,7 @@ public function render(): View
|
|||||||
[
|
[
|
||||||
'title' => 'Outlet',
|
'title' => 'Outlet',
|
||||||
'value' => Outlet::when($dateQuery || ($startDate && $endDate), $filterDate)->count(),
|
'value' => Outlet::when($dateQuery || ($startDate && $endDate), $filterDate)->count(),
|
||||||
|
'description' => 'Total jumlah outlet atau cabang toko yang terdaftar.',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Pegawai',
|
'title' => 'Pegawai',
|
||||||
@ -127,10 +132,12 @@ public function render(): View
|
|||||||
->when($dateQuery || ($startDate && $endDate), $filterDate)
|
->when($dateQuery || ($startDate && $endDate), $filterDate)
|
||||||
->withoutDeveloper()
|
->withoutDeveloper()
|
||||||
->count(),
|
->count(),
|
||||||
|
'description' => 'Jumlah karyawan aktif yang terdaftar di outlet terpilih.',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Tier',
|
'title' => 'Tier',
|
||||||
'value' => Tier::when($dateQuery || ($startDate && $endDate), $filterDate)->count(),
|
'value' => Tier::when($dateQuery || ($startDate && $endDate), $filterDate)->count(),
|
||||||
|
'description' => 'Jumlah tingkatan loyalitas member (seperti Bronze, Silver, Gold).',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Voucher Aktif',
|
'title' => 'Voucher Aktif',
|
||||||
@ -138,6 +145,7 @@ public function render(): View
|
|||||||
->when($dateQuery || ($startDate && $endDate), $filterDate)
|
->when($dateQuery || ($startDate && $endDate), $filterDate)
|
||||||
->active()
|
->active()
|
||||||
->count(),
|
->count(),
|
||||||
|
'description' => 'Jumlah kode promo atau voucher yang masih berlaku saat ini.',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Member',
|
'title' => 'Member',
|
||||||
@ -145,38 +153,45 @@ public function render(): View
|
|||||||
->when(! empty($outletIds), fn($q) => $q->whereHas('outlets', fn($q2) => $q2->whereIn('outlets.id', $outletIds)))
|
->when(! empty($outletIds), fn($q) => $q->whereHas('outlets', fn($q2) => $q2->whereIn('outlets.id', $outletIds)))
|
||||||
->when($dateQuery || ($startDate && $endDate), $filterDate)
|
->when($dateQuery || ($startDate && $endDate), $filterDate)
|
||||||
->count(),
|
->count(),
|
||||||
|
'description' => 'Total pelanggan yang sudah mendaftar sebagai member resmi.',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Customer',
|
'title' => 'Customer',
|
||||||
'value' => Customer::whereDoesntHave('user')
|
'value' => Customer::whereDoesntHave('user')
|
||||||
->when($dateQuery || ($startDate && $endDate), $filterDate)
|
->when($dateQuery || ($startDate && $endDate), $filterDate)
|
||||||
->count(),
|
->count(),
|
||||||
|
'description' => 'Jumlah pelanggan umum (guest) yang pernah melakukan transaksi.',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Kategori',
|
'title' => 'Kategori',
|
||||||
'value' => Category::when($dateQuery || ($startDate && $endDate), $filterDate)->count(),
|
'value' => Category::when($dateQuery || ($startDate && $endDate), $filterDate)->count(),
|
||||||
|
'description' => 'Jumlah kategori barang (seperti Parfum, Sabun, dll).',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Merek',
|
'title' => 'Merek',
|
||||||
'value' => Brand::when($dateQuery || ($startDate && $endDate), $filterDate)->count(),
|
'value' => Brand::when($dateQuery || ($startDate && $endDate), $filterDate)->count(),
|
||||||
|
'description' => 'Jumlah merek parfum yang terdaftar di sistem.',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Parfum',
|
'title' => 'Parfum',
|
||||||
'value' => Perfume::when(! empty($outletIds), fn($q) => $q->whereHas('outlets', fn($q2) => $q2->whereIn('outlets.id', $outletIds)))
|
'value' => Perfume::when(! empty($outletIds), fn($q) => $q->whereHas('outlets', fn($q2) => $q2->whereIn('outlets.id', $outletIds)))
|
||||||
->when($dateQuery || ($startDate && $endDate), $filterDate)
|
->when($dateQuery || ($startDate && $endDate), $filterDate)
|
||||||
->count(),
|
->count(),
|
||||||
|
'description' => 'Jumlah varian bibit parfum yang tersedia dalam katalog.',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Produk',
|
'title' => 'Produk',
|
||||||
'value' => Product::when(! empty($outletIds), fn($q) => $q->whereHas('outlets', fn($q2) => $q2->whereIn('outlets.id', $outletIds)))
|
'value' => Product::when(! empty($outletIds), fn($q) => $q->whereHas('outlets', fn($q2) => $q2->whereIn('outlets.id', $outletIds)))
|
||||||
->when($dateQuery || ($startDate && $endDate), $filterDate)
|
->when($dateQuery || ($startDate && $endDate), $filterDate)
|
||||||
->count(),
|
->count(),
|
||||||
|
'description' => 'Jumlah item produk jadi (seperti aksesoris) yang terdaftar.',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Botol',
|
'title' => 'Botol',
|
||||||
'value' => Bottle::when(! empty($outletIds), fn($q) => $q->whereHas('outlets', fn($q2) => $q2->whereIn('outlets.id', $outletIds)))
|
'value' => Bottle::when(! empty($outletIds), fn($q) => $q->whereHas('outlets', fn($q2) => $q2->whereIn('outlets.id', $outletIds)))
|
||||||
->when($dateQuery || ($startDate && $endDate), $filterDate)
|
->when($dateQuery || ($startDate && $endDate), $filterDate)
|
||||||
->count(),
|
->count(),
|
||||||
|
'description' => 'Jumlah jenis botol parfum yang tersedia.',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -218,52 +233,63 @@ public function render(): View
|
|||||||
[
|
[
|
||||||
'title' => 'Average Order Value (AOV)',
|
'title' => 'Average Order Value (AOV)',
|
||||||
'value' => formatCurrencyNumber($aov, 'Rp'),
|
'value' => formatCurrencyNumber($aov, 'Rp'),
|
||||||
|
'description' => 'Rata-rata nilai belanja pelanggan dalam satu kali checkout.',
|
||||||
],
|
],
|
||||||
auth()->user()->hasRole(['Developer', 'Owner']) ? [
|
$user->hasRole(['Developer', 'Owner']) ? [
|
||||||
'title' => 'Profit Margin',
|
'title' => 'Profit Margin',
|
||||||
'value' => round($profitMargin, 1) . '%',
|
'value' => round($profitMargin, 1) . '%',
|
||||||
|
'description' => 'Persentase keuntungan bersih dibandingkan dengan total pendapatan.',
|
||||||
] : null,
|
] : null,
|
||||||
[
|
[
|
||||||
'title' => 'Loyalty Rate',
|
'title' => 'Loyalty Rate',
|
||||||
'value' => round($loyaltyRate, 1) . '%',
|
'value' => round($loyaltyRate, 1) . '%',
|
||||||
|
'description' => 'Persentase pelanggan yang melakukan pembelian lebih dari satu kali.',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Item per Transaksi',
|
'title' => 'Item per Transaksi',
|
||||||
'value' => round($itemsPerOrder, 1),
|
'value' => round($itemsPerOrder, 1),
|
||||||
|
'description' => 'Rata-rata jumlah barang yang dibeli dalam satu transaksi.',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Total Order',
|
'title' => 'Total Order',
|
||||||
'value' => formatCurrencyNumber($totalOrdersCount),
|
'value' => formatCurrencyNumber($totalOrdersCount),
|
||||||
|
'description' => 'Total frekuensi transaksi atau pesanan yang masuk selama periode ini.',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Pendapatan',
|
'title' => 'Pendapatan',
|
||||||
'value' => formatCurrencyNumber($totalIncome, 'Rp'),
|
'value' => formatCurrencyNumber($totalIncome, 'Rp'),
|
||||||
|
'description' => 'Total nominal uang yang masuk dari penjualan (Omzet).',
|
||||||
],
|
],
|
||||||
|
|
||||||
auth()->user()->hasRole(['Developer', 'Owner']) ? [
|
$user->hasRole(['Developer', 'Owner']) ? [
|
||||||
'title' => 'HPP',
|
'title' => 'HPP',
|
||||||
'value' => formatCurrencyNumber($totalCogs, 'Rp'),
|
'value' => formatCurrencyNumber($totalCogs, 'Rp'),
|
||||||
|
'description' => 'Total modal barang atau Harga Pokok Penjualan (HPP).',
|
||||||
] : null,
|
] : null,
|
||||||
|
|
||||||
auth()->user()->hasRole(['Developer', 'Owner']) ? [
|
$user->hasRole(['Developer', 'Owner']) ? [
|
||||||
'title' => 'Laba Kotor',
|
'title' => 'Laba Kotor',
|
||||||
'value' => formatCurrencyNumber($grossProfit, 'Rp'),
|
'value' => formatCurrencyNumber($grossProfit, 'Rp'),
|
||||||
|
'description' => 'Pendapatan dikurangi dengan HPP dan Diskon.',
|
||||||
] : null,
|
] : null,
|
||||||
|
|
||||||
auth()->user()->hasRole(['Developer', 'Owner']) ? [
|
$user->hasRole(['Developer', 'Owner']) ? [
|
||||||
'title' => 'Laba Bersih',
|
'title' => 'Laba Bersih',
|
||||||
'value' => formatCurrencyNumber($netProfit, 'Rp'),
|
'value' => formatCurrencyNumber($netProfit, 'Rp'),
|
||||||
|
'description' => 'Laba kotor dikurangi dengan beban operasional dan gaji.',
|
||||||
] : null,
|
] : null,
|
||||||
|
|
||||||
[
|
[
|
||||||
'title' => 'Diskon',
|
'title' => 'Diskon',
|
||||||
'value' => formatCurrencyNumber($totalDiscount, 'Rp'),
|
'value' => formatCurrencyNumber($totalDiscount, 'Rp'),
|
||||||
|
'description' => 'Total nilai potongan harga (diskon) yang diberikan kepada pelanggan.',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Voucher Terpakai',
|
'title' => 'Voucher Terpakai',
|
||||||
'value' => formatCurrencyNumber(
|
'value' => formatCurrencyNumber(
|
||||||
(clone $orderQuery)->whereNotNull('voucher_id')->count()
|
(clone $orderQuery)->whereNotNull('voucher_id')->count()
|
||||||
),
|
),
|
||||||
|
'description' => 'Jumlah transaksi yang menggunakan voucher diskon selama periode ini.',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Parfum Terjual',
|
'title' => 'Parfum Terjual',
|
||||||
@ -272,6 +298,7 @@ public function render(): View
|
|||||||
->whereHas('order', fn($q) => $q->when(! empty($outletIds), fn($q2) => $q2->whereIn('outlet_id', $outletIds))->when($dateQuery || ($startDate && $endDate), $filterDate))
|
->whereHas('order', fn($q) => $q->when(! empty($outletIds), fn($q2) => $q2->whereIn('outlet_id', $outletIds))->when($dateQuery || ($startDate && $endDate), $filterDate))
|
||||||
->sum('quantity')
|
->sum('quantity')
|
||||||
) . ' ml',
|
) . ' ml',
|
||||||
|
'description' => 'Total volume cairan parfum yang terjual dalam satuan mililiter (ml).',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Produk Terjual',
|
'title' => 'Produk Terjual',
|
||||||
@ -280,6 +307,7 @@ public function render(): View
|
|||||||
->whereHas('order', fn($q) => $q->when(! empty($outletIds), fn($q2) => $q2->whereIn('outlet_id', $outletIds))->when($dateQuery || ($startDate && $endDate), $filterDate))
|
->whereHas('order', fn($q) => $q->when(! empty($outletIds), fn($q2) => $q2->whereIn('outlet_id', $outletIds))->when($dateQuery || ($startDate && $endDate), $filterDate))
|
||||||
->sum('quantity')
|
->sum('quantity')
|
||||||
) . ' pcs',
|
) . ' pcs',
|
||||||
|
'description' => 'Total jumlah unit produk yang terjual dalam satuan pcs.',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'title' => 'Botol Terjual',
|
'title' => 'Botol Terjual',
|
||||||
@ -288,6 +316,7 @@ public function render(): View
|
|||||||
->whereHas('order', fn($q) => $q->when(! empty($outletIds), fn($q2) => $q2->whereIn('outlet_id', $outletIds))->when($dateQuery || ($startDate && $endDate), $filterDate))
|
->whereHas('order', fn($q) => $q->when(! empty($outletIds), fn($q2) => $q2->whereIn('outlet_id', $outletIds))->when($dateQuery || ($startDate && $endDate), $filterDate))
|
||||||
->sum('quantity')
|
->sum('quantity')
|
||||||
) . ' pcs',
|
) . ' pcs',
|
||||||
|
'description' => 'Total jumlah unit botol yang terjual dalam satuan pcs.',
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -300,15 +329,17 @@ public function render(): View
|
|||||||
->sum('amount'),
|
->sum('amount'),
|
||||||
'Rp'
|
'Rp'
|
||||||
),
|
),
|
||||||
|
'description' => 'Total biaya operasional atau pengeluaran toko yang tercatat selama periode ini.',
|
||||||
],
|
],
|
||||||
|
|
||||||
auth()->user()->hasRole(['Developer', 'Owner']) ? [
|
$user->hasRole(['Developer', 'Owner']) ? [
|
||||||
'title' => 'Belanja Barang',
|
'title' => 'Belanja Barang',
|
||||||
'value' => formatCurrencyNumber(
|
'value' => formatCurrencyNumber(
|
||||||
Purchase::when($dateQuery || ($startDate && $endDate), $filterDate)
|
Purchase::when($dateQuery || ($startDate && $endDate), $filterDate)
|
||||||
->sum('total'),
|
->sum('total'),
|
||||||
'Rp'
|
'Rp'
|
||||||
),
|
),
|
||||||
|
'description' => 'Total pengeluaran untuk pembelian stok barang atau inventaris selama periode ini.',
|
||||||
] : null,
|
] : null,
|
||||||
|
|
||||||
[
|
[
|
||||||
@ -320,6 +351,7 @@ public function render(): View
|
|||||||
->sum('total_salary'),
|
->sum('total_salary'),
|
||||||
'Rp'
|
'Rp'
|
||||||
),
|
),
|
||||||
|
'description' => 'Total pengeluaran untuk gaji karyawan.',
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@ -44,15 +44,19 @@ class Overview extends Component
|
|||||||
|
|
||||||
public function mount(): void
|
public function mount(): void
|
||||||
{
|
{
|
||||||
$this->outlets = auth()->user()->outlets()->get()->pluck('name', 'id')->toArray();
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
|
$this->outlets = $user->outlets()->get()->pluck('name', 'id')->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
{
|
{
|
||||||
|
/** @var \App\Models\User $user */
|
||||||
|
$user = auth()->user();
|
||||||
$outletIds = $this->selectedOutletIds;
|
$outletIds = $this->selectedOutletIds;
|
||||||
|
|
||||||
if (count($this->outlets) === 1) {
|
if (count($this->outlets) === 1) {
|
||||||
$outletIds = auth()->user()->outlets()->pluck('outlets.id')->toArray();
|
$outletIds = $user->outlets()->pluck('outlets.id')->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
$todayOrder = Order::when(! empty($outletIds), fn($q) => $q->whereIn('outlet_id', $outletIds))
|
$todayOrder = Order::when(! empty($outletIds), fn($q) => $q->whereIn('outlet_id', $outletIds))
|
||||||
@ -279,7 +283,7 @@ public function render(): View
|
|||||||
];
|
];
|
||||||
|
|
||||||
$this->stats = array_values(array_filter([
|
$this->stats = array_values(array_filter([
|
||||||
auth()->user()->hasRole(['Developer', 'Owner']) ? [
|
$user->hasRole(['Developer', 'Owner']) ? [
|
||||||
'title' => 'Average Order Value (AOV)',
|
'title' => 'Average Order Value (AOV)',
|
||||||
'value' => formatCurrencyNumber($todayAov, 'Rp'),
|
'value' => formatCurrencyNumber($todayAov, 'Rp'),
|
||||||
'previous' => formatCurrencyNumber($yesterdayAov, 'Rp'),
|
'previous' => formatCurrencyNumber($yesterdayAov, 'Rp'),
|
||||||
@ -287,9 +291,10 @@ public function render(): View
|
|||||||
? round((($todayAov - $yesterdayAov) / $yesterdayAov) * 100, 1) . '%'
|
? round((($todayAov - $yesterdayAov) / $yesterdayAov) * 100, 1) . '%'
|
||||||
: '∞%',
|
: '∞%',
|
||||||
'trendUp' => $todayAov > $yesterdayAov,
|
'trendUp' => $todayAov > $yesterdayAov,
|
||||||
|
'description' => 'Rata-rata nilai belanja pelanggan dalam satu kali checkout.',
|
||||||
] : null,
|
] : null,
|
||||||
|
|
||||||
auth()->user()->hasRole(['Developer', 'Owner']) ? [
|
$user->hasRole(['Developer', 'Owner']) ? [
|
||||||
'title' => 'Profit Margin',
|
'title' => 'Profit Margin',
|
||||||
'value' => round($todayProfitMargin, 1) . '%',
|
'value' => round($todayProfitMargin, 1) . '%',
|
||||||
'previous' => round($yesterdayProfitMargin, 1) . '%',
|
'previous' => round($yesterdayProfitMargin, 1) . '%',
|
||||||
@ -297,6 +302,7 @@ public function render(): View
|
|||||||
? round($todayProfitMargin - $yesterdayProfitMargin, 1) . '%'
|
? round($todayProfitMargin - $yesterdayProfitMargin, 1) . '%'
|
||||||
: '∞%',
|
: '∞%',
|
||||||
'trendUp' => $todayProfitMargin > $yesterdayProfitMargin,
|
'trendUp' => $todayProfitMargin > $yesterdayProfitMargin,
|
||||||
|
'description' => 'Persentase keuntungan bersih dibandingkan dengan total pendapatan.',
|
||||||
] : null,
|
] : null,
|
||||||
|
|
||||||
[
|
[
|
||||||
@ -307,6 +313,7 @@ public function render(): View
|
|||||||
? round((($todayOrder - $yesterdayOrder) / $yesterdayOrder) * 100, 1) . '%'
|
? round((($todayOrder - $yesterdayOrder) / $yesterdayOrder) * 100, 1) . '%'
|
||||||
: '∞%',
|
: '∞%',
|
||||||
'trendUp' => $todayOrder > $yesterdayOrder,
|
'trendUp' => $todayOrder > $yesterdayOrder,
|
||||||
|
'description' => 'Total frekuensi transaksi atau pesanan yang masuk selama periode ini.',
|
||||||
],
|
],
|
||||||
|
|
||||||
[
|
[
|
||||||
@ -318,9 +325,10 @@ public function render(): View
|
|||||||
: '∞%',
|
: '∞%',
|
||||||
'trendUp' => $todayIncome > $yesterdayIncome,
|
'trendUp' => $todayIncome > $yesterdayIncome,
|
||||||
'formatted' => formatCurrencyNumber($todayIncome, 'Rp'),
|
'formatted' => formatCurrencyNumber($todayIncome, 'Rp'),
|
||||||
|
'description' => 'Total nominal uang yang masuk dari penjualan (Omzet).',
|
||||||
],
|
],
|
||||||
|
|
||||||
auth()->user()->hasRole(['Developer', 'Owner']) ? [
|
$user->hasRole(['Developer', 'Owner']) ? [
|
||||||
'title' => 'HPP',
|
'title' => 'HPP',
|
||||||
'value' => formatCurrencyNumber($todayCogs, 'Rp'),
|
'value' => formatCurrencyNumber($todayCogs, 'Rp'),
|
||||||
'previous' => formatCurrencyNumber($yesterdayCogs, 'Rp'),
|
'previous' => formatCurrencyNumber($yesterdayCogs, 'Rp'),
|
||||||
@ -329,6 +337,7 @@ public function render(): View
|
|||||||
: '∞%',
|
: '∞%',
|
||||||
'trendUp' => $todayCogs > $yesterdayCogs,
|
'trendUp' => $todayCogs > $yesterdayCogs,
|
||||||
'formatted' => formatCurrencyNumber($todayCogs, 'Rp'),
|
'formatted' => formatCurrencyNumber($todayCogs, 'Rp'),
|
||||||
|
'description' => 'Harga Pokok Penjualan, yaitu total modal dari barang-barang yang terjual.',
|
||||||
] : null,
|
] : null,
|
||||||
|
|
||||||
[
|
[
|
||||||
@ -339,6 +348,7 @@ public function render(): View
|
|||||||
? round((($todayNewMembers - $yesterdayNewMembers) / $yesterdayNewMembers) * 100, 1) . '%'
|
? round((($todayNewMembers - $yesterdayNewMembers) / $yesterdayNewMembers) * 100, 1) . '%'
|
||||||
: '∞%',
|
: '∞%',
|
||||||
'trendUp' => $todayNewMembers > $yesterdayNewMembers,
|
'trendUp' => $todayNewMembers > $yesterdayNewMembers,
|
||||||
|
'description' => 'Jumlah pelanggan baru yang mendaftar menjadi member selama periode ini.',
|
||||||
],
|
],
|
||||||
|
|
||||||
[
|
[
|
||||||
@ -350,6 +360,7 @@ public function render(): View
|
|||||||
: '∞%',
|
: '∞%',
|
||||||
'trendUp' => $todayDiscount > $yesterdayDiscount,
|
'trendUp' => $todayDiscount > $yesterdayDiscount,
|
||||||
'formatted' => formatCurrencyNumber($todayDiscount, 'Rp'),
|
'formatted' => formatCurrencyNumber($todayDiscount, 'Rp'),
|
||||||
|
'description' => 'Total nilai potongan harga (diskon) yang diberikan kepada pelanggan.',
|
||||||
],
|
],
|
||||||
|
|
||||||
[
|
[
|
||||||
@ -360,6 +371,7 @@ public function render(): View
|
|||||||
? round((($todayVoucher - $yesterdayVoucher) / $yesterdayVoucher) * 100, 1) . '%'
|
? round((($todayVoucher - $yesterdayVoucher) / $yesterdayVoucher) * 100, 1) . '%'
|
||||||
: '∞%',
|
: '∞%',
|
||||||
'trendUp' => $todayVoucher > $yesterdayVoucher,
|
'trendUp' => $todayVoucher > $yesterdayVoucher,
|
||||||
|
'description' => 'Jumlah transaksi yang menggunakan voucher diskon selama periode ini.',
|
||||||
],
|
],
|
||||||
|
|
||||||
[
|
[
|
||||||
@ -370,9 +382,10 @@ public function render(): View
|
|||||||
? round((($todayExpense - $yesterdayExpense) / $yesterdayExpense) * 100, 1) . '%'
|
? round((($todayExpense - $yesterdayExpense) / $yesterdayExpense) * 100, 1) . '%'
|
||||||
: '∞%',
|
: '∞%',
|
||||||
'trendUp' => $todayExpense > $yesterdayExpense,
|
'trendUp' => $todayExpense > $yesterdayExpense,
|
||||||
|
'description' => 'Total biaya operasional atau pengeluaran toko yang tercatat selama periode ini.',
|
||||||
],
|
],
|
||||||
|
|
||||||
auth()->user()->hasRole(['Developer', 'Owner']) ? [
|
$user->hasRole(['Developer', 'Owner']) ? [
|
||||||
'title' => 'Belanja Barang',
|
'title' => 'Belanja Barang',
|
||||||
'value' => formatCurrencyNumber($todayPurchase, 'Rp'),
|
'value' => formatCurrencyNumber($todayPurchase, 'Rp'),
|
||||||
'previous' => formatCurrencyNumber($yesterdayPurchase, 'Rp'),
|
'previous' => formatCurrencyNumber($yesterdayPurchase, 'Rp'),
|
||||||
@ -380,9 +393,10 @@ public function render(): View
|
|||||||
? round((($todayPurchase - $yesterdayPurchase) / $yesterdayPurchase) * 100, 1) . '%'
|
? round((($todayPurchase - $yesterdayPurchase) / $yesterdayPurchase) * 100, 1) . '%'
|
||||||
: '∞%',
|
: '∞%',
|
||||||
'trendUp' => $todayPurchase > $yesterdayPurchase,
|
'trendUp' => $todayPurchase > $yesterdayPurchase,
|
||||||
|
'description' => 'Total pengeluaran untuk pembelian stok barang atau inventaris selama periode ini.',
|
||||||
] : null,
|
] : null,
|
||||||
|
|
||||||
auth()->user()->hasRole(['Developer', 'Owner']) ? [
|
$user->hasRole(['Developer', 'Owner']) ? [
|
||||||
'title' => 'Laba Kotor',
|
'title' => 'Laba Kotor',
|
||||||
'value' => formatCurrencyNumber($todayGrossProfit, 'Rp'),
|
'value' => formatCurrencyNumber($todayGrossProfit, 'Rp'),
|
||||||
'previous' => formatCurrencyNumber($yesterdayGrossProfit, 'Rp'),
|
'previous' => formatCurrencyNumber($yesterdayGrossProfit, 'Rp'),
|
||||||
@ -390,9 +404,10 @@ public function render(): View
|
|||||||
? round((($todayGrossProfit - $yesterdayGrossProfit) / $yesterdayGrossProfit) * 100, 1) . '%'
|
? round((($todayGrossProfit - $yesterdayGrossProfit) / $yesterdayGrossProfit) * 100, 1) . '%'
|
||||||
: '∞%',
|
: '∞%',
|
||||||
'trendUp' => $todayGrossProfit > $yesterdayGrossProfit,
|
'trendUp' => $todayGrossProfit > $yesterdayGrossProfit,
|
||||||
|
'description' => 'Pendapatan dikurangi dengan HPP dan Diskon.',
|
||||||
] : null,
|
] : null,
|
||||||
|
|
||||||
auth()->user()->hasRole(['Developer', 'Owner']) ? [
|
$user->hasRole(['Developer', 'Owner']) ? [
|
||||||
'title' => 'Laba Bersih',
|
'title' => 'Laba Bersih',
|
||||||
'value' => formatCurrencyNumber($todayNetProfit, 'Rp'),
|
'value' => formatCurrencyNumber($todayNetProfit, 'Rp'),
|
||||||
'previous' => formatCurrencyNumber($yesterdayNetProfit, 'Rp'),
|
'previous' => formatCurrencyNumber($yesterdayNetProfit, 'Rp'),
|
||||||
@ -400,6 +415,7 @@ public function render(): View
|
|||||||
? round((($todayNetProfit - $yesterdayNetProfit) / $yesterdayNetProfit) * 100, 1) . '%'
|
? round((($todayNetProfit - $yesterdayNetProfit) / $yesterdayNetProfit) * 100, 1) . '%'
|
||||||
: '∞%',
|
: '∞%',
|
||||||
'trendUp' => $todayNetProfit > $yesterdayNetProfit,
|
'trendUp' => $todayNetProfit > $yesterdayNetProfit,
|
||||||
|
'description' => 'Laba kotor dikurangi dengan beban operasional dan gaji.',
|
||||||
] : null,
|
] : null,
|
||||||
|
|
||||||
[
|
[
|
||||||
@ -410,6 +426,7 @@ public function render(): View
|
|||||||
? round((($todaySoldPerfume - $yesterdaySoldPerfume) / $yesterdaySoldPerfume) * 100, 1) . '%'
|
? round((($todaySoldPerfume - $yesterdaySoldPerfume) / $yesterdaySoldPerfume) * 100, 1) . '%'
|
||||||
: '∞%',
|
: '∞%',
|
||||||
'trendUp' => $todaySoldPerfume > $yesterdaySoldPerfume,
|
'trendUp' => $todaySoldPerfume > $yesterdaySoldPerfume,
|
||||||
|
'description' => 'Total volume cairan parfum yang terjual dalam satuan mililiter (ml).',
|
||||||
],
|
],
|
||||||
|
|
||||||
[
|
[
|
||||||
@ -420,6 +437,7 @@ public function render(): View
|
|||||||
? round((($todayTopPerfume?->total_sold - $yesterdayTopPerfume?->total_sold) / $yesterdayTopPerfume?->total_sold) * 100, 1) . '%'
|
? round((($todayTopPerfume?->total_sold - $yesterdayTopPerfume?->total_sold) / $yesterdayTopPerfume?->total_sold) * 100, 1) . '%'
|
||||||
: '∞%',
|
: '∞%',
|
||||||
'trendUp' => ($todayTopPerfume?->total_sold ?? 0) > ($yesterdayTopPerfume?->total_sold ?? 0),
|
'trendUp' => ($todayTopPerfume?->total_sold ?? 0) > ($yesterdayTopPerfume?->total_sold ?? 0),
|
||||||
|
'description' => 'Nama varian parfum yang paling banyak terjual hari ini.',
|
||||||
],
|
],
|
||||||
]));
|
]));
|
||||||
|
|
||||||
|
|||||||
@ -45,8 +45,20 @@
|
|||||||
<flux:heading>Counting Data</flux:heading>
|
<flux:heading>Counting Data</flux:heading>
|
||||||
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6 gap-3 mb-6 mt-2">
|
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6 gap-3 mb-6 mt-2">
|
||||||
@foreach ($countingData as $item)
|
@foreach ($countingData as $item)
|
||||||
<div class="rounded-lg px-6 py-4 bg-zinc-200 dark:bg-zinc-700">
|
<div
|
||||||
|
class="relative rounded-lg px-6 py-4 bg-zinc-200 dark:bg-zinc-700 transition-all duration-300 hover:scale-[1.02] hover:shadow-lg dark:hover:shadow-zinc-900/50">
|
||||||
|
<div class="flex items-start justify-between">
|
||||||
<flux:subheading>{{ $item['title'] }}</flux:subheading>
|
<flux:subheading>{{ $item['title'] }}</flux:subheading>
|
||||||
|
|
||||||
|
@if (isset($item['description']))
|
||||||
|
<div class="absolute top-2 right-2">
|
||||||
|
<flux:tooltip toggleable content="{{ $item['description'] }}">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent hover:bg-zinc-300 dark:hover:bg-zinc-600" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
<flux:heading size="xl" class="mb-2">{{ $item['value'] }}</flux:heading>
|
<flux:heading size="xl" class="mb-2">{{ $item['value'] }}</flux:heading>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
@ -55,8 +67,20 @@
|
|||||||
<flux:heading>Order</flux:heading>
|
<flux:heading>Order</flux:heading>
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-4 mb-6 mt-2">
|
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-4 mb-6 mt-2">
|
||||||
@foreach ($orders as $order)
|
@foreach ($orders as $order)
|
||||||
<div class="rounded-lg px-6 py-4 bg-zinc-200 dark:bg-zinc-700">
|
<div
|
||||||
|
class="relative rounded-lg px-6 py-4 bg-zinc-200 dark:bg-zinc-700 transition-all duration-300 hover:scale-[1.02] hover:shadow-lg dark:hover:shadow-zinc-900/50">
|
||||||
|
<div class="flex items-start justify-between">
|
||||||
<flux:subheading>{{ $order['title'] }}</flux:subheading>
|
<flux:subheading>{{ $order['title'] }}</flux:subheading>
|
||||||
|
|
||||||
|
@if (isset($order['description']))
|
||||||
|
<div class="absolute top-2 right-2">
|
||||||
|
<flux:tooltip toggleable content="{{ $order['description'] }}">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent hover:bg-zinc-300 dark:hover:bg-zinc-600" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
<flux:heading size="xl" class="mb-2">{{ $order['value'] }}</flux:heading>
|
<flux:heading size="xl" class="mb-2">{{ $order['value'] }}</flux:heading>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
@ -65,8 +89,20 @@
|
|||||||
<flux:heading>Pengeluaran</flux:heading>
|
<flux:heading>Pengeluaran</flux:heading>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6 mt-2">
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6 mt-2">
|
||||||
@foreach ($expenses as $expense)
|
@foreach ($expenses as $expense)
|
||||||
<div class="rounded-lg px-6 py-4 bg-zinc-200 dark:bg-zinc-700">
|
<div
|
||||||
|
class="relative rounded-lg px-6 py-4 bg-zinc-200 dark:bg-zinc-700 transition-all duration-300 hover:scale-[1.02] hover:shadow-lg dark:hover:shadow-zinc-900/50">
|
||||||
|
<div class="flex items-start justify-between">
|
||||||
<flux:subheading>{{ $expense['title'] }}</flux:subheading>
|
<flux:subheading>{{ $expense['title'] }}</flux:subheading>
|
||||||
|
|
||||||
|
@if (isset($expense['description']))
|
||||||
|
<div class="absolute top-2 right-2">
|
||||||
|
<flux:tooltip toggleable content="{{ $expense['description'] }}">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent hover:bg-zinc-300 dark:hover:bg-zinc-600" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
<flux:heading size="xl" class="mb-2">{{ $expense['value'] }}</flux:heading>
|
<flux:heading size="xl" class="mb-2">{{ $expense['value'] }}</flux:heading>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
@ -74,31 +110,75 @@
|
|||||||
|
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8" x-data="analysisCharts">
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8" x-data="analysisCharts">
|
||||||
<!-- 1. Revenue & Profit Trend -->
|
<!-- 1. Revenue & Profit Trend -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Trend perbandingan pendapatan dan laba bersih perusahaan selama 30 hari terakhir.">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Trend Pendapatan & Laba (30 Hari Terakhir)</flux:heading>
|
<flux:heading class="mb-4">Trend Pendapatan & Laba (30 Hari Terakhir)</flux:heading>
|
||||||
<div class="h-80"><canvas id="revenueTrendChart"></canvas></div>
|
<div class="h-80"><canvas id="revenueTrendChart"></canvas></div>
|
||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 6. Member Growth (Area Chart) - Cumulative -->
|
<!-- 6. Member Growth (Area Chart) - Cumulative -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable content="Grafik akumulasi pertumbuhan jumlah member dari waktu ke waktu.">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Pertumbuhan Member (Akumulasi)</flux:heading>
|
<flux:heading class="mb-4">Pertumbuhan Member (Akumulasi)</flux:heading>
|
||||||
<div class="h-80"><canvas id="memberGrowthChart"></canvas></div>
|
<div class="h-80"><canvas id="memberGrowthChart"></canvas></div>
|
||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 2. busiest hour -->
|
<!-- 2. busiest hour -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Identifikasi jam-jam dengan volume transaksi tertinggi berdasarkan waktu pemesanan.">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Jam Sibuk (Total Order per Jam)</flux:heading>
|
<flux:heading class="mb-4">Jam Sibuk (Total Order per Jam)</flux:heading>
|
||||||
<div class="h-80"><canvas id="hourlySalesChart"></canvas></div>
|
<div class="h-80"><canvas id="hourlySalesChart"></canvas></div>
|
||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 5. Outlet Performance -->
|
<!-- 5. Outlet Performance -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Perbandingan total pendapatan antar outlet yang terdaftar di sistem.">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Performa Outlet (Pendapatan)</flux:heading>
|
<flux:heading class="mb-4">Performa Outlet (Pendapatan)</flux:heading>
|
||||||
<div class="h-80"><canvas id="outletPerformanceChart"></canvas></div>
|
<div class="h-80"><canvas id="outletPerformanceChart"></canvas></div>
|
||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 3. Product Category Distribution -->
|
<!-- 3. Product Category Distribution -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Pembagian pendapatan berdasarkan kategori produk (Parfum, Produk, Botol).">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Distribusi Penjualan</flux:heading>
|
<flux:heading class="mb-4">Distribusi Penjualan</flux:heading>
|
||||||
<div class="h-80 flex items-center justify-center">
|
<div class="h-80 flex items-center justify-center">
|
||||||
<canvas id="categoryDistributionChart"></canvas>
|
<canvas id="categoryDistributionChart"></canvas>
|
||||||
@ -106,7 +186,16 @@
|
|||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 4. Payment Method -->
|
<!-- 4. Payment Method -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Persentase penggunaan berbagai metode pembayaran oleh pelanggan.">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Metode Pembayaran</flux:heading>
|
<flux:heading class="mb-4">Metode Pembayaran</flux:heading>
|
||||||
<div class="h-80 flex items-center justify-center">
|
<div class="h-80 flex items-center justify-center">
|
||||||
<canvas id="paymentMethodChart"></canvas>
|
<canvas id="paymentMethodChart"></canvas>
|
||||||
@ -114,13 +203,31 @@
|
|||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 7. Day of Week Sales -->
|
<!-- 7. Day of Week Sales -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Analisa hari dalam seminggu saat volume penjualan paling tinggi.">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Performa Penjualan per Hari</flux:heading>
|
<flux:heading class="mb-4">Performa Penjualan per Hari</flux:heading>
|
||||||
<div class="h-80"><canvas id="dayOfWeekSalesChart"></canvas></div>
|
<div class="h-80"><canvas id="dayOfWeekSalesChart"></canvas></div>
|
||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 8. Customer Type Distribution -->
|
<!-- 8. Customer Type Distribution -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Perbandingan jumlah transaksi antara pelanggan terdaftar (Member) dan pelanggan umum (Guest).">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Segmentasi Pelanggan (Member vs Guest)</flux:heading>
|
<flux:heading class="mb-4">Segmentasi Pelanggan (Member vs Guest)</flux:heading>
|
||||||
<div class="h-80 flex items-center justify-center">
|
<div class="h-80 flex items-center justify-center">
|
||||||
<canvas id="customerTypeChart"></canvas>
|
<canvas id="customerTypeChart"></canvas>
|
||||||
@ -128,19 +235,44 @@
|
|||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 9. Transaction Trend -->
|
<!-- 9. Transaction Trend -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable content="Trend jumlah transaksi harian dalam sebulan terakhir.">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Trend Volume Transaksi (30 Hari)</flux:heading>
|
<flux:heading class="mb-4">Trend Volume Transaksi (30 Hari)</flux:heading>
|
||||||
<div class="h-80"><canvas id="transactionTrendChart"></canvas></div>
|
<div class="h-80"><canvas id="transactionTrendChart"></canvas></div>
|
||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 10. AOV Trend -->
|
<!-- 10. AOV Trend -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable content="Trend rata-rata nilai transaksi (Average Order Value).">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Trend Rata-rata Belanja (AOV)</flux:heading>
|
<flux:heading class="mb-4">Trend Rata-rata Belanja (AOV)</flux:heading>
|
||||||
<div class="h-80"><canvas id="aovTrendChart"></canvas></div>
|
<div class="h-80"><canvas id="aovTrendChart"></canvas></div>
|
||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 11. Expense Breakdown -->
|
<!-- 11. Expense Breakdown -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Perbandingan antara biaya operasional toko dengan biaya gaji karyawan.">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Komposisi Biaya Operasional</flux:heading>
|
<flux:heading class="mb-4">Komposisi Biaya Operasional</flux:heading>
|
||||||
<div class="h-80 flex items-center justify-center">
|
<div class="h-80 flex items-center justify-center">
|
||||||
<canvas id="expenseBreakdownChart"></canvas>
|
<canvas id="expenseBreakdownChart"></canvas>
|
||||||
@ -148,7 +280,16 @@
|
|||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 12. Revenue vs Cost -->
|
<!-- 12. Revenue vs Cost -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Perbandingan antara pendapatan (omzet) dengan total seluruh pengeluaran.">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Omzet vs Total Biaya</flux:heading>
|
<flux:heading class="mb-4">Omzet vs Total Biaya</flux:heading>
|
||||||
<div class="h-80 flex items-center justify-center">
|
<div class="h-80 flex items-center justify-center">
|
||||||
<canvas id="revenueVsCostChart"></canvas>
|
<canvas id="revenueVsCostChart"></canvas>
|
||||||
@ -156,7 +297,16 @@
|
|||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 13. Customer Retention -->
|
<!-- 13. Customer Retention -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Analisa persentase pelanggan setia (repeat order) dibandingkan pelanggan baru.">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Analisa Pelanggan (Baru vs Lama)</flux:heading>
|
<flux:heading class="mb-4">Analisa Pelanggan (Baru vs Lama)</flux:heading>
|
||||||
<div class="h-80 flex items-center justify-center">
|
<div class="h-80 flex items-center justify-center">
|
||||||
<canvas id="customerRetentionChart"></canvas>
|
<canvas id="customerRetentionChart"></canvas>
|
||||||
@ -164,7 +314,16 @@
|
|||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 14. Voucher Activity -->
|
<!-- 14. Voucher Activity -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Grafik efektivitas penggunaan voucher diskon dari waktu ke waktu.">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Efektivitas Voucher</flux:heading>
|
<flux:heading class="mb-4">Efektivitas Voucher</flux:heading>
|
||||||
<div class="h-80"><canvas id="voucherUsageTrendChart"></canvas></div>
|
<div class="h-80"><canvas id="voucherUsageTrendChart"></canvas></div>
|
||||||
</flux:card>
|
</flux:card>
|
||||||
@ -173,7 +332,8 @@
|
|||||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6 mt-2">
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6 mt-2">
|
||||||
<div>
|
<div>
|
||||||
<flux:heading>Top 5 Parfum</flux:heading>
|
<flux:heading>Top 5 Parfum</flux:heading>
|
||||||
<flux:card class="mb-6 mt-2 bg-zinc-200 dark:bg-zinc-700">
|
<flux:card
|
||||||
|
class="mb-6 mt-2 bg-zinc-200 dark:bg-zinc-700 transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50">
|
||||||
<flux:table>
|
<flux:table>
|
||||||
<flux:table.columns>
|
<flux:table.columns>
|
||||||
<flux:table.column>No</flux:table.column>
|
<flux:table.column>No</flux:table.column>
|
||||||
@ -201,7 +361,8 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<flux:heading>Top 5 Produk</flux:heading>
|
<flux:heading>Top 5 Produk</flux:heading>
|
||||||
<flux:card class="mb-6 mt-2 bg-zinc-200 dark:bg-zinc-700">
|
<flux:card
|
||||||
|
class="mb-6 mt-2 bg-zinc-200 dark:bg-zinc-700 transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50">
|
||||||
<flux:table>
|
<flux:table>
|
||||||
<flux:table.columns>
|
<flux:table.columns>
|
||||||
<flux:table.column>No</flux:table.column>
|
<flux:table.column>No</flux:table.column>
|
||||||
@ -229,7 +390,8 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<flux:heading>Top 5 Botol</flux:heading>
|
<flux:heading>Top 5 Botol</flux:heading>
|
||||||
<flux:card class="mb-6 mt-2 bg-zinc-200 dark:bg-zinc-700">
|
<flux:card
|
||||||
|
class="mb-6 mt-2 bg-zinc-200 dark:bg-zinc-700 transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50">
|
||||||
<flux:table>
|
<flux:table>
|
||||||
<flux:table.columns>
|
<flux:table.columns>
|
||||||
<flux:table.column>No</flux:table.column>
|
<flux:table.column>No</flux:table.column>
|
||||||
@ -246,7 +408,8 @@
|
|||||||
<flux:table.cell>{{ $topBottle['name'] }}</flux:table.cell>
|
<flux:table.cell>{{ $topBottle['name'] }}</flux:table.cell>
|
||||||
<flux:table.cell>{{ $topBottle['sale_price'] }}</flux:table.cell>
|
<flux:table.cell>{{ $topBottle['sale_price'] }}</flux:table.cell>
|
||||||
<flux:table.cell>{{ $topBottle['total_sold'] }}</flux:table.cell>
|
<flux:table.cell>{{ $topBottle['total_sold'] }}</flux:table.cell>
|
||||||
<flux:table.cell variant="strong">{{ $topBottle['total_sales'] }}</flux:table.cell>
|
<flux:table.cell variant="strong">{{ $topBottle['total_sales'] }}
|
||||||
|
</flux:table.cell>
|
||||||
</flux:table.row>
|
</flux:table.row>
|
||||||
@endforeach
|
@endforeach
|
||||||
</flux:table.rows>
|
</flux:table.rows>
|
||||||
@ -274,7 +437,10 @@
|
|||||||
return JSON.parse(JSON.stringify(data));
|
return JSON.parse(JSON.stringify(data));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Fallback for safety
|
// Fallback for safety
|
||||||
return { labels: [], datasets: [] };
|
return {
|
||||||
|
labels: [],
|
||||||
|
datasets: []
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -291,19 +457,31 @@
|
|||||||
|
|
||||||
// Watchers
|
// Watchers
|
||||||
this.$watch('$wire.revenueTrendChart', () => this.updateChart('revenue', this.getRevenueData));
|
this.$watch('$wire.revenueTrendChart', () => this.updateChart('revenue', this.getRevenueData));
|
||||||
this.$watch('$wire.memberGrowthChart', () => this.updateChart('memberGrowth', this.getMemberGrowthData));
|
this.$watch('$wire.memberGrowthChart', () => this.updateChart('memberGrowth', this
|
||||||
this.$watch('$wire.hourlySalesChart', () => this.updateChart('hourlySales', this.getHourlySalesData));
|
.getMemberGrowthData));
|
||||||
this.$watch('$wire.outletPerformanceChart', () => this.updateChart('outletPerformance', this.getOutletPerformanceData));
|
this.$watch('$wire.hourlySalesChart', () => this.updateChart('hourlySales', this
|
||||||
this.$watch('$wire.categoryDistributionChart', () => this.updateChart('categoryDist', this.getCategoryDistributionData));
|
.getHourlySalesData));
|
||||||
this.$watch('$wire.paymentMethodChart', () => this.updateChart('paymentMethod', this.getPaymentMethodData));
|
this.$watch('$wire.outletPerformanceChart', () => this.updateChart('outletPerformance', this
|
||||||
this.$watch('$wire.dayOfWeekSalesChart', () => this.updateChart('dayOfWeekSales', this.getDayOfWeekData));
|
.getOutletPerformanceData));
|
||||||
this.$watch('$wire.customerTypeChart', () => this.updateChart('customerType', this.getCustomerTypeData));
|
this.$watch('$wire.categoryDistributionChart', () => this.updateChart('categoryDist', this
|
||||||
this.$watch('$wire.transactionTrendChart', () => this.updateChart('transactionTrend', this.getTransactionTrendData));
|
.getCategoryDistributionData));
|
||||||
|
this.$watch('$wire.paymentMethodChart', () => this.updateChart('paymentMethod', this
|
||||||
|
.getPaymentMethodData));
|
||||||
|
this.$watch('$wire.dayOfWeekSalesChart', () => this.updateChart('dayOfWeekSales', this
|
||||||
|
.getDayOfWeekData));
|
||||||
|
this.$watch('$wire.customerTypeChart', () => this.updateChart('customerType', this
|
||||||
|
.getCustomerTypeData));
|
||||||
|
this.$watch('$wire.transactionTrendChart', () => this.updateChart('transactionTrend', this
|
||||||
|
.getTransactionTrendData));
|
||||||
this.$watch('$wire.aovTrendChart', () => this.updateChart('aovTrend', this.getAovTrendData));
|
this.$watch('$wire.aovTrendChart', () => this.updateChart('aovTrend', this.getAovTrendData));
|
||||||
this.$watch('$wire.expenseBreakdownChart', () => this.updateChart('expenseBreakdown', this.getExpenseBreakdownData));
|
this.$watch('$wire.expenseBreakdownChart', () => this.updateChart('expenseBreakdown', this
|
||||||
this.$watch('$wire.revenueVsCostChart', () => this.updateChart('revenueVsCost', this.getRevenueVsCostData));
|
.getExpenseBreakdownData));
|
||||||
this.$watch('$wire.customerRetentionChart', () => this.updateChart('customerRetention', this.getCustomerRetentionData));
|
this.$watch('$wire.revenueVsCostChart', () => this.updateChart('revenueVsCost', this
|
||||||
this.$watch('$wire.voucherUsageTrendChart', () => this.updateChart('voucherUsage', this.getVoucherUsageData));
|
.getRevenueVsCostData));
|
||||||
|
this.$watch('$wire.customerRetentionChart', () => this.updateChart('customerRetention', this
|
||||||
|
.getCustomerRetentionData));
|
||||||
|
this.$watch('$wire.voucherUsageTrendChart', () => this.updateChart('voucherUsage', this
|
||||||
|
.getVoucherUsageData));
|
||||||
},
|
},
|
||||||
|
|
||||||
updateChart(key, getDataFn) {
|
updateChart(key, getDataFn) {
|
||||||
@ -360,16 +538,23 @@
|
|||||||
|
|
||||||
initRevenueTrend() {
|
initRevenueTrend() {
|
||||||
this.createChart('revenueTrendChart', 'revenue', 'line', this.getRevenueData(), {
|
this.createChart('revenueTrendChart', 'revenue', 'line', this.getRevenueData(), {
|
||||||
plugins: { legend: { position: 'top' } },
|
plugins: {
|
||||||
scales: { y: { beginAtZero: true } }
|
legend: {
|
||||||
|
position: 'top'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
beginAtZero: true
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getRevenueData() {
|
getRevenueData() {
|
||||||
const data = this.unwrap($wire.revenueTrendChart);
|
const data = this.unwrap($wire.revenueTrendChart);
|
||||||
return {
|
return {
|
||||||
labels: data.labels || [],
|
labels: data.labels || [],
|
||||||
datasets: [
|
datasets: [{
|
||||||
{
|
|
||||||
label: 'Pendapatan',
|
label: 'Pendapatan',
|
||||||
data: data.revenue || [],
|
data: data.revenue || [],
|
||||||
borderColor: '#10b981',
|
borderColor: '#10b981',
|
||||||
@ -391,7 +576,11 @@
|
|||||||
|
|
||||||
initMemberGrowth() {
|
initMemberGrowth() {
|
||||||
this.createChart('memberGrowthChart', 'memberGrowth', 'line', this.getMemberGrowthData(), {
|
this.createChart('memberGrowthChart', 'memberGrowth', 'line', this.getMemberGrowthData(), {
|
||||||
scales: { y: { beginAtZero: true } }
|
scales: {
|
||||||
|
y: {
|
||||||
|
beginAtZero: true
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getMemberGrowthData() {
|
getMemberGrowthData() {
|
||||||
@ -425,7 +614,8 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
initOutletPerformance() {
|
initOutletPerformance() {
|
||||||
this.createChart('outletPerformanceChart', 'outletPerformance', 'bar', this.getOutletPerformanceData(), {
|
this.createChart('outletPerformanceChart', 'outletPerformance', 'bar', this
|
||||||
|
.getOutletPerformanceData(), {
|
||||||
indexAxis: 'y'
|
indexAxis: 'y'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -442,7 +632,8 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
initCategoryDistribution() {
|
initCategoryDistribution() {
|
||||||
this.createChart('categoryDistributionChart', 'categoryDist', 'doughnut', this.getCategoryDistributionData());
|
this.createChart('categoryDistributionChart', 'categoryDist', 'doughnut', this
|
||||||
|
.getCategoryDistributionData());
|
||||||
},
|
},
|
||||||
getCategoryDistributionData() {
|
getCategoryDistributionData() {
|
||||||
const data = this.unwrap($wire.categoryDistributionChart);
|
const data = this.unwrap($wire.categoryDistributionChart);
|
||||||
@ -499,7 +690,8 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
initTransactionTrend() {
|
initTransactionTrend() {
|
||||||
this.createChart('transactionTrendChart', 'transactionTrend', 'line', this.getTransactionTrendData());
|
this.createChart('transactionTrendChart', 'transactionTrend', 'line', this
|
||||||
|
.getTransactionTrendData());
|
||||||
},
|
},
|
||||||
getTransactionTrendData() {
|
getTransactionTrendData() {
|
||||||
const data = this.unwrap($wire.transactionTrendChart);
|
const data = this.unwrap($wire.transactionTrendChart);
|
||||||
@ -535,7 +727,8 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
initExpenseBreakdown() {
|
initExpenseBreakdown() {
|
||||||
this.createChart('expenseBreakdownChart', 'expenseBreakdown', 'doughnut', this.getExpenseBreakdownData());
|
this.createChart('expenseBreakdownChart', 'expenseBreakdown', 'doughnut', this
|
||||||
|
.getExpenseBreakdownData());
|
||||||
},
|
},
|
||||||
getExpenseBreakdownData() {
|
getExpenseBreakdownData() {
|
||||||
const data = this.unwrap($wire.expenseBreakdownChart);
|
const data = this.unwrap($wire.expenseBreakdownChart);
|
||||||
@ -564,7 +757,8 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
initCustomerRetention() {
|
initCustomerRetention() {
|
||||||
this.createChart('customerRetentionChart', 'customerRetention', 'bar', this.getCustomerRetentionData());
|
this.createChart('customerRetentionChart', 'customerRetention', 'bar', this
|
||||||
|
.getCustomerRetentionData());
|
||||||
},
|
},
|
||||||
getCustomerRetentionData() {
|
getCustomerRetentionData() {
|
||||||
const data = this.unwrap($wire.customerRetentionChart);
|
const data = this.unwrap($wire.customerRetentionChart);
|
||||||
|
|||||||
@ -18,9 +18,20 @@
|
|||||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-4 mb-6 mt-2">
|
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-4 mb-6 mt-2">
|
||||||
@foreach ($stats as $stat)
|
@foreach ($stats as $stat)
|
||||||
<div
|
<div
|
||||||
class="@if ($stat['title'] === 'Top Parfum') md:col-span-2 xl:col-span-2 @endif rounded-lg px-6 py-4 bg-zinc-200 dark:bg-zinc-700">
|
class="relative @if ($stat['title'] === 'Top Parfum') md:col-span-2 xl:col-span-2 @endif rounded-lg px-6 py-4 bg-zinc-200 dark:bg-zinc-700 transition-all duration-300 hover:scale-[1.02] hover:shadow-lg dark:hover:shadow-zinc-900/50">
|
||||||
|
<div class="flex items-start justify-between">
|
||||||
<flux:subheading>{{ $stat['title'] }}</flux:subheading>
|
<flux:subheading>{{ $stat['title'] }}</flux:subheading>
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
|
@if (isset($stat['description']))
|
||||||
|
<div class="absolute top-2 right-2">
|
||||||
|
<flux:tooltip toggleable content="{{ $stat['description'] }}">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!px-1 border-none bg-transparent hover:bg-zinc-300 dark:hover:bg-zinc-600" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between mt-1">
|
||||||
<flux:heading size="xl">{{ $stat['value'] }}</flux:heading>
|
<flux:heading size="xl">{{ $stat['value'] }}</flux:heading>
|
||||||
<flux:subheading size="xs">{{ $stat['previous'] }}</flux:subheading>
|
<flux:subheading size="xs">{{ $stat['previous'] }}</flux:subheading>
|
||||||
</div>
|
</div>
|
||||||
@ -35,7 +46,16 @@ class="flex items-center gap-1 font-medium text-sm @if ($stat['trendUp']) text-g
|
|||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6 mt-8">
|
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 gap-6 mt-8">
|
||||||
<!-- 1. Today vs Yesterday Hourly Comparison -->
|
<!-- 1. Today vs Yesterday Hourly Comparison -->
|
||||||
<flux:card class="md:col-span-2 xl:col-span-2" wire:ignore>
|
<flux:card
|
||||||
|
class="relative md:col-span-2 xl:col-span-2 transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Grafik perbandingan jumlah transaksi tiap jam antara hari ini dan kemarin.">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Perbandingan Order per Jam (Hari Ini vs Kemarin)</flux:heading>
|
<flux:heading class="mb-4">Perbandingan Order per Jam (Hari Ini vs Kemarin)</flux:heading>
|
||||||
<div class="h-80">
|
<div class="h-80">
|
||||||
<canvas id="hourlyComparisonChart"></canvas>
|
<canvas id="hourlyComparisonChart"></canvas>
|
||||||
@ -43,7 +63,16 @@ class="flex items-center gap-1 font-medium text-sm @if ($stat['trendUp']) text-g
|
|||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 2. Today Category Distribution -->
|
<!-- 2. Today Category Distribution -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Pembagian pendapatan berdasarkan kategori produk (Parfum, Produk, Botol).">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Distribusi Penjualan</flux:heading>
|
<flux:heading class="mb-4">Distribusi Penjualan</flux:heading>
|
||||||
<div class="h-80 flex items-center justify-center">
|
<div class="h-80 flex items-center justify-center">
|
||||||
<canvas id="todayCategoryChart"></canvas>
|
<canvas id="todayCategoryChart"></canvas>
|
||||||
@ -51,7 +80,15 @@ class="flex items-center gap-1 font-medium text-sm @if ($stat['trendUp']) text-g
|
|||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 3. Today Payment Methods -->
|
<!-- 3. Today Payment Methods -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable content="Persentase penggunaan berbagai metode pembayaran oleh pelanggan.">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Metode Pembayaran</flux:heading>
|
<flux:heading class="mb-4">Metode Pembayaran</flux:heading>
|
||||||
<div class="h-80 flex items-center justify-center">
|
<div class="h-80 flex items-center justify-center">
|
||||||
<canvas id="todayPaymentChart"></canvas>
|
<canvas id="todayPaymentChart"></canvas>
|
||||||
@ -59,7 +96,16 @@ class="flex items-center gap-1 font-medium text-sm @if ($stat['trendUp']) text-g
|
|||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 4. Today Customer Type -->
|
<!-- 4. Today Customer Type -->
|
||||||
<flux:card wire:ignore>
|
<flux:card
|
||||||
|
class="relative transition-all duration-300 hover:scale-[1.01] hover:shadow-lg dark:hover:shadow-zinc-900/50"
|
||||||
|
wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Perbandingan jumlah transaksi antara pelanggan terdaftar (Member) dan pelanggan umum (Guest).">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Member vs Guest</flux:heading>
|
<flux:heading class="mb-4">Member vs Guest</flux:heading>
|
||||||
<div class="h-80 flex items-center justify-center">
|
<div class="h-80 flex items-center justify-center">
|
||||||
<canvas id="todayCustomerTypeChart"></canvas>
|
<canvas id="todayCustomerTypeChart"></canvas>
|
||||||
@ -67,7 +113,14 @@ class="flex items-center gap-1 font-medium text-sm @if ($stat['trendUp']) text-g
|
|||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 5. Today Top Selling Items -->
|
<!-- 5. Today Top Selling Items -->
|
||||||
<flux:card wire:ignore>
|
<flux:card class="relative" wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Lima produk dengan jumlah unit terjual terbanyak selama periode ini.">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">5 Item Terlaris</flux:heading>
|
<flux:heading class="mb-4">5 Item Terlaris</flux:heading>
|
||||||
<div class="h-80 flex items-center justify-center">
|
<div class="h-80 flex items-center justify-center">
|
||||||
<canvas id="todayTopSellingChart"></canvas>
|
<canvas id="todayTopSellingChart"></canvas>
|
||||||
@ -75,7 +128,14 @@ class="flex items-center gap-1 font-medium text-sm @if ($stat['trendUp']) text-g
|
|||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 6. Today Top Customers -->
|
<!-- 6. Today Top Customers -->
|
||||||
<flux:card wire:ignore>
|
<flux:card class="relative" wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Lima pelanggan dengan total nominal belanja tertinggi selama periode ini.">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Top 5 Pelanggan</flux:heading>
|
<flux:heading class="mb-4">Top 5 Pelanggan</flux:heading>
|
||||||
<div class="h-80 flex items-center justify-center">
|
<div class="h-80 flex items-center justify-center">
|
||||||
<canvas id="todayTopCustomersChart"></canvas>
|
<canvas id="todayTopCustomersChart"></canvas>
|
||||||
@ -83,7 +143,14 @@ class="flex items-center gap-1 font-medium text-sm @if ($stat['trendUp']) text-g
|
|||||||
</flux:card>
|
</flux:card>
|
||||||
|
|
||||||
<!-- 7. Today Discount Distribution -->
|
<!-- 7. Today Discount Distribution -->
|
||||||
<flux:card wire:ignore>
|
<flux:card class="relative" wire:ignore>
|
||||||
|
<div class="absolute top-3 right-3">
|
||||||
|
<flux:tooltip toggleable
|
||||||
|
content="Perbandingan jumlah transaksi antara pelanggan terdaftar (Member) dan pelanggan umum (Guest).">
|
||||||
|
<flux:button icon="exclamation-circle" variant="subtle" size="sm"
|
||||||
|
class="!p-1 border-none bg-transparent" />
|
||||||
|
</flux:tooltip>
|
||||||
|
</div>
|
||||||
<flux:heading class="mb-4">Normal vs Diskon</flux:heading>
|
<flux:heading class="mb-4">Normal vs Diskon</flux:heading>
|
||||||
<div class="h-80 flex items-center justify-center">
|
<div class="h-80 flex items-center justify-center">
|
||||||
<canvas id="todayDiscountChart"></canvas>
|
<canvas id="todayDiscountChart"></canvas>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user