feat: Fix invite-codes page with AdminGuard and UI improvements
Some checks failed
ParentFlow CI/CD Pipeline / Backend Tests (push) Has been cancelled
ParentFlow CI/CD Pipeline / Frontend Tests (push) Has been cancelled
ParentFlow CI/CD Pipeline / Security Scanning (push) Has been cancelled
CI/CD Pipeline / Lint and Test (push) Has been cancelled
CI/CD Pipeline / E2E Tests (push) Has been cancelled
CI/CD Pipeline / Build Application (push) Has been cancelled
ParentFlow CI/CD Pipeline / Build Docker Images (map[context:maternal-app/maternal-app-backend dockerfile:Dockerfile.production name:backend]) (push) Has been cancelled
ParentFlow CI/CD Pipeline / Build Docker Images (map[context:maternal-web dockerfile:Dockerfile.production name:frontend]) (push) Has been cancelled
ParentFlow CI/CD Pipeline / Deploy to Development (push) Has been cancelled
ParentFlow CI/CD Pipeline / Deploy to Production (push) Has been cancelled

Backend changes:
- Added AdminGuard to InviteCodesController for authentication
- Added PATCH endpoint alongside PUT for invite code updates
- Secured all admin invite code endpoints

Frontend changes:
- Removed deprecated MUI Grid v1, replaced with CSS Grid
- Added thousand separators to all numbers (total codes, uses, etc.)
- Removed Grid import (no longer used)
- Applied .toLocaleString() to stats cards and DataGrid uses column
- Fixed responsive layout with CSS Grid breakpoints
This commit is contained in:
Andrei
2025-10-08 09:08:57 +00:00
parent 7d0d199e64
commit 45150860ce
2 changed files with 45 additions and 46 deletions

View File

@@ -17,7 +17,6 @@ import {
Switch,
Alert,
Tooltip,
Grid,
} from '@mui/material';
import { DataGrid, GridColDef } from '@mui/x-data-grid';
import {
@@ -178,7 +177,7 @@ export default function InviteCodesPage() {
width: 100,
renderCell: (params) => (
<Typography variant="body2">
{params.value} / {params.row.maxUses || '∞'}
{params.value.toLocaleString()} / {params.row.maxUses?.toLocaleString() || '∞'}
</Typography>
),
},
@@ -255,50 +254,42 @@ export default function InviteCodesPage() {
</Box>
</Box>
<Grid container spacing={3} sx={{ mb: 3 }}>
<Grid item xs={12} sm={6} md={3}>
<Paper sx={{ p: 2 }}>
<Typography variant="body2" color="text.secondary" gutterBottom>
Total Codes
</Typography>
<Typography variant="h4">{inviteCodes.length}</Typography>
</Paper>
</Grid>
<Grid item xs={12} sm={6} md={3}>
<Paper sx={{ p: 2 }}>
<Typography variant="body2" color="text.secondary" gutterBottom>
Active Codes
</Typography>
<Typography variant="h4">
{inviteCodes.filter(c => c.isActive).length}
</Typography>
</Paper>
</Grid>
<Grid item xs={12} sm={6} md={3}>
<Paper sx={{ p: 2 }}>
<Typography variant="body2" color="text.secondary" gutterBottom>
Total Uses
</Typography>
<Typography variant="h4">
{inviteCodes.reduce((sum, c) => sum + c.uses, 0)}
</Typography>
</Paper>
</Grid>
<Grid item xs={12} sm={6} md={3}>
<Paper sx={{ p: 2 }}>
<Typography variant="body2" color="text.secondary" gutterBottom>
Available
</Typography>
<Typography variant="h4">
{inviteCodes.filter(c => {
const isExpired = c.expiresAt && new Date(c.expiresAt) < new Date();
const isMaxedOut = c.maxUses && c.uses >= c.maxUses;
return c.isActive && !isExpired && !isMaxedOut;
}).length}
</Typography>
</Paper>
</Grid>
</Grid>
<Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: 3, mb: 3 }}>
<Paper sx={{ p: 2 }}>
<Typography variant="body2" color="text.secondary" gutterBottom>
Total Codes
</Typography>
<Typography variant="h4">{inviteCodes.length.toLocaleString()}</Typography>
</Paper>
<Paper sx={{ p: 2 }}>
<Typography variant="body2" color="text.secondary" gutterBottom>
Active Codes
</Typography>
<Typography variant="h4">
{inviteCodes.filter(c => c.isActive).length.toLocaleString()}
</Typography>
</Paper>
<Paper sx={{ p: 2 }}>
<Typography variant="body2" color="text.secondary" gutterBottom>
Total Uses
</Typography>
<Typography variant="h4">
{inviteCodes.reduce((sum, c) => sum + c.uses, 0).toLocaleString()}
</Typography>
</Paper>
<Paper sx={{ p: 2 }}>
<Typography variant="body2" color="text.secondary" gutterBottom>
Available
</Typography>
<Typography variant="h4">
{inviteCodes.filter(c => {
const isExpired = c.expiresAt && new Date(c.expiresAt) < new Date();
const isMaxedOut = c.maxUses && c.uses >= c.maxUses;
return c.isActive && !isExpired && !isMaxedOut;
}).length.toLocaleString()}
</Typography>
</Paper>
</Box>
<Paper sx={{ p: 2 }}>
<DataGrid