Overview v1
This commit is contained in:
parent
9ee76a0742
commit
b0b177c6d8
@ -1,14 +1,17 @@
|
||||
import * as icon from '@mdi/js';
|
||||
import Head from 'next/head'
|
||||
import React from 'react'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import type { ReactElement } from 'react'
|
||||
import LayoutAuthenticated from '../layouts/Authenticated'
|
||||
import SectionMain from '../components/SectionMain'
|
||||
import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton'
|
||||
import { getPageTitle } from '../config'
|
||||
import { useAppSelector, useAppDispatch } from '../stores/hooks';
|
||||
|
||||
|
||||
import axios from 'axios';
|
||||
import CardBox from '../components/CardBox';
|
||||
import BaseIcon from '../components/BaseIcon';
|
||||
import { mdiAccountMultiple, mdiCartOutline, mdiCalendarCheck } from '@mdi/js';
|
||||
import ChartLineSample from '../components/ChartLineSample/index';
|
||||
|
||||
const Dashboard = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
@ -16,16 +19,89 @@ const Dashboard = () => {
|
||||
const corners = useAppSelector((state) => state.style.corners);
|
||||
const cardsStyle = useAppSelector((state) => state.style.cardsStyle);
|
||||
|
||||
const [stats, setStats] = useState({
|
||||
customers: 0,
|
||||
menuItems: 0,
|
||||
reservations: 0,
|
||||
});
|
||||
const [chartData, setChartData] = useState(null);
|
||||
const [recentReservations, setRecentReservations] = useState([]);
|
||||
const [lowStockItems, setLowStockItems] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const loadData = async () => {
|
||||
try {
|
||||
const statsPromises = [
|
||||
axios.get('/customers', { params: { limit: 1 } }),
|
||||
axios.get('/menu_items', { params: { limit: 1 } }),
|
||||
axios.get('/reservations', { params: { limit: 1 } }),
|
||||
];
|
||||
|
||||
const chartPromise = axios.get('/payments');
|
||||
const reservationsPromise = axios.get('/reservations?limit=5&orderBy=createdAt_DESC');
|
||||
const inventoryPromise = axios.get('/inventory_items');
|
||||
|
||||
const [customersResponse, menuItemsResponse, reservationsResponse] = await Promise.all(statsPromises);
|
||||
|
||||
setStats({
|
||||
customers: customersResponse.data.count,
|
||||
menuItems: menuItemsResponse.data.count,
|
||||
reservations: reservationsResponse.data.count,
|
||||
});
|
||||
|
||||
const chartResponse = await chartPromise;
|
||||
const payments = chartResponse.data.rows;
|
||||
|
||||
if (payments) {
|
||||
const groupedData = payments.reduce((acc, payment) => {
|
||||
const date = new Date(payment.paid_at).toLocaleDateString();
|
||||
if (!acc[date]) {
|
||||
acc[date] = 0;
|
||||
}
|
||||
acc[date] += parseFloat(payment.amount);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const labels = Object.keys(groupedData);
|
||||
const data = Object.values(groupedData);
|
||||
|
||||
setChartData({
|
||||
labels,
|
||||
datasets: [
|
||||
{
|
||||
label: 'Revenue',
|
||||
data,
|
||||
fill: true,
|
||||
borderColor: '#4A5568',
|
||||
backgroundColor: '#4A556820',
|
||||
tension: 0.2,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
const recentReservationsResponse = await reservationsPromise;
|
||||
setRecentReservations(recentReservationsResponse.data.rows);
|
||||
|
||||
const inventoryResponse = await inventoryPromise;
|
||||
const inventoryItems = inventoryResponse.data.rows;
|
||||
if (inventoryItems) {
|
||||
const lowStock = inventoryItems.filter(
|
||||
(item) => item.quantity <= (item.reorder_level || 10)
|
||||
);
|
||||
setLowStockItems(lowStock);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to load dashboard data', error);
|
||||
}
|
||||
};
|
||||
|
||||
loadData();
|
||||
}, []);
|
||||
|
||||
const { currentUser } = useAppSelector((state) => state.auth);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
@ -40,6 +116,55 @@ const Dashboard = () => {
|
||||
main>
|
||||
{''}
|
||||
</SectionTitleLineWithButton>
|
||||
|
||||
<div className="grid grid-cols-1 gap-6 lg:grid-cols-3 mb-6">
|
||||
<CardBox
|
||||
title="Clients"
|
||||
number={stats.customers}
|
||||
icon={<BaseIcon path={mdiAccountMultiple} w="24" h="24" />}
|
||||
/>
|
||||
<CardBox
|
||||
title="Menu Items"
|
||||
number={stats.menuItems}
|
||||
icon={<BaseIcon path={mdiCartOutline} w="24" h="24" />}
|
||||
/>
|
||||
<CardBox
|
||||
title="Reservations"
|
||||
number={stats.reservations}
|
||||
icon={<BaseIcon path={mdiCalendarCheck} w="24" h="24" />}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{chartData && (
|
||||
<CardBox className="mb-6">
|
||||
<ChartLineSample data={chartData} />
|
||||
</CardBox>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
||||
<CardBox>
|
||||
<h2 className="text-xl font-semibold mb-4">Recent Reservations</h2>
|
||||
<ul>
|
||||
{recentReservations.map((reservation) => (
|
||||
<li key={reservation.id} className="flex justify-between items-center py-2 border-b">
|
||||
<span>{reservation.code}</span>
|
||||
<span>{new Date(reservation.start_at).toLocaleString()}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardBox>
|
||||
<CardBox>
|
||||
<h2 className="text-xl font-semibold mb-4">Low Stock Items</h2>
|
||||
<ul>
|
||||
{lowStockItems.map((item) => (
|
||||
<li key={item.id} className="flex justify-between items-center py-2 border-b">
|
||||
<span>{item.name}</span>
|
||||
<span className="text-red-500">{item.quantity}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardBox>
|
||||
</div>
|
||||
</SectionMain>
|
||||
</>
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user