feature(deals by category pie chart):
- add a pie chart that shows deals by category - change UI to make it more clear
This commit is contained in:
parent
1edfd7b9d4
commit
d7c06c38a6
@ -4,6 +4,8 @@
|
||||
|
||||
use App\Enums\UserTypes;
|
||||
use App\Http\Resources\ActiveUsersStatsCollection;
|
||||
use App\Http\Resources\DealsCountByCategoryCollection;
|
||||
use App\Models\DealCategory;
|
||||
use App\Queries\PageVisitStatsQuery;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
@ -22,4 +24,13 @@ public function getActiveUsers(Request $request, PageVisitStatsQuery $baseQuery)
|
||||
'activeBrokers' => new ActiveUsersStatsCollection($activeBrokers),
|
||||
]);
|
||||
}
|
||||
|
||||
public function getDealsByCategory()
|
||||
{
|
||||
return new DealsCountByCategoryCollection(
|
||||
DealCategory::select(['id', 'name'])
|
||||
->withCount('deals')
|
||||
->get()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
16
app/Http/Resources/DealsCountByCategoryCollection.php
Normal file
16
app/Http/Resources/DealsCountByCategoryCollection.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||
|
||||
class DealsCountByCategoryCollection extends ResourceCollection
|
||||
{
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'data' => $this->collection,
|
||||
];
|
||||
}
|
||||
}
|
||||
17
app/Http/Resources/DealsCountByCategoryResource.php
Normal file
17
app/Http/Resources/DealsCountByCategoryResource.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class DealsCountByCategoryResource extends JsonResource
|
||||
{
|
||||
public function toArray(Request $request): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->name,
|
||||
'dealsCount' => $this->deals_count,
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
<div id="active-users-chart-parent" class="col-span-2">
|
||||
<x-dashboard.card data-is-loading="false" class="h-75">
|
||||
<x-dashboard.card class="h-75">
|
||||
<div class="flex justify-between items-baseline">
|
||||
<h3 class="text-md font-bold mb-4">User Activity</h3>
|
||||
<x-ui.toggle-button-group class="mb-4">
|
||||
<x-ui.toggle-button :active="request('sortBy') == null">
|
||||
<button onclick="switchGraph(this, 30)" class="graphBtn flex items-center px-2 space-x-2">
|
||||
@ -14,22 +16,41 @@
|
||||
</x-ui.toggle-button>
|
||||
|
||||
<x-ui.toggle-button>
|
||||
<button class="flex items-center pt-0.5 px-4 space-x-2">
|
||||
<button id="dateRange" class="flex items-center pt-0.5 px-4 space-x-2">
|
||||
<x-heroicon-o-calendar-date-range class="w-4"/>
|
||||
</button>
|
||||
</x-ui.toggle-button>
|
||||
</x-ui.toggle-button-group>
|
||||
</div>
|
||||
|
||||
<div class="h-50">
|
||||
<div data-is-loading="false" class="h-50">
|
||||
<canvas id="active-users-chart"></canvas>
|
||||
</div>
|
||||
</x-dashboard.card>
|
||||
</div>
|
||||
@push('scripts')
|
||||
<script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
|
||||
|
||||
<script>
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
// BY default load 30 days data
|
||||
|
||||
flatpickr("#dateRange", {
|
||||
mode: "range",
|
||||
dateFormat: "Y-m-d",
|
||||
onClose: function (selectedDates) {
|
||||
if (selectedDates.length === 2) {
|
||||
const start = selectedDates[0].toISOString().split('T')[0];
|
||||
const end = selectedDates[1].toISOString().split('T')[0];
|
||||
|
||||
activeBtn(document.getElementById('dateRange'));
|
||||
|
||||
generateActiveUsersChart(start, end);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// By default load 30 days data
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setDate(end.getDate() - 30);
|
||||
|
||||
@ -1,37 +1,32 @@
|
||||
<x-dashboard.card class="col-span-1 h-75">
|
||||
<div id="deals-pie-chart-parent" class="col-span-1">
|
||||
<x-dashboard.card class="col-span-1 h-75">
|
||||
<h3 class="text-md font-bold mb-4">Deals by category</h3>
|
||||
<div data-is-loading="false" class="h-55">
|
||||
<canvas id="category-wise-deals-pie-chart"></canvas>
|
||||
</x-dashboard.card>
|
||||
</div>
|
||||
</x-dashboard.card>
|
||||
</div>
|
||||
@push('scripts')
|
||||
<script async>
|
||||
window.addEventListener('DOMContentLoaded', async () => {
|
||||
const dealsPieChart = document.getElementById('category-wise-deals-pie-chart');
|
||||
const dealsPieChartParent = document.getElementById('deals-pie-chart-parent');
|
||||
|
||||
if (!dealsPieChart || !dealsPieChartParent) {
|
||||
console.error('canvas not defined');
|
||||
return;
|
||||
}
|
||||
toggleShimmer(false, dealsPieChartParent);
|
||||
try {
|
||||
// const response = await axios.get('/api/stats/customer/active/30');
|
||||
// const apiData = response.data.data;
|
||||
const {data: apiData} = await axios.get('/api/stats/deals-by-category');
|
||||
|
||||
|
||||
// Fill the data from api response
|
||||
// const chartData = labels.map((date) => {
|
||||
// let found = apiData.find(item => item.date === date);
|
||||
// return found ? found.userCount : 0;
|
||||
// })
|
||||
const categories = apiData?.data.map((item) => item?.name);
|
||||
const dealsCounts = apiData?.data.map((item) => item?.dealsCount);
|
||||
|
||||
const data = {
|
||||
labels: [
|
||||
'Real Estate',
|
||||
'Food',
|
||||
'Sell & Deal',
|
||||
'Palaces'
|
||||
],
|
||||
labels: categories,
|
||||
datasets: [{
|
||||
label: 'My First Dataset',
|
||||
data: [30, 20, 15, 5],
|
||||
backgroundColor: [
|
||||
'rgb(255, 99, 132)',
|
||||
'rgb(54, 162, 235)',
|
||||
'rgb(255, 205, 86)',
|
||||
'rgb(99,102,255)',
|
||||
],
|
||||
data: dealsCounts,
|
||||
hoverOffset: 4
|
||||
}]
|
||||
};
|
||||
@ -42,10 +37,15 @@
|
||||
options: {
|
||||
maintainAspectRatio: false,
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'bottom',
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const chart = new Chart(dealsPieChart, config);
|
||||
// toggleShimmer(false, activeChartParent);
|
||||
toggleShimmer(true, dealsPieChartParent);
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
@ -19,6 +19,8 @@
|
||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||
<link href="https://fonts.bunny.net/css?family=instrument-sans:400,500,600" rel="stylesheet"/>
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
|
||||
|
||||
<!-- Styles / Scripts -->
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
|
||||
|
||||
@ -4,4 +4,5 @@
|
||||
|
||||
Route::prefix('/stats')->group(function () {
|
||||
Route::get('/active-users', [StatsController::class, 'getActiveUsers']);
|
||||
Route::get('/deals-by-category', [StatsController::class, 'getDealsByCategory'])->name('stats.deals-by-category');
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user