refactor(frontend): replace confirm() with modern confirmation modals

Replaced all confirm() dialogs with reusable ConfirmationModal component
for better UX. Modal dialogs provide clearer context, visual consistency,
and prevent accidental confirmations.

Changes:
- MatchesPage: Reject match request confirmation modal
- DashboardPage: Decline and cancel request confirmation modals
- ContactMessagesPage: Delete message confirmation modal

All modals support loading states during async operations and provide
clear action descriptions with destructive action styling.
This commit is contained in:
Radosław Gierwiało
2025-12-05 22:14:09 +01:00
parent bb8a876ab0
commit 76be8a4419
3 changed files with 122 additions and 21 deletions

View File

@@ -7,6 +7,7 @@ import { dashboardAPI, matchesAPI } from '../services/api';
import { connectSocket, disconnectSocket, getSocket } from '../services/socket';
import { DashboardSkeleton } from '../components/common/Skeleton';
import EmptyState from '../components/common/EmptyState';
import ConfirmationModal from '../components/modals/ConfirmationModal';
import {
DashboardEventCard,
DashboardMatchCard,
@@ -28,6 +29,9 @@ const DashboardPage = () => {
const { user } = useAuth();
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [showDeclineModal, setShowDeclineModal] = useState(false);
const [showCancelModal, setShowCancelModal] = useState(false);
const [matchToProcess, setMatchToProcess] = useState(null);
const [error, setError] = useState('');
const [processingMatchId, setProcessingMatchId] = useState(null);
@@ -105,12 +109,17 @@ const DashboardPage = () => {
}
};
const handleRejectMatch = async (matchSlug) => {
if (!confirm('Are you sure you want to decline this request?')) return;
const handleRejectMatch = (matchSlug) => {
setMatchToProcess(matchSlug);
setShowDeclineModal(true);
};
const confirmRejectMatch = async () => {
if (!matchToProcess) return;
try {
setProcessingMatchId(matchSlug);
await matchesAPI.deleteMatch(matchSlug);
setProcessingMatchId(matchToProcess);
await matchesAPI.deleteMatch(matchToProcess);
toast.success('Request declined.');
await loadDashboard();
} catch (err) {
@@ -118,15 +127,22 @@ const DashboardPage = () => {
toast.error('Failed to decline request. Please try again.');
} finally {
setProcessingMatchId(null);
setShowDeclineModal(false);
setMatchToProcess(null);
}
};
const handleCancelRequest = async (matchSlug) => {
if (!confirm('Are you sure you want to cancel this request?')) return;
const handleCancelRequest = (matchSlug) => {
setMatchToProcess(matchSlug);
setShowCancelModal(true);
};
const confirmCancelRequest = async () => {
if (!matchToProcess) return;
try {
setProcessingMatchId(matchSlug);
await matchesAPI.deleteMatch(matchSlug);
setProcessingMatchId(matchToProcess);
await matchesAPI.deleteMatch(matchToProcess);
toast.success('Request cancelled.');
await loadDashboard();
} catch (err) {
@@ -134,6 +150,8 @@ const DashboardPage = () => {
toast.error('Failed to cancel request. Please try again.');
} finally {
setProcessingMatchId(null);
setShowCancelModal(false);
setMatchToProcess(null);
}
};
@@ -316,6 +334,38 @@ const DashboardPage = () => {
</section>
)}
</div>
{/* Decline Confirmation Modal */}
<ConfirmationModal
isOpen={showDeclineModal}
onClose={() => {
setShowDeclineModal(false);
setMatchToProcess(null);
}}
onConfirm={confirmRejectMatch}
title="Decline Match Request"
message="Are you sure you want to decline this request? This action cannot be undone."
confirmText="Decline"
cancelText="Cancel"
isLoading={processingMatchId === matchToProcess}
loadingText="Declining..."
/>
{/* Cancel Confirmation Modal */}
<ConfirmationModal
isOpen={showCancelModal}
onClose={() => {
setShowCancelModal(false);
setMatchToProcess(null);
}}
onConfirm={confirmCancelRequest}
title="Cancel Match Request"
message="Are you sure you want to cancel this request? This action cannot be undone."
confirmText="Cancel Request"
cancelText="Keep Request"
isLoading={processingMatchId === matchToProcess}
loadingText="Cancelling..."
/>
</Layout>
);
};