Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/src/services/perplexity.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import axios from 'axios';
import { AwsSecretsService } from './aws-secrets.service';
import { LabValue } from 'src/document-processor/services/aws-bedrock.service';
import { LabValue } from '../document-processor/services/aws-bedrock.service';

export interface PerplexityMessage {
role: 'system' | 'user' | 'assistant';
Expand Down
13 changes: 6 additions & 7 deletions frontend/src/common/hooks/useChat.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { bedrockService } from '../services/ai/bedrock.service';

export const CHAT_QUERY_KEY = 'chat';
import { QueryKey } from 'common/utils/constants';

export function useChat(sessionId?: string) {
const queryClient = useQueryClient();

// Query for getting chat session
const { data: session } = useQuery({
queryKey: [CHAT_QUERY_KEY, sessionId],
queryKey: [QueryKey.Chat, sessionId],
queryFn: () => (sessionId ? bedrockService.getChatSession(sessionId) : undefined),
enabled: !!sessionId,
});

// Query for getting all sessions
const { data: sessions } = useQuery({
queryKey: [CHAT_QUERY_KEY, 'sessions'],
queryKey: [QueryKey.Chat, 'sessions'],
queryFn: () => bedrockService.getAllSessions(),
});

// Mutation for creating a new session
const createSession = useMutation({
mutationFn: () => bedrockService.createChatSession(),
onSuccess: (newSessionId) => {
queryClient.invalidateQueries({ queryKey: [CHAT_QUERY_KEY, 'sessions'] });
queryClient.invalidateQueries({ queryKey: [QueryKey.Chat, 'sessions'] });
return newSessionId;
},
});
Expand All @@ -35,8 +34,8 @@ export function useChat(sessionId?: string) {
return bedrockService.sendMessage(sessionId, message);
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [CHAT_QUERY_KEY, sessionId] });
queryClient.invalidateQueries({ queryKey: [CHAT_QUERY_KEY, 'sessions'] });
queryClient.invalidateQueries({ queryKey: [QueryKey.Chat, sessionId] });
queryClient.invalidateQueries({ queryKey: [QueryKey.Chat, 'sessions'] });
},
});

Expand Down
60 changes: 51 additions & 9 deletions frontend/src/common/hooks/useReports.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { fetchAllReports, fetchLatestReports, markReportAsRead } from '../api/reportService';
import {
fetchAllReports,
fetchLatestReports,
markReportAsRead,
toggleReportBookmark,
} from '../api/reportService';
import { MedicalReport } from '../models/medicalReport';

// Query keys
const REPORTS_KEY = 'reports';
const LATEST_REPORTS_KEY = 'latestReports';
import { QueryKey } from 'common/utils/constants';

