fix(ui): wrap RoleRoutes in ProtectedRoute settings.roles, add trailing star to dashboard route, and use dynamic tenant counts in Dashboard and CategoryList
This commit is contained in:
@@ -33,10 +33,10 @@ export default function CategoryList() {
|
||||
}, [fetchCategories]);
|
||||
|
||||
const stats = {
|
||||
total: categories.length || 0,
|
||||
active: categories.filter((c) => c.status === "active").length,
|
||||
products: 33008,
|
||||
families: 406,
|
||||
total: categories.length || 0,
|
||||
active: categories.filter((c) => c.status === "active").length,
|
||||
products: categories.reduce((sum, c) => sum + (Number(c.productCount) || 0), 0),
|
||||
families: categories.reduce((sum, c) => sum + (Number(c.familyCount) || 0), 0),
|
||||
};
|
||||
|
||||
const handleDeleteConfirm = async () => {
|
||||
|
||||
@@ -61,45 +61,67 @@ const recentActivity = [
|
||||
|
||||
|
||||
// ── Dashboard Component ───────────────────────────────────────────────────────
|
||||
import { useEffect, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { productsApi } from "../../products/api/products.api";
|
||||
import { channelsApi } from "../../channels/api/channels.api";
|
||||
|
||||
export default function Dashboard() {
|
||||
const user = useSelector((state: any) => state.auth?.user);
|
||||
const [productCount, setProductCount] = useState<number>(0);
|
||||
const [channelCount, setChannelCount] = useState<number>(0);
|
||||
const [publishedCount, setPublishedCount] = useState<number>(0);
|
||||
|
||||
useEffect(() => {
|
||||
async function loadStats() {
|
||||
try {
|
||||
const [products, channels] = await Promise.all([
|
||||
productsApi.getAll().catch(() => []),
|
||||
channelsApi.getAll().catch(() => [])
|
||||
]);
|
||||
setProductCount(products.length || 0);
|
||||
setPublishedCount(products.filter((p: any) => p.status === 'published' || p.status === 'active').length || 0);
|
||||
setChannelCount(channels.length || 0);
|
||||
} catch {
|
||||
// handled
|
||||
}
|
||||
}
|
||||
loadStats();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PageWrapper>
|
||||
<div className="mb-6">
|
||||
<h2 className="text-xl font-bold text-foreground mb-1">Welcome back, John</h2>
|
||||
<h2 className="text-xl font-bold text-foreground mb-1">
|
||||
Welcome back, {user?.first_name || user?.username || 'Tenant Administrator'}
|
||||
</h2>
|
||||
<p className="text-sm text-muted-foreground">Here's what's happening with your product catalog today.</p>
|
||||
</div>
|
||||
|
||||
|
||||
{/* KPI InfoCards */}
|
||||
<InfoCardGrid cols={4} className="mb-6">
|
||||
<InfoCard
|
||||
label="Total Products"
|
||||
value="12,459"
|
||||
value={productCount.toLocaleString()}
|
||||
icon={<Box className="w-5 h-5 text-primary-light" />}
|
||||
trend="+12.5%"
|
||||
trendDirection="up"
|
||||
subtitle="vs. last month"
|
||||
subtitle="Tenant Workspace Total"
|
||||
/>
|
||||
<InfoCard
|
||||
label="Pending Approvals"
|
||||
value="8"
|
||||
value="0"
|
||||
icon={<AlertCircle className="w-5 h-5 text-primary-light" />}
|
||||
subtitle="Requires attention"
|
||||
/>
|
||||
<InfoCard
|
||||
label="Published This Month"
|
||||
value="2,380"
|
||||
label="Published Products"
|
||||
value={publishedCount.toLocaleString()}
|
||||
icon={<CheckCircle2 className="w-5 h-5 text-primary-light" />}
|
||||
trend="+18.2%"
|
||||
trendDirection="up"
|
||||
subtitle="vs. last month"
|
||||
subtitle="Ready for syndication"
|
||||
/>
|
||||
<InfoCard
|
||||
label="Active Channels"
|
||||
value="24"
|
||||
value={channelCount.toLocaleString()}
|
||||
icon={<Radio className="w-5 h-5 text-primary-light" />}
|
||||
trend="+4.3%"
|
||||
trendDirection="up"
|
||||
subtitle="Publishing enabled"
|
||||
/>
|
||||
</InfoCardGrid>
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { Routes, Route } from 'react-router-dom';
|
||||
import RoleList from '../pages/RoleList';
|
||||
import NewRoleForm from '../pages/NewRoleForm';
|
||||
import { ProtectedRoute } from '../../../components/layouts/ProtectedRoute';
|
||||
|
||||
export const RoleRoutes = () => {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/" element={<RoleList />} />
|
||||
<Route path="/new" element={<NewRoleForm />} />
|
||||
<Route path="/:id/edit" element={<NewRoleForm />} />
|
||||
</Routes>
|
||||
<ProtectedRoute node="settings.roles">
|
||||
<Routes>
|
||||
<Route path="/" element={<RoleList />} />
|
||||
<Route path="/new" element={<NewRoleForm />} />
|
||||
<Route path="/:id/edit" element={<NewRoleForm />} />
|
||||
</Routes>
|
||||
</ProtectedRoute>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -54,7 +54,7 @@ const AppRoutes = () => {
|
||||
<Route path="/platform/overview" element={<PlatformGuard><PlatformOverview /></PlatformGuard>} />
|
||||
<Route path="/platform/tenants" element={<PlatformGuard><PlatformTenantsPage /></PlatformGuard>} />
|
||||
|
||||
<Route path="/dashboard" element={<DashboardRoutes />} />
|
||||
<Route path="/dashboard/*" element={<DashboardRoutes />} />
|
||||
|
||||
{/* Catalog */}
|
||||
<Route path="/products/*" element={<ProductRoutes />} />
|
||||
|
||||
Reference in New Issue
Block a user