Implementasi API table face dan ktp
This commit is contained in:
parent
7996568d74
commit
daf0e7e54d
@ -1 +1 @@
|
|||||||
Subproject commit addaac2b9a73b75761c7449341ecc23bfbe63cc2
|
Subproject commit e15616c8ba2cd26017469382b0f58121b07e8cac
|
0
SingleMessage.js
Normal file
0
SingleMessage.js
Normal 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 },
|
||||||
});
|
});
|
||||||
|
@ -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}`,
|
|
||||||
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',
|
|
||||||
});
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
const result = await response.json();
|
||||||
|
const { data, total } = result.details.details.data;
|
||||||
|
setTransactionData(data);
|
||||||
|
setTotalPages(Math.ceil(total / dataPerPage));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching transaction data:', error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return transactionData;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 */}
|
||||||
@ -276,59 +311,58 @@ const Transaction = () => {
|
|||||||
<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('transactionId')}>
|
<button className="btn" onClick={() => handleSort('transaction_id')}>
|
||||||
Transaction ID
|
Transaction ID
|
||||||
{sortConfig.key === 'transactionId' &&
|
{sortConfig.key === 'transaction_id' &&
|
||||||
(sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />)
|
(sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />)
|
||||||
}
|
}
|
||||||
{sortConfig.key !== 'transactionId' && <FaSort style={styles.iconMarginLeft} />}
|
{sortConfig.key !== 'transaction_id' && <FaSort style={styles.iconMarginLeft} />}
|
||||||
</button>
|
</button>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<button className="btn" onClick={() => handleSort('applicationName')}>
|
<button className="btn" onClick={() => handleSort('app_name')}>
|
||||||
Application Name
|
Application Name
|
||||||
{sortConfig.key === 'applicationName' &&
|
{sortConfig.key === 'app_name' &&
|
||||||
(sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />)
|
(sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />)
|
||||||
}
|
}
|
||||||
{sortConfig.key !== 'applicationName' && <FaSort style={styles.iconMarginLeft} />}
|
{sortConfig.key !== 'app_name' && <FaSort style={styles.iconMarginLeft} />}
|
||||||
</button>
|
</button>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<button className="btn" onClick={() => handleSort('createdAt')}>
|
<button className="btn" onClick={() => handleSort('created_at')}>
|
||||||
Created At
|
Created At
|
||||||
{sortConfig.key === 'createdAt' &&
|
{sortConfig.key === 'created_at' &&
|
||||||
(sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />)
|
(sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />)
|
||||||
}
|
}
|
||||||
{sortConfig.key !== 'createdAt' && <FaSort style={styles.iconMarginLeft} />}
|
{sortConfig.key !== 'created_at' && <FaSort style={styles.iconMarginLeft} />}
|
||||||
</button>
|
</button>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<button className="btn" onClick={() => handleSort('referenceId')}>
|
<button className="btn" onClick={() => handleSort('service_name')}>
|
||||||
Reference ID
|
Service Name
|
||||||
{sortConfig.key === 'referenceId' &&
|
{sortConfig.key === 'service_name' &&
|
||||||
(sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />)
|
(sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />)
|
||||||
}
|
}
|
||||||
{sortConfig.key !== 'referenceId' && <FaSort style={styles.iconMarginLeft} />}
|
{sortConfig.key !== 'service_name' && <FaSort style={styles.iconMarginLeft} />}
|
||||||
</button>
|
</button>
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<button className="btn" onClick={() => handleSort('status')}>
|
<button className="btn" onClick={() => handleSort('mode_name')}>
|
||||||
Status
|
|
||||||
{sortConfig.key === 'status' &&
|
|
||||||
(sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />)
|
|
||||||
}
|
|
||||||
{sortConfig.key !== 'status' && <FaSort style={styles.iconMarginLeft} />}
|
|
||||||
</button>
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
<button className="btn" onClick={() => handleSort('mode')}>
|
|
||||||
Mode
|
Mode
|
||||||
{sortConfig.key === 'mode' &&
|
{sortConfig.key === 'mode_name' &&
|
||||||
(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' && <FaSort style={styles.iconMarginLeft} />}
|
{sortConfig.key !== 'mode_name' && <FaSort style={styles.iconMarginLeft} />}
|
||||||
|
</button>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<button className="btn" onClick={() => handleSort('status_name')}>
|
||||||
|
Status
|
||||||
|
{sortConfig.key === 'status_name' &&
|
||||||
|
(sortConfig.direction === 'asc' ? <FaSortUp style={styles.iconMarginLeft} /> : <FaSortDown style={styles.iconMarginLeft} />)
|
||||||
|
}
|
||||||
|
{sortConfig.key !== 'status_name' && <FaSort style={styles.iconMarginLeft} />}
|
||||||
</button>
|
</button>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -338,19 +372,17 @@ const Transaction = () => {
|
|||||||
{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>
|
|
||||||
<td>{transaction.mode}</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan="7" className="text-center">
|
<td colSpan="6" className="text-center">
|
||||||
<div className="d-flex flex-column align-items-center mt-5">
|
<div className="d-flex flex-column align-items-center mt-5">
|
||||||
<img src={NoAvailable} alt="No Data Available" className="mb-3" style={styles.iconStyle} />
|
<img src={NoAvailable} alt="No Data Available" className="mb-3" style={styles.iconStyle} />
|
||||||
<p>Data not available</p>
|
<p>Data not available</p>
|
||||||
@ -397,4 +429,3 @@ const styles = {
|
|||||||
marginLeft: '0.7rem', // Adjust as needed
|
marginLeft: '0.7rem', // Adjust as needed
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user