Implementasi API table face dan ktp

This commit is contained in:
Rizqika 2025-01-02 18:38:56 +07:00
parent 7996568d74
commit daf0e7e54d
4 changed files with 145 additions and 113 deletions

@ -1 +1 @@
Subproject commit addaac2b9a73b75761c7449341ecc23bfbe63cc2 Subproject commit e15616c8ba2cd26017469382b0f58121b07e8cac

0
SingleMessage.js Normal file
View File

View File

@ -3,6 +3,7 @@ import { FaChevronLeft, FaChevronRight, FaFastBackward, FaFastForward, FaSort, F
import { NoAvailable } from '../../../assets/icon'; import { NoAvailable } from '../../../assets/icon';
const BASE_URL = process.env.REACT_APP_BASE_URL const BASE_URL = process.env.REACT_APP_BASE_URL
const LOCAL_URL = 'http://127.0.0.1:8000'
const API_KEY = process.env.REACT_APP_API_KEY const API_KEY = process.env.REACT_APP_API_KEY
// Pagination Component // Pagination Component
const Pagination = ({ currentPage, totalPages, onPageChange }) => { const Pagination = ({ currentPage, totalPages, onPageChange }) => {
@ -126,7 +127,7 @@ const Transaction = () => {
const fetchTransactionData = async (page, limit, search = '', sortColumn = 'tf.id', sortOrder = 'asc') => { const fetchTransactionData = async (page, limit, search = '', sortColumn = 'tf.id', sortOrder = 'asc') => {
try { try {
console.log(`Fetching data for page: ${page}, limit: ${limit}, search: ${search}, sortColumn: ${sortColumn}, sortOrder: ${sortOrder}`); // Log page, limit, and search console.log(`Fetching data for page: ${page}, limit: ${limit}, search: ${search}, sortColumn: ${sortColumn}, sortOrder: ${sortOrder}`); // Log page, limit, and search
const response = await fetch(`${BASE_URL}/trx_face/table-log?search=${search}&sortColumn=${sortColumn}&sortOrder=${sortOrder}&limit=${limit}&page=${page}`, { const response = await fetch(`${LOCAL_URL}/trx_face/table-log?search=${search}&sortColumn=${sortColumn}&sortOrder=${sortOrder}`, {
method: 'GET', method: 'GET',
headers: { 'accept': 'application/json', 'x-api-key': API_KEY }, headers: { 'accept': 'application/json', 'x-api-key': API_KEY },
}); });

View File

@ -2,6 +2,9 @@ import React, { useState, useEffect } from 'react';
import { FaChevronLeft, FaChevronRight, FaFastBackward, FaFastForward, FaSort, FaSortUp, FaSortDown } from 'react-icons/fa'; // Icons for sorting import { FaChevronLeft, FaChevronRight, FaFastBackward, FaFastForward, FaSort, FaSortUp, FaSortDown } from 'react-icons/fa'; // Icons for sorting
import { NoAvailable } from '../../../assets/icon'; import { NoAvailable } from '../../../assets/icon';
const BASE_URL = process.env.REACT_APP_BASE_URL
const LOCAL_URL = 'http://127.0.0.1:8000'
const API_KEY = process.env.REACT_APP_API_KEY
// Pagination Component // Pagination Component
const Pagination = ({ currentPage, totalPages, onPageChange }) => { const Pagination = ({ currentPage, totalPages, onPageChange }) => {
const handlePrev = () => { const handlePrev = () => {
@ -106,6 +109,10 @@ const Transaction = () => {
const [transactionData, setTransactionData] = useState([]); const [transactionData, setTransactionData] = useState([]);
const [sortConfig, setSortConfig] = useState({ key: null, direction: 'asc' }); // Sorting state const [sortConfig, setSortConfig] = useState({ key: null, direction: 'asc' }); // Sorting state
const dataPerPage = 10; // Data per page (10 data per page) const dataPerPage = 10; // Data per page (10 data per page)
const [totalPages, setTotalPages] = useState(1); // Total pages from API
const [searchTerm, setSearchTerm] = useState('');
const [sortColumn, setSortColumn] = useState('tf.id');
const [sortOrder, setSortOrder] = useState('asc');
const buttonData = [ const buttonData = [
{ label: 'Copy', enabled: true }, { label: 'Copy', enabled: true },
@ -116,30 +123,51 @@ const Transaction = () => {
{ label: 'Column Visibility', enabled: true }, { label: 'Column Visibility', enabled: true },
]; ];
// Fetch transaction data from API
// Generate 691 dummy transactions const fetchTransactionData = async (page, limit, search = '', sortColumn = 'tf.id', sortOrder = 'asc') => {
const generateDummyData = (numOfItems) => { try {
const transactionData = []; console.log(`Fetching data for page: ${page}, limit: ${limit}, search: ${search}, sortColumn: ${sortColumn}, sortOrder: ${sortOrder}`); // Log page, limit, and search
const response = await fetch(`${LOCAL_URL}/ocr-ktp/table-transactions?search=${search}&sortColumn=${sortColumn}&sortOrder=${sortOrder}`, {
for (let i = 1; i <= numOfItems; i++) { method: 'GET',
transactionData.push({ headers: { 'accept': 'application/json', 'x-api-key': API_KEY },
transactionId: `TX${String(i).padStart(3, '0')}`, });
applicationName: `App ${Math.floor(Math.random() * 5) + 1}`, if (!response.ok) {
createdAt: new Date(2023, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1).toLocaleDateString(), // Random date throw new Error(`HTTP error! status: ${response.status}`);
referenceId: `REF${String(i).padStart(3, '0')}`, }
status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], const result = await response.json();
mode: Math.random() > 0.5 ? 'Online' : 'Offline', const { data, total } = result.details.details.data;
}); setTransactionData(data);
} setTotalPages(Math.ceil(total / dataPerPage));
} catch (error) {
return transactionData; console.error('Error fetching transaction data:', error);
}
}; };
const fetchPaginationData = async (page, limit, search = '') => {
try {
console.log(`Fetching pagination data for page: ${page}, limit: ${limit}, search: ${search}`); // Log page, limit, and search
const url = `${BASE_URL}/header_detail_param/paging?header_id=1&page=${page}&limit=${limit}&search=${search}`;
console.log(`Fetching URL: ${url}`); // Log the URL
const response = await fetch(url, {
method: 'GET',
headers: { 'accept': 'application/json', 'x-api-key': API_KEY },
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
const { data } = result.details;
setTotalPages(Math.ceil(data.length / dataPerPage));
} catch (error) {
console.error('Error fetching pagination data:', error);
}
};
// Set the generated transaction data // Fetch data when component mounts and when currentPage changes
useEffect(() => { useEffect(() => {
setTransactionData(generateDummyData(3113)); // count data dummy transactions fetchTransactionData(currentPage, dataPerPage, searchTerm, sortColumn, sortOrder);
}, []); fetchPaginationData(currentPage, dataPerPage);
}, [currentPage, searchTerm, sortColumn, sortOrder]);
// Sorting function // Sorting function
const sortData = (data, config) => { const sortData = (data, config) => {
@ -177,8 +205,14 @@ const Transaction = () => {
setCurrentPage(page); setCurrentPage(page);
}; };
// Calculate total pages based on the data and data per page // Handle search
const totalPages = Math.ceil(transactionData.length / dataPerPage); const handleSearch = async (event) => {
const searchQuery = event.target.value;
setSearchTerm(searchQuery);
setCurrentPage(1); // Reset to first page on new search
await fetchPaginationData(1, dataPerPage, searchQuery);
await fetchTransactionData(1, dataPerPage, searchQuery);
};
// Paginated data // Paginated data
const paginatedData = getPaginatedData(transactionData, currentPage, dataPerPage); const paginatedData = getPaginatedData(transactionData, currentPage, dataPerPage);
@ -258,11 +292,12 @@ const Transaction = () => {
</div> </div>
{/* Search Bar with Icon */} {/* Search Bar with Icon */}
<div className="input-group" style={{ width: '250px', display: 'flex', alignItems: 'center', justifyContent: 'flex-end' }}> <div className="input-group" style={{ width: '350px', display: 'flex', alignItems: 'center', justifyContent: 'flex-end' }}>
<input <input
type="text" type="text"
placeholder="Search..." placeholder="Search Application Name or Subject ID" // Placeholder text
className="form-control" className="form-control"
onChange={handleSearch} // Add onChange handler
/> />
<span className="input-group-text"> <span className="input-group-text">
<i className="fas fa-search"></i> {/* FontAwesome search icon */} <i className="fas fa-search"></i> {/* FontAwesome search icon */}
@ -273,93 +308,90 @@ const Transaction = () => {
{/* Table */} {/* Table */}
<div className="table-responsive"> <div className="table-responsive">
<table className="table table-bordered" style={styles.tableContainer}> <table className="table table-bordered" style={styles.tableContainer}>
<thead> <thead>
<tr> <tr>
<th>No.</th> {/* Kolom untuk Nomor Urut */} <th>
<th> <button className="btn" onClick={() => handleSort('transaction_id')}>
<button className="btn" onClick={() => handleSort('transactionId')}> Transaction ID
Transaction ID {sortConfig.key === 'transaction_id' &&
{sortConfig.key === 'transactionId' && (sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />)
(sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />) }
} {sortConfig.key !== 'transaction_id' && <FaSort style={styles.iconMarginLeft} />}
{sortConfig.key !== 'transactionId' && <FaSort style={styles.iconMarginLeft} />} </button>
</button> </th>
</th> <th>
<th> <button className="btn" onClick={() => handleSort('app_name')}>
<button className="btn" onClick={() => handleSort('applicationName')}> Application Name
Application Name {sortConfig.key === 'app_name' &&
{sortConfig.key === 'applicationName' && (sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />)
(sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />) }
} {sortConfig.key !== 'app_name' && <FaSort style={styles.iconMarginLeft} />}
{sortConfig.key !== 'applicationName' && <FaSort style={styles.iconMarginLeft} />} </button>
</button> </th>
</th> <th>
<th> <button className="btn" onClick={() => handleSort('created_at')}>
<button className="btn" onClick={() => handleSort('createdAt')}> Created At
Created At {sortConfig.key === 'created_at' &&
{sortConfig.key === 'createdAt' && (sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />)
(sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />) }
} {sortConfig.key !== 'created_at' && <FaSort style={styles.iconMarginLeft} />}
{sortConfig.key !== 'createdAt' && <FaSort style={styles.iconMarginLeft} />} </button>
</button> </th>
</th> <th>
<th> <button className="btn" onClick={() => handleSort('service_name')}>
<button className="btn" onClick={() => handleSort('referenceId')}> Service Name
Reference ID {sortConfig.key === 'service_name' &&
{sortConfig.key === 'referenceId' && (sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />)
(sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />) }
} {sortConfig.key !== 'service_name' && <FaSort style={styles.iconMarginLeft} />}
{sortConfig.key !== 'referenceId' && <FaSort style={styles.iconMarginLeft} />} </button>
</button> </th>
</th> <th>
<th> <button className="btn" onClick={() => handleSort('mode_name')}>
<button className="btn" onClick={() => handleSort('status')}> Mode
Status {sortConfig.key === 'mode_name' &&
{sortConfig.key === 'status' && (sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />)
(sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />) }
} {sortConfig.key !== 'mode_name' && <FaSort style={styles.iconMarginLeft} />}
{sortConfig.key !== 'status' && <FaSort style={styles.iconMarginLeft} />} </button>
</button> </th>
</th> <th>
<th> <button className="btn" onClick={() => handleSort('status_name')}>
<button className="btn" onClick={() => handleSort('mode')}> Status
Mode {sortConfig.key === 'status_name' &&
{sortConfig.key === 'mode' && (sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />)
(sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />) }
} {sortConfig.key !== 'status_name' && <FaSort style={styles.iconMarginLeft} />}
{sortConfig.key !== 'mode' && <FaSort style={styles.iconMarginLeft} />} </button>
</button> </th>
</th> </tr>
</tr> </thead>
</thead>
<tbody> <tbody>
{paginatedData.length > 0 ? ( {paginatedData.length > 0 ? (
paginatedData.map((transaction, index) => ( paginatedData.map((transaction, index) => (
<tr key={index}> <tr key={index}>
{/* Kolom Nomor Urut */} <td>{transaction.transaction_id}</td>
<td>{(currentPage - 1) * dataPerPage + index + 1}</td> {/* Nomor urut berdasarkan halaman dan index */} <td>{transaction.app_name}</td>
<td>{transaction.transactionId}</td> <td>{transaction.service_name}</td>
<td>{transaction.applicationName}</td> <td>{new Date(transaction.created_at).toLocaleString()}</td>
<td>{transaction.createdAt}</td> <td>{transaction.mode_name}</td>
<td>{transaction.referenceId}</td> <td>{transaction.status_name}</td>
<td>{transaction.status}</td> </tr>
<td>{transaction.mode}</td> ))
</tr> ) : (
)) <tr>
) : ( <td colSpan="6" className="text-center">
<tr> <div className="d-flex flex-column align-items-center mt-5">
<td colSpan="7" className="text-center"> <img src={NoAvailable} alt="No Data Available" className="mb-3" style={styles.iconStyle} />
<div className="d-flex flex-column align-items-center mt-5"> <p>Data not available</p>
<img src={NoAvailable} alt="No Data Available" className="mb-3" style={styles.iconStyle} /> </div>
<p>Data not available</p> </td>
</div> </tr>
</td> )}
</tr> </tbody>
)} </table>
</tbody>
</table>
</div> </div>
{/* Pagination */} {/* Pagination */}
@ -397,4 +429,3 @@ const styles = {
marginLeft: '0.7rem', // Adjust as needed marginLeft: '0.7rem', // Adjust as needed
}, },
}; };