Compare commits
3 Commits
76e40ced3f
...
7a8a46ee64
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a8a46ee64 | |||
| c3b5ec2121 | |||
| 59c90c3519 |
@@ -1,49 +1,76 @@
|
|||||||
import { SendRequest } from '../components/Global/ApiRequest';
|
import { SendRequest } from '../components/Global/ApiRequest';
|
||||||
|
|
||||||
const getAllRole = async (queryParams) => {
|
const getAllRole = async (queryParams) => {
|
||||||
const response = await SendRequest({
|
try {
|
||||||
method: 'get',
|
const response = await SendRequest({
|
||||||
prefix: `roles/roles?${queryParams.toString()}`,
|
method: 'get',
|
||||||
});
|
prefix: `roles?${queryParams.toString()}`,
|
||||||
|
});
|
||||||
|
|
||||||
console.log('Role API Response:', response);
|
console.log('Role API Response:', response);
|
||||||
|
|
||||||
// Parse query params to get page and limit
|
// Check if backend returns paginated data
|
||||||
const params = Object.fromEntries(queryParams);
|
if (response.paging) {
|
||||||
const currentPage = parseInt(params.page) || 1;
|
// Backend already provides pagination info
|
||||||
const currentLimit = parseInt(params.limit) || 10;
|
return {
|
||||||
|
status: response.statusCode || 200,
|
||||||
|
data: {
|
||||||
|
data: response.data || [],
|
||||||
|
paging: response.paging,
|
||||||
|
total: response.paging.total || 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Backend returns all data, so we need to do client-side pagination
|
// Fallback: If backend returns all data without pagination
|
||||||
const allData = response.data || [];
|
const params = Object.fromEntries(queryParams);
|
||||||
const totalData = allData.length;
|
const currentPage = parseInt(params.page) || 1;
|
||||||
|
const currentLimit = parseInt(params.limit) || 10;
|
||||||
|
|
||||||
// Calculate start and end index for current page
|
const allData = response.data || [];
|
||||||
const startIndex = (currentPage - 1) * currentLimit;
|
const totalData = allData.length;
|
||||||
const endIndex = startIndex + currentLimit;
|
|
||||||
|
|
||||||
// Slice data for current page
|
// Client-side pagination
|
||||||
const paginatedData = allData.slice(startIndex, endIndex);
|
const startIndex = (currentPage - 1) * currentLimit;
|
||||||
|
const endIndex = startIndex + currentLimit;
|
||||||
|
const paginatedData = allData.slice(startIndex, endIndex);
|
||||||
|
|
||||||
// Transform response to match TableList expected structure
|
return {
|
||||||
return {
|
status: response.statusCode || 200,
|
||||||
status: response.statusCode || 200,
|
data: {
|
||||||
data: {
|
data: paginatedData,
|
||||||
data: paginatedData,
|
paging: {
|
||||||
paging: {
|
page: currentPage,
|
||||||
page: currentPage,
|
limit: currentLimit,
|
||||||
limit: currentLimit,
|
total: totalData,
|
||||||
|
page_total: Math.ceil(totalData / currentLimit),
|
||||||
|
},
|
||||||
total: totalData,
|
total: totalData,
|
||||||
page_total: Math.ceil(totalData / currentLimit),
|
|
||||||
},
|
},
|
||||||
total: totalData,
|
};
|
||||||
},
|
} catch (error) {
|
||||||
};
|
console.error('getAllRole error:', error);
|
||||||
|
return {
|
||||||
|
status: 500,
|
||||||
|
data: {
|
||||||
|
data: [],
|
||||||
|
paging: {
|
||||||
|
page: 1,
|
||||||
|
limit: 10,
|
||||||
|
total: 0,
|
||||||
|
page_total: 0
|
||||||
|
},
|
||||||
|
total: 0
|
||||||
|
},
|
||||||
|
error: error.message
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getRoleById = async (id) => {
|
const getRoleById = async (id) => {
|
||||||
const response = await SendRequest({
|
const response = await SendRequest({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
prefix: `roles/roles/${id}`,
|
prefix: `roles/${id}`,
|
||||||
});
|
});
|
||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
@@ -51,7 +78,7 @@ const getRoleById = async (id) => {
|
|||||||
const createRole = async (queryParams) => {
|
const createRole = async (queryParams) => {
|
||||||
const response = await SendRequest({
|
const response = await SendRequest({
|
||||||
method: 'post',
|
method: 'post',
|
||||||
prefix: `roles/roles`,
|
prefix: `roles`,
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -90,7 +117,7 @@ const createRole = async (queryParams) => {
|
|||||||
const updateRole = async (role_id, queryParams) => {
|
const updateRole = async (role_id, queryParams) => {
|
||||||
const response = await SendRequest({
|
const response = await SendRequest({
|
||||||
method: 'put',
|
method: 'put',
|
||||||
prefix: `roles/roles/${role_id}`,
|
prefix: `roles/${role_id}`,
|
||||||
params: queryParams,
|
params: queryParams,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -129,7 +156,7 @@ const updateRole = async (role_id, queryParams) => {
|
|||||||
const deleteRole = async (queryParams) => {
|
const deleteRole = async (queryParams) => {
|
||||||
const response = await SendRequest({
|
const response = await SendRequest({
|
||||||
method: 'delete',
|
method: 'delete',
|
||||||
prefix: `roles/roles/${queryParams}`,
|
prefix: `roles/${queryParams}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('Delete API Response:', response);
|
console.log('Delete API Response:', response);
|
||||||
|
|||||||
@@ -41,11 +41,32 @@ const DetailUser = (props) => {
|
|||||||
|
|
||||||
const validatePassword = (password) => {
|
const validatePassword = (password) => {
|
||||||
if (!password) return 'Password wajib diisi';
|
if (!password) return 'Password wajib diisi';
|
||||||
if (password.length < 8) return 'Password minimal 8 karakter';
|
|
||||||
if (!/[A-Z]/.test(password)) return 'Password harus ada huruf besar';
|
// Must be at least 8 characters long
|
||||||
if (!/[a-z]/.test(password)) return 'Password harus ada huruf kecil';
|
if (password.length < 8) {
|
||||||
if (!/\d/.test(password)) return 'Password harus ada angka';
|
return 'Password must be at least 8 characters long';
|
||||||
if (!/[!@#$%^&*(),.?":{}|<>]/.test(password)) return 'Password harus ada karakter spesial';
|
}
|
||||||
|
|
||||||
|
// Must contain at least one uppercase letter
|
||||||
|
if (!/[A-Z]/.test(password)) {
|
||||||
|
return 'Password must contain at least one uppercase letter';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must contain at least one lowercase letter
|
||||||
|
if (!/[a-z]/.test(password)) {
|
||||||
|
return 'Password must contain at least one lowercase letter';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must contain at least one number
|
||||||
|
if (!/\d/.test(password)) {
|
||||||
|
return 'Password must contain at least one number';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must contain at least one special character
|
||||||
|
if (!/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
|
||||||
|
return 'Password must contain at least one special character';
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
SearchOutlined,
|
SearchOutlined,
|
||||||
CheckOutlined,
|
CheckOutlined,
|
||||||
CloseOutlined,
|
CloseOutlined,
|
||||||
|
KeyOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { NotifAlert, NotifOk, NotifConfirmDialog } from '../../../components/Global/ToastNotif';
|
import { NotifAlert, NotifOk, NotifConfirmDialog } from '../../../components/Global/ToastNotif';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
@@ -49,7 +50,7 @@ const getRoleColor = (role_name, role_level) => {
|
|||||||
return 'default';
|
return 'default';
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = (showPreviewModal, showEditModal, showDeleteDialog, showApproveDialog) => [
|
const columns = (showPreviewModal, showEditModal, showDeleteDialog, showApproveDialog, showChangePasswordModal) => [
|
||||||
{
|
{
|
||||||
title: 'ID',
|
title: 'ID',
|
||||||
dataIndex: 'user_id',
|
dataIndex: 'user_id',
|
||||||
@@ -135,7 +136,7 @@ const columns = (showPreviewModal, showEditModal, showDeleteDialog, showApproveD
|
|||||||
title: 'Aksi',
|
title: 'Aksi',
|
||||||
key: 'aksi',
|
key: 'aksi',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: '15%',
|
width: '18%',
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Space>
|
<Space>
|
||||||
<Button
|
<Button
|
||||||
@@ -158,6 +159,12 @@ const columns = (showPreviewModal, showEditModal, showDeleteDialog, showApproveD
|
|||||||
icon={<EditOutlined style={{ color: '#faad14' }} />}
|
icon={<EditOutlined style={{ color: '#faad14' }} />}
|
||||||
onClick={() => showEditModal(record)}
|
onClick={() => showEditModal(record)}
|
||||||
/>
|
/>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
style={{ borderColor: '#722ed1' }}
|
||||||
|
icon={<KeyOutlined style={{ color: '#722ed1' }} />}
|
||||||
|
onClick={() => showChangePasswordModal(record)}
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
danger
|
danger
|
||||||
@@ -255,6 +262,11 @@ const ListUser = memo(function ListUser(props) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const showChangePasswordModal = (param) => {
|
||||||
|
props.setSelectedUserForPassword(param);
|
||||||
|
props.setShowChangePasswordModal(true);
|
||||||
|
};
|
||||||
|
|
||||||
const handleApprove = async (user_id) => {
|
const handleApprove = async (user_id) => {
|
||||||
const response = await approveUser(user_id);
|
const response = await approveUser(user_id);
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
@@ -366,7 +378,8 @@ const ListUser = memo(function ListUser(props) {
|
|||||||
showPreviewModal,
|
showPreviewModal,
|
||||||
showEditModal,
|
showEditModal,
|
||||||
showDeleteDialog,
|
showDeleteDialog,
|
||||||
showApproveDialog
|
showApproveDialog,
|
||||||
|
showChangePasswordModal
|
||||||
)}
|
)}
|
||||||
triger={trigerFilter}
|
triger={trigerFilter}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user