Add role-aware dashboard stats and recent proposals

GetStatsAsync now returns global counts for admins/sysadmins instead of
filtering by submitter. Dashboard recent proposals query uses mine=false
for admins so they see all proposals, not just their own.
This commit is contained in:
Adam Moussa 2026-05-22 17:29:26 -04:00
parent edb557fb23
commit ef052a81ac
2 changed files with 12 additions and 7 deletions

View file

@ -376,10 +376,12 @@ public class ProposalService : IProposalService
public async Task<ProposalStatsResponse> GetStatsAsync(CancellationToken ct = default)
{
var userId = _currentUser.UserId;
var query = _db.Proposals.AsQueryable();
var counts = await _db.Proposals
.Where(p => p.SubmittedById == userId)
if (_currentUser.Role == UserRole.Dispatcher)
query = query.Where(p => p.SubmittedById == _currentUser.UserId);
var counts = await query
.GroupBy(_ => 1)
.Select(g => new
{

View file

@ -24,8 +24,9 @@ import SendIcon from '@mui/icons-material/Send';
import { proposalsApi, type ProposalListItem, type ProposalStats } from '../../lib/api/proposals';
import { QUERY_KEYS } from '../../constants/queryKeys';
import { STATUS_COLORS, STATUS_LABELS, PRIORITY_ROW_SX } from '../../constants';
import { formatCurrency, formatDate } from '../../lib/format';
import { formatBidAmount, formatDate } from '../../lib/format';
import { useDocumentTitle } from '../../hooks/useDocumentTitle';
import { useAuth } from '../../hooks/useAuth';
function KpiCard({ icon, label, value }: { icon: React.ReactNode; label: string; value: string }) {
return (
@ -46,10 +47,12 @@ function KpiCard({ icon, label, value }: { icon: React.ReactNode; label: string;
export default function Dashboard() {
useDocumentTitle('Dashboard');
const navigate = useNavigate();
const { user } = useAuth();
const isAdmin = user?.role === 'Admin' || user?.role === 'SysAdmin';
const { data: recentData, isLoading: recentLoading, error: recentError } = useQuery<{ items: ProposalListItem[]; totalCount: number }>({
queryKey: [QUERY_KEYS.proposals, 'dashboard-recent'],
queryFn: () => proposalsApi.getAll({ page: 1, pageSize: 5, mine: true }),
queryKey: [QUERY_KEYS.proposals, 'dashboard-recent', isAdmin],
queryFn: () => proposalsApi.getAll({ page: 1, pageSize: 5, mine: !isAdmin }),
});
const { data: stats, isLoading: statsLoading } = useQuery<ProposalStats>({
@ -153,7 +156,7 @@ export default function Dashboard() {
<TableCell>
<Chip label={STATUS_LABELS[row.status] || row.status} size="small" color={STATUS_COLORS[row.status] || 'default'} />
</TableCell>
<TableCell align="right">{formatCurrency(row.totalBidAmount)}</TableCell>
<TableCell align="right">{formatBidAmount(row.totalBidAmount)}</TableCell>
<TableCell>{formatDate(row.submittedAt)}</TableCell>
</TableRow>
))}