/**
* Hook to fetch the latest reports.
Expand All @@ -13,7 +15,7 @@ const LATEST_REPORTS_KEY = 'latestReports';
*/
export const useGetLatestReports = (limit = 3) => {
return useQuery({
queryKey: [LATEST_REPORTS_KEY, limit],
queryKey: [QueryKey.LatestReports, limit],
queryFn: () => fetchLatestReports(limit),
refetchOnMount: true,
refetchOnWindowFocus: true,
Expand All @@ -27,7 +29,7 @@ export const useGetLatestReports = (limit = 3) => {
*/
export const useGetAllReports = () => {
return useQuery({
queryKey: [REPORTS_KEY],
queryKey: [QueryKey.Reports],
queryFn: fetchAllReports,
});
};
Expand All @@ -43,15 +45,15 @@ export const useMarkReportAsRead = () => {
mutationFn: (reportId: string) => markReportAsRead(reportId),
onSuccess: (updatedReport: MedicalReport) => {
// Update the reports cache
queryClient.setQueryData<MedicalReport[]>([REPORTS_KEY], (oldReports) => {
queryClient.setQueryData<MedicalReport[]>([QueryKey.Reports], (oldReports) => {
if (!oldReports) return undefined;
return oldReports.map((report) =>
report.id === updatedReport.id ? updatedReport : report,
);
});

// Update the latest reports cache
queryClient.setQueryData<MedicalReport[]>([LATEST_REPORTS_KEY], (oldReports) => {
queryClient.setQueryData<MedicalReport[]>([QueryKey.LatestReports], (oldReports) => {
if (!oldReports) return undefined;
return oldReports.map((report) =>
report.id === updatedReport.id ? updatedReport : report,
Expand All @@ -60,3 +62,43 @@ export const useMarkReportAsRead = () => {
},
});
};

/**
* Hook to toggle the bookmark status of a report.
* @returns Mutation result for toggling the bookmark status
*/
export const useToggleReportBookmark = () => {
const queryClient = useQueryClient();

return useMutation({
mutationFn: ({ reportId, isBookmarked }: { reportId: string; isBookmarked: boolean }) =>
toggleReportBookmark(reportId, isBookmarked),
onSuccess: (updatedReport: MedicalReport) => {
// Update the reports cache
queryClient.setQueryData<MedicalReport[]>([QueryKey.Reports], (oldReports) => {
if (!oldReports) return undefined;
return oldReports.map((report) =>
report.id === updatedReport.id ? updatedReport : report,
);
});

// Update the latest reports cache
queryClient.setQueryData<MedicalReport[]>([QueryKey.LatestReports], (oldReports) => {
if (!oldReports) return undefined;
return oldReports.map((report) =>
report.id === updatedReport.id ? updatedReport : report,
);
});

// Update the bookmark status in the report detail page
queryClient.setQueryData<MedicalReport | undefined>(
[QueryKey.ReportDetail, reportId],
(oldReport) => {
if (!oldReport) return undefined;
if (oldReport.id !== updatedReport.id) return oldReport;
return { ...oldReport, bookmarked: updatedReport.bookmarked };
},
);
},
});
};
4 changes: 4 additions & 0 deletions frontend/src/common/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ export enum QueryKey {
UserProfile = 'UserProfile',
Users = 'Users',
UserTokens = 'UserTokens',
Chat = 'Chat',
Reports = 'Reports',
LatestReports = 'LatestReports',
ReportDetail = 'ReportDetail',
}

/**
Expand Down
40 changes: 9 additions & 31 deletions frontend/src/pages/Home/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import {
import { useTranslation } from 'react-i18next';
import { useHistory } from 'react-router-dom';
import { useState } from 'react';
import { useGetLatestReports, useMarkReportAsRead } from 'common/hooks/useReports';
import {
useGetLatestReports,
useMarkReportAsRead,
useToggleReportBookmark,
} from 'common/hooks/useReports';
import { useCurrentUser } from 'common/hooks/useAuth';
import { toggleReportBookmark } from 'common/api/reportService';
import { useQueryClient } from '@tanstack/react-query';
import { MedicalReport } from 'common/models/medicalReport';
import Avatar from 'common/components/Icon/Avatar';
import ReportItem from './components/ReportItem/ReportItem';
import NoReportsMessage from './components/NoReportsMessage/NoReportsMessage';
Expand All @@ -30,7 +31,7 @@ import './HomePage.scss';
const HomePage: React.FC = () => {
const { t } = useTranslation('home');
const history = useHistory();
const queryClient = useQueryClient();
const toggleBookmark = useToggleReportBookmark();
const { data: reports, isLoading, isError } = useGetLatestReports(3);
const { mutate: markAsRead } = useMarkReportAsRead();
const currentUser = useCurrentUser();
Expand All @@ -47,31 +48,6 @@ const HomePage: React.FC = () => {
history.push(`/tabs/reports/${reportId}`);
};

const handleToggleBookmark = async (reportId: string, isCurrentlyBookmarked: boolean) => {
try {
// Toggle the bookmark status
const updatedReport = await toggleReportBookmark(reportId, !isCurrentlyBookmarked);

// Update the reports in the cache
queryClient.setQueryData<MedicalReport[]>(['reports'], (oldReports) => {
if (!oldReports) return [];
return oldReports.map((report) =>
report.id === updatedReport.id ? updatedReport : report,
);
});

// Update the latest reports cache with the correct query key including the limit
queryClient.setQueryData<MedicalReport[]>(['latestReports', 3], (oldReports) => {
if (!oldReports) return [];
return oldReports.map((report) =>
report.id === updatedReport.id ? updatedReport : report,
);
});
} catch (error) {
console.error('Failed to toggle bookmark:', error);
}
};

const handleUpload = () => {
history.push('/upload');
};
Expand Down Expand Up @@ -121,7 +97,9 @@ const HomePage: React.FC = () => {
key={report.id}
report={report}
onClick={() => handleReportClick(report.id)}
onToggleBookmark={() => handleToggleBookmark(report.id, report.bookmarked)}
onToggleBookmark={() =>
toggleBookmark.mutate({ reportId: report.id, isBookmarked: report.bookmarked })
}
showBookmarkButton={true}
/>
));
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/pages/Processing/ProcessingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import './ProcessingPage.scss';
import { getAuthConfig } from 'common/api/reportService';
import ProcessingError from './components/ProcessingError';
import ProcessingAnimation from './components/ProcessingAnimation';
import { QueryKey } from 'common/utils/constants';
import { useQueryClient } from '@tanstack/react-query';

const API_URL = import.meta.env.VITE_BASE_URL_API || '';

Expand All @@ -20,6 +22,7 @@ const ProcessingPage: React.FC = () => {
const firstName = currentUser?.name?.split(' ')[0];
const axios = useAxios();
const history = useHistory();
const queryClient = useQueryClient();

// States to track processing
const [isProcessing, setIsProcessing] = useState(true);
Expand Down Expand Up @@ -70,6 +73,9 @@ const ProcessingPage: React.FC = () => {

console.log('Processing complete');

queryClient.invalidateQueries({ queryKey: [QueryKey.Reports] });
queryClient.invalidateQueries({ queryKey: [QueryKey.LatestReports] });

history.push(`/tabs/reports/${reportId}`);
} else if (data.status === 'failed') {
if (data.isMedicalReport === false) {
Expand Down
17 changes: 14 additions & 3 deletions frontend/src/pages/Reports/ReportDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { IonPage, IonContent } from '@ionic/react';
import { useState } from 'react';
import { useHistory, useParams } from 'react-router-dom';
import './ReportDetailPage.scss';
import { useQuery } from '@tanstack/react-query';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import axios from 'axios';
import { MedicalReport } from '../../common/models/medicalReport';
import { useTranslation } from 'react-i18next';
Expand All @@ -16,6 +16,7 @@ import InfoCard from './components/InfoCard';
import ActionButtons from './components/ActionButtons';
import AiAnalysisTab from './components/AiAnalysisTab';
import UploadModal from 'common/components/Upload/UploadModal';
import { QueryKey } from 'common/utils/constants';

const API_URL = import.meta.env.VITE_BASE_URL_API || '';

Expand All @@ -38,6 +39,7 @@ const ReportDetailPage: React.FC = () => {
const { t } = useTranslation();
const { createToast } = useToasts();
const [isUploadModalOpen, setIsUploadModalOpen] = useState(false);
const queryClient = useQueryClient();

const handleUploadComplete = () => {
setIsUploadModalOpen(false);
Expand All @@ -46,7 +48,7 @@ const ReportDetailPage: React.FC = () => {

// Fetch report data using react-query
const { data, isLoading, error } = useQuery<MedicalReport>({
queryKey: ['report', reportId],
queryKey: [QueryKey.ReportDetail, reportId],
queryFn: () => fetchReportById(reportId!),
enabled: !!reportId,
});
Expand Down Expand Up @@ -107,6 +109,10 @@ const ReportDetailPage: React.FC = () => {
duration: 2000,
});

queryClient.invalidateQueries({ queryKey: [QueryKey.Reports] });
queryClient.invalidateQueries({ queryKey: [QueryKey.LatestReports] });
queryClient.invalidateQueries({ queryKey: [QueryKey.ReportDetail, reportId] });

// Navigate back
history.push('/tabs/home');
} catch (error) {
Expand All @@ -129,6 +135,11 @@ const ReportDetailPage: React.FC = () => {
setIsProcessing(true);
await axios.delete(`${API_URL}/api/reports/${reportId}`, await getAuthConfig());
setIsProcessing(false);

queryClient.invalidateQueries({ queryKey: [QueryKey.Reports] });
queryClient.invalidateQueries({ queryKey: [QueryKey.LatestReports] });
queryClient.invalidateQueries({ queryKey: [QueryKey.ReportDetail, reportId] });

setIsUploadModalOpen(true);
} catch (error) {
setIsProcessing(false);
Expand Down Expand Up @@ -168,7 +179,7 @@ const ReportDetailPage: React.FC = () => {

<UploadModal
isOpen={isUploadModalOpen}
onClose={() => setIsUploadModalOpen(false)}
onClose={handleUploadComplete}
onUploadComplete={handleUploadComplete}
/>
</IonContent>
Expand Down
Loading