diff --git a/src/components/CustomPagination.jsx b/src/components/CustomPagination.jsx
new file mode 100644
index 0000000..9d01fd4
--- /dev/null
+++ b/src/components/CustomPagination.jsx
@@ -0,0 +1,271 @@
+import React, { useState, useEffect } from 'react';
+import { useSelector } from 'react-redux';
+
+const CustomPagination = ({
+ currentPage = 1,
+ pageSize = 10,
+ totalCount = 0,
+ totalPages = 1,
+ loading = false,
+ onPageChange,
+ onPageSizeChange,
+ pageSizeOptions = [10, 20, 50, 100],
+ showInfo = true,
+ showPageSizeSelector = true,
+ compact = false,
+ className = ''
+}) => {
+ // Theme state for force re-render
+ const [themeKey, setThemeKey] = useState(0);
+
+ // Get theme from Redux and localStorage fallback
+ const reduxTheme = useSelector((state) => state.theme?.isDarkMode);
+ const localStorageTheme = localStorage.getItem('colorschema') === 'dark_mode';
+ const documentTheme = document.documentElement.getAttribute('data-layout-mode') === 'dark_mode';
+
+ const isDarkMode = reduxTheme || localStorageTheme || documentTheme;
+
+ // Listen for theme changes
+ useEffect(() => {
+ const handleThemeChange = () => {
+ setThemeKey(prev => prev + 1);
+ };
+
+ // Listen for data-layout-mode attribute changes
+ const observer = new MutationObserver((mutations) => {
+ mutations.forEach((mutation) => {
+ if (mutation.type === 'attributes' && mutation.attributeName === 'data-layout-mode') {
+ handleThemeChange();
+ }
+ });
+ });
+
+ observer.observe(document.documentElement, {
+ attributes: true,
+ attributeFilter: ['data-layout-mode']
+ });
+
+ // Also listen for localStorage changes
+ const handleStorageChange = (e) => {
+ if (e.key === 'colorschema') {
+ handleThemeChange();
+ }
+ };
+
+ window.addEventListener('storage', handleStorageChange);
+
+ return () => {
+ observer.disconnect();
+ window.removeEventListener('storage', handleStorageChange);
+ };
+ }, []);
+
+ // Calculate pagination info
+ const startRecord = totalCount === 0 ? 0 : (currentPage - 1) * pageSize + 1;
+ const endRecord = Math.min(currentPage * pageSize, totalCount);
+
+ // Handle page change
+ const handlePageClick = (page) => {
+ if (!loading && page !== currentPage && onPageChange) {
+ onPageChange(page);
+ }
+ };
+
+ // Handle page size change
+ const handlePageSizeClick = (newPageSize) => {
+ if (!loading && newPageSize !== pageSize && onPageSizeChange) {
+ onPageSizeChange(newPageSize);
+ }
+ };
+
+ // Container styles based on compact mode
+ const containerStyles = {
+ background: isDarkMode
+ ? 'linear-gradient(135deg, #2c3e50 0%, #34495e 100%)'
+ : 'linear-gradient(135deg, #ffffff, #f8f9fa)',
+ border: isDarkMode
+ ? '1px solid rgba(52, 152, 219, 0.3)'
+ : '1px solid rgba(0, 0, 0, 0.1)',
+ borderRadius: compact ? '8px' : '12px',
+ boxShadow: isDarkMode
+ ? (compact ? '0 4px 16px rgba(0, 0, 0, 0.2), 0 1px 4px rgba(52, 152, 219, 0.1)' : '0 8px 32px rgba(0, 0, 0, 0.3), 0 2px 8px rgba(52, 152, 219, 0.1)')
+ : (compact ? '0 1px 6px rgba(0, 0, 0, 0.06)' : '0 2px 12px rgba(0, 0, 0, 0.08)'),
+ backdropFilter: isDarkMode ? (compact ? 'blur(8px)' : 'blur(10px)') : 'none',
+ transition: compact ? 'all 0.2s ease' : 'all 0.3s ease',
+ position: 'relative',
+ overflow: 'hidden',
+ padding: compact ? '8px 16px' : '16px 24px',
+ margin: compact ? '8px 0' : '16px 0',
+ fontSize: compact ? '13px' : '14px'
+ };
+
+ // Button styles
+ const getButtonStyles = (isActive) => ({
+ background: loading
+ ? (isDarkMode ? 'linear-gradient(45deg, #7f8c8d, #95a5a6)' : 'linear-gradient(135deg, #f8f9fa, #e9ecef)')
+ : isActive
+ ? (isDarkMode ? 'linear-gradient(45deg, #f39c12, #e67e22)' : 'linear-gradient(135deg, #007bff, #0056b3)')
+ : (isDarkMode ? 'linear-gradient(45deg, #34495e, #2c3e50)' : 'linear-gradient(135deg, #ffffff, #f8f9fa)'),
+ border: isActive
+ ? (isDarkMode ? (compact ? '1px solid #f39c12' : '2px solid #f39c12') : (compact ? '1px solid #007bff' : '2px solid #007bff'))
+ : (isDarkMode ? '1px solid rgba(52, 152, 219, 0.3)' : '1px solid #dee2e6'),
+ borderRadius: '50%',
+ width: compact ? '24px' : '32px',
+ height: compact ? '24px' : '32px',
+ color: isActive
+ ? '#ffffff'
+ : (isDarkMode ? '#ffffff' : '#495057'),
+ fontSize: compact ? '11px' : '14px',
+ fontWeight: compact ? '600' : '700',
+ cursor: loading ? 'not-allowed' : 'pointer',
+ transition: compact ? 'all 0.2s ease' : 'all 0.3s ease',
+ boxShadow: loading
+ ? 'none'
+ : isActive
+ ? (isDarkMode ? (compact ? '0 2px 6px rgba(243, 156, 18, 0.3)' : '0 4px 12px rgba(243, 156, 18, 0.4)') : (compact ? '0 2px 4px rgba(0, 123, 255, 0.2)' : '0 3px 8px rgba(0, 123, 255, 0.3)'))
+ : (isDarkMode ? (compact ? '0 1px 4px rgba(52, 73, 94, 0.2)' : '0 2px 8px rgba(52, 73, 94, 0.3)') : (compact ? '0 1px 2px rgba(0, 0, 0, 0.08)' : '0 1px 3px rgba(0, 0, 0, 0.1)')),
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ opacity: loading ? 0.6 : 1
+ });
+
+ return (
+
+ {/* Pagination Info */}
+ {showInfo && (
+
+ {showPageSizeSelector && (
+
+ Row Per Page
+
+ Entries
+
+ )}
+
+
+
+ 📊
+
+
+ Showing {startRecord} to {endRecord} of {totalCount} entries
+
+
+
+ )}
+
+ {/* Pagination Buttons */}
+
+ {Array.from({ length: totalPages }, (_, i) => {
+ const pageNum = i + 1;
+ const isActive = currentPage === pageNum;
+
+ return (
+
+ );
+ })}
+
+
+ );
+};
+
+export default CustomPagination;
diff --git a/src/feature-module/inventory/productlist.jsx b/src/feature-module/inventory/productlist.jsx
index fb36df5..fb8ed9f 100644
--- a/src/feature-module/inventory/productlist.jsx
+++ b/src/feature-module/inventory/productlist.jsx
@@ -30,6 +30,7 @@ import {
deleteProduct,
clearProductError
} from "../../core/redux/actions/productActions";
+import CustomPagination from '../../components/CustomPagination';
// Add CSS animations for beautiful UI
const shimmerKeyframes = `
@@ -1252,182 +1253,21 @@ const ProductList = () => {
pagination={false} // Disable Ant Design pagination
/>
- {/* Table Pagination with Theme Integration */}
- {
- e.currentTarget.style.transform = 'translateY(-2px)';
- e.currentTarget.style.boxShadow = '0 12px 40px rgba(0, 0, 0, 0.4), 0 4px 12px rgba(52, 152, 219, 0.2)';
- }}
- onMouseLeave={(e) => {
- e.currentTarget.style.transform = 'translateY(0)';
- e.currentTarget.style.boxShadow = '0 8px 32px rgba(0, 0, 0, 0.3), 0 2px 8px rgba(52, 152, 219, 0.1)';
- }}
- >
- {/* Animated background glow */}
-
-
- {/* Row Per Page Section */}
-
-
- Row Per Page
-
- Entries
-
-
-
-
- 📊
-
-
- Showing {startRecord} to {endRecord} of {totalRecords} entries
- {debouncedSearchTerm && (
-
- (filtered from {totalProducts || totalRecords} total)
-
- )}
-
-
-
-
- {/* Pagination Section like the image */}
-
- {/* Numbered Pagination Buttons */}
- {Array.from({ length: actualTotalPages }, (_, i) => {
- const pageNum = i + 1;
- const isActive = currentPage === pageNum;
-
- return (
-
- );
- })}
-
-
+ {/* Reusable Custom Pagination Component */}
+
>
)}
diff --git a/src/feature-module/projects/projecttracker.jsx b/src/feature-module/projects/projecttracker.jsx
index 009a139..b910bea 100644
--- a/src/feature-module/projects/projecttracker.jsx
+++ b/src/feature-module/projects/projecttracker.jsx
@@ -8,32 +8,12 @@ import {
Plus
} from 'feather-icons-react';
import dayjs from 'dayjs';
-import { useSelector } from 'react-redux';
+import CustomPagination from '../../components/CustomPagination';
const { Option } = Select;
const { RangePicker } = DatePicker;
const ProjectTracker = () => {
- // Theme state for force re-render
- const [themeKey, setThemeKey] = useState(0);
-
- // Get theme from Redux
- const reduxTheme = useSelector((state) => state.theme?.isDarkMode);
-
- // Get theme from multiple sources with real-time detection
- const localStorageTheme = localStorage.getItem('colorschema') === 'dark_mode';
- const documentTheme = document.documentElement.getAttribute('data-layout-mode') === 'dark_mode';
-
- const isDarkMode = reduxTheme || localStorageTheme || documentTheme;
-
- // Debug theme state
- console.log('Theme Debug:', {
- reduxTheme: reduxTheme,
- localStorage: localStorage.getItem('colorschema'),
- documentAttribute: document.documentElement.getAttribute('data-layout-mode'),
- isDarkMode: isDarkMode,
- themeKey: themeKey
- });
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [filterStatus, setFilterStatus] = useState('All Status');
@@ -171,42 +151,7 @@ const ProjectTracker = () => {
loadProjects();
}, []);
- // Listen for theme changes
- useEffect(() => {
- const handleThemeChange = () => {
- // Force re-render when theme changes
- console.log('Theme changed, forcing re-render');
- setThemeKey(prev => prev + 1);
- };
- // Listen for data-layout-mode attribute changes
- const observer = new MutationObserver((mutations) => {
- mutations.forEach((mutation) => {
- if (mutation.type === 'attributes' && mutation.attributeName === 'data-layout-mode') {
- handleThemeChange();
- }
- });
- });
-
- observer.observe(document.documentElement, {
- attributes: true,
- attributeFilter: ['data-layout-mode']
- });
-
- // Also listen for localStorage changes
- const handleStorageChange = (e) => {
- if (e.key === 'colorschema') {
- handleThemeChange();
- }
- };
-
- window.addEventListener('storage', handleStorageChange);
-
- return () => {
- observer.disconnect();
- window.removeEventListener('storage', handleStorageChange);
- };
- }, []);
// Handle pagination change
const handlePageChange = (page) => {
@@ -231,9 +176,7 @@ const ProjectTracker = () => {
}
};
- // Calculate pagination info
- const startRecord = totalCount > 0 ? (currentPage - 1) * pageSize + 1 : 0;
- const endRecord = Math.min(currentPage * pageSize, totalCount);
+
// Table columns configuration
const columns = [
@@ -710,182 +653,21 @@ const ProjectTracker = () => {
- {/* Custom Pagination - Compact Size */}
-
- {/* Pagination Info - Compact */}
-
-
- Row Per Page
-
- Entries
-
-
-
-
- 📊
-
-
- Showing {startRecord} to {endRecord} of {totalCount} entries
-
-
-
-
- {/* Pagination Buttons - Compact */}
-
- {/* Numbered Pagination Buttons */}
- {Array.from({ length: totalPages }, (_, i) => {
- const pageNum = i + 1;
- const isActive = currentPage === pageNum;
-
- return (
-
- );
- })}
-
-
+ {/* Reusable Custom Pagination Component */}
+