From c9a47fce9140f7e6a72bf4401534413a16b65e4d Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Mon, 28 Apr 2025 09:43:55 +0700 Subject: [PATCH 1/4] remove button reset at add dialog wallet rule --- src/pages/master/walletRule/blocks/AddDialog.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/pages/master/walletRule/blocks/AddDialog.tsx b/src/pages/master/walletRule/blocks/AddDialog.tsx index 4995c45..48cfc40 100644 --- a/src/pages/master/walletRule/blocks/AddDialog.tsx +++ b/src/pages/master/walletRule/blocks/AddDialog.tsx @@ -383,9 +383,6 @@ const AddDialog = () => {
- - */} + {/* Left Side: Filters */} +
+ {/* Wallet Filter */} +
+ + +
+ + {/* Group Filter */} +
+ + +
+ + {/* Reset Filter Button */} +
+ + + + +
+ + {/* Right Side: Action Buttons */}
- + diff --git a/src/pages/master/walletRule/hooks/ManageWalletRuleContext.tsx b/src/pages/master/walletRule/hooks/ManageWalletRuleContext.tsx index fe6232a..7f3d6b4 100644 --- a/src/pages/master/walletRule/hooks/ManageWalletRuleContext.tsx +++ b/src/pages/master/walletRule/hooks/ManageWalletRuleContext.tsx @@ -205,14 +205,22 @@ const ManageWalletRuleContextProvider = ({ children }: { children: React.ReactNo const getWalletRuleLists = async (page: number, limit: number, sorting: any, filter: any) => { try { sorting = sorting.length == 0 ? [{ id: 'name', desc: false }] : sorting; - filter = filter.length == 0 ? {} : { any: filter[0].value?.toLowerCase() }; + + let filterObject = {}; + + if (filter.length > 0 && filter[0].value) { + const parsedFilter = JSON.parse(filter[0].value); + + filterObject = { ...parsedFilter }; + } + const response = await GetData(`${API_URL_WALLET}/dashboard/wallet_rule`, { limit, page: page + 1, with_deleted: false, order_field: sorting[0].id, order_direction: sorting[0].desc == false ? 'ASC' : 'DESC', - filter: JSON.stringify(filter) + filter: JSON.stringify(filterObject) }); // console.log(response?.data); setWalletRules(response?.data.list); From cc2cd469a9f489b0ba7b79027e8d7bdce8faf08d Mon Sep 17 00:00:00 2001 From: wayanrivan Date: Mon, 28 Apr 2025 10:38:34 +0700 Subject: [PATCH 3/4] update profile --- .../AccountUserProfileContent.tsx | 3 + .../home/user-profile/blocks/PinCode.tsx | 200 ++++++++++++++++++ 2 files changed, 203 insertions(+) create mode 100644 src/pages/account/home/user-profile/blocks/PinCode.tsx diff --git a/src/pages/account/home/user-profile/AccountUserProfileContent.tsx b/src/pages/account/home/user-profile/AccountUserProfileContent.tsx index 06e35be..76cc820 100644 --- a/src/pages/account/home/user-profile/AccountUserProfileContent.tsx +++ b/src/pages/account/home/user-profile/AccountUserProfileContent.tsx @@ -1,4 +1,5 @@ import { BasicSettings, Password } from './blocks'; +import { PinCode } from './blocks/PinCode'; import { AccountUserProfileContextProvider } from './hooks'; const AccountUserProfileContent = () => { @@ -7,6 +8,8 @@ const AccountUserProfileContent = () => { + + {/* Uncomment the line below to enable the Delete Account feature */} {/* */}
diff --git a/src/pages/account/home/user-profile/blocks/PinCode.tsx b/src/pages/account/home/user-profile/blocks/PinCode.tsx new file mode 100644 index 0000000..da647ca --- /dev/null +++ b/src/pages/account/home/user-profile/blocks/PinCode.tsx @@ -0,0 +1,200 @@ +import { useState, useContext, useEffect, useCallback, MouseEvent } from 'react'; +import { AccountUserProfileContext } from '../hooks'; +import { toast } from 'sonner'; +import { useAuthContext } from '@/auth'; +import { KeenIcon } from '@/components'; +import clsx from 'clsx'; + +type PasswordType = 'password' | 'retype_password' | 'current_password'; +const PinCode = () => { + const { setPassword } = useContext(AccountUserProfileContext); + const { getUser } = useAuthContext(); + + const [newPassword, setNewPassword] = useState(''); + const [currentPassword, setCurrentPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + const [isSubmitting, setIsSubmitting] = useState(false); + const [messagePassword, setMessagePassword] = useState(true); + const [showPassword, setShowPassword] = useState({ + current_password: false, + password: false, + retype_password: false + }); + + const [passwordErrors, setPasswordErrors] = useState([]); + + const validatePassword = (password: string) => { + const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password); + const hasCapitalLetter = /[A-Z]/.test(password); + const hasNumber = /[0-9]/.test(password); + return hasSpecialChar && hasCapitalLetter && hasNumber; + }; + + useEffect(() => { + const passwordsMatch = newPassword === confirmPassword; + const isPasswordValid = validatePassword(newPassword); + setMessagePassword(passwordsMatch && isPasswordValid); + + const errors: string[] = []; + if (newPassword) { + if (!/[A-Z]/.test(newPassword)) { + errors.push('Password must contain at least one capital letter'); + } + if (!/[0-9]/.test(newPassword)) { + errors.push('Password must contain at least one number'); + } + if (!/[!@#$%^&*(),.?":{}|<>]/.test(newPassword)) { + errors.push('Password must contain at least one special character'); + } + if (newPassword !== confirmPassword) { + errors.push('Passwords do not match'); + } + } + setPasswordErrors(errors); + }, [newPassword, confirmPassword]); + + const handleResetPassword = useCallback(async () => { + const user: any = await getUser(); + + if (!messagePassword) { + toast.error('Passwords do not match!'); + return; + } + + setIsSubmitting(true); + + try { + await setPassword({ + current_password: currentPassword, + password: newPassword, + retype_password: confirmPassword, + username: user.data.username ?? '' + }); + + setNewPassword(''); + setConfirmPassword(''); + setCurrentPassword(''); + } catch (error: any) { + const errorMessage = + error?.response?.data?.message || + error?.message || + 'An error occurred while resetting the password.'; + toast.error(errorMessage); + } finally { + setIsSubmitting(false); + } + }, [currentPassword, newPassword, newPassword, messagePassword, getUser]); + + const isButtonDisabled = isSubmitting || !newPassword || !confirmPassword || !messagePassword; + + const togglePassword = useCallback((event: MouseEvent, key: string) => { + event.preventDefault(); + setShowPassword((prev) => ({ ...prev, [key]: !prev[key as PasswordType] })); + }, []); + + return ( +
+
+

Pin Code

+
+
+
+ +
+ setCurrentPassword(e.target.value)} + disabled={isSubmitting} + /> + +
+
+
+ +
+ setNewPassword(e.target.value)} + disabled={isSubmitting} + type={showPassword.password ? 'text' : 'password'} + /> + +
+
+
+
+ +
+ setConfirmPassword(e.target.value)} + disabled={isSubmitting} + /> + +
+
+
+ + {passwordErrors.length > 0 && ( +
+ {passwordErrors.map((error, index) => ( +

{error}

+ ))} +
+ )} +
+
+ +
+ +
+
+
+ ); +}; + +export { PinCode }; From 6acea6499de25cad3a4c8bce8d37578159743bb1 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Mon, 28 Apr 2025 11:10:00 +0700 Subject: [PATCH 4/4] update profile logo and title on topbar --- src/layouts/demo2/header/HeaderTopbar.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/layouts/demo2/header/HeaderTopbar.tsx b/src/layouts/demo2/header/HeaderTopbar.tsx index 5256605..30e26f1 100644 --- a/src/layouts/demo2/header/HeaderTopbar.tsx +++ b/src/layouts/demo2/header/HeaderTopbar.tsx @@ -25,21 +25,21 @@ const HeaderTopbar = () => { const handleDropdownChatShow = () => { window.dispatchEvent(new Event('resize')); }; - + return (
-
+
{getAuth()?.user.username} - - {getAuth()?.role_name} + + as {getAuth()?.role_name}
- + { ] }} > - + User avatar @@ -70,4 +70,4 @@ const HeaderTopbar = () => { ); }; -export { HeaderTopbar }; \ No newline at end of file +export { HeaderTopbar };