diff --git a/src/App.js b/src/App.js
index b6a2a14..dadb07a 100644
--- a/src/App.js
+++ b/src/App.js
@@ -34,6 +34,8 @@ import {
} from './screens/Biometric/OcrKtp';
import {
+ SummaryNpwp,
+ TransactionNpwp,
VerifyNpwp
} from './screens/Biometric/OcrNpwp';
@@ -86,6 +88,8 @@ const App = () => {
{/* Biometric - NPWP */}
} />
+ } />
+ } />
{/* } /> */}
{/* Continue for each link */}
diff --git a/src/screens/Biometric/OcrNpwp/Summary.jsx b/src/screens/Biometric/OcrNpwp/Summary.jsx
new file mode 100644
index 0000000..f3604fc
--- /dev/null
+++ b/src/screens/Biometric/OcrNpwp/Summary.jsx
@@ -0,0 +1,267 @@
+import React, { useState, useEffect } from 'react';
+import {
+ Extract,
+ Transaction,
+ Failed
+} from '../../../assets/icon';
+
+const Summary = () => {
+ const [startDate, setStartDate] = useState('');
+ const [endDate, setEndDate] = useState('');
+ const [application, setApplication] = useState('');
+ const [isMobile, setIsMobile] = useState(false);
+
+ const menuData = [
+ { id: 1, value: '150', label: 'Total Transaction', icon: Transaction },
+ { id: 2, value: '4', label: 'Total Extract', icon: Extract },
+ { id: 3, value: '65', label: 'Total Failed', icon: Failed },
+ ];
+
+ const handleApply = () => {
+ console.log({ startDate, endDate, application });
+ };
+
+ const handleCancel = () => {
+ setStartDate('');
+ setEndDate('');
+ setApplication('');
+ };
+
+ // Detect if the device is mobile based on window width
+ useEffect(() => {
+ const handleResize = () => {
+ setIsMobile(window.innerWidth <= 768); // Define mobile screen as width <= 768px
+ };
+
+ // Initialize on component mount
+ handleResize();
+
+ // Add event listener to update state on resize
+ window.addEventListener('resize', handleResize);
+
+ // Cleanup event listener on component unmount
+ return () => {
+ window.removeEventListener('resize', handleResize);
+ };
+ }, []);
+
+ return (
+
+ {/* Welcome Message */}
+
+
+
+
+ Alert
+
+
+ Get started now by creating an Application ID and explore all the demo services available on the dashboard.
+ Experience the ease and flexibility of trying out all our features firsthand.
+
+
+
+
+
+
+
+ {/* Row 1: Start Date and End Date */}
+
+ setStartDate(e.target.value)}
+ style={styles.filterInput}
+ placeholder="Start Date"
+ />
+ setEndDate(e.target.value)}
+ style={styles.filterInput}
+ placeholder="End Date"
+ />
+
+
+ {/* Row 2: Application Select */}
+
+ setApplication(e.target.value)}
+ style={styles.filterInput}
+ >
+ Application
+ App1
+ App2
+
+
+
+ {/* Row 3: Apply and Cancel Buttons */}
+
+
+ Apply
+
+
+ Cancel
+
+
+
+
+
+ {menuData.map((item) => (
+
+
+
{item.value}
+
{item.label}
+
+
+
+
+
+ ))}
+
+
+
+
+
+ );
+};
+
+const styles = {
+ container: {
+ margin: '3rem',
+ },
+ filters: {
+ display: 'flex',
+ justifyContent: 'space-between',
+ marginBottom: '20px',
+ flexDirection: 'row', // Horizontal layout on desktop
+ gap: '10px',
+ },
+ filtersMobile: {
+ display: 'flex',
+ flexDirection: 'column', // Vertical layout on mobile
+ gap: '15px',
+ },
+ filterRow: {
+ display: 'flex',
+ justifyContent: 'space-between',
+ gap: '10px',
+ width: '100%',
+ },
+ filterInput: {
+ padding: '10px',
+ border: '1px solid #ccc',
+ borderRadius: '5px',
+ fontSize: '16px',
+ width: '48%', // Adjust width to take up 48% of the row for input elements
+ },
+ applyButton: {
+ backgroundColor: '#0542cc',
+ color: '#fff',
+ padding: '10px 20px',
+ border: 'none',
+ borderRadius: '5px',
+ cursor: 'pointer',
+ width: '48%', // Adjust button width to take half of the row
+ },
+ cancelButton: {
+ backgroundColor: '#fff',
+ color: '#000',
+ padding: '10px 20px',
+ border: '1px solid gray',
+ borderRadius: '5px',
+ cursor: 'pointer',
+ width: '48%', // Adjust button width to take half of the row
+ },
+ summaryContainer: {
+ padding: '20px',
+ border: '0.1px solid rgba(0, 0, 0, 0.2)',
+ borderLeft: '4px solid #0542cc',
+ borderRadius: '10px',
+ width: '100%',
+ },
+ summaryCards: {
+ display: 'grid',
+ gridTemplateColumns: 'repeat(4, 1fr)', // 4 columns on desktop
+ gap: '20px',
+ marginTop: '20px',
+ },
+ summaryCardsMobile: {
+ display: 'grid',
+ gridTemplateColumns: '1fr', // 1 column on mobile (full width)
+ gap: '15px',
+ marginTop: '20px',
+ },
+ card: {
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ padding: '15px', // Reduced padding for a more compact card
+ backgroundColor: 'white',
+ borderRadius: '8px', // Slightly smaller border-radius for a sharper look
+ boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',
+ textAlign: 'left',
+ minWidth: '200px', // Ensure minimum width for mobile responsiveness
+ maxWidth: '300px', // Limit the maximum width to prevent cards from becoming too wide
+ width: '100%',
+ transition: 'transform 0.3s ease', // Smooth transition for hover effects
+ },
+ cardHover: {
+ transform: 'scale(1.05)', // Slight zoom on hover for interactivity
+ },
+ iconContainer: {
+ display: 'flex',
+ justifyContent: 'flex-end',
+ alignItems: 'center',
+ },
+ textContainer: {
+ display: 'flex',
+ flexDirection: 'column',
+ },
+ icon: {
+ width: '36px', // Smaller icon size for a more compact card
+ height: '36px', // Matching height for the icon
+ },
+ cardTitle: {
+ fontSize: '18px', // Smaller font size for title to prevent overflow
+ margin: '0',
+ fontWeight: 'bold',
+ },
+ cardText: {
+ fontSize: '12px', // Smaller text size for description to keep it balanced
+ color: '#555',
+ },
+
+ // Optional: Hover effect for the cards to enhance interactivity
+ cardHover: {
+ transform: 'scale(1.05)', // Slight zoom effect when hovering over card
+ },
+
+ // Media query for smaller screens (e.g., phones in portrait mode)
+ "@media (max-width: 768px)": {
+ summaryCards: {
+ gridTemplateColumns: '1fr', // 1 column on mobile screens
+ },
+ card: {
+ padding: '10px', // Smaller padding for smaller screens
+ minWidth: '180px', // Adjust min width for mobile devices
+ maxWidth: '250px', // Adjust max width for mobile devices
+ },
+ icon: {
+ width: '30px', // Slightly smaller icon size for mobile
+ height: '30px', // Matching height for mobile icon
+ },
+ cardTitle: {
+ fontSize: '16px', // Smaller font size for the card title
+ },
+ cardText: {
+ fontSize: '10px', // Smaller font size for card description
+ },
+ },
+};
+
+export default Summary;
diff --git a/src/screens/Biometric/OcrNpwp/Transaction.jsx b/src/screens/Biometric/OcrNpwp/Transaction.jsx
new file mode 100644
index 0000000..7271084
--- /dev/null
+++ b/src/screens/Biometric/OcrNpwp/Transaction.jsx
@@ -0,0 +1,400 @@
+import React, { useState, useEffect } from 'react';
+import { FaChevronLeft, FaChevronRight, FaFastBackward, FaFastForward, FaSort, FaSortUp, FaSortDown } from 'react-icons/fa'; // Icons for sorting
+import { NoAvailable } from '../../../assets/icon';
+
+// Pagination Component
+const Pagination = ({ currentPage, totalPages, onPageChange }) => {
+ const handlePrev = () => {
+ if (currentPage > 1) {
+ onPageChange(currentPage - 1);
+ }
+ };
+
+ const handleNext = () => {
+ if (currentPage < totalPages) {
+ onPageChange(currentPage + 1);
+ }
+ };
+
+ const handleFirst = () => {
+ onPageChange(1); // Go to first page
+ };
+
+ const handleLast = () => {
+ onPageChange(totalPages); // Go to last page
+ };
+
+ // Logic to display only 3 pages in pagination
+ const getPaginationRange = () => {
+ const range = [];
+ const totalPagesCount = totalPages;
+
+ let start = currentPage - 1;
+ let end = currentPage + 1;
+
+ // Adjust start and end if near the boundaries
+ if (currentPage === 1) {
+ start = 1;
+ end = Math.min(3, totalPagesCount);
+ } else if (currentPage === totalPages) {
+ start = Math.max(totalPagesCount - 2, 1);
+ end = totalPagesCount;
+ }
+
+ for (let i = start; i <= end; i++) {
+ range.push(i);
+ }
+
+ return range;
+ };
+
+ const pageRange = getPaginationRange();
+
+ return (
+
+ {/* First Page Button */}
+
+ {/* Double Arrow Left */}
+
+
+
+ {/* Single Arrow Left */}
+
+
+ {/* Page Numbers */}
+ {pageRange.map((pageNum) => (
+ onPageChange(pageNum)}
+ >
+ {pageNum}
+
+ ))}
+
+
+ {/* Single Arrow Right */}
+
+
+ {/* Last Page Button */}
+
+ {/* Double Arrow Right */}
+
+
+ );
+};
+
+const Transaction = () => {
+ const [currentPage, setCurrentPage] = useState(1);
+ const [isMobile, setIsMobile] = useState(false); // State to detect mobile view
+ const [transactionData, setTransactionData] = useState([]);
+ const [sortConfig, setSortConfig] = useState({ key: null, direction: 'asc' }); // Sorting state
+ const dataPerPage = 10; // Data per page (10 data per page)
+
+ const buttonData = [
+ { label: 'Copy', enabled: true },
+ { label: 'CSV', enabled: true },
+ { label: 'Excel', enabled: true },
+ { label: 'PDF', enabled: true },
+ { label: 'Print', enabled: true },
+ { label: 'Column Visibility', enabled: true },
+ ];
+
+
+ // Generate 691 dummy transactions
+ const generateDummyData = (numOfItems) => {
+ const transactionData = [];
+
+ for (let i = 1; i <= numOfItems; i++) {
+ transactionData.push({
+ transactionId: `TX${String(i).padStart(3, '0')}`,
+ applicationName: `App ${Math.floor(Math.random() * 5) + 1}`,
+ createdAt: new Date(2023, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1).toLocaleDateString(), // Random date
+ referenceId: `REF${String(i).padStart(3, '0')}`,
+ status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)],
+ mode: Math.random() > 0.5 ? 'Online' : 'Offline',
+ });
+ }
+
+ return transactionData;
+ };
+
+
+ // Set the generated transaction data
+ useEffect(() => {
+ setTransactionData(generateDummyData(52)); // count data dummy transactions
+ }, []);
+
+ // Sorting function
+ const sortData = (data, config) => {
+ const { key, direction } = config;
+ return [...data].sort((a, b) => {
+ if (a[key] < b[key]) {
+ return direction === 'asc' ? -1 : 1;
+ }
+ if (a[key] > b[key]) {
+ return direction === 'asc' ? 1 : -1;
+ }
+ return 0;
+ });
+ };
+
+ // Handle column header sort click
+ const handleSort = (key) => {
+ let direction = 'asc';
+ if (sortConfig.key === key && sortConfig.direction === 'asc') {
+ direction = 'desc'; // Toggle direction if the same column is clicked
+ }
+ setSortConfig({ key, direction });
+ };
+
+ // Get the paginated data
+ const getPaginatedData = (data, page, perPage) => {
+ const sortedData = sortData(data, sortConfig);
+ const startIndex = (page - 1) * perPage;
+ const endIndex = startIndex + perPage;
+ return sortedData.slice(startIndex, endIndex);
+ };
+
+ // Handle page change
+ const handlePageChange = (page) => {
+ setCurrentPage(page);
+ };
+
+ // Calculate total pages based on the data and data per page
+ const totalPages = Math.ceil(transactionData.length / dataPerPage);
+
+ // Paginated data
+ const paginatedData = getPaginatedData(transactionData, currentPage, dataPerPage);
+
+ // Detect screen size and update isMobile state
+ useEffect(() => {
+ const handleResize = () => {
+ setIsMobile(window.innerWidth <= 768); // Change 768 to your breakpoint
+ };
+
+ handleResize();
+ window.addEventListener('resize', handleResize);
+ return () => window.removeEventListener('resize', handleResize);
+ }, []);
+
+ return (
+
+ {/* Welcome Message */}
+
+
+
+
+ Alert
+
+
+ Get started now by creating an Application ID and explore all the demo services available on the dashboard.
+ Experience the ease and flexibility of trying out all our features firsthand.
+
+
+
+
+
+
+ {/* Filter Form */}
+
+
+
+ Start Date
+
+
+
+ End Date
+
+
+
+ Application
+
+ Select Application
+ App 1
+ App 2
+ App 3
+ App 4
+ App 5
+
+
+
+ Apply
+ Cancel
+
+
+
+
+ {/* Action Buttons */}
+
+
+ {buttonData.map((button, index) =>
+ button.enabled ? (
+
+ {button.label}
+
+ ) : null
+ )}
+
+
+ {/* Search Bar with Icon */}
+
+
+
+ {/* FontAwesome search icon */}
+
+
+
+
+
+ {/* Table */}
+
+
+
+
+ No. {/* Kolom untuk Nomor Urut */}
+
+ handleSort('transactionId')}>
+ Transaction ID
+ {sortConfig.key === 'transactionId' &&
+ (sortConfig.direction === 'asc' ? : )
+ }
+ {sortConfig.key !== 'transactionId' && }
+
+
+
+ handleSort('applicationName')}>
+ Application Name
+ {sortConfig.key === 'applicationName' &&
+ (sortConfig.direction === 'asc' ? : )
+ }
+ {sortConfig.key !== 'applicationName' && }
+
+
+
+ handleSort('createdAt')}>
+ Created At
+ {sortConfig.key === 'createdAt' &&
+ (sortConfig.direction === 'asc' ? : )
+ }
+ {sortConfig.key !== 'createdAt' && }
+
+
+
+ handleSort('referenceId')}>
+ Reference ID
+ {sortConfig.key === 'referenceId' &&
+ (sortConfig.direction === 'asc' ? : )
+ }
+ {sortConfig.key !== 'referenceId' && }
+
+
+
+ handleSort('status')}>
+ Status
+ {sortConfig.key === 'status' &&
+ (sortConfig.direction === 'asc' ? : )
+ }
+ {sortConfig.key !== 'status' && }
+
+
+
+ handleSort('mode')}>
+ Mode
+ {sortConfig.key === 'mode' &&
+ (sortConfig.direction === 'asc' ? : )
+ }
+ {sortConfig.key !== 'mode' && }
+
+
+
+
+
+
+ {paginatedData.length > 0 ? (
+ paginatedData.map((transaction, index) => (
+
+ {/* Kolom Nomor Urut */}
+ {(currentPage - 1) * dataPerPage + index + 1} {/* Nomor urut berdasarkan halaman dan index */}
+ {transaction.transactionId}
+ {transaction.applicationName}
+ {transaction.createdAt}
+ {transaction.referenceId}
+ {transaction.status}
+ {transaction.mode}
+
+ ))
+ ) : (
+
+
+
+
+
Data not available
+
+
+
+ )}
+
+
+
+
+ {/* Pagination */}
+
+
+
+ );
+};
+
+export default Transaction;
+
+const styles = {
+ contentContainer: {
+ padding: '20px',
+ border: '0.1px solid rgba(0, 0, 0, 0.2)',
+ borderLeft: '4px solid #0542cc',
+ borderRadius: '10px',
+ width: '100%',
+ },
+ tableContainer: {
+ minHeight: '300px',
+ maxHeight: '1500px',
+ overflowY: 'auto',
+ },
+ iconStyle: {
+ width: '50px',
+ height: '50px',
+ },
+ // Add margin-left style for icons
+ iconMarginLeft: {
+ marginLeft: '0.7rem', // Adjust as needed
+ },
+};
+
diff --git a/src/screens/Biometric/OcrNpwp/index.js b/src/screens/Biometric/OcrNpwp/index.js
index f0655f4..28800e9 100644
--- a/src/screens/Biometric/OcrNpwp/index.js
+++ b/src/screens/Biometric/OcrNpwp/index.js
@@ -1,5 +1,9 @@
import VerifyNpwp from "./Verify";
+import SummaryNpwp from "./Summary";
+import TransactionNpwp from "./Transaction";
export {
- VerifyNpwp
+ VerifyNpwp,
+ SummaryNpwp,
+ TransactionNpwp
}
\ No newline at end of file