Skip to content

Commit f06dd4a

Browse files
committed
Improve top of the screen
1 parent d2c10ca commit f06dd4a

File tree

5 files changed

+132
-10
lines changed

5 files changed

+132
-10
lines changed

frontend/src/common/api/reportService.ts

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ const mockReports: MedicalReport[] = [
1111
category: ReportCategory.HEART,
1212
date: '2024-01-01',
1313
status: ReportStatus.UNREAD,
14-
documentUrl: 'https://example.com/reports/1/heart_scan.pdf'
14+
documentUrl: 'https://example.com/reports/1/heart_scan.pdf',
15+
bookmarked: false
1516
}
1617
];
1718

@@ -129,7 +130,8 @@ export const uploadReport = async (
129130
category: determineCategory(file.name),
130131
date: new Date().toISOString().split('T')[0], // Today's date in YYYY-MM-DD format
131132
status: ReportStatus.UNREAD,
132-
documentUrl: `https://example.com/reports/${mockReports.length + 1}/${file.name}` // Mock URL
133+
documentUrl: `https://example.com/reports/${mockReports.length + 1}/${file.name}`, // Mock URL
134+
bookmarked: false
133135
};
134136

135137
// Add to mock data
@@ -220,3 +222,37 @@ export const markReportAsRead = async (reportId: string): Promise<MedicalReport>
220222
throw new ReportError('Failed to mark report as read');
221223
}
222224
};
225+
226+
/**
227+
* Toggles the bookmark status of a report.
228+
* @param reportId - ID of the report to toggle bookmark status
229+
* @param isBookmarked - Boolean indicating if the report should be bookmarked or not
230+
* @returns Promise with the updated report
231+
*/
232+
export const toggleReportBookmark = async (reportId: string, isBookmarked: boolean): Promise<MedicalReport> => {
233+
try {
234+
await axios.patch(`${API_URL}/api/reports/${reportId}/bookmark`, {
235+
bookmarked: isBookmarked
236+
}, await getAuthConfig());
237+
238+
// In a real implementation, this would return the response from the API
239+
// return response.data;
240+
241+
// For now, we'll mock the response
242+
const report = mockReports.find(r => r.id === reportId);
243+
244+
if (!report) {
245+
throw new Error(`Report with ID ${reportId} not found`);
246+
}
247+
248+
// Update the bookmark status
249+
report.bookmarked = isBookmarked;
250+
251+
return { ...report };
252+
} catch (error) {
253+
if (axios.isAxiosError(error)) {
254+
throw new ReportError(`Failed to toggle bookmark status: ${error.message}`);
255+
}
256+
throw new ReportError('Failed to toggle bookmark status');
257+
}
258+
};

frontend/src/common/models/medicalReport.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@ export interface MedicalReport {
3333
content?: string;
3434
doctor?: string;
3535
facility?: string;
36-
}
36+
bookmarked?: boolean;
37+
}

frontend/src/common/utils/i18n/resources/en/report.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
"wbc": "WBC (White Blood Cells)",
1919
"vitaminD": "Vitamin D (25-OH)",
2020
"cholesterol": "Total Cholesterol",
21+
"bookmarkAdded": "Report added to bookmarks",
22+
"bookmarkRemoved": "Report removed from bookmarks",
2123
"aiInsightsContent": "Based on the blood test results, our AI has identified several points of interest that may require attention or further discussion with your healthcare provider.",
2224
"insight1Title": "Hemoglobin Level",
2325
"insight1Content": "Your hemoglobin level is slightly below the reference range. This could indicate mild anemia, which may cause fatigue and weakness.",

