frontend phase 13
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { ThemeProvider } from '../../theme';
|
||||
import PatientHeader, { PatientHeaderProps } from './PatientHeader';
|
||||
|
||||
function renderHeader(props: Partial<PatientHeaderProps> = {}) {
|
||||
return render(
|
||||
<ThemeProvider>
|
||||
<PatientHeader
|
||||
displayName="Zahra Mohammadi"
|
||||
relationLabel="Parent"
|
||||
genderLabel="Female"
|
||||
ageLabel="70 yrs"
|
||||
conditionLabels={['Elderly']}
|
||||
noConditionsLabel="No conditions"
|
||||
{...props}
|
||||
/>
|
||||
</ThemeProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
describe('<PatientHeader/> component', () => {
|
||||
it('renders name, relation, meta line and conditions', () => {
|
||||
renderHeader();
|
||||
expect(screen.getByText('Zahra Mohammadi')).toBeInTheDocument();
|
||||
expect(screen.getByText('Parent')).toBeInTheDocument();
|
||||
expect(screen.getByText('70 yrs · Female')).toBeInTheDocument();
|
||||
expect(screen.getByText('Elderly')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows the no-conditions caption when there are none', () => {
|
||||
renderHeader({ conditionLabels: [] });
|
||||
expect(screen.getByText('No conditions')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('omits the relation chip when no relation is set', () => {
|
||||
renderHeader({ relationLabel: undefined });
|
||||
expect(screen.queryByText('Parent')).not.toBeInTheDocument();
|
||||
// meta line still renders age · gender
|
||||
expect(screen.getByText('70 yrs · Female')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,71 @@
|
||||
'use client';
|
||||
import { FunctionComponent } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Chip from '@mui/material/Chip';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Typography from '@mui/material/Typography';
|
||||
|
||||
export interface PatientHeaderProps {
|
||||
/** The patient's display name. */
|
||||
displayName: string;
|
||||
/** Translated relation label; omitted when the patient has no relation set. */
|
||||
relationLabel?: string;
|
||||
/** Translated gender label. */
|
||||
genderLabel: string;
|
||||
/** Translated age label (e.g. "70 yrs"); omitted when the birth date is unknown. */
|
||||
ageLabel?: string;
|
||||
/** Translated condition labels; empty renders the "no conditions" line. */
|
||||
conditionLabels: string[];
|
||||
noConditionsLabel: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The patient identity block — bold name + relation chip, a secondary "age · gender" meta line, and outlined
|
||||
* condition chips (or a "no conditions" caption). Extracted from `PatientCard` so the E1 list card and the E2
|
||||
* record viewer render the exact same header. Purely presentational; the caller translates every label and
|
||||
* tolerates a missing relation / empty conditions (both are client-augmented, may be empty on a real read).
|
||||
* @component PatientHeader
|
||||
*/
|
||||
const PatientHeader: FunctionComponent<PatientHeaderProps> = ({
|
||||
displayName,
|
||||
relationLabel,
|
||||
genderLabel,
|
||||
ageLabel,
|
||||
conditionLabels,
|
||||
noConditionsLabel,
|
||||
}) => {
|
||||
const meta = [ageLabel, genderLabel].filter(Boolean).join(' · ');
|
||||
|
||||
return (
|
||||
<Stack sx={{ gap: 0.75, minWidth: 0 }}>
|
||||
<Stack direction="row" sx={{ alignItems: 'center', gap: 1, flexWrap: 'wrap' }}>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 700 }}>
|
||||
{displayName}
|
||||
</Typography>
|
||||
{relationLabel ? (
|
||||
<Chip size="small" label={relationLabel} sx={{ bgcolor: 'var(--bal-primary-soft)', fontWeight: 600 }} />
|
||||
) : null}
|
||||
</Stack>
|
||||
|
||||
{meta ? (
|
||||
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
|
||||
{meta}
|
||||
</Typography>
|
||||
) : null}
|
||||
|
||||
{conditionLabels.length > 0 ? (
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5, mt: 0.25 }}>
|
||||
{conditionLabels.map((label) => (
|
||||
<Chip key={label} size="small" variant="outlined" label={label} />
|
||||
))}
|
||||
</Box>
|
||||
) : (
|
||||
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
|
||||
{noConditionsLabel}
|
||||
</Typography>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default PatientHeader;
|
||||
@@ -0,0 +1,4 @@
|
||||
import PatientHeader from './PatientHeader';
|
||||
|
||||
export type { PatientHeaderProps } from './PatientHeader';
|
||||
export { PatientHeader as default, PatientHeader };
|
||||
Reference in New Issue
Block a user