diff --git a/src/api/user.jsx b/src/api/user.jsx
index a437190..f771f6a 100644
--- a/src/api/user.jsx
+++ b/src/api/user.jsx
@@ -156,6 +156,19 @@ const approveUser = async (user_id) => {
};
};
+const rejectUser = async (user_id) => {
+ const response = await SendRequest({
+ method: 'put',
+ prefix: `user/${user_id}/reject`,
+ });
+ // Return full response with statusCode
+ return {
+ statusCode: response.statusCode || 200,
+ data: response.data,
+ message: response.message
+ };
+};
+
const changePassword = async (user_id, new_password) => {
const response = await SendRequest({
method: 'put',
@@ -175,4 +188,4 @@ const changePassword = async (user_id, new_password) => {
};
};
-export { getAllUser, getUserById, createUser, updateUser, deleteUser, approveUser, changePassword };
\ No newline at end of file
+export { getAllUser, getUserById, createUser, updateUser, deleteUser, approveUser, rejectUser, changePassword };
\ No newline at end of file
diff --git a/src/pages/user/component/DetailUser.jsx b/src/pages/user/component/DetailUser.jsx
index 9403a99..34cccd5 100644
--- a/src/pages/user/component/DetailUser.jsx
+++ b/src/pages/user/component/DetailUser.jsx
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
import { Modal, Input, Divider, Typography, Switch, Button, ConfigProvider, Select } from 'antd';
import { CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons';
import { NotifAlert, NotifOk } from '../../../components/Global/ToastNotif';
-import { createUser, updateUser } from '../../../api/user';
+import { createUser, updateUser, changePassword } from '../../../api/user';
import { getAllRole } from '../../../api/role';
const { Text } = Typography;
@@ -23,6 +23,8 @@ const DetailUser = (props) => {
is_active: true,
password: '',
confirmPassword: '',
+ newPassword: '',
+ confirmNewPassword: '',
};
const [FormData, setFormData] = useState(defaultData);
@@ -38,6 +40,15 @@ const DetailUser = (props) => {
hasSpecialChar: false,
});
+ // New password requirements state for edit mode
+ const [newPasswordRequirements, setNewPasswordRequirements] = useState({
+ minLength: false,
+ hasUppercase: false,
+ hasLowercase: false,
+ hasNumber: false,
+ hasSpecialChar: false,
+ });
+
const handleCancel = () => {
props.setSelectedData(null);
props.setActionMode('list');
@@ -63,6 +74,17 @@ const DetailUser = (props) => {
});
};
+ // Check new password requirements for edit mode
+ const checkNewPasswordRequirements = (password) => {
+ setNewPasswordRequirements({
+ minLength: password.length >= 8,
+ hasUppercase: /[A-Z]/.test(password),
+ hasLowercase: /[a-z]/.test(password),
+ hasNumber: /\d/.test(password),
+ hasSpecialChar: /[!@#$%^&*(),.?":{}|<>]/.test(password),
+ });
+ };
+
const validatePhone = (phone) => {
const phoneRegex = /^(?:\+62|0)8\d{7,10}$/;
return phoneRegex.test(phone);
@@ -147,6 +169,20 @@ const DetailUser = (props) => {
}
}
+ // Password validation for edit mode (optional)
+ if (FormData.user_id && FormData.newPassword) {
+ const passwordError = validatePassword(FormData.newPassword);
+ if (passwordError) {
+ newErrors.newPassword = passwordError;
+ }
+
+ if (!FormData.confirmNewPassword) {
+ newErrors.confirmNewPassword = 'Konfirmasi password wajib diisi';
+ } else if (FormData.newPassword !== FormData.confirmNewPassword) {
+ newErrors.confirmNewPassword = 'Password tidak cocok';
+ }
+ }
+
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
@@ -218,13 +254,48 @@ const DetailUser = (props) => {
// Check if response is successful
if (response && (response.statusCode === 200 || response.statusCode === 201)) {
- NotifOk({
- icon: 'success',
- title: 'Berhasil',
- message: `User "${
- response.data?.user_fullname || FormData.user_fullname
- }" berhasil ${FormData.user_id ? 'diubah' : 'ditambahkan'}.`,
- });
+ // If in edit mode and newPassword is provided, change password
+ if (FormData.user_id && FormData.newPassword) {
+ try {
+ const passwordResponse = await changePassword(
+ FormData.user_id,
+ FormData.newPassword
+ );
+
+ if (passwordResponse && passwordResponse.statusCode === 200) {
+ NotifOk({
+ icon: 'success',
+ title: 'Berhasil',
+ message: `User "${
+ response.data?.user_fullname || FormData.user_fullname
+ }" berhasil diubah dan password berhasil diperbarui.`,
+ });
+ } else {
+ NotifAlert({
+ icon: 'warning',
+ title: 'Perhatian',
+ message: `User berhasil diubah, namun gagal mengubah password: ${
+ passwordResponse?.message || 'Unknown error'
+ }`,
+ });
+ }
+ } catch (passwordError) {
+ console.error('Change Password Error:', passwordError);
+ NotifAlert({
+ icon: 'warning',
+ title: 'Perhatian',
+ message: 'User berhasil diubah, namun gagal mengubah password.',
+ });
+ }
+ } else {
+ NotifOk({
+ icon: 'success',
+ title: 'Berhasil',
+ message: `User "${
+ response.data?.user_fullname || FormData.user_fullname
+ }" berhasil ${FormData.user_id ? 'diubah' : 'ditambahkan'}.`,
+ });
+ }
props.setActionMode('list');
setFormData(defaultData);
@@ -260,6 +331,11 @@ const DetailUser = (props) => {
checkPasswordRequirements(value);
}
+ // Check new password requirements on new password change (for edit mode)
+ if (name === 'newPassword') {
+ checkNewPasswordRequirements(value);
+ }
+
// Clear error for this field
if (errors[name]) {
setErrors({
@@ -408,6 +484,39 @@ const DetailUser = (props) => {