From 47115a8ebb1ed2892ef6dbb8275cdaedaa5c8497 Mon Sep 17 00:00:00 2001 From: Rizqika Date: Thu, 14 Nov 2024 18:11:35 +0700 Subject: [PATCH] Slicing UI --- src/App.js | 4 + src/screens/Biometric/OcrNpwp/Summary.jsx | 267 ++++++++++++ src/screens/Biometric/OcrNpwp/Transaction.jsx | 400 ++++++++++++++++++ src/screens/Biometric/OcrNpwp/index.js | 6 +- 4 files changed, 676 insertions(+), 1 deletion(-) create mode 100644 src/screens/Biometric/OcrNpwp/Summary.jsx create mode 100644 src/screens/Biometric/OcrNpwp/Transaction.jsx 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 */} +
+ +
+ + {/* Row 3: Apply and Cancel Buttons */} +
+ + +
+
+ +
+ {menuData.map((item) => ( +
+
+

{item.value}

+

{item.label}

+
+
+ {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 */} + + + + + {/* Page Numbers */} + {pageRange.map((pageNum) => ( + + ))} + + + + {/* Last Page Button */} + +
+ ); +}; + +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 */} +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + {/* Action Buttons */} +
+
+ {buttonData.map((button, index) => + button.enabled ? ( + + ) : null + )} +
+ + {/* Search Bar with Icon */} +
+ + + {/* FontAwesome search icon */} + +
+
+ + + {/* Table */} +
+ + + + {/* Kolom untuk Nomor Urut */} + + + + + + + + + + + {paginatedData.length > 0 ? ( + paginatedData.map((transaction, index) => ( + + {/* Kolom Nomor Urut */} + {/* Nomor urut berdasarkan halaman dan index */} + + + + + + + + )) + ) : ( + + + + )} + +
No. + + + + + + + + + + + +
{(currentPage - 1) * dataPerPage + index + 1}{transaction.transactionId}{transaction.applicationName}{transaction.createdAt}{transaction.referenceId}{transaction.status}{transaction.mode}
+
+ No Data Available +

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