✨ Split out stats into multiple sub views

This commit is contained in:
nikolark committed 2022-02-19 17:21:44 +01:00
1 parent 158f5c5652
commit 2e5fbb6fa6
7 files changed
+171 -109

No files matched your search

+4
View File
@@ -5,6 +5,8 @@ import { UserCreate } from "./features/auth/UserCreate";
import { Deposit } from "./features/deposit/Deposit";
import { Log } from "./features/log/Log";
import { Register } from "./features/register/Register";
import { OrderStats } from "./features/stats/OrderStats";
import { ProductStats } from "./features/stats/ProductStats";
import { Stats } from "./features/stats/Stats";
import { UserDetail } from "./features/users/UserDetail";
import { UserList } from "./features/users/UserList";
@@ -14,6 +16,8 @@ export const Routes: React.FC = () => (
<Route path="/deposit" element={<Deposit />} />
<Route path="/log" element={<Log />} />
<Route path="/stats" element={<Stats />} />
<Route path="/stats/orders" element={<OrderStats />} />
<Route path="/stats/products" element={<ProductStats />} />
<Route path="/users" element={<UserList />} />
<Route path="/user/create" element={<UserCreate />} />
<Route path="/user/:userId" element={<UserDetail />} />
@@ -0,0 +1,79 @@
import { useQuery } from "@apollo/client";
import { Bar, BarDatum } from "@nivo/bar";
import React from "react";
import { OrderStatsDocument, OrderStatsByTime } from "../../types";
import { StatsView } from "./StatsView";
const days = { 1: "Mandag", 2: "Tirsdag", 3: "Onsdag", 4: "Torsdag", 5: "Fredag", 6: "Lørdag", 7: "Søndag" };
const months = {
1: "Januar",
2: "Februar",
3: "Mars",
4: "April",
5: "Mai",
6: "Juni",
7: "Juli",
8: "August",
9: "September",
10: "Oktober",
11: "November",
12: "Desember",
};
const OrderBar = ({ data }: { data: BarDatum[] }) => (
<Bar
data={data}
margin={{ left: 60, bottom: 40 }}
width={1200}
height={400}
colorBy="indexValue"
enableLabel={false}
tooltipLabel={(d) => d.id.toString()}
axisLeft={{ legend: "Ordre", legendPosition: "middle", legendOffset: -50 }}
/>
);
export const OrderStats = () => {
const { data, loading } = useQuery(OrderStatsDocument);
return (
<StatsView loading={loading}>
<h3>Ordre per time</h3>
<OrderBar
data={(data?.orderStats?.hourly || []).map((stat: OrderStatsByTime) => ({
id: `${stat.period.toString().padStart(2, "0")}:00`,
label: stat.period,
value: stat.count,
}))}
/>
<h3>Ordre per ukedag</h3>
<OrderBar
data={(data?.orderStats?.daily || []).map((stat: OrderStatsByTime) => ({
/* @ts-expect-error Here, stat.period can only be a key in days range. */
id: days[stat.period],
label: stat.period,
value: stat.count,
}))}
/>
<h3>Ordre per måned</h3>
<OrderBar
data={(data?.orderStats?.monthly || []).map((stat: OrderStatsByTime) => ({
/* @ts-expect-error Here, stat.period can only be a key in months range. */
id: months[stat.period],
label: stat.period,
value: stat.count,
}))}
/>
<h3>Ordre per år</h3>
<OrderBar
data={(data?.orderStats?.yearly || []).map((stat: OrderStatsByTime) => ({
id: stat.period,
label: stat.period,
value: stat.count,
}))}
/>
</StatsView>
);
};
@@ -0,0 +1,40 @@
import { useQuery } from "@apollo/client";
import { Pie } from "@nivo/pie";
import React from "react";
import { ProductStatsDocument } from "../../types";
import styles from "./Stats.module.css";
import { StatsView } from "./StatsView";
type UserCount = {
name: string;
count: number;
};
export const ProductStats = () => {
const { data, loading } = useQuery(ProductStatsDocument, {
variables: { active: true },
});
return (
<StatsView loading={loading}>
<div className={styles.products}>
{(data?.allProducts || []).map((product) => (
<div key={product.id}>
{product.name}
<Pie
margin={{ top: 40, right: 120, bottom: 40, left: 120 }}
data={product.userCounts.map((uc: UserCount) => ({
id: uc.name,
label: uc.name,
value: uc.count,
}))}
width={400}
height={300}
/>
</div>
))}
</div>
</StatsView>
);
};
@@ -4,3 +4,6 @@
gap: 1rem;
grid-template-columns: repeat(3, 1fr);
}
.statsNav {
margin-bottom: 1rem;
}
+3 -108
View File
@@ -1,113 +1,8 @@
import { useQuery } from "@apollo/client";
import { Bar, BarDatum } from "@nivo/bar";
import { Pie } from "@nivo/pie";
import React from "react";
import { OrderStatsDocument, ProductStatsDocument, OrderStatsByTime } from "../../types";
import styles from "./Stats.module.css";
type UserCount = {
name: string;
count: number;
};
const days = { 1: "Mandag", 2: "Tirsdag", 3: "Onsdag", 4: "Torsdag", 5: "Fredag", 6: "Lørdag", 7: "Søndag" };
const months = {
1: "Januar",
2: "Februar",
3: "Mars",
4: "April",
5: "Mai",
6: "Juni",
7: "Juli",
8: "August",
9: "September",
10: "Oktober",
11: "November",
12: "Desember",
};
const OrderBar = ({ data }: { data: BarDatum[] }) => (
<Bar
data={data}
margin={{ left: 60, bottom: 40 }}
width={1200}
height={400}
colorBy="indexValue"
enableLabel={false}
tooltipLabel={(d) => d.id.toString()}
axisLeft={{ legend: "Ordre", legendPosition: "middle", legendOffset: -50 }}
/>
);
import { StatsView } from "./StatsView";
export const Stats = () => {
const { data: productData, loading: productLoading } = useQuery(ProductStatsDocument, {
variables: { active: true },
});
const { data: orderData, loading: orderLoading } = useQuery(OrderStatsDocument);
const loading = false;
const loading = orderLoading || productLoading;
if (loading) {
return <div>Loading...</div>;
}
return (
<div className={styles.stats}>
<h2>Stats</h2>
<h3>Produkter</h3>
<div className={styles.products}>
{(productData?.allProducts || []).map((product) => (
<div key={product.id}>
{product.name}
<Pie
margin={{ top: 40, right: 120, bottom: 40, left: 120 }}
data={product.userCounts.map((uc: UserCount) => ({
id: uc.name,
label: uc.name,
value: uc.count,
}))}
width={400}
height={300}
/>
</div>
))}
</div>
<h3>Ordre per time</h3>
<OrderBar
data={(orderData?.orderStats?.hourly || []).map((stat: OrderStatsByTime) => ({
id: `${stat.period.toString().padStart(2, "0")}:00`,
label: stat.period,
value: stat.count,
}))}
/>
<h3>Ordre per ukedag</h3>
<OrderBar
data={(orderData?.orderStats?.daily || []).map((stat: OrderStatsByTime) => ({
/* @ts-expect-error Here, stat.period can only be a key in days range. */
id: days[stat.period],
label: stat.period,
value: stat.count,
}))}
/>
<h3>Ordre per måned</h3>
<OrderBar
data={(orderData?.orderStats?.monthly || []).map((stat: OrderStatsByTime) => ({
/* @ts-expect-error Here, stat.period can only be a key in months range. */
id: months[stat.period],
label: stat.period,
value: stat.count,
}))}
/>
<h3>Ordre per år</h3>
<OrderBar
data={(orderData?.orderStats?.yearly || []).map((stat: OrderStatsByTime) => ({
id: stat.period,
label: stat.period,
value: stat.count,
}))}
/>
</div>
);
return <StatsView loading={loading}>TODO</StatsView>;
};
+41
View File
@@ -0,0 +1,41 @@
import React from "react";
import { NavLink } from "react-router-dom";
import styles from "./Stats.module.css";
const navLinkStyles = ({ isActive }: { isActive: boolean }) => (isActive ? "nav-link active" : "nav-link");
export const StatsNav = () => (
<div className={styles.statsNav}>
<ul className="nav nav-tabs">
<li className="nav-item">
<NavLink className={navLinkStyles} to="/stats" end>
Oversikt
</NavLink>
</li>
<li className="nav-item">
<NavLink className={navLinkStyles} to="/stats/products">
Produkter
</NavLink>
</li>
<li className="nav-item">
<NavLink className={navLinkStyles} to="/stats/orders">
Ordre
</NavLink>
</li>
<li className="nav-item">
<NavLink className="nav-link disabled" to="/stats/users" title="TODO">
Folk
</NavLink>
</li>
</ul>
</div>
);
export const StatsView = ({ children, loading }: { children: React.ReactNode; loading: boolean }) => (
<div className={styles.stats}>
<h2>Statistikk</h2>
<StatsNav />
{loading && <div>Loading...</div>}
{!loading && children}
</div>
);