feat: enhance notification fetching with pagination and filtering options

This commit is contained in:
2025-11-26 11:44:50 +07:00
parent 309d191bce
commit 14f8a5d472
2 changed files with 242 additions and 202 deletions

View File

@@ -1,9 +1,21 @@
import { SendRequest } from '../components/Global/ApiRequest';
export const getAllNotification = async () => {
const getAllNotification = async (queryParams) => {
const response = await SendRequest({
method: 'get',
prefix: 'notification',
prefix: `notification?${queryParams.toString()}`,
});
return response.data;
};
const getNotificationById = async (id) => {
const response = await SendRequest({
method: 'get',
prefix: `notification/${id}`,
});
return response.data;
};
export { getAllNotification, getNotificationById };

View File

@@ -146,22 +146,44 @@ const ListNotification = memo(function ListNotification(props) {
const navigate = useNavigate();
// Fetch notifications from API
const fetchNotifications = async () => {
const fetchNotifications = async (page = 1, limit = 10, isRead = null) => {
setLoading(true);
try {
const response = await getAllNotification();
const queryParams = new URLSearchParams({
page: page.toString(),
limit: limit.toString(),
});
if (isRead !== null) {
queryParams.append('is_read', isRead.toString());
}
const response = await getAllNotification(queryParams);
if (response && response.data) {
const transformedData = transformNotificationData(response.data);
setNotifications(transformedData);
// Update pagination with mock data (since API doesn't provide pagination info)
// Update pagination with API response or calculate from data
if (response.paging) {
setPagination({
current_page: response.paging.current_page || page,
current_limit: response.paging.current_limit || limit,
total_limit: response.paging.total_limit || transformedData.length,
total_page:
response.paging.total_page || Math.ceil(transformedData.length / limit),
});
} else {
// Fallback: calculate pagination from data
const totalItems = transformedData.length;
setPagination((prev) => ({
...prev,
current_page: page,
current_limit: limit,
total_limit: totalItems,
total_page: Math.ceil(totalItems / prev.current_limit),
total_page: Math.ceil(totalItems / limit),
}));
}
}
} catch (error) {
console.error('Error fetching notifications:', error);
setNotifications([]);
@@ -178,13 +200,10 @@ const ListNotification = memo(function ListNotification(props) {
current_page: page,
current_limit: pageSize,
}));
};
// Get paginated notifications
const getPaginatedNotifications = () => {
const startIndex = (pagination.current_page - 1) * pagination.current_limit;
const endIndex = startIndex + pagination.current_limit;
return filteredNotifications.slice(startIndex, endIndex);
// Fetch notifications with new pagination
const isReadFilter = activeTab === 'read' ? true : activeTab === 'unread' ? false : null;
fetchNotifications(page, pageSize, isReadFilter);
};
useEffect(() => {
@@ -194,9 +213,10 @@ const ListNotification = memo(function ListNotification(props) {
return;
}
// Fetch notifications on component mount
fetchNotifications();
}, []);
// Fetch notifications on component mount and when tab changes
const isReadFilter = activeTab === 'read' ? true : activeTab === 'unread' ? false : null;
fetchNotifications(pagination.current_page, pagination.current_limit, isReadFilter);
}, [activeTab]);
const getIconAndColor = (type) => {
switch (type) {
@@ -248,22 +268,17 @@ const ListNotification = memo(function ListNotification(props) {
setSearchTerm('');
};
const filteredNotifications = notifications
.filter((n) => {
const matchesTab =
activeTab === 'all' ||
(activeTab === 'unread' && !n.isRead) ||
(activeTab === 'read' && n.isRead);
return matchesTab;
})
.filter((n) => {
if (!searchTerm) return true;
const getUnreadCount = () => notifications.filter((n) => !n.isRead).length;
// Filter notifications based on search term
const getFilteredNotifications = () => {
if (!searchTerm) return notifications;
// Search by title and error code name
return notifications.filter((n) => {
const searchableText = `${n.title} ${n.issue}`.toLowerCase();
return searchableText.includes(searchTerm.toLowerCase());
});
const getUnreadCount = () => notifications.filter((n) => !n.isRead).length;
};
const tabButtonStyle = (isActive) => ({
padding: '12px 16px',
@@ -279,8 +294,7 @@ const ListNotification = memo(function ListNotification(props) {
});
const renderDeviceNotifications = () => {
const paginatedNotifications = getPaginatedNotifications();
const filteredNotifications = getFilteredNotifications();
return (
<Space direction="vertical" size="middle" style={{ display: 'flex' }}>
{filteredNotifications.length === 0 ? (
@@ -288,8 +302,10 @@ const ListNotification = memo(function ListNotification(props) {
Tidak ada notifikasi
</div>
) : (
paginatedNotifications.map((notification) => {
const { IconComponent, color, bgColor } = getIconAndColor(notification.type);
filteredNotifications.map((notification) => {
const { IconComponent, color, bgColor } = getIconAndColor(
notification.type
);
return (
<Card
key={notification.id}
@@ -300,7 +316,13 @@ const ListNotification = memo(function ListNotification(props) {
}}
onClick={() => handleMarkAsRead(notification.id)}
>
<div style={{ display: 'flex', gap: '16px', alignItems: 'flex-start' }}>
<div
style={{
display: 'flex',
gap: '16px',
alignItems: 'flex-start',
}}
>
<div
style={{
width: '40px',
@@ -357,10 +379,17 @@ const ListNotification = memo(function ListNotification(props) {
}}
>
<MailOutlined
style={{ marginTop: '4px', color: '#1890ff' }}
style={{
marginTop: '4px',
color: '#1890ff',
}}
/>
<Paragraph
style={{ color: '#595959', margin: 0, flex: 1 }}
style={{
color: '#595959',
margin: 0,
flex: 1,
}}
>
{notification.details}
</Paragraph>
@@ -1212,16 +1241,15 @@ const ListNotification = memo(function ListNotification(props) {
</div>
</div>
<Spin spinning={loading}>
{renderDeviceNotifications()}
</Spin>
<Spin spinning={loading}>{renderDeviceNotifications()}</Spin>
{/* PAGINATION */}
<Row justify="space-between" align="middle" style={{ marginTop: '16px' }}>
<Col>
<div>
Menampilkan {pagination.current_limit} data halaman{' '}
{pagination.current_page} dari total {pagination.total_limit} data
{pagination.current_page} dari total {pagination.total_limit}{' '}
data
</div>
</Col>
<Col>