fixing card list master status

This commit is contained in:
2025-10-22 15:53:22 +07:00
parent 784ffc5e87
commit 6e256e3c42
3 changed files with 170 additions and 164 deletions

View File

@@ -54,41 +54,40 @@ const CardList = ({
}
style={getCardStyle()}
actions={[
<Space
size="middle"
style={{ display: 'flex', justifyContent: 'center' }}
>
<Button
type="text"
<EyeOutlined
style={{ color: '#1890ff' }}
icon={<EyeOutlined />}
key="preview"
onClick={() => showPreviewModal(item)}
/>
<Button
type="text"
/>,
<EditOutlined
style={{ color: '#faad14' }}
icon={<EditOutlined />}
key="edit"
onClick={() => showEditModal(item)}
/>
<Button
type="text"
danger
icon={<DeleteOutlined />}
/>,
<DeleteOutlined
style={{ color: '#ff1818' }}
key="delete"
onClick={() => showDeleteDialog(item)}
/>
</Space>,
/>,
]}
>
<div style={{ textAlign: 'left' }}>
{column.map((itemCard, index) => (
<React.Fragment key={index}>
{!itemCard.hidden && itemCard.title !== 'No' && itemCard.title !== 'Aksi' && (
{!itemCard.hidden &&
itemCard.title !== 'No' &&
itemCard.title !== 'Aksi' && (
<p style={{ margin: '8px 0' }}>
<Text strong>{itemCard.title}:</Text>{' '}
{itemCard.render
? itemCard.render(item[itemCard.dataIndex], item, index)
: item[itemCard.dataIndex] || item[itemCard.key] || '-'
}
? itemCard.render(
item[itemCard.dataIndex],
item,
index
)
: item[itemCard.dataIndex] ||
item[itemCard.key] ||
'-'}
</p>
)}
</React.Fragment>

View File

@@ -13,46 +13,74 @@ const IndexStatus = memo(function IndexStatus() {
const [actionMode, setActionMode] = useState('list');
const [selectedData, setSelectedData] = useState(null);
const [isModalVisible, setIsModalVisible] = useState(false);
const [readOnly, setReadOnly] = useState(false);
const [showModal, setShowModal] = useState(false);
const setMode = (param) => {
setShowModal(true);
switch (param) {
case 'add':
setReadOnly(false);
break;
case 'edit':
setReadOnly(false);
break;
case 'preview':
setReadOnly(true);
break;
default:
setShowModal(false);
break;
}
setActionMode(param);
};
useEffect(() => {
const token = localStorage.getItem('token');
if (token) {
setBreadcrumbItems([
{ title: <Text strong> Master</Text> },
{ title: <Text strong>Status</Text> }
{
title: (
<Text strong style={{ fontSize: '14px' }}>
Master
</Text>
),
},
{
title: (
<Text strong style={{ fontSize: '14px' }}>
Status
</Text>
),
},
]);
} else {
navigate('/signin');
}
}, [navigate, setBreadcrumbItems]);
useEffect(() => {
if (actionMode === 'add' || actionMode === 'edit' || actionMode === 'preview') {
setIsModalVisible(true);
setReadOnly(actionMode === 'preview');
} else {
setIsModalVisible(false);
}
}, [actionMode]);
}, []);
return (
<React.Fragment>
{actionMode === 'list' &&
{actionMode === 'list' && (
<ListStatus
setActionMode={setActionMode}
setSelectedData={setSelectedData}
actionMode={actionMode}
/>
}
<DetailStatus
showModal={isModalVisible}
setActionMode={setActionMode}
setActionMode={setMode}
selectedData={selectedData}
setSelectedData={setSelectedData}
readOnly={readOnly}
/>
)}
<DetailStatus
setActionMode={setMode}
selectedData={selectedData}
setSelectedData={setSelectedData}
readOnly={readOnly}
showModal={showModal}
actionMode={actionMode}
/>
</React.Fragment>
);
});

View File

@@ -1,68 +1,89 @@
import React, { memo, useState, useEffect } from 'react';
import { Space, ConfigProvider, Button, Row, Col, Card, Input, Segmented, Table, Pagination } from 'antd';
import { Space, ConfigProvider, Button, Row, Col, Card, Input } from 'antd';
import {
PlusOutlined,
EditOutlined,
DeleteOutlined,
EyeOutlined,
SearchOutlined,
AppstoreOutlined,
TableOutlined,
} from '@ant-design/icons';
import { NotifAlert, NotifConfirmDialog } from '../../../../components/Global/ToastNotif';
import { useNavigate } from 'react-router-dom';
import { deleteStatus, getAllStatuss } from '../../../../api/master-status';
import TableList from '../../../../components/Global/TableList';
const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
{ title: 'Number', dataIndex: 'status_number', key: 'status_number', width: '15%' },
{ title: 'Name', dataIndex: 'status_name', key: 'status_name', width: '25%' },
{
title: 'Description',
dataIndex: 'status_description',
key: 'status_description',
width: '40%',
},
{
title: 'Aksi',
key: 'aksi',
align: 'center',
width: '20%',
render: (_, record) => (
<Space>
<Button
type="text"
style={{ borderColor: '#1890ff' }}
icon={<EyeOutlined style={{ color: '#1890ff' }} />}
onClick={() => showPreviewModal(record)}
/>
<Button
type="text"
style={{ borderColor: '#faad14' }}
icon={<EditOutlined style={{ color: '#faad14' }} />}
onClick={() => showEditModal(record)}
/>
<Button
type="text"
danger
style={{ borderColor: 'red' }}
icon={<DeleteOutlined />}
onClick={() => showDeleteDialog(record)}
/>
</Space>
),
},
];
const ListStatus = memo(function ListStatus(props) {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const [viewMode, setViewMode] = useState('card');
const [trigerFilter, setTrigerFilter] = useState(false);
const defaultFilter = { criteria: '' };
const [formDataFilter, setFormDataFilter] = useState(defaultFilter);
const [searchValue, setSearchValue] = useState('');
const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0 });
const navigate = useNavigate();
const fetchData = async (page = 1, pageSize = 10) => {
setLoading(true);
try {
const params = new URLSearchParams();
params.append('page', page);
params.append('limit', pageSize);
if (searchValue) {
params.append('search', searchValue);
}
const response = await getAllStatuss(params);
setData(response.data || []);
setPagination(prev => ({ ...prev, total: response.paging?.total || 0, current: page, pageSize: pageSize }));
} catch (error) {
console.error("Failed to fetch status data:", error);
setData([]);
} finally {
setLoading(false);
}
};
useEffect(() => {
const token = localStorage.getItem('token');
if (!token) {
navigate('/signin');
return;
if (token) {
if (props.actionMode === 'list') {
setFormDataFilter(defaultFilter);
doFilter();
}
fetchData(pagination.current, pagination.pageSize);
}, [props.actionMode, trigerFilter, navigate]);
} else {
navigate('/signin');
}
}, [props.actionMode]);
const doFilter = () => {
setTrigerFilter(prev => !prev);
setTrigerFilter((prev) => !prev);
};
const handleSearch = (value) => {
setSearchValue(value);
setPagination(prev => ({ ...prev, current: 1 })); // Reset to first page on search
doFilter();
const handleSearch = () => {
setFormDataFilter({ criteria: searchValue });
setTrigerFilter((prev) => !prev);
};
const handlePaginationChange = (page, pageSize) => {
fetchData(page, pageSize);
const handleSearchClear = () => {
setSearchValue('');
setFormDataFilter({ criteria: '' });
setTrigerFilter((prev) => !prev);
};
const showPreviewModal = (record) => {
@@ -93,40 +114,24 @@ const ListStatus = memo(function ListStatus(props) {
try {
const response = await deleteStatus(status_id);
if (response.statusCode === 200) {
NotifAlert({ icon: 'success', title: 'Berhasil', message: 'Data Status berhasil dihapus.' });
NotifAlert({
icon: 'success',
title: 'Berhasil',
message: 'Data Status berhasil dihapus.',
});
doFilter();
} else {
NotifAlert({ icon: 'error', title: 'Gagal', message: response?.message || 'Gagal Menghapus Data' });
NotifAlert({
icon: 'error',
title: 'Gagal',
message: response?.message || 'Gagal Menghapus Data',
});
}
} catch (error) {
NotifAlert({ icon: 'error', title: 'Error', message: error.message });
}
};
const columns = [
{ title: 'Number', dataIndex: 'status_number', key: 'status_number', width: '15%' },
{ title: 'Name', dataIndex: 'status_name', key: 'status_name', width: '25%' },
{ title: 'Description', dataIndex: 'status_description', key: 'status_description', width: '40%' },
{
title: 'Aksi', key: 'aksi', align: 'center', width: '20%',
render: (_, record) => (
<Space>
<Button type="text" icon={<EyeOutlined />} onClick={() => showPreviewModal(record)} />
<Button type="text" icon={<EditOutlined />} onClick={() => showEditModal(record)} />
<Button danger type="text" icon={<DeleteOutlined />} onClick={() => showDeleteDialog(record)} />
</Space>
),
},
];
const getCardStyle = (color) => {
return { border: `2px solid ${color || '#d9d9d9'}`, height: '100%' };
};
const getTitleStyle = (color) => {
return { backgroundColor: color || 'transparent', color: '#fff', padding: '2px 8px', borderRadius: '4px', display: 'inline-block' };
};
return (
<Card>
<Row justify="space-between" align="middle" gutter={[16, 16]}>
@@ -134,7 +139,16 @@ const ListStatus = memo(function ListStatus(props) {
<Input.Search
placeholder="Search by status name..."
onSearch={handleSearch}
allowClear
onChange={(e) => {
const value = e.target.value;
setSearchValue(value);
if (value === '') {
handleSearchClear();
}
}}
allowClear={{
clearIcon: <span onClick={handleSearchClear}></span>,
}}
enterButton={
<Button
type="primary"
@@ -167,57 +181,22 @@ const ListStatus = memo(function ListStatus(props) {
</Button>
</ConfigProvider>
</Col>
</Row>
<Row style={{ marginTop: 16 }}>
<Col>
<Segmented
options={[{ value: 'card', icon: <AppstoreOutlined /> }, { value: 'table', icon: <TableOutlined /> }]}
value={viewMode}
onChange={setViewMode}
<Col xs={24} style={{ marginTop: '16px' }}>
<TableList
mobile
cardColor={'#42AAFF'}
header={'status_name'}
showPreviewModal={showPreviewModal}
showEditModal={showEditModal}
showDeleteDialog={showDeleteDialog}
getData={getAllStatuss}
queryParams={formDataFilter}
columns={columns(showPreviewModal, showEditModal, showDeleteDialog)}
triger={trigerFilter}
/>
</Col>
</Row>
<div style={{ marginTop: 24 }}>
{viewMode === 'card' ? (
<Row gutter={[16, 16]}>
{data.map(item => (
<Col xs={24} sm={12} md={8} lg={6} key={item.status_id}>
<Card
title={<span style={getTitleStyle(item.status_color)}>{item.status_name}</span>}
style={getCardStyle(item.status_color)}
actions={[
<EyeOutlined key="preview" onClick={() => showPreviewModal(item)} />,
<EditOutlined key="edit" onClick={() => showEditModal(item)} />,
<DeleteOutlined key="delete" onClick={() => showDeleteDialog(item)} />,
]}
>
<p><b>Number:</b> {item.status_number}</p>
<p><b>Description:</b> {item.status_description}</p>
</Card>
</Col>
))}
</Row>
) : (
<>
<Table
columns={columns}
dataSource={data.map(item => ({ ...item, key: item.status_id }))}
pagination={false}
loading={loading}
/>
<Pagination
style={{ marginTop: 16, textAlign: 'right' }}
current={pagination.current}
pageSize={pagination.pageSize}
total={pagination.total}
onChange={handlePaginationChange}
showSizeChanger
/>
</>
)}
</div>
</Card>
);
});