lavoce #30

Merged
bragaz_rexita merged 4 commits from lavoce into main 2025-12-31 03:20:52 +00:00
11 changed files with 348 additions and 246 deletions

View File

@@ -46,10 +46,20 @@ const getNotificationLogByNotificationId = async (notificationId) => {
return response.data; return response.data;
}; };
// Resend notification to specific user
const resendNotificationToUser = async (notificationId, userId) => {
const response = await SendRequest({
method: 'post',
prefix: `notification/${notificationId}/resend/${userId}`,
});
return response.data;
};
export { export {
getAllNotification, getAllNotification,
getNotificationById, getNotificationById,
getNotificationDetail, getNotificationDetail,
createNotificationLog, createNotificationLog,
getNotificationLogByNotificationId getNotificationLogByNotificationId,
resendNotificationToUser,
}; };

View File

@@ -30,18 +30,18 @@ instance.interceptors.response.use(
originalRequest._retry = true; originalRequest._retry = true;
try { try {
console.log('🔄 Refresh token dipanggil...'); // console.log('🔄 Refresh token dipanggil...');
const refreshRes = await refreshApi.post('/auth/refresh-token'); const refreshRes = await refreshApi.post('/auth/refresh-token');
const newAccessToken = refreshRes.data.data.accessToken; const newAccessToken = refreshRes.data.data.accessToken;
localStorage.setItem('token', newAccessToken); localStorage.setItem('token', newAccessToken);
console.log('✅ Token refreshed successfully'); // console.log('✅ Token refreshed successfully');
// update token di header // update token di header
instance.defaults.headers.common['Authorization'] = `Bearer ${newAccessToken}`; instance.defaults.headers.common['Authorization'] = `Bearer ${newAccessToken}`;
originalRequest.headers['Authorization'] = `Bearer ${newAccessToken}`; originalRequest.headers['Authorization'] = `Bearer ${newAccessToken}`;
console.log('🔁 Retrying original request...'); // console.log('🔁 Retrying original request...');
return instance(originalRequest); return instance(originalRequest);
} catch (refreshError) { } catch (refreshError) {
console.error( console.error(
@@ -85,20 +85,20 @@ async function ApiRequest({ method = 'GET', params = {}, prefix = '/', token = t
if (token && rawToken) { if (token && rawToken) {
const cleanToken = rawToken.replace(/"/g, ''); const cleanToken = rawToken.replace(/"/g, '');
request.headers['Authorization'] = `Bearer ${cleanToken}`; request.headers['Authorization'] = `Bearer ${cleanToken}`;
console.log('🔐 Sending request with token:', cleanToken.substring(0, 20) + '...'); // console.log('🔐 Sending request with token:', cleanToken.substring(0, 20) + '...');
} else { } else {
console.warn('⚠️ No token found in localStorage'); console.warn('⚠️ No token found in localStorage');
} }
console.log('📤 API Request:', { method, url: prefix, hasToken: !!rawToken }); // console.log('📤 API Request:', { method, url: prefix, hasToken: !!rawToken });
try { try {
const response = await instance(request); const response = await instance(request);
console.log('✅ API Response:', { // console.log('✅ API Response:', {
url: prefix, // url: prefix,
status: response.status, // status: response.status,
statusCode: response.data?.statusCode, // statusCode: response.data?.statusCode,
}); // });
return { ...response, error: false }; return { ...response, error: false };
} catch (error) { } catch (error) {
const status = error?.response?.status || 500; const status = error?.response?.status || 500;
@@ -143,17 +143,10 @@ async function cekError(status, message = '') {
const SendRequest = async (queryParams) => { const SendRequest = async (queryParams) => {
try { try {
const response = await ApiRequest(queryParams); const response = await ApiRequest(queryParams);
console.log('📦 SendRequest response:', {
hasError: response.error,
status: response.status,
statusCode: response.data?.statusCode,
data: response.data,
});
// If ApiRequest returned error flag, return error structure // If ApiRequest returned error flag, return error structure
if (response.error) { if (response.error) {
const errorMsg = response.data?.message || response.statusText || 'Request failed'; const errorMsg = response.data?.message || response.statusText || 'Request failed';
console.error('❌ SendRequest error response:', errorMsg);
// Return consistent error structure instead of empty array // Return consistent error structure instead of empty array
return { return {

View File

@@ -267,9 +267,6 @@ const ListContact = memo(function ListContact(props) {
} }
} }
// Backend doesn't support is_active filter or order parameter
// Contact hanya supports: criteria, name, code, limit, page
const queryParams = new URLSearchParams(); const queryParams = new URLSearchParams();
Object.entries(searchParams).forEach(([key, value]) => { Object.entries(searchParams).forEach(([key, value]) => {
if (value !== '' && value !== null && value !== undefined) { if (value !== '' && value !== null && value !== undefined) {
@@ -309,11 +306,10 @@ const ListContact = memo(function ListContact(props) {
// Listen for saved contact data // Listen for saved contact data
useEffect(() => { useEffect(() => {
if (props.lastSavedContact) { if (props.lastSavedContact) {
fetchContacts(); // Refetch all contacts when data is saved fetchContacts();
} }
}, [props.lastSavedContact]); }, [props.lastSavedContact]);
// Get contacts (already filtered by backend)
const getFilteredContacts = () => { const getFilteredContacts = () => {
return filteredContacts; return filteredContacts;
}; };
@@ -326,7 +322,7 @@ const ListContact = memo(function ListContact(props) {
const showAddModal = () => { const showAddModal = () => {
props.setSelectedData(null); props.setSelectedData(null);
props.setActionMode('add'); props.setActionMode('add');
// Pass the current active tab to determine contact type
props.setContactType?.(activeTab); props.setContactType?.(activeTab);
}; };

View File

@@ -38,7 +38,7 @@ const DetailPlantSubSection = (props) => {
return; return;
} }
console.log(`📝 Input change: ${name} = ${value}`); // console.log(`📝 Input change: ${name} = ${value}`);
if (name) { if (name) {
setFormData((prev) => ({ setFormData((prev) => ({
@@ -74,16 +74,20 @@ const DetailPlantSubSection = (props) => {
return; return;
try { try {
console.log('💾 Current formData before save:', formData); // console.log('💾 Current formData before save:', formData);
const payload = { const payload = {
plant_sub_section_name: formData.plant_sub_section_name, plant_sub_section_name: formData.plant_sub_section_name,
plant_sub_section_description: (formData.plant_sub_section_description && formData.plant_sub_section_description.trim() !== '') ? formData.plant_sub_section_description : ' ', plant_sub_section_description:
formData.plant_sub_section_description &&
formData.plant_sub_section_description.trim() !== ''
? formData.plant_sub_section_description
: ' ',
table_name_value: formData.table_name_value, // Fix field name table_name_value: formData.table_name_value, // Fix field name
is_active: formData.is_active, is_active: formData.is_active,
}; };
console.log('📤 Payload to be sent:', payload); // console.log('📤 Payload to be sent:', payload);
const response = const response =
props.actionMode === 'edit' props.actionMode === 'edit'
@@ -126,17 +130,17 @@ const DetailPlantSubSection = (props) => {
}; };
useEffect(() => { useEffect(() => {
console.log('🔄 Modal state changed:', { // console.log('🔄 Modal state changed:', {
showModal: props.showModal, // showModal: props.showModal,
actionMode: props.actionMode, // actionMode: props.actionMode,
selectedData: props.selectedData, // selectedData: props.selectedData,
}); // });
if (props.selectedData) { if (props.selectedData) {
console.log('📋 Setting form data from selectedData:', props.selectedData); // console.log('📋 Setting form data from selectedData:', props.selectedData);
setFormData(props.selectedData); setFormData(props.selectedData);
} else { } else {
console.log('📋 Resetting to default data'); // console.log('📋 Resetting to default data');
setFormData(defaultData); setFormData(defaultData);
} }
}, [props.showModal, props.selectedData, props.actionMode]); }, [props.showModal, props.selectedData, props.actionMode]);

View File

@@ -112,9 +112,9 @@ const DetailShift = (props) => {
is_active: formData.is_active, is_active: formData.is_active,
}; };
console.log('Payload yang dikirim:', payload); // console.log('Payload yang dikirim:', payload);
console.log('Type start_time:', typeof payload.start_time, payload.start_time); // console.log('Type start_time:', typeof payload.start_time, payload.start_time);
console.log('Type end_time:', typeof payload.end_time, payload.end_time); // console.log('Type end_time:', typeof payload.end_time, payload.end_time);
const response = const response =
props.actionMode === 'edit' props.actionMode === 'edit'

View File

@@ -95,11 +95,11 @@ const DetailSparepart = (props) => {
const newFile = fileList.length > 0 ? fileList[0] : null; const newFile = fileList.length > 0 ? fileList[0] : null;
if (newFile && newFile.originFileObj) { if (newFile && newFile.originFileObj) {
console.log('Uploading file:', newFile.originFileObj); // console.log('Uploading file:', newFile.originFileObj);
const uploadResponse = await uploadFile(newFile.originFileObj, 'images'); const uploadResponse = await uploadFile(newFile.originFileObj, 'images');
// Log untuk debugging // Log untuk debugging
console.log('Upload response:', uploadResponse); // console.log('Upload response:', uploadResponse);
// Cek berbagai kemungkinan struktur respons dari API // Cek berbagai kemungkinan struktur respons dari API
let uploadedUrl = null; let uploadedUrl = null;
@@ -169,7 +169,7 @@ const DetailSparepart = (props) => {
} }
if (uploadedUrl) { if (uploadedUrl) {
console.log('Successfully extracted image URL:', uploadedUrl); // console.log('Successfully extracted image URL:', uploadedUrl);
imageUrl = uploadedUrl; imageUrl = uploadedUrl;
} else { } else {
console.error('Upload response structure:', uploadResponse); console.error('Upload response structure:', uploadResponse);
@@ -209,7 +209,10 @@ const DetailSparepart = (props) => {
sparepart_name: formData.sparepart_name, // Wajib sparepart_name: formData.sparepart_name, // Wajib
}; };
payload.sparepart_description = (formData.sparepart_description && formData.sparepart_description.trim() !== '') ? formData.sparepart_description : ' '; payload.sparepart_description =
formData.sparepart_description && formData.sparepart_description.trim() !== ''
? formData.sparepart_description
: ' ';
if (formData.sparepart_model && formData.sparepart_model.trim() !== '') { if (formData.sparepart_model && formData.sparepart_model.trim() !== '') {
payload.sparepart_model = formData.sparepart_model; payload.sparepart_model = formData.sparepart_model;
} }
@@ -233,13 +236,13 @@ const DetailSparepart = (props) => {
payload.sparepart_foto = imageUrl; payload.sparepart_foto = imageUrl;
} }
console.log('Sending payload:', payload); // console.log('Sending payload:', payload);
const response = formData.sparepart_id const response = formData.sparepart_id
? await updateSparepart(formData.sparepart_id, payload) ? await updateSparepart(formData.sparepart_id, payload)
: await createSparepart(payload); : await createSparepart(payload);
console.log('API response:', response); // console.log('API response:', response);
if (response && (response.statusCode === 200 || response.statusCode === 201)) { if (response && (response.statusCode === 200 || response.statusCode === 201)) {
NotifOk({ NotifOk({

View File

@@ -164,7 +164,7 @@ const ListUnit = memo(function ListUnit(props) {
const handleDelete = async (param) => { const handleDelete = async (param) => {
try { try {
const response = await deleteUnit(param.unit_id); const response = await deleteUnit(param.unit_id);
console.log('deleteUnit response:', response); // console.log('deleteUnit response:', response);
if (response.statusCode === 200) { if (response.statusCode === 200) {
NotifAlert({ NotifAlert({

View File

@@ -38,7 +38,11 @@ import {
SearchOutlined, SearchOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
import { useNavigate, Link as RouterLink } from 'react-router-dom'; import { useNavigate, Link as RouterLink } from 'react-router-dom';
import { getAllNotification, getNotificationLogByNotificationId } from '../../../api/notification'; import {
getAllNotification,
getNotificationLogByNotificationId,
getNotificationDetail,
} from '../../../api/notification';
const { Text, Paragraph, Link: AntdLink } = Typography; const { Text, Paragraph, Link: AntdLink } = Typography;
@@ -77,31 +81,6 @@ const transformNotificationData = (apiData) => {
})); }));
}; };
// Dummy data untuk user history
const userHistoryData = [
{
id: '1',
name: 'John Doe',
phone: '081234567890',
status: 'Delivered',
timestamp: '04-11-2025 11:40 WIB',
},
{
id: '2',
name: 'Jane Smith',
phone: '087654321098',
status: 'Delivered',
timestamp: '04-11-2025 11:41 WIB',
},
{
id: '3',
name: 'Peter Jones',
phone: '082345678901',
status: 'Delivered',
timestamp: '04-11-2025 11:42 WIB',
},
];
const ListNotification = memo(function ListNotification(props) { const ListNotification = memo(function ListNotification(props) {
const [notifications, setNotifications] = useState([]); const [notifications, setNotifications] = useState([]);
const [activeTab, setActiveTab] = useState('all'); const [activeTab, setActiveTab] = useState('all');
@@ -113,6 +92,8 @@ const ListNotification = memo(function ListNotification(props) {
const [selectedNotification, setSelectedNotification] = useState(null); const [selectedNotification, setSelectedNotification] = useState(null);
const [logHistoryData, setLogHistoryData] = useState([]); const [logHistoryData, setLogHistoryData] = useState([]);
const [logLoading, setLogLoading] = useState(false); const [logLoading, setLogLoading] = useState(false);
const [userHistoryData, setUserHistoryData] = useState([]);
const [userLoading, setUserLoading] = useState(false);
const [pagination, setPagination] = useState({ const [pagination, setPagination] = useState({
current_page: 1, current_page: 1,
current_limit: 10, current_limit: 10,
@@ -290,6 +271,42 @@ const ListNotification = memo(function ListNotification(props) {
} }
}; };
// Fetch user history from API
const fetchUserHistory = async (notificationId) => {
try {
setUserLoading(true);
const response = await getNotificationDetail(notificationId);
if (response && response.data && response.data.users) {
// Transform API data to component format
const transformedUsers = response.data.users.map((user) => ({
id: user.notification_error_user_id.toString(),
name: user.contact_name,
phone: user.contact_phone,
status: user.is_send ? 'Delivered' : 'Pending',
timestamp: user.created_at
? new Date(user.created_at).toLocaleString('id-ID', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
}) + ' WIB'
: 'N/A',
}));
setUserHistoryData(transformedUsers);
} else {
setUserHistoryData([]);
}
} catch (err) {
console.error('Error fetching user history:', err);
setUserHistoryData([]); // Set empty array on error
} finally {
setUserLoading(false);
}
};
const tabButtonStyle = (isActive) => ({ const tabButtonStyle = (isActive) => ({
padding: '12px 16px', padding: '12px 16px',
border: 'none', border: 'none',
@@ -467,8 +484,18 @@ const ListNotification = memo(function ListNotification(props) {
border: '1px solid #1890ff', border: '1px solid #1890ff',
borderRadius: '4px', borderRadius: '4px',
}} }}
onClick={(e) => { onClick={async (e) => {
e.stopPropagation(); e.stopPropagation();
setSelectedNotification(notification);
// Extract notification ID from the notification object
const notificationId =
notification.id.split('-')[1];
// Fetch user history for the selected notification
await fetchUserHistory(notificationId);
setModalContent('user'); setModalContent('user');
}} }}
/> />
@@ -535,6 +562,11 @@ const ListNotification = memo(function ListNotification(props) {
const renderUserHistory = () => ( const renderUserHistory = () => (
<> <>
{userLoading ? (
<div style={{ textAlign: 'center', padding: '24px' }}>
<Spin size="large" />
</div>
) : (
<Space direction="vertical" size="middle" style={{ display: 'flex' }}> <Space direction="vertical" size="middle" style={{ display: 'flex' }}>
{userHistoryData.map((user) => ( {userHistoryData.map((user) => (
<Card key={user.id} style={{ borderColor: '#91d5ff' }}> <Card key={user.id} style={{ borderColor: '#91d5ff' }}>
@@ -547,25 +579,52 @@ const ListNotification = memo(function ListNotification(props) {
<MobileOutlined /> {user.phone} <MobileOutlined /> {user.phone}
</Text> </Text>
<Text>|</Text> <Text>|</Text>
<Badge status="success" text={user.status} /> <Badge
status={
user.status === 'Delivered' ? 'success' : 'default'
}
text={user.status}
/>
</Space> </Space>
<Divider style={{ margin: '8px 0' }} /> <Divider style={{ margin: '8px 0' }} />
<Space align="center"> <Space align="center">
{user.status === 'Delivered' ? (
<CheckCircleFilled style={{ color: '#52c41a' }} /> <CheckCircleFilled style={{ color: '#52c41a' }} />
) : (
<ClockCircleOutlined style={{ color: '#faad14' }} />
)}
<Text type="secondary"> <Text type="secondary">
Success Delivered at {user.timestamp} {user.status === 'Delivered'
? 'Success Delivered at'
: 'Status '}{' '}
{user.timestamp}
</Text> </Text>
</Space> </Space>
</Col> </Col>
<Col> <Col>
<Button type="primary" ghost icon={<SendOutlined />}> <Button
type="primary"
ghost
icon={<SendOutlined />}
onClick={() => {
message.info(
'Resend feature is not available yet. This feature is still under development.'
);
}}
>
Resend Resend
</Button> </Button>
</Col> </Col>
</Row> </Row>
</Card> </Card>
))} ))}
{userHistoryData.length === 0 && (
<div style={{ textAlign: 'center', padding: '24px', color: '#8c8c8c' }}>
No user history available
</div>
)}
</Space> </Space>
)}
</> </>
); );
@@ -580,7 +639,17 @@ const ListNotification = memo(function ListNotification(props) {
Tidak ada log history Tidak ada log history
</div> </div>
) : ( ) : (
<div style={{ padding: '0 16px', position: 'relative' }}> <div
style={{
height: '400px',
overflowY: 'auto',
padding: '0 16px',
position: 'relative',
border: '1px solid #f0f0f0',
borderRadius: '4px'
}}
>
<div style={{ position: 'relative' }}>
{/* Garis vertikal yang menyambung */} {/* Garis vertikal yang menyambung */}
<div <div
style={{ style={{
@@ -672,6 +741,7 @@ const ListNotification = memo(function ListNotification(props) {
</Row> </Row>
))} ))}
</div> </div>
</div>
)} )}
</> </>
); );

View File

@@ -38,6 +38,7 @@ import {
getNotificationDetail, getNotificationDetail,
createNotificationLog, createNotificationLog,
getNotificationLogByNotificationId, getNotificationLogByNotificationId,
resendNotificationToUser,
} from '../../api/notification'; } from '../../api/notification';
const { Content } = Layout; const { Content } = Layout;
@@ -94,38 +95,21 @@ const transformNotificationData = (apiData) => {
device_location: apiData.device_location, device_location: apiData.device_location,
brand_name: apiData.brand_name, brand_name: apiData.brand_name,
}, },
users: apiData.users || [],
}; };
}; };
// Dummy data baru untuk user history // Function to get actual users from notification data
const getDummyUsers = (notification) => { const getUsersFromNotification = (notification) => {
if (!notification) return []; if (!notification || !notification.users) return [];
return [
{ return notification.users.map((user) => ({
id: '1', id: user.notification_error_user_id.toString(),
name: 'John Doe', name: user.contact_name,
phone: '081234567890', phone: user.contact_phone,
status: 'delivered', status: user.is_send ? 'sent' : 'pending',
}, loading: user.loading || false,
{ }));
id: '2',
name: 'Jane Smith',
phone: '082345678901',
status: 'sent',
},
{
id: '3',
name: 'Bob Johnson',
phone: '083456789012',
status: 'failed',
},
{
id: '4',
name: 'Alice Brown',
phone: '084567890123',
status: 'delivered',
},
];
}; };
const getStatusTag = (status) => { const getStatusTag = (status) => {
@@ -469,7 +453,7 @@ const NotificationDetailTab = (props) => {
size={2} size={2}
style={{ width: '100%' }} style={{ width: '100%' }}
> >
{getDummyUsers(notification).map((user) => ( {getUsersFromNotification(notification).map((user) => (
<Card <Card
key={user.id} key={user.id}
size="small" size="small"
@@ -510,11 +494,64 @@ const NotificationDetailTab = (props) => {
type="primary" type="primary"
icon={<SendOutlined />} icon={<SendOutlined />}
size="small" size="small"
onClick={(e) => { loading={user.loading}
onClick={async (e) => {
e.stopPropagation(); e.stopPropagation();
console.log( const userId = parseInt(user.id);
`Resend to ${user.name}` try {
// Update user status to show loading
const updatedUsers = notification.users.map(u =>
u.notification_error_user_id === userId
? { ...u, loading: true }
: u
); );
setNotification({
...notification,
users: updatedUsers
});
// Call the resend API
const response = await resendNotificationToUser(
notification.notification_error_id,
userId
);
if (response && response.statusCode === 200) {
message.success(`Notification resent to ${user.name}`);
// Update user status
const updatedUsersAfterSuccess = notification.users.map(u =>
u.notification_error_user_id === userId
? {
...u,
is_send: true,
status: 'sent',
loading: false
}
: { ...u, loading: false }
);
setNotification({
...notification,
users: updatedUsersAfterSuccess
});
} else {
throw new Error(response?.message || 'Failed to resend notification');
}
} catch (error) {
console.error('Error resending notification:', error);
message.error(error.message || 'Failed to resend notification');
// Reset loading state
const resetUsers = notification.users.map(u =>
u.notification_error_user_id === userId
? { ...u, loading: false }
: u
);
setNotification({
...notification,
users: resetUsers
});
}
}} }}
> >
Resend Resend

View File

@@ -115,7 +115,7 @@ const ChangePasswordModal = (props) => {
try { try {
const response = await changePassword(props.selectedUser.user_id, formData.newPassword); const response = await changePassword(props.selectedUser.user_id, formData.newPassword);
console.log('Change Password Response:', response); // console.log('Change Password Response:', response);
if (response && response.statusCode === 200) { if (response && response.statusCode === 200) {
NotifOk({ NotifOk({

View File

@@ -220,35 +220,27 @@ const DetailUser = (props) => {
// For update mode: only send email if it has changed // For update mode: only send email if it has changed
if (FormData.user_id) { if (FormData.user_id) {
// Only include email if it has changed from original
if (FormData.user_email !== originalEmail) { if (FormData.user_email !== originalEmail) {
payload.user_email = FormData.user_email; payload.user_email = FormData.user_email;
} }
// Add is_active for update mode
payload.is_active = FormData.is_active; payload.is_active = FormData.is_active;
} else { } else {
// For create mode: always send email
payload.user_email = FormData.user_email; payload.user_email = FormData.user_email;
} }
// Only add role_id if it exists (backend requires number >= 1, no null)
if (FormData.role_id) { if (FormData.role_id) {
payload.role_id = FormData.role_id; payload.role_id = FormData.role_id;
} }
// Add password and name for new user (create mode) // Add password and name for new user (create mode)
if (!FormData.user_id) { if (!FormData.user_id) {
payload.user_name = FormData.user_name; // Username only for create payload.user_name = FormData.user_name;
payload.user_password = FormData.password; // Backend expects 'user_password' payload.user_password = FormData.password;
// Don't send confirmPassword, is_sa for create
} }
// For update mode:
// - Don't send 'user_name' (username is immutable)
// - is_active is now sent for update mode
// - Only send email if it has changed
try { try {
console.log('Payload being sent:', payload); // console.log('Payload being sent:', payload);
let response; let response;
if (!FormData.user_id) { if (!FormData.user_id) {
@@ -257,11 +249,10 @@ const DetailUser = (props) => {
response = await updateUser(FormData.user_id, payload); response = await updateUser(FormData.user_id, payload);
} }
console.log('Save User Response:', response); // console.log('Save User Response:', response);
// Check if response is successful // Check if response is successful
if (response && (response.statusCode === 200 || response.statusCode === 201)) { if (response && (response.statusCode === 200 || response.statusCode === 201)) {
// If in edit mode and newPassword is provided, change password
if (FormData.user_id && FormData.newPassword) { if (FormData.user_id && FormData.newPassword) {
try { try {
const passwordResponse = await changePassword( const passwordResponse = await changePassword(
@@ -385,9 +376,9 @@ const DetailUser = (props) => {
search: '', search: '',
}); });
console.log('Fetching roles with params:', queryParams.toString()); // console.log('Fetching roles with params:', queryParams.toString());
const response = await getAllRole(queryParams); const response = await getAllRole(queryParams);
console.log('Fetched roles response:', response); // console.log('Fetched roles response:', response);
// Handle different response structures // Handle different response structures
if (response && response.data) { if (response && response.data) {
@@ -408,7 +399,7 @@ const DetailUser = (props) => {
} }
setRoleList(roles); setRoleList(roles);
console.log('Setting role list:', roles); // console.log('Setting role list:', roles);
} else { } else {
// Add mock data as fallback // Add mock data as fallback
console.warn('No response data, using mock data'); console.warn('No response data, using mock data');
@@ -418,7 +409,7 @@ const DetailUser = (props) => {
{ role_id: 3, role_name: 'User', role_level: 3 }, { role_id: 3, role_name: 'User', role_level: 3 },
]; ];
setRoleList(mockRoles); setRoleList(mockRoles);
console.log('Setting mock role list:', mockRoles); // console.log('Setting mock role list:', mockRoles);
} }
} catch (error) { } catch (error) {
console.error('Error fetching roles:', error); console.error('Error fetching roles:', error);
@@ -429,7 +420,7 @@ const DetailUser = (props) => {
{ role_id: 3, role_name: 'User', role_level: 3 }, { role_id: 3, role_name: 'User', role_level: 3 },
]; ];
setRoleList(mockRoles); setRoleList(mockRoles);
console.log('Setting mock role list due to error:', mockRoles); // console.log('Setting mock role list due to error:', mockRoles);
// Only show error notification if we don't have fallback data // Only show error notification if we don't have fallback data
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
@@ -1146,9 +1137,7 @@ const DetailUser = (props) => {
))} ))}
</Select> </Select>
{errors.role_id && ( {errors.role_id && (
<Text style={{ color: 'red', fontSize: '12px' }}> <Text style={{ color: 'red', fontSize: '12px' }}>{errors.role_id}</Text>
{errors.role_id}
</Text>
)} )}
</div> </div>
</div> </div>