Skip to content

Commit c348bea

Browse files
Merge pull request #10 from ModusCreateOrg/ADE-27
[ADE-27] - Personalized Home Screen with Latest Medical Reports and AI Assistance
2 parents 714e14d + bec1471 commit c348bea

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1791
-66
lines changed

.cursor/rules/general.mdc

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,18 @@ Technologies:
5656

5757
For visual context, you can use this images:
5858

59-
[1 - Home.png](mdc:docs/assets/images/1 - Home.png)
60-
[3 - upload2.png](mdc:docs/assets/images/3 - upload2.png)
61-
[4 - processing.png](mdc:docs/assets/images/4 - processing.png)
62-
[5 - Results analysis.png](mdc:docs/assets/images/5 - Results analysis.png)
63-
[6 - Results Archive.png](mdc:docs/assets/images/6 - Results Archive.png)
64-
[8 - AI.png](mdc:docs/assets/images/8 - AI.png)
59+
[1 - Home copy.png](mdc:docs/assets/images/1 - Home copy.png)
60+
[1 - Home_avatar.png](mdc:docs/assets/images/1 - Home_avatar.png)
61+
[1a - Home_NoReports.png](mdc:docs/assets/images/1a - Home_NoReports.png)
62+
[1b - Home_NoLoad.png](mdc:docs/assets/images/1b - Home_NoLoad.png)
63+
[2 - upload1.png](mdc:docs/assets/images/2 - upload1.png)
64+
[2 - upload1_url.png](mdc:docs/assets/images/2 - upload1_url.png)
65+
[3 - upload2.png](mdc:docs/assets/images/3 - upload2.png)
66+
[3 - upload2_url.png](mdc:docs/assets/images/3 - upload2_url.png)
67+
[4 - processing.png](mdc:docs/assets/images/4 - processing.png)
68+
[5 - Results analysis.png](mdc:docs/assets/images/5 - Results analysis.png)
69+
[6 - Results Archive.png](mdc:docs/assets/images/6 - Results Archive.png)
70+
[7 - Detail.png](mdc:docs/assets/images/7 - Detail.png)
6571

72+
73+
AWS architecture: [aws architecture.pdf](mdc:docs/assets/aws architecture.pdf)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#!/usr/bin/env sh
22
. "$(dirname -- "$0")/_/husky.sh"
33

4-
cd frontend && npx lint-staged
4+
cd frontend && npm run lint
File renamed without changes.

docs/assets/aws architecture.pdf

131 KB
Binary file not shown.

docs/assets/components/tabbar.png

70.2 KB
Loading

docs/assets/images/1 - Home copy.png

207 KB
Loading

docs/assets/images/1 - Home.png

-180 KB
Binary file not shown.
201 KB
Loading
192 KB
Loading
196 KB
Loading

docs/assets/images/2 - upload1.png

93.4 KB
Loading
57.2 KB
Loading

docs/assets/images/3 - upload2.png

1.23 KB
Loading
58.5 KB
Loading

docs/assets/images/4 - processing.png

2.71 KB
Loading
22.3 KB
Loading
992 Bytes
Loading

docs/assets/images/7 - Detail.png

121 KB
Loading

docs/assets/images/8 - AI.png

-165 KB
Binary file not shown.

frontend/package-lock.json

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"@capacitor/keyboard": "6.0.3",
3737
"@capacitor/status-bar": "6.0.2",
3838
"@fortawesome/fontawesome-svg-core": "6.7.2",
39+
"@fortawesome/free-regular-svg-icons": "6.7.2",
3940
"@fortawesome/free-solid-svg-icons": "6.7.2",
4041
"@fortawesome/react-fontawesome": "0.2.2",
4142
"@ionic/react": "8.4.1",
@@ -44,6 +45,7 @@
4445
"@tanstack/react-query-devtools": "5.62.16",
4546
"axios": "1.7.9",
4647
"classnames": "2.5.1",
48+
"date-fns": "4.1.0",
4749
"dayjs": "1.11.13",
4850
"formik": "2.4.6",
4951
"i18next": "24.2.1",

frontend/src/assets/img/healthcare.svg

