Skip to content

Commit d8c8a90

Browse files
committed
BN-75 | Refactor dashboard schema validation and remove unused parameters
1 parent 91712ff commit d8c8a90

File tree

7 files changed

+40
-75
lines changed

7 files changed

+40
-75
lines changed

src/components/clinical/dashboardContainer/DashboardContainer.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,16 @@ const DashboardContainer: React.FC<DashboardContainerProps> = ({
2020
sections,
2121
activeItemId,
2222
}) => {
23-
// Create a ref map for each section - fix the type definition here
23+
// Create a ref map for each section using section name as key
2424
const sectionRefs = useRef<{
2525
[key: string]: React.RefObject<HTMLDivElement | null>;
2626
}>({});
2727

2828
// Initialize refs for each section
2929
useEffect(() => {
3030
sections.forEach((section) => {
31-
if (!sectionRefs.current[section.id]) {
32-
sectionRefs.current[section.id] = React.createRef<HTMLDivElement>();
31+
if (!sectionRefs.current[section.name]) {
32+
sectionRefs.current[section.name] = React.createRef<HTMLDivElement>();
3333
}
3434
});
3535
}, [sections]);
@@ -39,12 +39,12 @@ const DashboardContainer: React.FC<DashboardContainerProps> = ({
3939
if (activeItemId) {
4040
// Find the section that corresponds to the activeItemId
4141
const activeSection = sections.find(
42-
(section) => section.id === activeItemId,
42+
(section) => section.name === activeItemId,
4343
);
4444

45-
if (activeSection && sectionRefs.current[activeSection.id]?.current) {
45+
if (activeSection && sectionRefs.current[activeSection.name]?.current) {
4646
// Added optional chaining and null check to prevent errors
47-
const sectionDiv = sectionRefs.current[activeSection.id].current;
47+
const sectionDiv = sectionRefs.current[activeSection.name].current;
4848
if (sectionDiv) {
4949
sectionDiv.scrollIntoView({
5050
behavior: 'smooth',
@@ -62,17 +62,17 @@ const DashboardContainer: React.FC<DashboardContainerProps> = ({
6262
return (
6363
<Section>
6464
<Grid>
65-
{sections.map((section) => (
65+
{sections.map((section, index) => (
6666
<Column
6767
lg={16}
6868
md={8}
6969
sm={4}
70-
key={section.id}
70+
key={`${section.name}-${index}`}
7171
className={styles.sectionColumn}
7272
>
7373
<DashboardSection
7474
section={section}
75-
ref={sectionRefs.current[section.id]}
75+
ref={sectionRefs.current[section.name]}
7676
/>
7777
</Column>
7878
))}

src/components/clinical/dashboardContainer/__tests__/DashboardContainer.test.tsx

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { render, screen, waitFor } from '@testing-library/react';
33
import DashboardContainer from '../DashboardContainer';
4-
import { DashboardSectionConfig as DashboardSectionType } from '@types/dashboardConfig';
4+
import { DashboardSectionConfig as DashboardSectionType } from '@/types/dashboardConfig';
55

66
// Mock scrollIntoView
77
const mockScrollIntoView = jest.fn();
@@ -28,21 +28,6 @@ jest.mock('../../dashboardSection/DashboardSection', () => {
2828
));
2929
});
3030

31-
// Mock the Carbon components with ref forwarding
32-
jest.mock('@carbon/react', () => ({
33-
Grid: jest.fn(({ children }) => (
34-
<div data-testid="carbon-grid">{children}</div>
35-
)),
36-
Column: jest.fn(({ children, ref }) => (
37-
<div data-testid="carbon-column" ref={ref}>
38-
{children}
39-
</div>
40-
)),
41-
Section: jest.fn(({ children }) => (
42-
<div data-testid="carbon-section">{children}</div>
43-
)),
44-
}));
45-
4631
describe('DashboardContainer Component', () => {
4732
// Set up and reset mocks before each test
4833
beforeEach(() => {
@@ -59,19 +44,18 @@ describe('DashboardContainer Component', () => {
5944
afterEach(() => {
6045
// Clean up the mock after each test
6146
if (HTMLElement.prototype.scrollIntoView === mockScrollIntoView) {
62-
delete HTMLElement.prototype.scrollIntoView;
47+
// Use Reflect.deleteProperty to safely delete the property
48+
Reflect.deleteProperty(HTMLElement.prototype, 'scrollIntoView');
6349
}
6450
});
6551

6652
const mockSections: DashboardSectionType[] = [
6753
{
68-
id: 'section-1-id',
6954
name: 'Section 1',
7055
icon: 'icon-1',
7156
controls: [],
7257
},
7358
{
74-
id: 'section-2-id',
7559
name: 'Section 2',
7660
icon: 'icon-2',
7761
controls: [],
@@ -104,7 +88,7 @@ describe('DashboardContainer Component', () => {
10488
expect(screen.getAllByTestId('carbon-column').length).toBe(2); // One column per section
10589
});
10690

107-
it('scrolls to the active section when activeItemId matches section id', async () => {
91+
it('scrolls to the active section when activeItemId matches section name', async () => {
10892
// Create a spy div element with scrollIntoView method
10993
const spyElement = document.createElement('div');
11094
const scrollSpy = jest.spyOn(spyElement, 'scrollIntoView');
@@ -114,11 +98,11 @@ describe('DashboardContainer Component', () => {
11498
current: spyElement,
11599
}));
116100

117-
// Render component with activeItemId matching a section id
101+
// Render component with activeItemId matching a section name
118102
render(
119103
<DashboardContainer
120104
sections={mockSections}
121-
activeItemId="section-1-id"
105+
activeItemId="Section 1"
122106
/>,
123107
);
124108

@@ -176,7 +160,6 @@ describe('DashboardContainer Component', () => {
176160
const updatedSections: DashboardSectionType[] = [
177161
...mockSections,
178162
{
179-
id: 'section-3-id',
180163
name: 'Section 3',
181164
icon: 'icon-3',
182165
controls: [],
@@ -193,7 +176,7 @@ describe('DashboardContainer Component', () => {
193176
rerender(
194177
<DashboardContainer
195178
sections={updatedSections}
196-
activeItemId="section-3-id"
179+
activeItemId="Section 3"
197180
/>,
198181
);
199182

@@ -226,7 +209,7 @@ describe('DashboardContainer Component', () => {
226209
rerender(
227210
<DashboardContainer
228211
sections={reducedSections}
229-
activeItemId="section-2-id"
212+
activeItemId="Section 2"
230213
/>,
231214
);
232215

src/components/clinical/dashboardSection/DashboardSection.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const renderSectionContent = (section: DashboardSectionConfig) => {
1919
return (
2020
<div className="section-controls">
2121
{section.controls.map((control, index) => (
22-
<div key={index}>
22+
<div key={`${control.type}-${index}`}>
2323
{renderControlContent(control.type)}
2424
</div>
2525
))}
@@ -68,7 +68,7 @@ const DashboardSection: React.FC<DashboardSectionProps> = ({
6868
}) => {
6969
const { t } = useTranslation();
7070
return (
71-
<Tile id={`section-${section.id}`} ref={ref}>
71+
<Tile id={`section-${section.name.toLowerCase().replace(/\s+/g, '-')}`} ref={ref}>
7272
<p className={styles.sectionTitle}>
7373
{t(section.translationKey || section.name)}
7474
</p>

src/components/clinical/dashboardSection/__tests__/DashboardSection.test.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,13 @@ jest.mock('@displayControls/conditions/ConditionsTable', () => ({
3434

3535
describe('DashboardSection Component', () => {
3636
const mockSection: DashboardSectionConfig = {
37-
id: 'test-section-id',
3837
name: 'Test Section',
3938
icon: 'test-icon',
4039
controls: [],
4140
};
4241

4342
// Handle for forwardRef in tests
44-
const mockRef = jest.fn();
43+
const mockRef = React.createRef<HTMLDivElement>();
4544

4645
it('renders with the correct section name', () => {
4746
render(<DashboardSection section={mockSection} ref={mockRef} />);
@@ -50,14 +49,14 @@ describe('DashboardSection Component', () => {
5049
expect(screen.getByText('Test Section')).toBeInTheDocument();
5150
});
5251

53-
it('has the correct id attribute', () => {
52+
it('has the correct id attribute based on section name', () => {
5453
const { container } = render(
5554
<DashboardSection section={mockSection} ref={mockRef} />,
5655
);
5756

58-
// Check if the div has the correct id
57+
// Check if the div has the correct id based on section name
5958
const sectionDiv = container.querySelector(
60-
`div[id="section-${mockSection.id}"]`,
59+
`div[id="section-test-section"]`,
6160
);
6261
expect(sectionDiv).not.toBeNull();
6362
});
@@ -70,7 +69,7 @@ describe('DashboardSection Component', () => {
7069
});
7170

7271
it('accepts a ref prop', () => {
73-
const mockRefFn = jest.fn();
72+
const mockRefFn = React.createRef<HTMLDivElement>();
7473

7574
render(<DashboardSection section={mockSection} ref={mockRefFn} />);
7675

@@ -81,7 +80,6 @@ describe('DashboardSection Component', () => {
8180

8281
it('uses translationKey instead of name when available', () => {
8382
const sectionWithTranslationKey: DashboardSectionConfig = {
84-
id: 'test-section-id',
8583
name: 'Test Section',
8684
translationKey: 'custom.translation.key',
8785
icon: 'test-icon',
@@ -100,7 +98,6 @@ describe('DashboardSection Component', () => {
10098
describe('content rendering', () => {
10199
it('renders AllergiesTable when section name is Allergies', () => {
102100
const allergiesSection: DashboardSectionConfig = {
103-
id: 'allergies-id',
104101
name: 'Allergies',
105102
icon: 'test-icon',
106103
controls: [],
@@ -113,7 +110,6 @@ describe('DashboardSection Component', () => {
113110

114111
it('renders ConditionsTable when section name is Conditions', () => {
115112
const conditionsSection: DashboardSectionConfig = {
116-
id: 'conditions-id',
117113
name: 'Conditions',
118114
icon: 'test-icon',
119115
controls: [],
@@ -126,7 +122,6 @@ describe('DashboardSection Component', () => {
126122

127123
it('renders no content for unknown section types', () => {
128124
const unknownSection: DashboardSectionConfig = {
129-
id: 'unknown-section-id',
130125
name: 'Unknown Section',
131126
icon: 'test-icon',
132127
controls: [],

src/displayControls/diagnoses/styles/Diagnoses.module.scss

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
.tableHeader {
66
display: flex;
7-
padding: 1rem 1rem;
7+
padding: 1rem;
88
background-color: #ffffff;
99
border-bottom: 1px solid #e0e0e0;
1010
font-size: 0.875rem;
@@ -17,8 +17,8 @@
1717
}
1818

1919
.recordedByColumn {
20-
width: 200px;
21-
padding-right: 1rem;
20+
width: 180px;
21+
padding-right: 1rem;
2222
}
2323

2424
.accordionItem {
@@ -27,10 +27,6 @@
2727
padding-inline: 0px;
2828
}
2929

30-
:global(.cds--accordion__heading) {
31-
padding-left: 1rem !important;
32-
padding-right: 1rem !important;
33-
}
3430

3531
:global(.cds--accordion__wrapper) {
3632
padding-inline: 0px !important;
@@ -46,12 +42,7 @@
4642

4743
.diagnosisRow {
4844
display: flex;
49-
padding: 1rem;
5045
align-items: center;
51-
52-
&:last-child {
53-
border-bottom: none;
54-
}
5546
}
5647

5748
.diagnosisCell {

src/schemas/dashboardConfig.schema.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,21 @@
2828
},
2929
"controls": {
3030
"type": "array",
31-
"description": "List of controls in the section"
31+
"description": "List of controls in the section",
32+
"items": {
33+
"type": "object",
34+
"additionalProperties": false,
35+
"required": ["type"],
36+
"properties": {
37+
"type": {
38+
"type": "string"
39+
}
40+
}
41+
}
42+
}
3243
}
3344
}
3445
}
3546
}
3647
}
37-
}
48+

src/types/dashboardConfig.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,17 @@ export type ControlType = 'allergies' | 'conditions' | 'diagnoses' | 'labInvesti
33

44
// Enhanced control configuration interface
55
export interface ControlConfig {
6-
id: string;
76
type: ControlType;
8-
props?: Record<string, any>; // Control-specific props
9-
config?: Record<string, any>; // Control-specific configuration
10-
enabled?: boolean; // Whether the control is enabled
117
}
128

139
// Updated DashboardSectionConfig with better typing
1410
export interface DashboardSectionConfig {
15-
id: string;
1611
name: string;
1712
translationKey?: string;
1813
icon: string;
1914
controls: ControlConfig[]; // Changed from fixed array to flexible array
20-
enabled?: boolean; // Whether the section is enabled
21-
order?: number; // Display order
2215
}
2316

2417
export interface DashboardConfig {
2518
sections: DashboardSectionConfig[];
26-
version?: string; // Configuration version for future compatibility
27-
}
28-
29-
// Control component interface for registry
30-
export interface ControlComponent {
31-
component: React.ComponentType<any>;
32-
defaultProps?: Record<string, any>;
33-
displayName?: string;
3419
}

0 commit comments

Comments
 (0)