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
84 changes: 84 additions & 0 deletions frontend/src/common/components/Modal/ConfirmationModal.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
.confirmation-modal {
--height: auto;
--border-radius: 16px 16px 0 0;
--box-shadow: none;
align-items: flex-end;
--background: #ffffff;

&__container {
padding: 24px;
width: 100%;
}

&__title {
font-family: 'Inter', sans-serif;
font-size: 22px;
font-weight: 600;
color: #313e4c;
margin: 0 0 16px;
text-align: left;
}

&__message {
font-family: 'Inter', sans-serif;
font-size: 16px;
font-weight: 400;
color: #313e4c;
margin: 0 0 24px;
text-align: left;
line-height: 1.5;
}

&__actions {
display: flex;
gap: 16px;
}

&__button {
flex: 1;
min-height: 56px;
margin: 0;
--border-radius: 12px;
font-size: 20px;
font-weight: 600;
text-transform: none;

&--cancel {
--background: #ffffff;
--background-hover: rgba(67, 95, 240, 0.04);
--background-activated: rgba(67, 95, 240, 0.08);
--color: #435ff0; /* Blue color for No button */
--border-color: #435ff0;
--border-width: 1px;
--border-style: solid;
--box-shadow: none;
}

&--confirm {
--background: #ffffff; /* White background for Yes button */
--background-hover: rgba(175, 27, 63, 0.04);
--background-activated: rgba(175, 27, 63, 0.08);
--color: #af1b3f; /* Red color for Yes button */
--border-color: #af1b3f; /* Red border for Yes button */
--border-width: 1px;
--border-style: solid;
}
}

// Media queries for larger screens
@media screen and (min-width: 768px) {
&__container {
max-width: 500px;
margin: 0 auto;
}
}

// Handle the pull indicator
&::part(handle) {
background: #D9D9D9;
width: 36px;
height: 4px;
border-radius: 2px;
margin-top: 12px;
}
}
77 changes: 77 additions & 0 deletions frontend/src/common/components/Modal/ConfirmationModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from 'react';
import { IonButton, IonModal } from '@ionic/react';
import './ConfirmationModal.scss';

interface ConfirmationModalProps {
isOpen: boolean;
title: string;
message: string;
confirmText: string;
cancelText: string;
onConfirm: () => void;
onCancel: () => void;
itemName?: string;
testid?: string;
}

/**
* A reusable confirmation modal component that presents as a bottom sheet
* Used for confirming destructive actions like deleting or discarding items
*/
const ConfirmationModal: React.FC<ConfirmationModalProps> = ({
isOpen,
title,
message,
confirmText,
cancelText,
onConfirm,
onCancel,
itemName,
testid = 'confirmation-modal',
}) => {
// Replace placeholder with actual item name if provided
const formattedMessage = itemName
? message.replace('{itemName}', `"${itemName}"`)
: message;

return (
<IonModal
isOpen={isOpen}
onDidDismiss={onCancel}
className="confirmation-modal"
data-testid={testid}
>
<div className="confirmation-modal__container">
<h2 className="confirmation-modal__title">{title}</h2>

<p className="confirmation-modal__message">
{formattedMessage}
</p>

<div className="confirmation-modal__actions">
<IonButton
expand="block"
fill="outline"
className="confirmation-modal__button confirmation-modal__button--cancel"
onClick={onCancel}
data-testid={`${testid}-cancel`}
>
{cancelText}
</IonButton>

<IonButton
expand="block"
fill="outline"
className="confirmation-modal__button confirmation-modal__button--confirm"
onClick={onConfirm}
data-testid={`${testid}-confirm`}
>
{confirmText}
</IonButton>
</div>
</div>
</IonModal>
);
};

export default ConfirmationModal;
4 changes: 2 additions & 2 deletions frontend/src/common/utils/i18n/resources/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@
"loading": {
"report": "Loading report..."
},
"no": "no",
"no": "No",
"updated": "updated",
"welcome": "Welcome",
"yes": "yes",
"yes": "Yes",
"pages": {
"chat": {
"title": "AI Assistant"
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/common/utils/i18n/resources/es/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@
"loading": {
"report": "Cargando informe..."
},
"no": "no",
"no": "No",
"updated": "actualizado",
"welcome": "Bienvenido",
"yes": "",
"yes": "",
"pages": {
"chat": {
"title": "Asistente IA"
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/common/utils/i18n/resources/fr/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@
"loading": {
"report": "Chargement du rapport..."
},
"no": "non",
"no": "Non",
"updated": "mis à jour",
"welcome": "Bienvenu",
"yes": "oui",
"yes": "Oui",
"pages": {
"chat": {
"title": "Assistant IA"
Expand Down
36 changes: 33 additions & 3 deletions frontend/src/pages/Reports/ReportDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import axios from 'axios';
import { MedicalReport } from '../../common/models/medicalReport';
import { useTranslation } from 'react-i18next';
import { getAuthConfig } from 'common/api/reportService';
import { useToasts } from 'common/hooks/useToasts';

// Import components
import ReportHeader from './components/ReportHeader';
Expand Down Expand Up @@ -35,6 +36,7 @@ const ReportDetailPage: React.FC = () => {
const { reportId } = useParams<{ reportId: string }>();
const history = useHistory();
const { t } = useTranslation();
const { createToast } = useToasts();

// Fetch report data using react-query
const { data, isLoading, error } = useQuery<MedicalReport>({
Expand Down Expand Up @@ -85,8 +87,31 @@ const ReportDetailPage: React.FC = () => {

// Handle action buttons
const handleDiscard = async () => {
await axios.delete(`${API_URL}/api/reports/${reportId}`, await getAuthConfig());
history.push('/tabs/home');
try {
await axios.delete(`${API_URL}/api/reports/${reportId}`, await getAuthConfig());

// Show toast notification
createToast({
message: t('report.discard.success', {
ns: 'reportDetail',
defaultValue: 'Report deleted successfully',
}),
duration: 2000,
});

// Navigate back
history.push('/tabs/home');
} catch (error) {
console.error('Error discarding report:', error);
createToast({
message: t('report.discard.error', {
ns: 'reportDetail',
defaultValue: 'Failed to delete report',
}),
duration: 2000,
color: 'danger',
});
}
};

const handleNewUpload = () => {
Expand Down Expand Up @@ -114,7 +139,12 @@ const ReportDetailPage: React.FC = () => {
<InfoCard />

{/* Action buttons at the bottom */}
<ActionButtons onDiscard={handleDiscard} onNewUpload={handleNewUpload} />
<ActionButtons
onDiscard={handleDiscard}
onNewUpload={handleNewUpload}
reportTitle={reportData.title || reportData.category}
reportId={reportId}
/>
</IonContent>
</IonPage>
);
Expand Down
Loading