From f304a2849384b662b217d3e69cc5f8997eec2d87 Mon Sep 17 00:00:00 2001
From: Rafiafrzl
Date: Thu, 20 Nov 2025 19:45:45 +0700
Subject: [PATCH] enhance search and pagination functionality to
ListNotification component
---
.../component/ListNotification.jsx | 189 +++++++++++++-----
1 file changed, 144 insertions(+), 45 deletions(-)
diff --git a/src/pages/notification/component/ListNotification.jsx b/src/pages/notification/component/ListNotification.jsx
index 97c3412..9967802 100644
--- a/src/pages/notification/component/ListNotification.jsx
+++ b/src/pages/notification/component/ListNotification.jsx
@@ -12,6 +12,8 @@ import {
Modal,
Tag,
message,
+ Spin,
+ Pagination,
} from 'antd';
import {
CloseCircleFilled,
@@ -33,6 +35,7 @@ import {
FilePdfOutlined,
PlusOutlined,
ExclamationCircleOutlined,
+ SearchOutlined,
} from '@ant-design/icons';
import { useNavigate, Link as RouterLink } from 'react-router-dom';
import { getAllNotification } from '../../../api/notification';
@@ -129,25 +132,61 @@ const ListNotification = memo(function ListNotification(props) {
const [notifications, setNotifications] = useState([]);
const [activeTab, setActiveTab] = useState('all');
const [searchTerm, setSearchTerm] = useState('');
+ const [searchValue, setSearchValue] = useState('');
+ const [loading, setLoading] = useState(false);
const [modalContent, setModalContent] = useState(null); // 'user', 'log', 'details', or null
const [isAddingLog, setIsAddingLog] = useState(false);
const [selectedNotification, setSelectedNotification] = useState(null);
+ const [pagination, setPagination] = useState({
+ current_page: 1,
+ current_limit: 10,
+ total_limit: 0,
+ total_page: 1,
+ });
const navigate = useNavigate();
// Fetch notifications from API
const fetchNotifications = async () => {
+ setLoading(true);
try {
const response = await getAllNotification();
if (response && response.data) {
const transformedData = transformNotificationData(response.data);
setNotifications(transformedData);
+
+ // Update pagination with mock data (since API doesn't provide pagination info)
+ const totalItems = transformedData.length;
+ setPagination((prev) => ({
+ ...prev,
+ total_limit: totalItems,
+ total_page: Math.ceil(totalItems / prev.current_limit),
+ }));
}
} catch (error) {
console.error('Error fetching notifications:', error);
setNotifications([]);
+ } finally {
+ setTimeout(() => {
+ setLoading(false);
+ }, 500);
}
};
+ const handlePaginationChange = (page, pageSize) => {
+ setPagination((prev) => ({
+ ...prev,
+ 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);
+ };
+
useEffect(() => {
const token = localStorage.getItem('token');
if (!token) {
@@ -200,6 +239,15 @@ const ListNotification = memo(function ListNotification(props) {
);
};
+ const handleSearch = () => {
+ setSearchTerm(searchValue);
+ };
+
+ const handleSearchClear = () => {
+ setSearchValue('');
+ setSearchTerm('');
+ };
+
const filteredNotifications = notifications
.filter((n) => {
const matchesTab =
@@ -210,8 +258,8 @@ const ListNotification = memo(function ListNotification(props) {
})
.filter((n) => {
if (!searchTerm) return true;
- const searchableText =
- `${n.title} ${n.issue} ${n.description} ${n.location} ${n.details}`.toLowerCase();
+ // Search by title and error code name
+ const searchableText = `${n.title} ${n.issue}`.toLowerCase();
return searchableText.includes(searchTerm.toLowerCase());
});
@@ -230,14 +278,17 @@ const ListNotification = memo(function ListNotification(props) {
transition: 'all 0.3s',
});
- const renderDeviceNotifications = () => (
-
- {filteredNotifications.length === 0 ? (
-
- Tidak ada notifikasi
-
- ) : (
- filteredNotifications.map((notification) => {
+ const renderDeviceNotifications = () => {
+ const paginatedNotifications = getPaginatedNotifications();
+
+ return (
+
+ {filteredNotifications.length === 0 ? (
+
+ Tidak ada notifikasi
+
+ ) : (
+ paginatedNotifications.map((notification) => {
const { IconComponent, color, bgColor } = getIconAndColor(notification.type);
return (
-
+
{notification.link}
e.stopPropagation()}
>
}
+ icon={
+
+ }
title="Details"
style={{
border: '1px solid #1890ff',
@@ -422,8 +482,9 @@ const ListNotification = memo(function ListNotification(props) {
);
})
)}
-
- );
+
+ );
+ };
const renderUserHistory = () => (
<>
@@ -635,9 +696,7 @@ const ListNotification = memo(function ListNotification(props) {
Treshold
-
- N/A
-
+ N/A
@@ -1042,23 +1101,23 @@ const ListNotification = memo(function ListNotification(props) {
{logHistoryData.map((log) => (
-
+
-
- {log.addedBy.name}:{' '}
- {log.description}
-
-
- {log.timestamp}
-
-
- ))}
+ {log.addedBy.name}:{' '}
+ {log.description}
+
+
+ {log.timestamp}
+
+
+ ))}
@@ -1087,17 +1146,35 @@ const ListNotification = memo(function ListNotification(props) {
Riwayat notifikasi yang dikirim ke engineer
-
-
+
+
setSearchTerm(e.target.value)}
- style={{ width: 300 }}
+ placeholder="Search by notification name or error code name..."
+ value={searchValue}
+ onChange={(e) => {
+ const value = e.target.value;
+ setSearchValue(value);
+ if (value === '') {
+ handleSearchClear();
+ }
+ }}
+ onSearch={handleSearch}
+ allowClear={{
+ clearIcon: ✕,
+ }}
+ enterButton={
+ }
+ style={{
+ backgroundColor: '#23A55A',
+ borderColor: '#23A55A',
+ }}
+ >
+ Search
+
+ }
+ size="large"
/>
@@ -1135,7 +1212,29 @@ const ListNotification = memo(function ListNotification(props) {
- {renderDeviceNotifications()}
+
+ {renderDeviceNotifications()}
+
+
+ {/* PAGINATION */}
+
+
+
+ Menampilkan {pagination.current_limit} data halaman{' '}
+ {pagination.current_page} dari total {pagination.total_limit} data
+
+
+
+
+
+