first commit
This commit is contained in:
83
src/app/(workspace)/staff/page.tsx
Normal file
83
src/app/(workspace)/staff/page.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
'use client';
|
||||
|
||||
import {VStack} from '@astryxdesign/core/Layout';
|
||||
import {Grid} from '@astryxdesign/core/Grid';
|
||||
import {PageHeader} from '@/components/primitives/PageHeader';
|
||||
import {ChartCard} from '@/components/charts/ChartCard';
|
||||
import {BarChartView} from '@/components/charts/BarChartView';
|
||||
import {StaffKpis} from '@/features/staff/StaffKpis';
|
||||
import {StaffGrid} from '@/features/staff/StaffGrid';
|
||||
import {AttendanceChart} from '@/features/staff/AttendanceChart';
|
||||
import {Leaderboard} from '@/features/staff/Leaderboard';
|
||||
import {useResource} from '@/lib/api/useResource';
|
||||
import {endpoints} from '@/lib/api/client';
|
||||
import {useWorkspace} from '@/components/shell/WorkspaceProvider';
|
||||
import {storeName} from '@/lib/mock/stores';
|
||||
import {formatCompact} from '@/lib/format';
|
||||
|
||||
/**
|
||||
* The team.
|
||||
*
|
||||
* Ordered attendance-first: the question that brings a merchant here in the
|
||||
* morning is "who is in today", and only then "who is performing".
|
||||
*/
|
||||
export default function StaffPage() {
|
||||
const {storeId, range} = useWorkspace();
|
||||
const scope = {range, storeId};
|
||||
|
||||
const summary = useResource(endpoints.staffSummary(scope), {
|
||||
// A summary object is never "empty" the way a list is — zero present is
|
||||
// a real answer, not an absence of data.
|
||||
isEmpty: () => false,
|
||||
});
|
||||
const staff = useResource(endpoints.staff(scope));
|
||||
const attendance = useResource(endpoints.staffAttendance(scope));
|
||||
|
||||
const scopeLabel = storeId === 'all' ? 'all stores' : storeName(storeId);
|
||||
|
||||
return (
|
||||
<VStack gap={5}>
|
||||
<PageHeader
|
||||
title="Staff"
|
||||
description={`Attendance, sales contribution and performance across ${scopeLabel}.`}
|
||||
/>
|
||||
|
||||
<StaffKpis resource={summary} />
|
||||
|
||||
<Grid columns={{minWidth: 360, max: 2, repeat: 'fit'}} gap={4}>
|
||||
<AttendanceChart resource={attendance} />
|
||||
|
||||
<ChartCard
|
||||
title="Sales by team member"
|
||||
subtitle="Top 8 by transactions in the selected period"
|
||||
resource={staff}
|
||||
>
|
||||
{(rows) => (
|
||||
<BarChartView
|
||||
data={[...rows]
|
||||
.sort((a, b) => b.salesCount - a.salesCount)
|
||||
.slice(0, 8)
|
||||
.map((m) => ({
|
||||
// First name only — full names overflow the axis at this
|
||||
// width and the leaderboard below carries the detail.
|
||||
name: m.name.split(' ')[0],
|
||||
sales: m.salesCount,
|
||||
rewards: m.rewardsIssued,
|
||||
}))}
|
||||
xKey="name"
|
||||
yFormat={formatCompact}
|
||||
series={[
|
||||
{key: 'sales', label: 'Sales'},
|
||||
{key: 'rewards', label: 'Rewards issued'},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</ChartCard>
|
||||
</Grid>
|
||||
|
||||
<Leaderboard resource={staff} />
|
||||
|
||||
<StaffGrid resource={staff} />
|
||||
</VStack>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user