From ff6e87e74670ebe533c42037171e3d009393de07 Mon Sep 17 00:00:00 2001 From: adityapat24 Date: Thu, 9 Apr 2026 15:15:43 -0400 Subject: [PATCH 1/2] confirmation for needed actions --- .../main-page/grants/edit-grant/EditGrant.tsx | 14 +++++++- frontend/src/main-page/settings/Settings.tsx | 35 +++++++++++++++++-- .../users/components/UserApprove.tsx | 25 +++++++++++-- 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/frontend/src/main-page/grants/edit-grant/EditGrant.tsx b/frontend/src/main-page/grants/edit-grant/EditGrant.tsx index 43f7592b..77c969ca 100644 --- a/frontend/src/main-page/grants/edit-grant/EditGrant.tsx +++ b/frontend/src/main-page/grants/edit-grant/EditGrant.tsx @@ -46,6 +46,7 @@ const EditGrant: React.FC<{ // State to track if form was submitted successfully const [saving, setSaving] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false); + const [showSaveModal, setShowSaveModal] = useState(false); const [form, dispatch] = useReducer(reducer, { organization: grantToEdit?.organization ?? "", @@ -170,7 +171,7 @@ const EditGrant: React.FC<{ - +

+ Your Notifications +

+
+ +
- {liveNotifications && liveNotifications.length > 0 ? ( - liveNotifications.map((n) => ( - - )) - ) : ( -

No new notifications

- )} + {liveNotifications && liveNotifications.length > 0 ? ( + liveNotifications.map((n) => ( + + setConfirm({ + kind: "one", + id, + message: n.message, + }) + } + avatarUrl={user?.profilePicUrl ?? null} + firstName={user?.firstName ?? ""} + lastName={user?.lastName ?? ""} + /> + )) + ) : ( +

+ No new notifications +

+ )}
+ - , - document.body + , + document.body, ); -}); + }, +); -export default NotificationPopup; \ No newline at end of file +export default NotificationPopup; diff --git a/frontend/src/main-page/settings/ChangePasswordModal.tsx b/frontend/src/main-page/settings/ChangePasswordModal.tsx index 2e842872..8628354c 100644 --- a/frontend/src/main-page/settings/ChangePasswordModal.tsx +++ b/frontend/src/main-page/settings/ChangePasswordModal.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, useEffect } from "react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faXmark } from "@fortawesome/free-solid-svg-icons"; import { @@ -6,6 +6,7 @@ import { PasswordRequirements, isPasswordValid, } from "../../sign-up"; +import ActionConfirmation from "../../components/ActionConfirmation"; export type ChangePasswordFormValues = { currentPassword: string; @@ -28,6 +29,11 @@ export default function ChangePasswordModal({ const [currentPassword, setCurrentPassword] = useState(""); const [newPassword, setNewPassword] = useState(""); const [reEnterPassword, setReEnterPassword] = useState(""); + const [showConfirm, setShowConfirm] = useState(false); + + useEffect(() => { + if (!isOpen) setShowConfirm(false); + }, [isOpen]); if (!isOpen) return null; @@ -46,11 +52,16 @@ export default function ChangePasswordModal({ setCurrentPassword(""); setNewPassword(""); setReEnterPassword(""); + setShowConfirm(false); onClose(); }; - const handleSave = () => { + const requestSave = () => { if (!canSave) return; + setShowConfirm(true); + }; + + const handleConfirmedSave = () => { onSubmit?.({ currentPassword: currentPassword.trim(), newPassword, @@ -64,6 +75,16 @@ export default function ChangePasswordModal({ aria-modal="true" aria-labelledby="change-password-title" > + setShowConfirm(false)} + onConfirmDelete={handleConfirmedSave} + title="Change password" + subtitle="Are you sure you want to change" + boldSubtitle="your password" + warningMessage="You will use your new password the next time you sign in." + variant="update" + />

diff --git a/frontend/src/main-page/settings/ProfilePictureModal.tsx b/frontend/src/main-page/settings/ProfilePictureModal.tsx index 7ade673f..a80c8325 100644 --- a/frontend/src/main-page/settings/ProfilePictureModal.tsx +++ b/frontend/src/main-page/settings/ProfilePictureModal.tsx @@ -1,4 +1,4 @@ -import { useState, useCallback } from "react"; +import { useState, useCallback, useEffect } from "react"; import Cropper, { Area } from "react-easy-crop"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faXmark } from "@fortawesome/free-solid-svg-icons"; @@ -15,6 +15,7 @@ import { getAppStore } from "../../external/bcanSatchel/store"; import { updateUserProfile } from "../../external/bcanSatchel/actions"; import { setActiveUsers } from "../../external/bcanSatchel/actions"; import { User } from "../../../../middle-layer/types/User"; +import ActionConfirmation from "../../components/ActionConfirmation"; type ProfilePictureModalProps = { isOpen: boolean; @@ -36,9 +37,14 @@ export default function ProfilePictureModal({ const [uploadError, setUploadError] = useState(null); const [isUploading, setIsUploading] = useState(false); const [validationError, setValidationError] = useState(null); + const [showUploadConfirm, setShowUploadConfirm] = useState(false); const user = getAppStore().user; + useEffect(() => { + if (!isOpen) setShowUploadConfirm(false); + }, [isOpen]); + const onCropComplete = useCallback((_croppedArea: Area, croppedAreaPixels: Area) => { setCroppedAreaPixels(croppedAreaPixels); }, []); @@ -51,6 +57,7 @@ export default function ProfilePictureModal({ setUploadError(null); setValidationError(null); setIsUploading(false); + setShowUploadConfirm(false); onClose(); }; @@ -82,7 +89,7 @@ export default function ProfilePictureModal({ reader.readAsDataURL(file); }; - const handleSave = async () => { + const performUpload = async () => { if (!imageSrc || !croppedAreaPixels || !user) return; setIsUploading(true); @@ -152,6 +159,18 @@ export default function ProfilePictureModal({ aria-modal="true" aria-labelledby="profile-picture-title" > + setShowUploadConfirm(false)} + onConfirmDelete={() => { + void performUpload(); + }} + title="Update profile picture" + subtitle="Are you sure you want to upload" + boldSubtitle="this profile picture" + warningMessage="This will replace your current profile picture for your account." + variant="update" + />