feat: Add collapsible sections and mobile grid layout
Some checks failed
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

- Convert Active Sessions and Trusted Devices to collapsible Accordion components
- Display count badge in collapsed state
- Show loading state in accordion header
- Implement 2-card grid layout on mobile (xs=6)
- Responsive card sizing and spacing
- Centered layout on mobile, horizontal on desktop
- Hide full birthdate on mobile, show age only

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-04 08:08:24 +00:00
parent ec3f0264a0
commit 426b5a309e
5 changed files with 79 additions and 43 deletions

View File

@@ -22,6 +22,9 @@ import {
Divider,
ToggleButton,
ToggleButtonGroup,
Accordion,
AccordionSummary,
AccordionDetails,
} from '@mui/material';
import {
Devices,
@@ -32,6 +35,7 @@ import {
CheckCircle,
Shield,
ShieldOutlined,
ExpandMore,
} from '@mui/icons-material';
import { devicesApi, type DeviceInfo } from '@/lib/api/devices';
import { motion } from 'framer-motion';
@@ -143,26 +147,41 @@ export function DeviceTrustManagement() {
if (isLoading) {
return (
<Card>
<CardContent sx={{ display: 'flex', justifyContent: 'center', py: 4 }}>
<CircularProgress />
</CardContent>
</Card>
<Accordion>
<AccordionSummary expandIcon={<ExpandMore />}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, width: '100%' }}>
<Shield color="primary" />
<Typography variant="h6" fontWeight="600">
Trusted Devices
</Typography>
<CircularProgress size={20} sx={{ ml: 'auto' }} />
</Box>
</AccordionSummary>
</Accordion>
);
}
return (
<>
<Card>
<CardContent>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 2 }}>
<Accordion>
<AccordionSummary
expandIcon={<ExpandMore />}
sx={{
'& .MuiAccordionSummary-content': {
margin: '12px 0',
},
}}
>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, width: '100%' }}>
<Shield color="primary" />
<Typography variant="h6" fontWeight="600">
Device Trust Management
Trusted Devices
</Typography>
<Chip label={`${devices.length} devices`} size="small" sx={{ ml: 'auto' }} />
<Chip label={`${devices.length}`} size="small" sx={{ ml: 'auto', mr: 1 }} />
</Box>
</AccordionSummary>
<AccordionDetails>
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
Manage which devices are trusted to access your account. Untrusted devices will require additional verification.
</Typography>
@@ -278,8 +297,8 @@ export function DeviceTrustManagement() {
)}
</>
)}
</CardContent>
</Card>
</AccordionDetails>
</Accordion>
{/* Remove Device Dialog */}
<Dialog open={removeDialogOpen} onClose={() => setRemoveDialogOpen(false)} maxWidth="sm" fullWidth>

View File

@@ -20,6 +20,9 @@ import {
ListItemSecondaryAction,
IconButton,
Divider,
Accordion,
AccordionSummary,
AccordionDetails,
} from '@mui/material';
import {
Devices,
@@ -28,6 +31,7 @@ import {
Tablet,
Delete,
CheckCircle,
ExpandMore,
} from '@mui/icons-material';
import { sessionsApi, type SessionInfo } from '@/lib/api/sessions';
import { motion } from 'framer-motion';
@@ -116,26 +120,41 @@ export function SessionsManagement() {
if (isLoading) {
return (
<Card>
<CardContent sx={{ display: 'flex', justifyContent: 'center', py: 4 }}>
<CircularProgress />
</CardContent>
</Card>
<Accordion>
<AccordionSummary expandIcon={<ExpandMore />}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, width: '100%' }}>
<Devices color="primary" />
<Typography variant="h6" fontWeight="600">
Active Sessions
</Typography>
<CircularProgress size={20} sx={{ ml: 'auto' }} />
</Box>
</AccordionSummary>
</Accordion>
);
}
return (
<>
<Card>
<CardContent>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 2 }}>
<Accordion>
<AccordionSummary
expandIcon={<ExpandMore />}
sx={{
'& .MuiAccordionSummary-content': {
margin: '12px 0',
},
}}
>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, width: '100%' }}>
<Devices color="primary" />
<Typography variant="h6" fontWeight="600">
Active Sessions
</Typography>
<Chip label={`${sessions.length} active`} size="small" sx={{ ml: 'auto' }} />
<Chip label={`${sessions.length}`} size="small" sx={{ ml: 'auto', mr: 1 }} />
</Box>
</AccordionSummary>
<AccordionDetails>
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
Manage your active sessions across different devices. You can revoke access from any device.
</Typography>
@@ -220,8 +239,8 @@ export function SessionsManagement() {
)}
</>
)}
</CardContent>
</Card>
</AccordionDetails>
</Accordion>
{/* Revoke Session Dialog */}
<Dialog open={revokeDialogOpen} onClose={() => setRevokeDialogOpen(false)} maxWidth="sm" fullWidth>