Lines changed: 9 additions & 0 deletions
Loading
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import axios from 'axios';
2+
import { MedicalReport, ReportStatus, ReportCategory } from '../models/medicalReport';
3+
4+
// Base API URL - should be configured from environment variables in a real app
5+
// Removed unused API_URL variable
6+
7+
/**
8+
* Error thrown when report operations fail.
9+
*/
10+
export class ReportError extends Error {
11+
constructor(message: string) {
12+
super(message);
13+
this.name = 'ReportError';
14+
}
15+
}
16+
17+
/**
18+
* Fetches the latest reports (limited to a specified count).
19+
* @param limit - Maximum number of reports to fetch
20+
* @returns Promise with the latest reports
21+
*/
22+
export const fetchLatestReports = async (limit = 3): Promise<MedicalReport[]> => {
23+
try {
24+
// In a real app, this would be an actual API call
25+
// const response = await axios.get(`/api/reports/latest?limit=${limit}`);
26+
// return response.data;
27+
28+
// For now, return mock data
29+
return mockReports.slice(0, limit);
30+
} catch (error) {
31+
if (axios.isAxiosError(error)) {
32+
throw new ReportError(`Failed to fetch latest reports: ${error.message}`);
33+
}
34+
throw new ReportError('Failed to fetch latest reports');
35+
}
36+
};
37+
38+
/**
39+
* Fetches all reports.
40+
* @returns Promise with all reports
41+
*/
42+
export const fetchAllReports = async (): Promise<MedicalReport[]> => {
43+
try {
44+
// In a real app, this would be an actual API call
45+
// const response = await axios.get(`/api/reports`);
46+
// return response.data;
47+
48+
// For now, return mock data
49+
return mockReports;
50+
} catch (error) {
51+
if (axios.isAxiosError(error)) {
52+
throw new ReportError(`Failed to fetch all reports: ${error.message}`);
53+
}
54+
throw new ReportError('Failed to fetch all reports');
55+
}
56+
};
57+
58+
/**
59+
* Marks a report as read.
60+
* @param reportId - ID of the report to mark as read
61+
* @returns Promise with the updated report
62+
*/
63+
export const markReportAsRead = async (reportId: string): Promise<MedicalReport> => {
64+
try {
65+
// In a real app, this would be an actual API call
66+
// const response = await axios.patch(`/api/reports/${reportId}`, {
67+
// status: ReportStatus.READ
68+
// });
69+
// return response.data;
70+
71+
// For now, update mock data
72+
const report = mockReports.find(r => r.id === reportId);
73+
if (!report) {
74+
throw new Error(`Report with ID ${reportId} not found`);
75+
}
76+
77+
report.status = ReportStatus.READ;
78+
return { ...report };
79+
} catch (error) {
80+
if (axios.isAxiosError(error)) {
81+
throw new ReportError(`Failed to mark report as read: ${error.message}`);
82+
}
83+
throw new ReportError('Failed to mark report as read');
84+
}
85+
};
86+
87+
// Mock data for development
88+
const mockReports: MedicalReport[] = [
89+
{
90+
id: '1',
91+
title: 'Blood Test',
92+
category: ReportCategory.GENERAL,
93+
date: '2025-01-27',
94+
status: ReportStatus.UNREAD,
95+
doctor: 'Dr. Smith',
96+
facility: 'City Hospital'
97+
},
98+
{
99+
id: '2',
100+
title: 'Cranial Nerve Exam',
101+
category: ReportCategory.NEUROLOGICAL,
102+
date: '2025-01-19',
103+
status: ReportStatus.UNREAD,
104+
doctor: 'Dr. Johnson',
105+
facility: 'Neurology Center'
106+
},
107+
{
108+
id: '3',
109+
title: 'Stress Test',
110+
category: ReportCategory.HEART,
111+
date: '2024-12-26',
112+
status: ReportStatus.READ,
113+
doctor: 'Dr. Williams',
114+
facility: 'Heart Institute'
115+
}
116+
];

