diff --git a/packages/insight/src/components/data-box.tsx b/packages/insight/src/components/data-box.tsx
index eec3695db14..3ff608ae97e 100644
--- a/packages/insight/src/components/data-box.tsx
+++ b/packages/insight/src/components/data-box.tsx
@@ -1,29 +1,41 @@
-import {Children, FC, ReactNode} from 'react';
-import {useTheme} from 'styled-components';
+import {CSSProperties, FC, ReactNode} from 'react';
+import styled from 'styled-components';
+
+const DataBox: FC<{
+ children: ReactNode,
+ label?: string,
+ style?: CSSProperties,
+ centerLabel?: boolean,
+ colorDark?: string,
+ colorLight?: string}> = ({children, label, style, centerLabel, colorDark='#5f5f5f', colorLight='#ccc'}) => {
+
+ const DataBoxFieldset = styled.fieldset`
+ border: 2.5px solid ${({theme: {dark}}) => dark ? colorDark : colorLight};
+ border-radius: 5px;
+ padding: 0.1rem 0.4rem;
+ word-break: break-all;
+ white-space: normal;
+ width: fit-content;
+ height: fit-content;
+ margin: 0.7rem 0.2rem;
+ `;
-const DataBox: FC<{children: ReactNode, label: string, style?: object}> = ({children, label, style}) => {
- const theme = useTheme();
- const modifiedChildren = typeof children === 'object'
- ? Children.map(children as JSX.Element, (child: JSX.Element) => {
- return
;
- })
- : children;
-
return (
-
+
+ { label &&
+
+ }
+ {children}
+
);
}
diff --git a/packages/insight/src/components/dropdown.tsx b/packages/insight/src/components/dropdown.tsx
new file mode 100644
index 00000000000..7bc68250003
--- /dev/null
+++ b/packages/insight/src/components/dropdown.tsx
@@ -0,0 +1,51 @@
+import { FC, CSSProperties } from 'react';
+import ArrowDown from '../assets/images/arrow-down.svg';
+import ArrowDownBlack from '../assets/images/arrow-down-black.svg';
+import { useTheme } from 'styled-components';
+
+const Dropdown: FC<{
+ options: string[],
+ value?: string,
+ onChange?: (value: string) => void,
+ style?: CSSProperties
+}> = ({options, value, onChange, style}) => {
+ const theme = useTheme();
+ return (
+
+
+

+
+ );
+}
+
+export default Dropdown;
\ No newline at end of file
diff --git a/packages/insight/src/components/info-card.tsx b/packages/insight/src/components/info-card.tsx
new file mode 100644
index 00000000000..e99bc4f9f22
--- /dev/null
+++ b/packages/insight/src/components/info-card.tsx
@@ -0,0 +1,45 @@
+import { FC } from 'react';
+import CopyText from './copy-text';
+import styled from 'styled-components';
+
+
+type InfoCardType = {
+ data: Array<{label: string, value: any, copyText?: boolean}>,
+};
+
+const Card = styled.div`
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ background-color: ${({theme: {dark}}) => dark ? '#222' : '#fff'};
+ padding: 14px;
+ border-radius: 8px;
+`;
+
+const Label = styled.span`
+ color: ${({theme: {dark}}) => dark ? '#888' : '#474d53'};
+ align-self: flex-start;
+ line-height: 1.6;
+ margin-bottom: -2;
+ font-size: 18px;
+`;
+
+const InfoCard: FC
= ({data}) => {
+ return (
+
+ {data.map((d, index) => {
+ const { label, value, copyText } = d;
+ return (<>
+
+
+ {value}
+ {copyText && }
+
+ { index !== data.length - 1 &&
}
+ >);
+ })}
+
+ );
+}
+
+export default InfoCard;
\ No newline at end of file
diff --git a/packages/insight/src/components/transaction-details.tsx b/packages/insight/src/components/transaction-details.tsx
index d970727d981..2719a87d530 100644
--- a/packages/insight/src/components/transaction-details.tsx
+++ b/packages/insight/src/components/transaction-details.tsx
@@ -204,27 +204,21 @@ const TransactionDetails: FC = ({
-
-
- goToTx(item.mintTxid, undefined, item.mintIndex)
- }>
- {item.mintTxid}
-
-
+
+ goToTx(item.mintTxid, undefined, item.mintIndex)
+ }>
+ {item.mintTxid}
+
-
- {item.mintIndex}
-
+ {item.mintIndex}
{item.uiConfirmations && confirmations > 0 ? (
-
- {item.uiConfirmations + confirmations}
-
+ {item.uiConfirmations + confirmations}
) : null}
diff --git a/packages/insight/src/pages/blocks.tsx b/packages/insight/src/pages/blocks.tsx
index fb3f0ba21c9..d5a27ecade4 100644
--- a/packages/insight/src/pages/blocks.tsx
+++ b/packages/insight/src/pages/blocks.tsx
@@ -1,188 +1,79 @@
-import React, {useEffect, useState} from 'react';
-import {MainTitle} from '../assets/styles/titles';
-import {fetcher} from '../api/api';
-import InfiniteScroll from 'react-infinite-scroll-component';
-
-import InfiniteScrollLoadSpinner from '../components/infinite-scroll-load-spinner';
-import Info from '../components/info';
-import SupCurrencyLogo from '../components/icons/sup-currency-logo';
-
-import {getApiRoot, getFormattedDate, normalizeParams, sleep} from '../utilities/helper-methods';
-import {BlocksType} from '../utilities/models';
-import {size} from '../utilities/constants';
-
-import styled from 'styled-components';
-import {motion} from 'framer-motion';
-import {routerFadeIn} from '../utilities/animations';
-import {useParams, useNavigate} from 'react-router-dom';
-import {useAppDispatch} from '../utilities/hooks';
-import {changeCurrency, changeNetwork} from '../store/app.actions';
-import {LightBlack, NeutralSlate, Slate30} from '../assets/styles/colors';
+import BlockList from 'src/components/block-list';
+import React, {createContext, useContext, useEffect, useState} from 'react';
+import ChainHeader from '../components/chain-header';
+import {useParams} from 'react-router-dom';
+import {useDispatch} from 'react-redux';
+import {changeCurrency, changeNetwork} from 'src/store/app.actions';
+import {getApiRoot, normalizeParams} from 'src/utilities/helper-methods';
+import {fetcher} from 'src/api/api';
import nProgress from 'nprogress';
+import {BitcoinBlockType} from 'src/utilities/models';
+import Info from 'src/components/info';
-const BlockListTable = styled.table`
- width: 100%;
- border-collapse: collapse;
- overflow-x: hidden;
-`;
-
-const BlockListTableHead = styled.tr`
- text-align: center;
- line-height: 45px;
- background-color: ${({theme: {dark}}) => (dark ? '#090909' : NeutralSlate)};
- font-size: 16px;
-
- @media screen and (max-width: ${size.tablet}) {
- font-size: 14px;
- line-height: 30px;
- }
-`;
-
-const BlockListTableRow = styled(motion.tr)`
- text-align: center;
- line-height: 45px;
-
- &:nth-child(odd) {
- background-color: ${({theme: {dark}}) => (dark ? LightBlack : Slate30)};
- }
-
- &:nth-child(even) {
- background-color: ${({theme: {dark}}) => (dark ? '#090909' : NeutralSlate)};
- }
-
- transition: transform 200ms ease, box-shadow 200ms ease;
- font-size: 16px;
-
- @media screen and (max-width: ${size.tablet}) {
- font-size: 14px;
- line-height: 30px;
- }
-`;
+type BlocksContextType = {
+ blocks: BitcoinBlockType[] | undefined;
+ setBlocks: React.Dispatch>;
+};
-const TdLink = styled.td`
- color: ${({theme: {colors}}) => colors.link};
-`;
+const BlocksContext = createContext(undefined);
-const getBlocksUrl = (currency: string, network: string) => {
- return `${getApiRoot(currency)}/${currency}/${network}/block?limit=200`;
+export const BlocksProvider: React.FC<{children: React.ReactNode}> = ({ children }) => {
+ const [blocks, setBlocks] = useState();
+ return (
+
+ {children}
+
+ );
};
-const listAnime = {
- whileHover: {
- cursor: 'pointer',
- scale: 1.02,
- transition: {
- bounce: 0,
- duration: 0.05,
- ease: 'linear',
- },
- },
+export const useBlocks = () => {
+ const ctx = useContext(BlocksContext);
+ if (!ctx) throw new Error('useBlocks must be used within a BlocksProvider');
+ return ctx;
};
const Blocks: React.FC = () => {
let {currency, network} = useParams<{currency: string; network: string}>();
- const dispatch = useAppDispatch();
- const navigate = useNavigate();
- const [isLoading, setIsLoading] = useState(true);
- const [blocksList, setBlocksList] = useState();
+ const dispatch = useDispatch();
+
+ const { blocks, setBlocks } = useBlocks();
const [error, setError] = useState('');
- const [hasMore, setHasMore] = useState(true);
useEffect(() => {
- if (!currency || !network) return;
nProgress.start();
- const _normalizeParams = normalizeParams(currency, network);
- currency = _normalizeParams.currency;
- network = _normalizeParams.network;
-
- dispatch(changeCurrency(currency));
- dispatch(changeNetwork(network));
-
- Promise.all([fetcher(getBlocksUrl(currency, network)), sleep(500)])
+ if (!currency || !network)
+ return;
+ Promise.all([fetcher(`${getApiRoot(currency)}/${currency}/${network}/block?limit=200`)])
.then(([data]) => {
- setBlocksList(data);
+ setBlocks(data);
})
.catch((e: any) => {
setError(e.message || 'Something went wrong. Please try again later.');
})
.finally(() => {
- setIsLoading(false);
nProgress.done();
});
- }, [currency, network]);
+ }, []);
- const fetchMore = async (_blocksList: BlocksType[]) => {
- if (!_blocksList.length || !currency || !network) return;
- const since = _blocksList[_blocksList.length - 1].height;
- try {
- const newData: [BlocksType] = await fetcher(
- `${getBlocksUrl(currency, network)}&since=${since}&paging=height&direction=-1`,
- );
- if (newData?.length) {
- setBlocksList(_blocksList.concat(newData));
- } else {
- setHasMore(false);
- }
- } catch (e: any) {
- setError(e.message || 'Something went wrong. Please try again later.');
- }
- };
+ useEffect(() => {
+ if (!currency || !network) return;
+ const _normalizeParams = normalizeParams(currency, network);
+ currency = _normalizeParams.currency;
+ network = _normalizeParams.network;
+
+ dispatch(changeCurrency(currency));
+ dispatch(changeNetwork(network));
+ }, [currency, network]);
- const gotoSingleBlockDetailsView = async (hash: string) => {
- await navigate(`/${currency}/${network}/block/${hash}`);
- };
+ if (!currency || !network) return null;
return (
<>
- {!isLoading ? (
- <>
- {error ? : null}
- {blocksList?.length ? (
-
-
- Blocks
- {currency && }
-
-
- fetchMore(blocksList)}
- hasMore={hasMore}
- loader={}
- dataLength={blocksList.length}>
-
-
-
- Height |
- Timestamp |
- Transactions |
- Size |
-
-
-
- {blocksList.map((block: BlocksType, index: number) => {
- const {height, hash, transactionCount, time, size} = block;
- return (
- gotoSingleBlockDetailsView(hash)}>
- {height}
- {getFormattedDate(time)} |
- {transactionCount} |
- {size} |
-
- );
- })}
-
-
-
-
- ) : null}
- >
- ) : null}
+ {error ? : null}
+
+ { blocks && }
>
);
-};
+}
-export default Blocks;
+export default Blocks;
\ No newline at end of file
diff --git a/packages/insight/src/pages/index.tsx b/packages/insight/src/pages/index.tsx
index f24f49be01b..072433425be 100644
--- a/packages/insight/src/pages/index.tsx
+++ b/packages/insight/src/pages/index.tsx
@@ -1,5 +1,4 @@
import {SUPPORTED_CURRENCIES} from '../utilities/constants';
-import {SecondaryTitle} from '../assets/styles/titles';
import CurrencyTile from '../components/currency-tile';
import Masonry from 'react-masonry-css';
import {motion} from 'framer-motion';
@@ -24,8 +23,6 @@ const Home: React.FC = () => {
return (
- Latest Blocks
-
{
switch (currency.toUpperCase()) {
case 'BTC':
- default:
return BitcoreLib;
case 'BCH':
return BitcoreLibCash;
@@ -180,11 +179,70 @@ export const getLib = (currency: string) => {
return BitcoreLibDoge;
case 'LTC':
return BitcoreLibLtc;
+ default:
+ return BitcoreLib;
}
};
+export const getName = (currency: string) => {
+ switch (currency.toUpperCase()) {
+ case 'BTC':
+ return 'Bitcoin';
+ case 'BCH':
+ return 'Bitcoin Cash';
+ case 'DOGE':
+ return 'Doge';
+ case 'LTC':
+ return 'Litecoin';
+ case 'ETH':
+ return 'Ethereum';
+ default:
+ return 'Bitcoin';
+ }
+}
+
export const getDifficultyFromBits = (bits: number) => {
const maxBody = Math.log(0x00ffff);
const scaland = Math.log(256);
return Math.exp(maxBody - Math.log(bits & 0x00ffffff) + scaland * (0x1d - ((bits & 0xff000000) >> 24)));
+}
+
+/**
+ * Merges the source object into the destination object.
+ * For each property in the source object:
+ * It sets the destination object property to the source property unless
+ * both properties are object and the destination object property is not an array.
+ *
+ * @param object destination object
+ * @param source source object
+ */
+export const merge = (dest: TDest, src: TSrc): TDest & TSrc => {
+ for (const key in src) {
+ const destProp = dest !== undefined ? (dest as any)[key] : undefined;
+ const srcProp = src[key];
+ let result;
+ if (srcProp instanceof Object && destProp instanceof Object && !Array.isArray(destProp)) {
+ result = merge(destProp, srcProp);
+ } else {
+ result = srcProp;
+ }
+ (dest as any)[key] = result;
+ }
+ return dest as TDest & TSrc;
+}
+export default merge;
+
+export const darkenHexColor = (hex: string, amount: number) => {
+ hex = hex.replace(/^#/, '');
+
+ let r = parseInt(hex.substring(0, 2), 16);
+ let g = parseInt(hex.substring(2, 4), 16);
+ let b = parseInt(hex.substring(4, 6), 16);
+
+ r = Math.max(0, r - amount);
+ g = Math.max(0, g - amount);
+ b = Math.max(0, b - amount);
+
+ const toHex = (v: number) => v.toString(16).padStart(2, '0');
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
\ No newline at end of file
diff --git a/packages/insight/src/utilities/models.ts b/packages/insight/src/utilities/models.ts
index 2128c1fd3e1..cddc781fffc 100644
--- a/packages/insight/src/utilities/models.ts
+++ b/packages/insight/src/utilities/models.ts
@@ -109,3 +109,20 @@ export interface BlocksType {
size: number;
hash: string;
}
+
+export type BitcoinBlockType = BlocksType & {
+ merkleRoot: string,
+ bits: number,
+ nonce: number,
+ reward: number,
+ version: number,
+ confirmations: number,
+ feeData: FeeData;
+};
+
+export type FeeData = {
+ feeTotal: number;
+ mean: number;
+ median: number;
+ mode: number;
+}