diff --git a/apps/frontend/app/(client)/(main)/settings/_components/ConfirmModal.tsx b/apps/frontend/app/(client)/(main)/settings/_components/ConfirmModal.tsx
new file mode 100644
index 000000000..942556fe6
--- /dev/null
+++ b/apps/frontend/app/(client)/(main)/settings/_components/ConfirmModal.tsx
@@ -0,0 +1,61 @@
+import BaseModal from '@/components/BaseModal'
+import {
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogFooter
+} from '@/components/shadcn/alert-dialog'
+
+interface ModalProps {
+ open: boolean
+ handleOpen: () => void
+ handleClose: () => void
+ confirmAction: () => void
+ title?: string
+ description?: string
+}
+
+/**
+ *
+ * ConfirmModal component renders a modal dialog with confirm and cancel actions.
+ *
+ * @param open - Determines if the modal is open.
+ * @param handleClose - Function to close the modal.
+ * @param confirmAction - Function to execute when the user confirms.
+ * @param title - Title of the modal.
+ * @param description - Description of the modal.
+ *
+ * @remarks
+ * * AlertDialogFooter section (Button section) is separated using ConfirmModal component for reusability.
+ */
+export default function ConfirmModal({
+ open,
+ handleClose,
+ confirmAction,
+ title = '',
+ description = ''
+}: ModalProps) {
+ return (
+
+
+
+ Leave
+
+
+ Stay
+
+
+
+ )
+}
diff --git a/apps/frontend/app/(client)/(main)/settings/_components/ConfirmNavigation.tsx b/apps/frontend/app/(client)/(main)/settings/_components/ConfirmNavigation.tsx
index 5e7afa67c..4cc473bb8 100644
--- a/apps/frontend/app/(client)/(main)/settings/_components/ConfirmNavigation.tsx
+++ b/apps/frontend/app/(client)/(main)/settings/_components/ConfirmNavigation.tsx
@@ -2,7 +2,7 @@ import type { Route } from 'next'
import type { NavigateOptions } from 'next/dist/shared/lib/app-router-context.shared-runtime'
import { useRouter } from 'next/navigation'
import type { MutableRefObject } from 'react'
-import { useEffect } from 'react'
+import { useEffect, useState } from 'react'
import { toast } from 'sonner'
// const beforeUnloadHandler = (event: BeforeUnloadEvent) => {
@@ -22,6 +22,9 @@ export const useConfirmNavigation = (
updateNow: boolean
) => {
const router = useRouter()
+ const [isConfirmModalOpen, setIsConfirmModalOpen] = useState(false)
+ const [confirmAction, setConfirmAction] = useState<() => void>(() => () => {})
+
useEffect(() => {
const originalPush = router.push
const newPush = (
@@ -37,12 +40,11 @@ export const useConfirmNavigation = (
return
}
if (!bypassConfirmation.current) {
- const isConfirmed = window.confirm(
- 'Are you sure you want to leave?\nYour changes have not been saved.\nIf you leave this page, all changes will be lost.\nDo you still want to proceed?'
- )
- if (isConfirmed) {
+ setIsConfirmModalOpen(true)
+ setConfirmAction(() => () => {
+ setIsConfirmModalOpen(false)
originalPush(href as Route, options)
- }
+ })
return
}
originalPush(href as Route, options)
@@ -52,4 +54,6 @@ export const useConfirmNavigation = (
router.push = originalPush
}
}, [router, bypassConfirmation.current])
+
+ return { isConfirmModalOpen, setIsConfirmModalOpen, confirmAction }
}
diff --git a/apps/frontend/app/(client)/(main)/settings/page.tsx b/apps/frontend/app/(client)/(main)/settings/page.tsx
index b32b8352f..f5af4c615 100644
--- a/apps/frontend/app/(client)/(main)/settings/page.tsx
+++ b/apps/frontend/app/(client)/(main)/settings/page.tsx
@@ -9,6 +9,7 @@ import { useState } from 'react'
import { useForm } from 'react-hook-form'
import { toast } from 'sonner'
import { z } from 'zod'
+import ConfirmModal from './_components/ConfirmModal'
import { useConfirmNavigation } from './_components/ConfirmNavigation'
import CurrentPwSection from './_components/CurrentPwSection'
import IdSection from './_components/IdSection'
@@ -91,8 +92,6 @@ export default function Page() {
fetchDefaultProfile()
}, [])
- useConfirmNavigation(bypassConfirmation, !!updateNow)
-
const {
register,
handleSubmit,
@@ -112,6 +111,8 @@ export default function Page() {
}
})
+ const { isConfirmModalOpen, setIsConfirmModalOpen, confirmAction } =
+ useConfirmNavigation(bypassConfirmation, !!updateNow)
const [isCheckButtonClicked, setIsCheckButtonClicked] =
useState(false)
const [isPasswordCorrect, setIsPasswordCorrect] = useState(false)
@@ -324,6 +325,15 @@ export default function Page() {
onSubmitClick={onSubmitClick}
/>
+
+ setIsConfirmModalOpen(true)}
+ handleClose={() => setIsConfirmModalOpen(false)}
+ confirmAction={confirmAction}
+ />
)
}
diff --git a/apps/frontend/components/BaseModal.tsx b/apps/frontend/components/BaseModal.tsx
new file mode 100644
index 000000000..23810a408
--- /dev/null
+++ b/apps/frontend/components/BaseModal.tsx
@@ -0,0 +1,68 @@
+import { Loader2 } from 'lucide-react'
+import React, { Fragment, type ReactNode } from 'react'
+import {
+ AlertDialog,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogHeader,
+ AlertDialogOverlay,
+ AlertDialogTitle
+} from './shadcn/alert-dialog'
+
+interface BaseModalProps {
+ open: boolean
+ handleClose: () => void
+ children?: ReactNode
+ loading?: boolean
+ loadingMessage?: string
+ title?: string
+ description?: string
+ modalBgDarkMode?: boolean
+}
+
+/**
+ *
+ * @remarks
+ * * Use BaseModal Component by creating a new component(which includes 'AlertDialogFooter') that extends BaseModal
+ * * AlertDialogFooter section (Button section) is separated using ConfirmModal component for reusability.
+ */
+export default function BaseModal({
+ open,
+ handleClose,
+ children,
+ loading = false,
+ loadingMessage = '',
+ title = '',
+ description = '',
+ modalBgDarkMode = false
+}: BaseModalProps) {
+ const formattedDescription =
+ description.split('\n').map((line, index) => (
+
+ {line}
+
+
+ )) ?? ''
+
+ return (
+
+
+
+
+ {title}
+
+ {loading ? (
+
+
+ {loadingMessage}
+
+ ) : (
+ formattedDescription
+ )}
+
+
+ {children}
+
+
+ )
+}
diff --git a/apps/frontend/components/shadcn/alert-dialog.tsx b/apps/frontend/components/shadcn/alert-dialog.tsx
index baaf9e0e1..1a67ebd19 100644
--- a/apps/frontend/components/shadcn/alert-dialog.tsx
+++ b/apps/frontend/components/shadcn/alert-dialog.tsx
@@ -13,11 +13,16 @@ const AlertDialogPortal = AlertDialogPrimitive.Portal
const AlertDialogOverlay = React.forwardRef<
React.ElementRef,
- React.ComponentPropsWithoutRef
->(({ className, ...props }, ref) => (
+ React.ComponentPropsWithoutRef & {
+ darkMode?: boolean
+ }
+>(({ className, darkMode = false, ...props }, ref) => (