frontend/src/pages/Reports/ReportDetailPage.scss

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
.report-detail-page {
22
--background: var(--ion-color-light);
33

4+
ion-toolbar {
5+
--background: #fff;
6+
}
7+
8+
ion-back-button {
9+
--color: var(--ion-color-primary);
10+
}
11+
412
&__header {
513
background-color: #fff;
614
border-bottom: 1px solid var(--ion-color-light-shade);
715
}
816

917
.report-category {
10-
color: var(--ion-color-medium);
18+
color: var(--ion-color-primary);
1119
font-size: 1rem;
1220
margin-bottom: 0.25rem;
1321
}
@@ -26,6 +34,29 @@
2634

2735
.report-segment {
2836
padding-top: 0.5rem;
37+
38+
ion-segment-button {
39+
--color: var(--ion-color-medium);
40+
--color-checked: var(--ion-color-primary);
41+
--indicator-color: var(--ion-color-primary);
42+
}
43+
44+
&--ai-insights {
45+
--padding-start: 1rem;
46+
--padding-end: 1rem;
47+
}
48+
}
49+
50+
.bookmark-button {
51+
--color: var(--ion-color-primary);
52+
53+
&--active {
54+
--color: var(--ion-color-primary);
55+
}
56+
57+
&--inactive {
58+
--color: var(--ion-color-medium);
59+
}
2960
}
3061

3162
.report-metadata {

frontend/src/pages/Reports/ReportDetailPage.tsx

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@ import {
1313
IonCardContent,
1414
IonText,
1515
IonButton,
16-
IonIcon
16+
IonIcon,
17+
IonToast
1718
} from '@ionic/react';
1819
import { useState, useEffect } from 'react';
1920
import { useParams } from 'react-router-dom';
2021
import { useTranslation } from 'react-i18next';
2122
import { format } from 'date-fns';
22-
import { bookmarkOutline } from 'ionicons/icons';
23+
import { bookmark, bookmarkOutline } from 'ionicons/icons';
2324
import { MedicalReport } from 'common/models/medicalReport';
24-
import { useQuery } from '@tanstack/react-query';
25-
import { fetchAllReports } from 'common/api/reportService';
25+
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
26+
import { fetchAllReports, toggleReportBookmark } from 'common/api/reportService';
2627

2728
import './ReportDetailPage.scss';
2829

@@ -51,13 +52,52 @@ const ReportDetailPage: React.FC = () => {
5152
const { reportId } = useParams<ReportDetailParams>();
5253
const [selectedSegment, setSelectedSegment] = useState<'aiInsights' | 'testResults'>('aiInsights');
5354
const [report, setReport] = useState<MedicalReport | null>(null);
55+
const [showBookmarkToast, setShowBookmarkToast] = useState(false);
56+
const [bookmarkToastMessage, setBookmarkToastMessage] = useState('');
57+
const queryClient = useQueryClient();
5458

5559
// Fetch all reports and find the one we need
5660
const { data: reports = [] } = useQuery({
5761
queryKey: ['reports'],
5862
queryFn: fetchAllReports
5963
});
6064

65+
// Toggle bookmark mutation
66+
const { mutate: toggleBookmark } = useMutation({
67+
mutationFn: ({ reportId, isBookmarked }: { reportId: string; isBookmarked: boolean }) => {
68+
return toggleReportBookmark(reportId, isBookmarked);
69+
},
70+
onSuccess: (updatedReport) => {
71+
// Update the report state with the updated bookmarked status
72+
setReport(updatedReport);
73+
74+
// Update the reports query cache
75+
queryClient.setQueryData(['reports'], (oldData: MedicalReport[] | undefined) => {
76+
if (!oldData) return [];
77+
return oldData.map(oldReport =>
78+
oldReport.id === updatedReport.id ? updatedReport : oldReport
79+
);
80+
});
81+
82+
// Show toast notification
83+
setBookmarkToastMessage(updatedReport.bookmarked ?
84+
t('detail.bookmarkAdded') :
85+
t('detail.bookmarkRemoved')
86+
);
87+
setShowBookmarkToast(true);
88+
}
89+
});
90+
91+
// Handle bookmark click
92+
const handleBookmarkClick = () => {
93+
if (report) {
94+
toggleBookmark({
95+
reportId: report.id,
96+
isBookmarked: !report.bookmarked
97+
});
98+
}
99+
};
100+
61101
// Mock blood test data based on the screenshot
62102
const bloodTestData: BloodTestData = {
63103
results: [
@@ -118,8 +158,11 @@ const ReportDetailPage: React.FC = () => {
118158
</IonButtons>
119159
<IonTitle>{t('detail.title')}</IonTitle>
120160
<IonButtons slot="end">
121-
<IonButton>
122-
<IonIcon slot="icon-only" icon={bookmarkOutline} />
161+
<IonButton
162+
className={`bookmark-button ${report.bookmarked ? 'bookmark-button--active' : 'bookmark-button--inactive'}`}
163+
onClick={handleBookmarkClick}
164+
>
165+
<IonIcon slot="icon-only" icon={report.bookmarked ? bookmark : bookmarkOutline} />
123166
</IonButton>
124167
</IonButtons>
125168
</IonToolbar>
@@ -209,6 +252,15 @@ const ReportDetailPage: React.FC = () => {
209252
</IonText>
210253
)}
211254
</div>
255+
256+
<IonToast
257+
isOpen={showBookmarkToast}
258+
onDidDismiss={() => setShowBookmarkToast(false)}
259+
message={bookmarkToastMessage}
260+
duration={2000}
261+
position="bottom"
262+
color="primary"
263+
/>
212264
</IonContent>
213265
</IonPage>
214266
);

0 commit comments

Comments
 (0)