/** * Component: TransactionsList * Author: Nearblocks Pte Ltd * License: Business Source License 1.1 * Description: Table of Transactions on Near Protocol. * @interface Props * @param {string} [network] - The network data to show, either mainnet or testnet * @param {number} [currentPage] - The current page number being displayed. (Optional) * Example: If provided, currentPage=3 will display the third page of blocks. * @param {Object.<string, string>} [filters] - Key-value pairs for filtering transactions. (Optional) * Example: If provided, method=batch will filter the blocks with method=batch. * @param {function} [setPage] - A function used to set the current page. (Optional) * Example: setPage={handlePageChange} where handlePageChange is a function to update the page. * @param {function} [handleFilter] - Function to handle filter changes. (Optional) * Example: handleFilter={handlePageFilter} where handlePageFilter is a function to filter the page. * @param {function} onFilterClear - Function to clear a specific or all filters. (Optional) * Example: onFilterClear={handleClearFilter} where handleClearFilter is a function to clear the applied filters. */ /* INCLUDE: "includes/formats.jsx" */ function localFormat(number) { const formattedNumber = Number(number).toLocaleString('en', { minimumFractionDigits: 0, maximumFractionDigits: 5, }); return formattedNumber; } function dollarFormat(number) { const formattedNumber = Number(number).toLocaleString('en', { minimumFractionDigits: 2, maximumFractionDigits: 2, }); return formattedNumber; } function dollarNonCentFormat(number) { const formattedNumber = Number(number).toLocaleString('en', { minimumFractionDigits: 0, maximumFractionDigits: 0, }); return formattedNumber; } function weight(number) { const suffixes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; let suffixIndex = 0; while (number >= 1000 && suffixIndex < suffixes.length - 1) { number /= 1000; suffixIndex++; } return number.toFixed(2) + ' ' + suffixes[suffixIndex]; } function convertToUTC(timestamp, hour) { const date = new Date(timestamp); // Get UTC date components const utcYear = date.getUTCFullYear(); const utcMonth = ('0' + (date.getUTCMonth() + 1)).slice(-2); // Adding 1 because months are zero-based const utcDay = ('0' + date.getUTCDate()).slice(-2); const utcHours = ('0' + date.getUTCHours()).slice(-2); const utcMinutes = ('0' + date.getUTCMinutes()).slice(-2); const utcSeconds = ('0' + date.getUTCSeconds()).slice(-2); // Array of month abbreviations const monthAbbreviations = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', ]; const monthIndex = Number(utcMonth) - 1; // Format the date as required (Jul-25-2022 16:25:37) let formattedDate = monthAbbreviations[monthIndex] + '-' + utcDay + '-' + utcYear + ' ' + utcHours + ':' + utcMinutes + ':' + utcSeconds; if (hour) { // Convert hours to 12-hour format let hour12 = parseInt(utcHours); const ampm = hour12 >= 12 ? 'PM' : 'AM'; hour12 = hour12 % 12 || 12; // Add AM/PM to the formatted date (Jul-25-2022 4:25:37 PM) formattedDate = monthAbbreviations[monthIndex] + '-' + utcDay + '-' + utcYear + ' ' + hour12 + ':' + utcMinutes + ':' + utcSeconds + ' ' + ampm; } return formattedDate; } function getTimeAgoString(timestamp) { const currentUTC = Date.now(); const date = new Date(timestamp); const seconds = Math.floor((currentUTC - date.getTime()) / 1000); const intervals = { year: seconds / (60 * 60 * 24 * 365), month: seconds / (60 * 60 * 24 * 30), week: seconds / (60 * 60 * 24 * 7), day: seconds / (60 * 60 * 24), hour: seconds / (60 * 60), minute: seconds / 60, }; if (intervals.year == 1) { return Math.ceil(intervals.year) + ' year ago'; } else if (intervals.year > 1) { return Math.ceil(intervals.year) + ' years ago'; } else if (intervals.month > 1) { return Math.ceil(intervals.month) + ' months ago'; } else if (intervals.week > 1) { return Math.ceil(intervals.week) + ' weeks ago'; } else if (intervals.day > 1) { return Math.ceil(intervals.day) + ' days ago'; } else if (intervals.hour > 1) { return Math.ceil(intervals.hour) + ' hours ago'; } else if (intervals.minute > 1) { return Math.ceil(intervals.minute) + ' minutes ago'; } else { return 'a few seconds ago'; } } function formatWithCommas(number) { return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } function formatTimestampToString(timestamp) { const date = new Date(timestamp); // Format the date to 'YYYY-MM-DD HH:mm:ss' format const formattedDate = date.toISOString().replace('T', ' ').split('.')[0]; return formattedDate; } function convertToMetricPrefix(number) { const prefixes = ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']; // Metric prefixes let count = 0; while (Math.abs(number) >= 1000 && count < prefixes.length - 1) { number /= 1000; count++; } // Check if the number is close to an integer value if (Math.abs(number) >= 10) { number = Math.round(number); // Round the number to the nearest whole number return number + ' ' + prefixes[count]; } return ( Number(Math.floor(number * 100) / 100).toFixed(2) + ' ' + prefixes[count] ); } function gasFee(gas, price) { const near = yoctoToNear(Big(gas).mul(Big(price)).toString(), true); return `${near} Ⓝ`; } function currency(number) { let absNumber = Math.abs(number); const suffixes = ['', 'K', 'M', 'B', 'T', 'Q']; let suffixIndex = 0; while (absNumber >= 1000 && suffixIndex < suffixes.length - 1) { absNumber /= 1000; suffixIndex++; } let shortNumber = parseFloat(absNumber.toFixed(2)); return (number < 0 ? '-' : '') + shortNumber + ' ' + suffixes[suffixIndex]; } function formatDate(dateString) { const inputDate = new Date(dateString); const days = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', ]; const months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', ]; const dayOfWeek = days[inputDate.getDay()]; const month = months[inputDate.getMonth()]; const day = inputDate.getDate(); const year = inputDate.getFullYear(); const formattedDate = dayOfWeek + ', ' + month + ' ' + day + ', ' + year; return formattedDate; } function formatCustomDate(inputDate) { var date = new Date(inputDate); // Array of month names var monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', ]; // Get month and day var month = monthNames[date.getMonth()]; var day = date.getDate(); // Create formatted date string in "MMM DD" format var formattedDate = month + ' ' + (day < 10 ? '0' + day : day); return formattedDate; } function shortenHex(address) { return `${address && address.substr(0, 6)}...${address.substr(-4)}`; } function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } function shortenToken(token) { return truncateString(token, 14, ''); } function shortenTokenSymbol(token) { return truncateString(token, 5, ''); } function gasPercentage(gasUsed, gasAttached) { if (!gasAttached) return 'N/A'; const formattedNumber = (Big(gasUsed).div(Big(gasAttached)) * 100).toFixed(2); return `${formattedNumber}%`; } function serialNumber(index, page, perPage) { return index + 1 + (page - 1) * perPage; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function getTimeAgoString(timestamp) { const currentUTC = Date.now(); const date = new Date(timestamp); const seconds = Math.floor((currentUTC - date.getTime()) / 1000); const intervals = { year: seconds / (60 * 60 * 24 * 365), month: seconds / (60 * 60 * 24 * 30), week: seconds / (60 * 60 * 24 * 7), day: seconds / (60 * 60 * 24), hour: seconds / (60 * 60), minute: seconds / 60, }; if (intervals.year == 1) { return Math.ceil(intervals.year) + ' year ago'; } else if (intervals.year > 1) { return Math.ceil(intervals.year) + ' years ago'; } else if (intervals.month > 1) { return Math.ceil(intervals.month) + ' months ago'; } else if (intervals.week > 1) { return Math.ceil(intervals.week) + ' weeks ago'; } else if (intervals.day > 1) { return Math.ceil(intervals.day) + ' days ago'; } else if (intervals.hour > 1) { return Math.ceil(intervals.hour) + ' hours ago'; } else if (intervals.minute > 1) { return Math.ceil(intervals.minute) + ' minutes ago'; } else { return 'a few seconds ago'; } } function formatWithCommas(number) { return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } function formatTimestampToString(timestamp) { const date = new Date(timestamp); // Format the date to 'YYYY-MM-DD HH:mm:ss' format const formattedDate = date.toISOString().replace('T', ' ').split('.')[0]; return formattedDate; } function convertToMetricPrefix(number) { const prefixes = ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']; // Metric prefixes let count = 0; while (Math.abs(number) >= 1000 && count < prefixes.length - 1) { number /= 1000; count++; } // Check if the number is close to an integer value if (Math.abs(number) >= 10) { number = Math.round(number); // Round the number to the nearest whole number return number + ' ' + prefixes[count]; } return ( Number(Math.floor(number * 100) / 100).toFixed(2) + ' ' + prefixes[count] ); } function gasFee(gas, price) { const near = yoctoToNear(Big(gas).mul(Big(price)).toString(), true); return `${near} Ⓝ`; } function currency(number) { let absNumber = Math.abs(number); const suffixes = ['', 'K', 'M', 'B', 'T', 'Q']; let suffixIndex = 0; while (absNumber >= 1000 && suffixIndex < suffixes.length - 1) { absNumber /= 1000; suffixIndex++; } let shortNumber = parseFloat(absNumber.toFixed(2)); return (number < 0 ? '-' : '') + shortNumber + ' ' + suffixes[suffixIndex]; } function formatDate(dateString) { const inputDate = new Date(dateString); const days = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', ]; const months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', ]; const dayOfWeek = days[inputDate.getDay()]; const month = months[inputDate.getMonth()]; const day = inputDate.getDate(); const year = inputDate.getFullYear(); const formattedDate = dayOfWeek + ', ' + month + ' ' + day + ', ' + year; return formattedDate; } function formatCustomDate(inputDate) { var date = new Date(inputDate); // Array of month names var monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', ]; // Get month and day var month = monthNames[date.getMonth()]; var day = date.getDate(); // Create formatted date string in "MMM DD" format var formattedDate = month + ' ' + (day < 10 ? '0' + day : day); return formattedDate; } function shortenHex(address) { return `${address && address.substr(0, 6)}...${address.substr(-4)}`; } function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } function shortenToken(token) { return truncateString(token, 14, ''); } function shortenTokenSymbol(token) { return truncateString(token, 5, ''); } function gasPercentage(gasUsed, gasAttached) { if (!gasAttached) return 'N/A'; const formattedNumber = (Big(gasUsed).div(Big(gasAttached)) * 100).toFixed(2); return `${formattedNumber}%`; } function serialNumber(index, page, perPage) { return index + 1 + (page - 1) * perPage; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function formatTimestampToString(timestamp) { const date = new Date(timestamp); // Format the date to 'YYYY-MM-DD HH:mm:ss' format const formattedDate = date.toISOString().replace('T', ' ').split('.')[0]; return formattedDate; } function convertToMetricPrefix(number) { const prefixes = ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']; // Metric prefixes let count = 0; while (Math.abs(number) >= 1000 && count < prefixes.length - 1) { number /= 1000; count++; } // Check if the number is close to an integer value if (Math.abs(number) >= 10) { number = Math.round(number); // Round the number to the nearest whole number return number + ' ' + prefixes[count]; } return ( Number(Math.floor(number * 100) / 100).toFixed(2) + ' ' + prefixes[count] ); } function gasFee(gas, price) { const near = yoctoToNear(Big(gas).mul(Big(price)).toString(), true); return `${near} Ⓝ`; } function currency(number) { let absNumber = Math.abs(number); const suffixes = ['', 'K', 'M', 'B', 'T', 'Q']; let suffixIndex = 0; while (absNumber >= 1000 && suffixIndex < suffixes.length - 1) { absNumber /= 1000; suffixIndex++; } let shortNumber = parseFloat(absNumber.toFixed(2)); return (number < 0 ? '-' : '') + shortNumber + ' ' + suffixes[suffixIndex]; } function formatDate(dateString) { const inputDate = new Date(dateString); const days = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', ]; const months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', ]; const dayOfWeek = days[inputDate.getDay()]; const month = months[inputDate.getMonth()]; const day = inputDate.getDate(); const year = inputDate.getFullYear(); const formattedDate = dayOfWeek + ', ' + month + ' ' + day + ', ' + year; return formattedDate; } function formatCustomDate(inputDate) { var date = new Date(inputDate); // Array of month names var monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', ]; // Get month and day var month = monthNames[date.getMonth()]; var day = date.getDate(); // Create formatted date string in "MMM DD" format var formattedDate = month + ' ' + (day < 10 ? '0' + day : day); return formattedDate; } function shortenHex(address) { return `${address && address.substr(0, 6)}...${address.substr(-4)}`; } function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } function shortenToken(token) { return truncateString(token, 14, ''); } function shortenTokenSymbol(token) { return truncateString(token, 5, ''); } function gasPercentage(gasUsed, gasAttached) { if (!gasAttached) return 'N/A'; const formattedNumber = (Big(gasUsed).div(Big(gasAttached)) * 100).toFixed(2); return `${formattedNumber}%`; } function serialNumber(index, page, perPage) { return index + 1 + (page - 1) * perPage; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } function shortenToken(token) { return truncateString(token, 14, ''); } function shortenTokenSymbol(token) { return truncateString(token, 5, ''); } function gasPercentage(gasUsed, gasAttached) { if (!gasAttached) return 'N/A'; const formattedNumber = (Big(gasUsed).div(Big(gasAttached)) * 100).toFixed(2); return `${formattedNumber}%`; } function serialNumber(index, page, perPage) { return index + 1 + (page - 1) * perPage; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } /* END_INCLUDE: "includes/formats.jsx" */ /* INCLUDE: "includes/near.jsx" */ function txnMethod(actions) { const count = actions?.length || 0; if (!count) return 'Unknown'; if (count > 1) return 'Batch Transaction'; const action = actions[0]; if (action.action === 'FUNCTION_CALL') { return action.method; } return action.action; } function gasPrice(yacto) { const near = Big(yoctoToNear(yacto, false)).mul(Big(10).pow(12)).toString(); return `${localFormat(near)} Ⓝ / Tgas`; } function tokenAmount(amount, decimal, format) { if (amount === undefined || amount === null) return 'N/A'; const near = Big(amount).div(Big(10).pow(+decimal)); return format ? near.toString().toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: 8, }) : near; } function mapRpcActionToAction(action) { if (action === 'CreateAccount') { return { action_kind: 'CreateAccount', args: {}, }; } if (typeof action === 'object') { const kind = Object.keys(action)[0]; return { action_kind: kind, args: action[kind], }; } return null; } const valueFromObj = (obj) => { const keys = Object.keys(obj); for (let i = 0; i < keys.length; i++) { const key = keys[i]; const value = obj[key]; if (typeof value === 'string') { return value; } if (typeof value === 'object') { const nestedValue = valueFromObj(value ); if (nestedValue) { return nestedValue; } } } return undefined; }; function txnLogs(txn) { let txLogs = []; const outcomes = txn?.receipts_outcome || []; for (let i = 0; i < outcomes.length; i++) { const outcome = outcomes[i]; let logs = outcome?.outcome?.logs || []; if (logs.length > 0) { const mappedLogs = logs.map((log) => ({ contract: outcome?.outcome?.executor_id || '', logs: log, })); txLogs = [...txLogs, ...mappedLogs]; } } return txLogs; } function txnActions(txn) { const txActions = []; const receipts = txn?.receipts || []; for (let i = 0; i < receipts.length; i++) { const receipt = receipts[i]; const from = receipt?.predecessor_id; const to = receipt?.receiver_id; if (Array.isArray(receipt?.receipt)) { const actions = receipt.receipt; for (let j = 0; j < actions.length; j++) { const action = actions[j]; txActions.push({ from, to, ...action }); } } else { const actions = receipt?.receipt?.Action?.actions || []; for (let j = 0; j < actions.length; j++) { const action = mapRpcActionToAction(actions[j]); txActions.push({ from, to, ...action }); } } } return txActions.filter( (action) => action.action_kind !== 'FunctionCall' && action.from !== 'system', ); } function txnErrorMessage(txn) { const kind = txn?.status?.Failure?.ActionError?.kind; if (typeof kind === 'string') return kind; if (typeof kind === 'object') { return valueFromObj(kind); } return null; } function formatLine(line, offset, format) { let result = `${offset.toString(16).padStart(8, '0')} `; const bytes = line.split(' ').filter(Boolean); bytes.forEach((byte, index) => { if (index > 0 && index % 4 === 0) { result += ' '; } result += byte.toUpperCase().padEnd(2, ' ') + ' '; }); if (format === 'default') { result += ` ${String.fromCharCode( ...bytes.map((b) => parseInt(b, 16)), )}`; } return result.trimEnd(); } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function localFormat(number) { const formattedNumber = Number(number).toLocaleString('en', { minimumFractionDigits: 0, maximumFractionDigits: 5, }); return formattedNumber; } function localFormat(number) { const formattedNumber = Number(number).toLocaleString('en', { minimumFractionDigits: 0, maximumFractionDigits: 5, }); return formattedNumber; } function localFormat(number) { const formattedNumber = Number(number).toLocaleString('en', { minimumFractionDigits: 0, maximumFractionDigits: 5, }); return formattedNumber; } function localFormat(number) { const formattedNumber = Number(number).toLocaleString('en', { minimumFractionDigits: 0, maximumFractionDigits: 5, }); return formattedNumber; } function localFormat(number) { const formattedNumber = Number(number).toLocaleString('en', { minimumFractionDigits: 0, maximumFractionDigits: 5, }); return formattedNumber; } function localFormat(number) { const formattedNumber = Number(number).toLocaleString('en', { minimumFractionDigits: 0, maximumFractionDigits: 5, }); return formattedNumber; } /* END_INCLUDE: "includes/near.jsx" */ /* INCLUDE: "includes/libs.jsx" */ function getConfig(network) { switch (network) { case 'mainnet': return { ownerId: 'nearblocks.near', nodeUrl: 'https://rpc.mainnet.near.org', backendUrl: 'https://api3.nearblocks.io/v1/', rpcUrl: 'https://archival-rpc.testnet.near.org', appUrl: 'https://nearblocks.io/', }; case 'testnet': return { ownerId: 'nearblocks.testnet', nodeUrl: 'https://rpc.testnet.near.org', backendUrl: 'https://api3-testnet.nearblocks.io/v1/', rpcUrl: 'https://archival-rpc.testnet.near.org', appUrl: 'https://testnet.nearblocks.io/', }; default: return {}; } } function debounce( delay, func, ) { let timer; let active = true; console.log('hgjhgh'); const debounced = (arg) => { if (active) { clearTimeout(timer); timer = setTimeout(() => { active && func(arg); timer = undefined; }, delay); } else { func(arg); } }; debounced.isPending = () => { return timer !== undefined; }; debounced.cancel = () => { active = false; }; debounced.flush = (arg) => func(arg); return debounced; } function shortenAddress(address) { const string = String(address); if (string.length <= 20) return string; return `${string.substr(0, 10)}...${string.substr(-7)}`; } function nanoToMilli(nano) { return new Big(nano).div(new Big(10).pow(6)).round().toNumber(); } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function getConfig(network) { switch (network) { case 'mainnet': return { ownerId: 'nearblocks.near', nodeUrl: 'https://rpc.mainnet.near.org', backendUrl: 'https://api3.nearblocks.io/v1/', rpcUrl: 'https://archival-rpc.testnet.near.org', appUrl: 'https://nearblocks.io/', }; case 'testnet': return { ownerId: 'nearblocks.testnet', nodeUrl: 'https://rpc.testnet.near.org', backendUrl: 'https://api3-testnet.nearblocks.io/v1/', rpcUrl: 'https://archival-rpc.testnet.near.org', appUrl: 'https://testnet.nearblocks.io/', }; default: return {}; } } function debounce( delay, func, ) { let timer; let active = true; console.log('hgjhgh'); const debounced = (arg) => { if (active) { clearTimeout(timer); timer = setTimeout(() => { active && func(arg); timer = undefined; }, delay); } else { func(arg); } }; debounced.isPending = () => { return timer !== undefined; }; debounced.cancel = () => { active = false; }; debounced.flush = (arg) => func(arg); return debounced; } function shortenAddress(address) { const string = String(address); if (string.length <= 20) return string; return `${string.substr(0, 10)}...${string.substr(-7)}`; } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function getConfig(network) { switch (network) { case 'mainnet': return { ownerId: 'nearblocks.near', nodeUrl: 'https://rpc.mainnet.near.org', backendUrl: 'https://api3.nearblocks.io/v1/', rpcUrl: 'https://archival-rpc.testnet.near.org', appUrl: 'https://nearblocks.io/', }; case 'testnet': return { ownerId: 'nearblocks.testnet', nodeUrl: 'https://rpc.testnet.near.org', backendUrl: 'https://api3-testnet.nearblocks.io/v1/', rpcUrl: 'https://archival-rpc.testnet.near.org', appUrl: 'https://testnet.nearblocks.io/', }; default: return {}; } } function debounce( delay, func, ) { let timer; let active = true; console.log('hgjhgh'); const debounced = (arg) => { if (active) { clearTimeout(timer); timer = setTimeout(() => { active && func(arg); timer = undefined; }, delay); } else { func(arg); } }; debounced.isPending = () => { return timer !== undefined; }; debounced.cancel = () => { active = false; }; debounced.flush = (arg) => func(arg); return debounced; } function shortenAddress(address) { const string = String(address); if (string.length <= 20) return string; return `${string.substr(0, 10)}...${string.substr(-7)}`; } function yoctoToNear(yocto, format) { const YOCTO_PER_NEAR = Big(10).pow(24).toString(); const near = Big(yocto).div(YOCTO_PER_NEAR).toString(); return format ? localFormat(near) : near; } function fiatValue(big, price) { // @ts-ignore const value = Big(big).mul(Big(price)).toString(); const formattedNumber = Number(value).toLocaleString('en', { minimumFractionDigits: 2, maximumFractionDigits: 6, }); return formattedNumber; } function nanoToMilli(nano) { return new Big(nano).div(new Big(10).pow(6)).round().toNumber(); } function truncateString(str, maxLength, suffix) { if (str.length <= maxLength) { return str; } return str.substring(0, maxLength) + suffix; } function getConfig(network) { switch (network) { case 'mainnet': return { ownerId: 'nearblocks.near', nodeUrl: 'https://rpc.mainnet.near.org', backendUrl: 'https://api3.nearblocks.io/v1/', rpcUrl: 'https://archival-rpc.testnet.near.org', appUrl: 'https://nearblocks.io/', }; case 'testnet': return { ownerId: 'nearblocks.testnet', nodeUrl: 'https://rpc.testnet.near.org', backendUrl: 'https://api3-testnet.nearblocks.io/v1/', rpcUrl: 'https://archival-rpc.testnet.near.org', appUrl: 'https://testnet.nearblocks.io/', }; default: return {}; } } function debounce( delay, func, ) { let timer; let active = true; console.log('hgjhgh'); const debounced = (arg) => { if (active) { clearTimeout(timer); timer = setTimeout(() => { active && func(arg); timer = undefined; }, delay); } else { func(arg); } }; debounced.isPending = () => { return timer !== undefined; }; debounced.cancel = () => { active = false; }; debounced.flush = (arg) => func(arg); return debounced; } function shortenAddress(address) { const string = String(address); if (string.length <= 20) return string; return `${string.substr(0, 10)}...${string.substr(-7)}`; } function localFormat(number) { const formattedNumber = Number(number).toLocaleString('en', { minimumFractionDigits: 0, maximumFractionDigits: 5, }); return formattedNumber; } function formatWithCommas(number) { return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); } /* END_INCLUDE: "includes/libs.jsx" */ /* INCLUDE COMPONENT: "includes/icons/FaLongArrowAltRight.jsx" */ const FaLongArrowAltRight = () => { return ( <svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 448 512"> <path d="M313.941 216H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12h301.941v46.059c0 21.382 25.851 32.09 40.971 16.971l86.059-86.059c9.373-9.373 9.373-24.569 0-33.941l-86.059-86.059c-15.119-15.119-40.971-4.411-40.971 16.971V216" fill="#ffffff" /> </svg> ); };/* END_INCLUDE COMPONENT: "includes/icons/FaLongArrowAltRight.jsx" */ /* INCLUDE COMPONENT: "includes/Common/Status.jsx" */ const FaCheckCircle = () => { return ( <svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 512 512"> <path d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z" fill="#50C878" /> </svg> ); }; const FaTimesCircle = () => { return ( <svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 512 512"> <path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm121.6 313.1c4.7 4.7 4.7 12.3 0 17L338 377.6c-4.7 4.7-12.3 4.7-17 0L256 312l-65.1 65.6c-4.7 4.7-12.3 4.7-17 0L134.4 338c-4.7-4.7-4.7-12.3 0-17l65.6-65-65.6-65.1c-4.7-4.7-4.7-12.3 0-17l39.6-39.6c4.7-4.7 12.3-4.7 17 0l65 65.7 65.1-65.6c4.7-4.7 12.3-4.7 17 0l39.6 39.6c4.7 4.7 4.7 12.3 0 17L312 256l65.6 65.1z" fill="#ff0000" /> </svg> ); }; const FaHourglassStart = () => { return ( <svg xmlns="http://www.w3.org/2000/svg" height="1em" viewBox="0 0 384 512"> <path d="M32 0C14.3 0 0 14.3 0 32S14.3 64 32 64V75c0 42.4 16.9 83.1 46.9 113.1L146.7 256 78.9 323.9C48.9 353.9 32 394.6 32 437v11c-17.7 0-32 14.3-32 32s14.3 32 32 32H64 320h32c17.7 0 32-14.3 32-32s-14.3-32-32-32V437c0-42.4-16.9-83.1-46.9-113.1L237.3 256l67.9-67.9c30-30 46.9-70.7 46.9-113.1V64c17.7 0 32-14.3 32-32s-14.3-32-32-32H320 64 32zM288 437v11H96V437c0-25.5 10.1-49.9 28.1-67.9L192 301.3l67.9 67.9c18 18 28.1 42.4 28.1 67.9z" fill="#FFEB3B" /> </svg> ); }; const getOptions = (status) => { switch (status) { case null: return { bg: 'bg-yellow-50', text: 'text-yellow-500', icon: FaHourglassStart, label: 'Pending', }; case false: return { bg: 'bg-red-50', text: 'text-red-500', icon: FaTimesCircle, label: 'Failure', }; default: return { bg: 'bg-emerald-50', text: 'text-emerald-500', icon: FaCheckCircle, label: 'Success', }; } }; const TxnStatus = (props) => { const option = getOptions(props.status); const Icon = option.icon; return ( <div className="w-full md:w-3/4 break-words"> <span className={`inline-flex items-center text-xs rounded py-1 ${ option.bg } ${option.text} ${props.showLabel ? ' px-2' : ' px-1'}`} > <Icon /> {props.showLabel && <span className="ml-2">{option.label}</span>} </span> </div> ); };/* END_INCLUDE COMPONENT: "includes/Common/Status.jsx" */ /* INCLUDE COMPONENT: "includes/Common/Filter.jsx" */ const Filter = (props) => { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width={16} height={16} {...props} > <path fill="none" d="M0 0h24v24H0z" /> <path d="M14 14v6l-4 2v-8L4 5V3h16v2l-6 9zM6.404 5L12 13.394 17.596 5H6.404z" /> </svg> ); };/* END_INCLUDE COMPONENT: "includes/Common/Filter.jsx" */ /* INCLUDE COMPONENT: "includes/icons/SortIcon.jsx" */ const ArrowUp = (props) => { return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width={24} height={24} {...props} > <path fill="none" d="M0 0h24v24H0z" /> <path d="M12 10.828l-4.95 4.95-1.414-1.414L12 8l6.364 6.364-1.414 1.414z" /> </svg> ); }; const SortIcon = (props) => { return ( <ArrowUp className={`h-3 w-3 fill-current transition-transform mr-1 duration-700 ${ props.order !== 'asc' ? 'transform rotate-180' : 'transform rotate-0' }`} /> ); };/* END_INCLUDE COMPONENT: "includes/icons/SortIcon.jsx" */ /* INCLUDE COMPONENT: "includes/Common/Skelton.jsx" */ /** * @interface Props * @param {string} [className] - The CSS class name(s) for styling purposes. */ const Skelton = (props) => { return ( <div className={`bg-gray-200 h-5 rounded shadow-sm animate-pulse ${props.className}`} ></div> ); };/* END_INCLUDE COMPONENT: "includes/Common/Skelton.jsx" */ /* INCLUDE COMPONENT: "includes/icons/CloseCircle.jsx" */ const CloseCircle = (props) => { const handleClick = () => { if (props.onClick) { props.onClick('All'); } }; return ( <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width={24} height={24} className={props.className} onClick={handleClick} > <path fill="none" d="M0 0h24v24H0z" /> <path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 100-16 8 8 0 000 16zm0-9.414l2.828-2.829 1.415 1.415L13.414 12l2.829 2.828-1.415 1.415L12 13.414l-2.828 2.829-1.415-1.415L10.586 12 7.757 9.172l1.415-1.415L12 10.586z" /> </svg> ); };/* END_INCLUDE COMPONENT: "includes/icons/CloseCircle.jsx" */ function MainComponent(props) { const [isLoading, setIsLoading] = useState(false); const [totalCount, setTotalCount] = useState(1); const [txns, setTxns] = useState([]); const [showAge, setShowAge] = useState(true); const [sorting, setSorting] = useState('desc'); const config = getConfig(props.network); const toggleShowAge = () => setShowAge((s) => !s); useEffect(() => { function fetchTotalTxns(qs) { setIsLoading(true); const queryParams = qs ? '?' + qs : ''; asyncFetch(`${config?.backendUrl}txns/count${queryParams}`, { method: 'GET', headers: { 'Content-Type': 'application/json', }, }) .then( (data ) => { const resp = data?.body?.txns?.[0]; setTotalCount(0); setTotalCount(resp?.count); }, ) .catch(() => {}) .finally(() => { setIsLoading(false); }); } function fetchTxnsData(qs, sqs) { setIsLoading(true); const queryParams = qs ? qs + '&' : ''; asyncFetch( `${config?.backendUrl}txns?${queryParams}order=${sqs}&page=${props.currentPage}&per_page=25`, { method: 'GET', headers: { 'Content-Type': 'application/json', }, }, ) .then((data) => { const resp = data?.body?.txns; if (Array.isArray(resp) && resp.length > 0) { setTxns(resp); } }) .catch(() => {}); setIsLoading(false); } let urlString = ''; if (props?.filters && Object.keys(props.filters).length > 0) { urlString = Object.keys(props.filters) .map( (key) => `${encodeURIComponent(key)}=${encodeURIComponent( props?.filters[key], )}`, ) .join('&'); } if (urlString && sorting) { fetchTotalTxns(urlString); fetchTxnsData(urlString, sorting); } else if (urlString) { fetchTotalTxns(urlString); fetchTxnsData(urlString); } else if ( sorting && (!props.filters || Object.keys(props.filters).length === 0) ) { fetchTotalTxns(); fetchTxnsData('', sorting); } }, [config?.backendUrl, props.currentPage, props?.filters, sorting]); let filterValue; const onInputChange = (event) => { filterValue = event.target.value; // Do something with the value if needed }; const onFilter = ( e, name, ) => { e.preventDefault(); props.handleFilter(name, filterValue); }; const onClear = (name) => { if (props.onFilterClear && props.filters) { props.onFilterClear(name); } }; const onOrder = () => { setSorting((state) => (state === 'asc' ? 'desc' : 'asc')); }; const columns = [ { header: '', key: '', cell: (row) => ( <span className="pl-5 pr-2 py-4 whitespace-nowrap text-sm text-gray-500 flex justify-end "> <TxnStatus status={row.outcomes.status} showLabel={false} /> </span> ), }, { header: ( <span className="px-5 py-4 text-left text-xs font-semibold text-nearblue-600 uppercase tracking-wider"> TXN HASH </span> ), key: 'transaction_hash', cell: (row) => ( <span> <Tooltip.Provider> <Tooltip.Root> <Tooltip.Trigger asChild> <span className="truncate max-w-[120px] inline-block align-bottom text-green-500"> <a href={`/txns/${row.transaction_hash}`} className="hover:no-underline" > <a className="text-green-500 font-medium"> {truncateString(row.transaction_hash, 15, '...')} </a> </a> </span> </Tooltip.Trigger> <Tooltip.Content className="h-auto max-w-xs bg-black bg-opacity-90 z-10 text-xs text-white px-3 py-2 break-words" sideOffset={8} place="bottom" > {row.transaction_hash} </Tooltip.Content> </Tooltip.Root> </Tooltip.Provider> </span> ), }, { header: ( <Popover.Root> <Popover.Trigger asChild className="flex items-center px-6 py-4 text-left text-xs font-semibold text-nearblue-600 uppercase tracking-wider focus:outline-none" > <button className="IconButton" aria-label="Update dimensions"> METHOD <Filter className="h-3 w-3 fill-current mr-2" /> </button> </Popover.Trigger> <Popover.Content className="bg-white shadow-lg border rounded-b-lg p-2" sideOffset={5} > <div> <input name="type" value={props?.filters ? props?.filters?.method : ''} onChange={onInputChange} placeholder="Search by method" className="border rounded h-8 mb-2 px-2 text-gray-500 text-xs" /> <div className="flex"> <button type="submit" onClick={(e) => onFilter(e, 'method')} className="flex items-center justify-center flex-1 rounded bg-green-500 h-7 text-white text-xs mr-2" > <Filter className="h-3 w-3 fill-current mr-2" /> Filter </button> <button name="type" type="button" onClick={() => onClear('method')} className="flex-1 rounded bg-gray-300 text-xs h-7" > Clear </button> </div> </div> </Popover.Content> </Popover.Root> ), key: 'actions', cell: (row) => ( <span> <Tooltip.Provider> <Tooltip.Root> <Tooltip.Trigger asChild className="px-5 py-4 whitespace-nowrap text-sm text-gray-500" > <span className="bg-blue-900/10 text-xs text-gray-500 rounded-xl px-2 py-1 max-w-[120px] inline-flex truncate"> <span className="block truncate"> {truncateString(txnMethod(row.actions).trim(), 15, '...')} </span> </span> </Tooltip.Trigger> <Tooltip.Content className="h-auto max-w-xs bg-black bg-opacity-90 z-10 text-xs text-white px-3 py-2 break-words" sideOffset={8} place="bottom" > {txnMethod(row.actions)} </Tooltip.Content> </Tooltip.Root> </Tooltip.Provider> </span> ), }, { header: ( <span className="px-5 py-4 text-left text-xs font-semibold text-nearblue-600 uppercase tracking-wider whitespace-nowrap"> DEPOSIT VALUE </span> ), key: 'deposit', cell: (row) => ( <span className="px-5 py-4 whitespace-nowrap text-sm text-gray-500"> {yoctoToNear(row.actions_agg?.deposit || 0, true)} Ⓝ </span> ), }, { header: ( <span className="px-5 py-4 text-left text-xs font-semibold text-nearblue-600 uppercase tracking-wider whitespace-nowrap"> TXN FEE </span> ), key: 'transaction_fee', cell: (row) => ( <span className="px-6 py-4 whitespace-nowrap text-sm text-gray-500"> {' '} {yoctoToNear(row.outcomes_agg?.transaction_fee || 0, true)} Ⓝ </span> ), }, { header: ( <Popover.Root> <Popover.Trigger asChild className="flex items-center text-left text-xs font-semibold text-nearblue-600 uppercase tracking-wider focus:outline-none" > <button className="IconButton" aria-label="Update dimensions"> FROM <Filter className="h-3 w-3 fill-current mr-2" /> </button> </Popover.Trigger> <Popover.Content className="bg-white shadow-lg border rounded-b-lg p-2" sideOffset={5} > <input name="from" value={props?.filters ? props?.filters?.from : ''} onChange={onInputChange} placeholder={'Search by address e.g. Ⓝ..'} className="border rounded h-8 mb-2 px-2 text-gray-500 text-xs" /> <div className="flex"> <button type="submit" onClick={(e) => onFilter(e, 'from')} className="flex items-center justify-center flex-1 rounded bg-green-500 h-7 text-white text-xs mr-2" > <Filter className="h-3 w-3 fill-current mr-2" /> Filter </button> <button name="from" type="button" onClick={() => onClear('from')} className="flex-1 rounded bg-gray-300 text-xs h-7" > Clear </button> </div> </Popover.Content> </Popover.Root> ), key: 'signer_account_id', cell: (row) => ( <span> <Tooltip.Provider> <Tooltip.Root> <Tooltip.Trigger asChild> <span className="truncate max-w-[120px] inline-block align-bottom text-green-500"> <a href={`/address/${row.signer_account_id}`} className="hover:no-underline" > <a className="text-green-500"> {truncateString(row.signer_account_id, 18, '...')} </a> </a> </span> </Tooltip.Trigger> <Tooltip.Content className="h-auto max-w-xs bg-black bg-opacity-90 z-10 text-xs text-white px-3 py-2 break-words" sideOffset={8} place="bottom" > {row.signer_account_id} </Tooltip.Content> </Tooltip.Root> </Tooltip.Provider> </span> ), }, { header: '', key: '', cell: () => ( <div className="w-5 h-5 p-1 bg-green-100 rounded-full text-center flex justify-center items-center mx-auto text-white"> <FaLongArrowAltRight /> </div> ), }, { header: ( <Popover.Root> <Popover.Trigger asChild className="flex items-center text-left text-xs font-semibold text-nearblue-600 uppercase tracking-wider focus:outline-none" > <button className="IconButton" aria-label="Update dimensions"> To <Filter className="h-3 w-3 fill-current mr-2" /> </button> </Popover.Trigger> <Popover.Content className="bg-white shadow-lg border rounded-b-lg p-2" sideOffset={5} > <input name="to" value={props?.filters ? props?.filters?.to : ''} onChange={onInputChange} placeholder={'Search by address e.g. Ⓝ..'} className="border rounded h-8 mb-2 px-2 text-gray-500 text-xs" /> <div className="flex"> <button type="submit" onClick={(e) => onFilter(e, 'to')} className="flex items-center justify-center flex-1 rounded bg-green-500 h-7 text-white text-xs mr-2" > <Filter className="h-3 w-3 fill-current mr-2" /> Filter </button> <button name="to" type="button" onClick={() => onClear('to')} className="flex-1 rounded bg-gray-300 text-xs h-7" > Clear </button> </div> </Popover.Content> </Popover.Root> ), key: 'receiver_account_id', cell: (row) => ( <span> <Tooltip.Provider> <Tooltip.Root> <Tooltip.Trigger asChild> <span className="truncate max-w-[120px] inline-block align-bottom text-green-500"> <a href={`/address/${row.receiver_account_id}`} className="hover:no-underline" > <a className="text-green-500"> {truncateString(row.receiver_account_id, 17, '...')} </a> </a> </span> </Tooltip.Trigger> <Tooltip.Content className="h-auto max-w-xs bg-black bg-opacity-90 z-10 text-xs text-white px-3 py-2 break-words" sideOffset={8} place="bottom" > {row.receiver_account_id} </Tooltip.Content> </Tooltip.Root> </Tooltip.Provider> </span> ), }, { header: ( <span className="px-5 py-4 text-left text-xs font-semibold text-nearblue-600 uppercase tracking-wider whitespace-nowrap"> BLOCK HEIGHT </span> ), key: 'block_height', cell: (row) => ( <span className="px-5 py-4 whitespace-nowrap text-sm text-gray-500 font-medium"> <a href={`/blocks/${row.included_in_block_hash}`} className="hover:no-underline" > <a className="text-green-500"> {localFormat(row.block?.block_height)} </a> </a> </span> ), }, { header: ( <span className="inline-flex"> <div className="w-full inline-flex px-5 py-4"> <button type="button" onClick={toggleShowAge} className="text-left text-xs w-full font-semibold uppercase tracking-wider text-nearblue-600 focus:outline-none whitespace-nowrap" > {showAge ? 'AGE' : 'DATE TIME (UTC)'} </button> <button type="button" onClick={onOrder} className="px-2"> <div className="text-gray-500 font-semibold"> <SortIcon order={sorting} /> </div> </button> </div> </span> ), key: 'block_timestamp', cell: (row) => ( <span className="px-5 py-4 whitespace-nowrap text-sm text-gray-500"> <Tooltip.Provider> <Tooltip.Root> <Tooltip.Trigger asChild> <span> {!showAge ? formatTimestampToString( nanoToMilli(Number(row.block_timestamp || 0)), ) : getTimeAgoString( nanoToMilli(Number(row.block_timestamp || 0)), )} </span> </Tooltip.Trigger> <Tooltip.Content className="h-auto max-w-xs bg-black bg-opacity-90 z-10 text-xs text-white px-3 py-2 break-words" sideOffset={8} place="bottom" > {showAge ? formatTimestampToString( nanoToMilli(Number(row.block_timestamp || 0)), ) : getTimeAgoString( nanoToMilli(Number(row.block_timestamp || 0)), )} </Tooltip.Content> </Tooltip.Root> </Tooltip.Provider> </span> ), }, ]; return ( <div> <div className="bg-hero-pattern h-72"> <div className="container mx-auto px-3"> <h1 className="mb-4 pt-8 sm:sm:text-2xl text-xl text-white"> Latest Near Protocol transactions </h1> </div> </div> <div className="container mx-auto px-3 -mt-48"> <div className="block lg:flex lg:space-x-2"> <div className="w-full"> <div className="bg-white border soft-shadow rounded-lg overflow-hidden"> {isLoading ? ( <Skelton /> ) : ( <div className={`flex flex-col lg:flex-row pt-4`}> <div className="flex flex-col"> <p className="leading-7 pl-6 text-sm mb-4 text-gray-500"> {`More than > ${totalCount} transactions found`} </p> </div> {props?.filters && Object.keys(props?.filters).length > 0 && ( <div className="flex items-center px-2 text-sm mb-4 text-gray-500 lg:ml-auto"> Filtered By: <span className="flex items-center bg-gray-100 rounded-full px-3 py-1 ml-1 space-x-2"> {props?.filters && Object.keys(props?.filters).map((key) => ( <span className="flex" key={key}> {capitalizeFirstLetter(key)}:{' '} <span className="inline-block truncate max-w-[120px]"> <span className="font-semibold"> {props?.filters[key]} </span> </span> </span> ))} <CloseCircle className="w-4 h-4 fill-current cursor-pointer" onClick={onClear} /> </span> </div> )} </div> )} { <Widget src={`${config.ownerId}/widget/bos-components.components.Shared.Table`} props={{ columns: columns, data: txns, isLoading: isLoading, isPagination: true, count: totalCount, page: props.currentPage, limit: 25, pageLimit: 200, setPage: props.setPage, }} /> } </div> </div> </div> </div> </div> ); } return MainComponent(props, context);