From 1e72fe111c92f7fcfd756df0890c427f66dbcdcd Mon Sep 17 00:00:00 2001 From: sajjad isvand Date: Wed, 22 Jul 2026 23:35:16 +0330 Subject: [PATCH] feat(ui): enhance ConfirmationModal with primary variant and improved UX --- src/components/blur-mode/blur-mode.button.tsx | 65 ++++++++++++++---- src/components/modal/confirmation-modal.tsx | 66 +++++++++++-------- src/icons/packs/default.tsx | 5 +- src/icons/types.ts | 1 + src/layouts/bookmark/bookmark-grid.tsx | 12 ++-- .../tabs/user-profile/user-profile.tsx | 1 + src/layouts/widgets/habit/habits.layout.tsx | 2 +- src/layouts/widgets/todos/todo.item.tsx | 3 +- 8 files changed, 104 insertions(+), 51 deletions(-) diff --git a/src/components/blur-mode/blur-mode.button.tsx b/src/components/blur-mode/blur-mode.button.tsx index 7da24c8b..05a58d6d 100644 --- a/src/components/blur-mode/blur-mode.button.tsx +++ b/src/components/blur-mode/blur-mode.button.tsx @@ -1,27 +1,64 @@ +import { useState } from 'react' import { useGeneralSetting } from '@/context/general-setting.context' import Tooltip from '../toolTip' import { Icon } from '@/src/icons' +import { ConfirmationModal } from '../modal/confirmation-modal' +import Analytics from '@/analytics' export function BlurModeButton() { const { blurMode, updateSetting } = useGeneralSetting() + const [showConfirm, setShowConfirm] = useState(false) + + const applyBlurMode = (value: boolean) => { + updateSetting('blurMode', value) + } const handleBlurModeToggle = () => { - const newBlurMode = !blurMode - updateSetting('blurMode', newBlurMode) + if (!blurMode) { + setShowConfirm(true) + Analytics.event('blurModeConfirm') + } else { + applyBlurMode(false) + } + } + + const handleConfirm = () => { + applyBlurMode(true) + setShowConfirm(false) } return ( - -
- {blurMode ? ( - - ) : ( - - )} -
-
+ <> + +
+ {blurMode ? ( + + ) : ( + + )} +
+
+ + setShowConfirm(false)} + onConfirm={handleConfirm} + variant="primary" + title="حالت مخفی فعال میشه!" + icon={} + message={ +
+ با فعال کردن «حالت مخفی»، اطلاعات حساس، وظایف و محتوای ویجت‌ها + به‌صورت خودکار تار میشن تا اگر کسی از کنار صفحه یا پشت سرت نگاه + کرد، نتونه چیزی بخونه 🔒 +
+ } + confirmText="بریم تو حالت مخفی" + cancelText="نه فعلا" + /> + ) } diff --git a/src/components/modal/confirmation-modal.tsx b/src/components/modal/confirmation-modal.tsx index 1244b141..2dcb2b7f 100644 --- a/src/components/modal/confirmation-modal.tsx +++ b/src/components/modal/confirmation-modal.tsx @@ -12,7 +12,7 @@ interface ConfirmationModalProps { message?: string | ReactNode confirmText?: ReactNode cancelText?: string - variant?: 'danger' | 'warning' | 'info' + variant?: 'danger' | 'warning' | 'info' | 'primary' isLoading?: boolean icon?: ReactNode direction?: 'rtl' | 'ltr' @@ -20,35 +20,46 @@ interface ConfirmationModalProps { const variantConfig = { danger: { - icon: , + icon: , + accentBar: 'bg-error', iconBg: 'bg-error/10', iconColor: 'text-error', confirmBg: 'bg-error hover:bg-error/90', confirmText: 'text-white', }, warning: { - icon: , + icon: , + accentBar: 'bg-warning', iconBg: 'bg-warning/10', iconColor: 'text-warning', confirmBg: 'bg-warning hover:bg-warning/90', confirmText: 'text-white', }, info: { - icon: , + icon: , + accentBar: 'bg-info', iconBg: 'bg-info/10', iconColor: 'text-info', confirmBg: 'bg-info/80 hover:bg-info/90', confirmText: 'text-white', }, + primary: { + icon: , + accentBar: 'bg-primary', + iconBg: 'bg-primary/10', + iconColor: 'text-primary', + confirmBg: 'bg-primary/80 hover:bg-primary/90', + confirmText: 'text-white', + }, } export function ConfirmationModal({ isOpen, onClose, onConfirm, - title = 'تأیید عملیات', + title = 'تایید عملیات', message = 'آیا از انجام این عملیات اطمینان دارید؟', - confirmText = 'تأیید', + confirmText = 'تایید', cancelText = 'انصراف', variant = 'danger', isLoading = false, @@ -78,24 +89,35 @@ export function ConfirmationModal({ direction={direction} closeOnBackdropClick={!isLoading} showCloseButton={!isLoading} - title={' '} - > -
-
+ title={ +
{displayIcon}
+ {title && ( +

{title}

+ )}
- - {title &&

{title}

} - -
+ } + > +
+
{typeof message === 'string' ?

{message}

: message}
-
+
+ +
+
} - className={`flex-1 ${config.confirmBg} ${config.confirmText} border-none rounded-2xl`} + className={`${config.confirmBg} ${config.confirmText} w-fit px-8 border-none rounded-2xl`} > {confirmText} -
diff --git a/src/icons/packs/default.tsx b/src/icons/packs/default.tsx index e4ec0c3d..87bbdde0 100644 --- a/src/icons/packs/default.tsx +++ b/src/icons/packs/default.tsx @@ -59,6 +59,7 @@ import { FaSpinner, FaTelegramPlane, FaUpload, + FaUserSecret, } from 'react-icons/fa' import { TbCloudOff, @@ -253,7 +254,5 @@ export const defaultIcons = { simple_ui: LuLayoutTemplate, arrowRightLeft: TbArrowsRightLeft, bookmark: HiBookmark, + userSecret: FaUserSecret, } satisfies IconMap - - - diff --git a/src/icons/types.ts b/src/icons/types.ts index 002f8ad7..b13ef183 100644 --- a/src/icons/types.ts +++ b/src/icons/types.ts @@ -130,4 +130,5 @@ export type IconName = | 'simple_ui' | 'arrowRightLeft' | 'bookmark' + | 'userSecret' export type IconMap = Record diff --git a/src/layouts/bookmark/bookmark-grid.tsx b/src/layouts/bookmark/bookmark-grid.tsx index 250e9cb2..7839a271 100644 --- a/src/layouts/bookmark/bookmark-grid.tsx +++ b/src/layouts/bookmark/bookmark-grid.tsx @@ -14,6 +14,7 @@ import { validate } from 'uuid' import { useAuth } from '@/context/auth.context' import { AuthRequiredModal } from '@/components/auth/AuthRequiredModal' import { showToast } from '@/common/toast' +import { Icon } from '@/src/icons' interface BookmarkGridProps { displayedBookmarks: Bookmark[] @@ -228,15 +229,14 @@ export function BookmarkGrid({ isOpen={showDeleteConfirmationModal} onClose={handleCancelDelete} onConfirm={handleConfirmDelete} - title="حذف بوکمارک" + title="حذف بوکمارک؟" message={ bookmarkToDelete?.type === 'FOLDER' ? (
-

- آیا از حذف پوشه "{bookmarkToDelete.title}" اطمینان دارید؟ -

-

- تمام بوکمارک‌های داخل این پوشه نیز حذف خواهند شد. +

آیا از حذف پوشه "{bookmarkToDelete.title}" مطمئن هستی؟

+

+ با حذف این پوشه، تمام بوکمارک‌های داخلش هم برای همیشه حذف + میشن و این عمل قابل بازگشت نیست!

) : ( diff --git a/src/layouts/setting/tabs/account/tabs/user-profile/user-profile.tsx b/src/layouts/setting/tabs/account/tabs/user-profile/user-profile.tsx index 72aea54b..b2059aef 100644 --- a/src/layouts/setting/tabs/account/tabs/user-profile/user-profile.tsx +++ b/src/layouts/setting/tabs/account/tabs/user-profile/user-profile.tsx @@ -118,6 +118,7 @@ export const UserProfile = () => { isOpen={showConfirm} onClose={() => setShowConfirm(false)} onConfirm={() => onClickLogout()} + icon={} message="مطمعنی میخای از حسابت خارج بشی؟" title="خروج از حساب کاربری" confirmText="بله، خروج" diff --git a/src/layouts/widgets/habit/habits.layout.tsx b/src/layouts/widgets/habit/habits.layout.tsx index e6f1c724..7b732940 100644 --- a/src/layouts/widgets/habit/habits.layout.tsx +++ b/src/layouts/widgets/habit/habits.layout.tsx @@ -199,7 +199,7 @@ export function HabitsContent() { onClose={() => setArchiveConfirm(null)} onConfirm={handleConfirmArchive} variant="danger" - title="" + title="بایگانی عادت؟" message={`از بایگانی کردن این عادت اطمینان داری؟`} confirmText="بله، بایگانی کن" cancelText="انصراف" diff --git a/src/layouts/widgets/todos/todo.item.tsx b/src/layouts/widgets/todos/todo.item.tsx index de42364b..06c5070d 100644 --- a/src/layouts/widgets/todos/todo.item.tsx +++ b/src/layouts/widgets/todos/todo.item.tsx @@ -236,8 +236,9 @@ export function TodoItem({ todo, blurMode = false, onEdit, onUpdated }: Prop) { onClose={() => setShowConfirmation(false)} onConfirm={onConfirmDelete} confirmText={isPending ? : 'حذف'} - message="آیا از حذف مطمئن هستید؟" + message="این عمل قابل بازگشت نیست و وظیفه برای همیشه حذف خواهد شد" variant="danger" + title="حذف این تسک؟" /> )}