frontend/src/common/components/Icon/Icon.tsx

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { IonText } from '@ionic/react';
33
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
44
import { IconProp } from '@fortawesome/fontawesome-svg-core';
55
import {
6+
faBookmark,
67
faBuilding,
78
faCalendar,
89
faCircleInfo,
@@ -21,7 +22,19 @@ import {
2122
faUserGear,
2223
faUsers,
2324
faXmark,
25+
faArrowUpFromBracket,
26+
faHome,
27+
faFileLines as faSolidFileLines,
28+
faUpload,
29+
faComment,
30+
faUserCircle
2431
} from '@fortawesome/free-solid-svg-icons';
32+
import {
33+
faFileLines as faRegularFileLines,
34+
faComment as faRegularComment,
35+
faUser as faRegularUser,
36+
faBookmark as faRegularBookmark
37+
} from '@fortawesome/free-regular-svg-icons';
2538
import classNames from 'classnames';
2639

2740
import { BaseComponentProps } from '../types';
@@ -30,11 +43,18 @@ import { BaseComponentProps } from '../types';
3043
* A union type of all Font Awesome icon names (without the `fa-` prefix)
3144
* used in the applciation.
3245
*/
46+
export type IconStyle = 'solid' | 'regular';
47+
3348
export type IconName =
49+
| 'arrowUpFromBracket'
50+
| 'bookmark'
3451
| 'building'
3552
| 'calendar'
3653
| 'circleInfo'
54+
| 'comment'
3755
| 'envelope'
56+
| 'fileLines'
57+
| 'home'
3858
| 'house'
3959
| 'link'
4060
| 'mapLocationDot'
@@ -45,7 +65,9 @@ export type IconName =
4565
| 'signOut'
4666
| 'trash'
4767
| 'triangleExclamation'
68+
| 'upload'
4869
| 'user'
70+
| 'userCircle'
4971
| 'users'
5072
| 'userGear'
5173
| 'xmark';
@@ -60,16 +82,22 @@ export interface IconProps
6082
Omit<ComponentPropsWithoutRef<typeof FontAwesomeIcon>, 'color' | 'icon'>,
6183
Pick<ComponentPropsWithoutRef<typeof IonText>, 'color' | 'slot'> {
6284
icon: IconName;
85+
iconStyle?: IconStyle;
6386
}
6487

6588
/**
66-
* A key/value mapping of every icon used in the application.
89+
* A key/value mapping of every solid icon used in the application.
6790
*/
68-
const icons: Record<IconName, IconProp> = {
91+
const solidIcons: Record<IconName, IconProp> = {
92+
arrowUpFromBracket: faArrowUpFromBracket,
93+
bookmark: faBookmark,
6994
building: faBuilding,
7095
calendar: faCalendar,
7196
circleInfo: faCircleInfo,
97+
comment: faComment,
7298
envelope: faEnvelope,
99+
fileLines: faSolidFileLines,
100+
home: faHome,
73101
house: faHouse,
74102
link: faLink,
75103
mapLocationDot: faMapLocationDot,
@@ -80,12 +108,25 @@ const icons: Record<IconName, IconProp> = {
80108
signOut: faSignOutAlt,
81109
trash: faTrash,
82110
triangleExclamation: faTriangleExclamation,
83-
userGear: faUserGear,
111+
upload: faUpload,
84112
user: faUser,
113+
userCircle: faUserCircle,
114+
userGear: faUserGear,
85115
users: faUsers,
86116
xmark: faXmark,
87117
};
88118

119+
/**
120+
* A key/value mapping of regular icons used in the application.
121+
* Only includes icons that have regular variants.
122+
*/
123+
const regularIcons: Partial<Record<IconName, IconProp>> = {
124+
comment: faRegularComment,
125+
fileLines: faRegularFileLines,
126+
user: faRegularUser,
127+
bookmark: faRegularBookmark
128+
};
129+
89130
/**
90131
* The `Icon` component renders an icon. Wraps the `FontAwesomeIcon` component.
91132
*
@@ -97,11 +138,15 @@ const Icon = ({
97138
className,
98139
color,
99140
icon,
141+
iconStyle = 'solid',
100142
slot = '',
101143
testid = 'icon',
102144
...iconProps
103145
}: IconProps): JSX.Element => {
104-
const faIcon = icons[icon];
146+
// Select icon based on style
147+
const faIcon = iconStyle === 'regular' && regularIcons[icon]
148+
? regularIcons[icon]
149+
: solidIcons[icon];
105150

106151
return (
107152
<IonText color={color} slot={slot} data-testid={testid}>

frontend/src/common/components/Router/TabNavigation.scss

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,50 @@
11
.ls-tab-navigation {
22
&__bar {
3+
border-radius: 2rem;
4+
margin: 0 0.75rem 1.5rem;
5+
box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.1);
6+
height: 3.5rem;
7+
--background: #ffffff;
8+
39
&-button {
10+
--color: #435FF0;
11+
--color-selected: #fd7bf4;
12+
413
&-icon {
5-
margin-top: 0.375rem;
6-
margin-bottom: 0.125rem;
14+
margin: 0;
15+
font-size: 1.25rem;
16+
}
17+
18+
&.tab-selected {
19+
.ls-tab-navigation__bar-button-icon {
20+
color: var(--color-selected);
21+
}
22+
}
23+
24+
&--upload {
25+
position: relative;
26+
overflow: visible;
27+
28+
.ls-tab-navigation__bar-button-upload-wrapper {
29+
display: flex;
30+
align-items: center;
31+
justify-content: center;
32+
background-color: #4765ff;
33+
color: white;
34+
width: 3rem;
35+
height: 3rem;
36+
border-radius: 50%;
37+
position: absolute;
38+
top: 0.25rem;
39+
left: 50%;
40+
transform: translateX(-50%);
41+
box-shadow: 0 0.25rem 0.5rem rgba(71, 101, 255, 0.3);
42+
43+
.ls-tab-navigation__bar-button-icon {
44+
color: white;
45+
margin: 0;
46+
}
47+
}
748
}
849
}
950
}

0 commit comments

Comments
 (0)