├── lib └── graphql │ ├── index.ts │ ├── apolloClient.ts │ └── queries.graphql ├── hero.png ├── img ├── demo.png ├── menu.png ├── badge.png ├── astra-home.png ├── astra-login.png ├── cql-console.png ├── astra-create.png ├── gql-gettokens.png ├── astra-graphql-1.png ├── astra-graphql-2.png ├── astra-graphql-3.png ├── astra-graphql-4.png ├── astra-block-request.png ├── astra-initializing.png ├── gql-documentation.png ├── gql-list-keyspaces.png ├── astra-block-request-1.png ├── astra-block-request-2.png └── astra-block-request-3.png ├── slides └── slides.pdf ├── public ├── favicon.ico ├── favicon.png ├── robots.txt ├── sitemap.xml └── sitemap-0.xml ├── next.config.js ├── utils ├── createEmotionCache.ts ├── sessionStorage.ts ├── sitemapUtils.ts └── api.ts ├── pages ├── 404.tsx ├── api │ ├── status.ts │ ├── getLatestBlockGroup.ts │ ├── getDashboardAnalytics.ts │ ├── getDashboardAnalyticsHeader.ts │ ├── getNextBlock.ts │ ├── getPreviousBlock.ts │ ├── getLatestTransactionsList.ts │ ├── getLatestBlocksList.ts │ ├── getLatestEthBlock.ts │ ├── getInternalTransactionsByBlock.ts │ ├── getPaginatedBlocks.ts │ ├── getTransactionsSitemap.ts │ ├── getPaginatedTransactions.ts │ └── getBlocksSitemap.ts ├── index.tsx ├── server-sitemap-index.xml.tsx ├── blocks-sitemap-index.xml.tsx ├── server-sitemaps │ ├── blocks │ │ └── [startingBlock].tsx │ └── transactions │ │ └── [timestamp].tsx ├── _app.tsx ├── transactions-sitemap-index.xml.tsx ├── _document.tsx ├── block │ └── [block].tsx ├── internal-transactions │ └── index.tsx └── blocks.tsx ├── constants ├── routes.ts ├── index.ts └── stubs.tsx ├── next-env.d.ts ├── components ├── shared │ ├── 404 │ │ ├── styles.ts │ │ └── index.tsx │ ├── Tabs │ │ ├── CustomTabs │ │ │ ├── styles.ts │ │ │ └── index.tsx │ │ └── CustomTabsPanel │ │ │ └── index.tsx │ ├── CopyClipboard │ │ ├── styles.ts │ │ └── CopyClipboard.tsx │ ├── Chart │ │ ├── styles.ts │ │ └── index.tsx │ ├── Pagination │ │ ├── BottomPagination │ │ │ ├── styles.ts │ │ │ └── index.tsx │ │ └── UpperPagination │ │ │ ├── styles.ts │ │ │ └── index.tsx │ ├── SplitButton │ │ ├── styles.ts │ │ └── index.tsx │ ├── Chip │ │ ├── styles.ts │ │ └── index.tsx │ ├── CustomSkeleton │ │ └── index.tsx │ ├── Hero │ │ ├── styles.ts │ │ └── index.tsx │ ├── Footer │ │ ├── index.tsx │ │ └── styles.ts │ ├── HTMLParser │ │ └── index.tsx │ ├── DataBox │ │ ├── styles.ts │ │ └── index.tsx │ ├── PaginationButton │ │ ├── styles.ts │ │ └── index.tsx │ ├── Search │ │ ├── styles.ts │ │ └── index.tsx │ ├── Header │ │ ├── styles.ts │ │ └── index.tsx │ └── Logo │ │ └── index.tsx ├── TransactionDetail │ ├── TransactionDetailRow │ │ └── styles.ts │ ├── TransactionLogs │ │ ├── DecodeRow │ │ │ ├── styles.ts │ │ │ └── index.tsx │ │ ├── DecodedData │ │ │ └── index.tsx │ │ └── styles.ts │ ├── TransactionHero │ │ ├── DropdownButton │ │ │ ├── styles.ts │ │ │ └── index.tsx │ │ └── PaginationButton │ │ │ ├── styles.ts │ │ │ └── index.tsx │ ├── styles.ts │ └── index.tsx ├── Home │ ├── Hero │ │ ├── index.tsx │ │ └── styles.ts │ ├── LatestData │ │ ├── styles.ts │ │ └── index.tsx │ ├── SummaryBlock │ │ ├── styles.ts │ │ └── index.tsx │ ├── Graph │ │ ├── styles.ts │ │ └── index.tsx │ ├── TransactionsList │ │ ├── styles.ts │ │ └── index.tsx │ ├── BlocksList │ │ ├── styles.ts │ │ └── index.tsx │ └── SummaryBlocks │ │ ├── styles.tsx │ │ └── index.tsx ├── Layout │ ├── styles.ts │ └── index.tsx ├── InternalTxnsTab │ ├── index.tsx │ └── Table │ │ ├── styles.ts │ │ └── index.tsx ├── InternalTransactions │ ├── styles.ts │ └── index.tsx ├── Blocks │ └── Table │ │ └── styles.ts ├── Transactions │ └── Table │ │ └── styles.ts └── BlocksDetail │ ├── styles.ts │ ├── index.tsx │ └── BlockDetailRow │ └── index.tsx ├── styles ├── globals.css └── ThemeProvider │ ├── colors.ts │ └── theme.ts ├── .gitignore ├── astra.json ├── next-sitemap.config.js ├── codegen.ts ├── .gitpod.yml ├── tsconfig.json ├── package.json └── types └── index.ts /lib/graphql/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Client } from './apolloClient'; 2 | -------------------------------------------------------------------------------- /hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/hero.png -------------------------------------------------------------------------------- /img/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/demo.png -------------------------------------------------------------------------------- /img/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/menu.png -------------------------------------------------------------------------------- /img/badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/badge.png -------------------------------------------------------------------------------- /slides/slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/slides/slides.pdf -------------------------------------------------------------------------------- /img/astra-home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/astra-home.png -------------------------------------------------------------------------------- /img/astra-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/astra-login.png -------------------------------------------------------------------------------- /img/cql-console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/cql-console.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/public/favicon.ico -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/public/favicon.png -------------------------------------------------------------------------------- /img/astra-create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/astra-create.png -------------------------------------------------------------------------------- /img/gql-gettokens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/gql-gettokens.png -------------------------------------------------------------------------------- /img/astra-graphql-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/astra-graphql-1.png -------------------------------------------------------------------------------- /img/astra-graphql-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/astra-graphql-2.png -------------------------------------------------------------------------------- /img/astra-graphql-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/astra-graphql-3.png -------------------------------------------------------------------------------- /img/astra-graphql-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/astra-graphql-4.png -------------------------------------------------------------------------------- /img/astra-block-request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/astra-block-request.png -------------------------------------------------------------------------------- /img/astra-initializing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/astra-initializing.png -------------------------------------------------------------------------------- /img/gql-documentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/gql-documentation.png -------------------------------------------------------------------------------- /img/gql-list-keyspaces.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/gql-list-keyspaces.png -------------------------------------------------------------------------------- /img/astra-block-request-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/astra-block-request-1.png -------------------------------------------------------------------------------- /img/astra-block-request-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/astra-block-request-2.png -------------------------------------------------------------------------------- /img/astra-block-request-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-astra-block/main/img/astra-block-request-3.png -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | trailingSlash: true, 5 | }; 6 | 7 | module.exports = nextConfig; 8 | -------------------------------------------------------------------------------- /utils/createEmotionCache.ts: -------------------------------------------------------------------------------- 1 | import createCache from '@emotion/cache'; 2 | const createEmotionCache = () => { 3 | return createCache({ key: 'css' }); 4 | }; 5 | export default createEmotionCache; 6 | -------------------------------------------------------------------------------- /pages/404.tsx: -------------------------------------------------------------------------------- 1 | import NotFoundPage from '@components/shared/404'; 2 | import React from 'react'; 3 | 4 | const NotFound = () => { 5 | return ; 6 | }; 7 | 8 | export default NotFound; 9 | -------------------------------------------------------------------------------- /constants/routes.ts: -------------------------------------------------------------------------------- 1 | const ROUTES = [ 2 | { 3 | name: 'Blocks', 4 | link: '/blocks', 5 | }, 6 | { 7 | name: 'Transactions', 8 | link: '/transactions', 9 | }, 10 | ]; 11 | 12 | export { ROUTES }; 13 | -------------------------------------------------------------------------------- /next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /components/shared/Tabs/CustomTabs/styles.ts: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/system'; 2 | import colors from '@styles/ThemeProvider/colors'; 3 | import { Tab } from '@mui/material'; 4 | 5 | export const CustomTab = styled(Tab)({ 6 | color: colors.neutral100, 7 | }); 8 | -------------------------------------------------------------------------------- /components/shared/CopyClipboard/styles.ts: -------------------------------------------------------------------------------- 1 | import { Box } from '@mui/material'; 2 | import { styled } from '@mui/system'; 3 | 4 | const Button = styled(Box)({ 5 | minWidth: 'fit-content', 6 | marginRight: '6.67px', 7 | display: 'flex', 8 | }); 9 | 10 | export { Button }; 11 | -------------------------------------------------------------------------------- /components/shared/Chart/styles.ts: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/system'; 2 | import { Box } from '@mui/material'; 3 | 4 | const Container = styled(Box)({ 5 | marginTop: '16px', 6 | padding: 0, 7 | marginRight: 0, 8 | width: '100%', 9 | height: '191px', 10 | }); 11 | export { Container }; 12 | -------------------------------------------------------------------------------- /pages/api/status.ts: -------------------------------------------------------------------------------- 1 | import type { NextApiRequest, NextApiResponse } from 'next'; 2 | 3 | type Data = { 4 | status: string; 5 | }; 6 | 7 | export default function handler( 8 | req: NextApiRequest, 9 | res: NextApiResponse 10 | ) { 11 | res.status(200).json({ status: 'Live' }); 12 | } 13 | -------------------------------------------------------------------------------- /components/TransactionDetail/TransactionDetailRow/styles.ts: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/system'; 2 | import colors from '@styles/ThemeProvider/colors'; 3 | 4 | const BlockEffect = styled('div')({ 5 | cursor: 'pointer', 6 | color: colors.actionSecondary, 7 | }); 8 | 9 | export { BlockEffect }; 10 | -------------------------------------------------------------------------------- /styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: Roboto; 6 | background: linear-gradient(180deg, #121212 100%, #1d2025 100%); 7 | } 8 | 9 | a { 10 | color: inherit; 11 | text-decoration: none; 12 | } 13 | 14 | * { 15 | box-sizing: border-box; 16 | } 17 | -------------------------------------------------------------------------------- /components/shared/404/styles.ts: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/system'; 2 | import { Box } from '@mui/material'; 3 | 4 | const Container = styled(Box)({ 5 | color: 'white', 6 | display: 'flex', 7 | justifyContent: 'center', 8 | alignItems: 'center', 9 | height: '68vh', 10 | }); 11 | export { Container }; 12 | -------------------------------------------------------------------------------- /components/shared/404/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Container } from './styles'; 3 | const NotFoundPage = () => { 4 | return ( 5 |
6 | 7 |

No Results Found!

8 |
9 |
10 | ); 11 | }; 12 | 13 | export default NotFoundPage; 14 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # * 2 | User-agent: * 3 | Allow: / 4 | 5 | # Host 6 | Host: https://eth-explorer.datastax.com 7 | 8 | # Sitemaps 9 | Sitemap: https://eth-explorer.datastax.com/sitemap.xml 10 | Sitemap: https://eth-explorer.datastax.com/blocks-sitemap-index.xml 11 | Sitemap: https://eth-explorer.datastax.com/transactions-sitemap-index.xml 12 | -------------------------------------------------------------------------------- /components/Home/Hero/index.tsx: -------------------------------------------------------------------------------- 1 | import Search from '@components/shared/Search'; 2 | import { SearchContainer, TitleText } from './styles'; 3 | 4 | const Hero = () => { 5 | return ( 6 | <> 7 | Real-time Blockchain Data 8 | 9 | 10 | 11 | 12 | ); 13 | }; 14 | 15 | export default Hero; 16 | -------------------------------------------------------------------------------- /components/shared/Pagination/BottomPagination/styles.ts: -------------------------------------------------------------------------------- 1 | import { Box, styled } from '@mui/material'; 2 | 3 | const FontStyling = styled(Box)({ 4 | fontWeight: '500', 5 | fontSize: '14px', 6 | lineHeight: '24px', 7 | }); 8 | 9 | const Records = styled(Box)({ 10 | padding: '20px', 11 | paddingLeft: '0px', 12 | paddingRight: '0px', 13 | }); 14 | 15 | export { FontStyling, Records }; 16 | -------------------------------------------------------------------------------- /public/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | https://eth-explorer.datastax.com/sitemap-0.xml 4 | https://eth-explorer.datastax.com/blocks-sitemap-index.xml 5 | https://eth-explorer.datastax.com/transactions-sitemap-index.xml 6 | -------------------------------------------------------------------------------- /components/Home/LatestData/styles.ts: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/system'; 2 | import { Box } from '@mui/material'; 3 | import theme from '@styles/ThemeProvider/theme'; 4 | 5 | const Container = styled(Box)({ 6 | width: '50%', 7 | [theme.breakpoints.down('xmd')]: { 8 | width: '100%', 9 | }, 10 | [theme.breakpoints.down('xsA')]: { 11 | width: '470px', 12 | }, 13 | }); 14 | 15 | export { Container }; 16 | -------------------------------------------------------------------------------- /components/shared/SplitButton/styles.ts: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/system'; 2 | import colors from '@styles/ThemeProvider/colors'; 3 | import { Button } from '@mui/material'; 4 | 5 | export const CustomArrowButton = styled(Button)({ 6 | background: colors.nordic, 7 | '&:disabled': { 8 | color: colors.neutral300, 9 | border: `1px solid ${colors.neutral300}`, 10 | background: 'none', 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /components/shared/Pagination/UpperPagination/styles.ts: -------------------------------------------------------------------------------- 1 | import { Box, styled } from '@mui/material'; 2 | import colors from '@styles/ThemeProvider/colors'; 3 | 4 | const FontStyling = styled(Box)({ 5 | fontWeight: '500', 6 | fontSize: '14px', 7 | lineHeight: '24px', 8 | paddingBottom: '27px', 9 | }); 10 | const BlockStyle = styled('span')({ 11 | color: colors.neutral300, 12 | marginLeft: '5px', 13 | }); 14 | 15 | export { FontStyling, BlockStyle }; 16 | -------------------------------------------------------------------------------- /components/TransactionDetail/TransactionLogs/DecodeRow/styles.ts: -------------------------------------------------------------------------------- 1 | import colors from '@styles/ThemeProvider/colors'; 2 | import { Select, styled } from '@mui/material'; 3 | 4 | const CustomSelect = styled(Select)({ 5 | color: colors.actionPrimary, 6 | height: '27px', 7 | width: '80px', 8 | fontSize: '11px', 9 | border: `1px solid ${colors.neutral100}`, 10 | padding: '5px', 11 | '& svg': { fill: colors.neutral100, marginLeft: '10px' }, 12 | }); 13 | 14 | export { CustomSelect }; 15 | -------------------------------------------------------------------------------- /components/TransactionDetail/TransactionHero/DropdownButton/styles.ts: -------------------------------------------------------------------------------- 1 | import { Button } from '@mui/material'; 2 | import { styled } from '@mui/system'; 3 | import colors from '@styles/ThemeProvider/colors'; 4 | const CustomDropButton = styled(Button)({ 5 | backgroundColor: colors.nordic, 6 | color: colors.neutral100, 7 | border: `1px solid ${colors.actionPrimary}`, 8 | height: '32px', 9 | }); 10 | const TextStyle = styled('span')({ 11 | fontSize: '12px', 12 | }); 13 | export { CustomDropButton, TextStyle }; 14 | -------------------------------------------------------------------------------- /components/shared/Chip/styles.ts: -------------------------------------------------------------------------------- 1 | import { Chip, styled } from '@mui/material'; 2 | import { ChipProps } from 'types'; 3 | 4 | const CustomChip = styled(Chip)( 5 | ({ bgcolor, border, titlecolor, icon, cursor }: ChipProps) => ({ 6 | backgroundColor: bgcolor, 7 | border: border, 8 | color: titlecolor, 9 | paddingLeft: icon && '10px', 10 | '& .css-6od3lo-MuiChip-label': { 11 | paddingLeft: icon && '5px', 12 | }, 13 | cursor: cursor, 14 | }) 15 | ); 16 | 17 | export { CustomChip }; 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | .DS_Store 7 | application.yml 8 | 9 | ### STS ### 10 | .apt_generated 11 | .classpath 12 | .factorypath 13 | .project 14 | .settings 15 | .springBeans 16 | .sts4-cache 17 | 18 | ### IntelliJ IDEA ### 19 | .idea 20 | *.iws 21 | *.iml 22 | *.ipr 23 | 24 | ### NetBeans ### 25 | /nbproject/private/ 26 | /nbbuild/ 27 | /dist/ 28 | /nbdist/ 29 | /.nb-gradle/ 30 | build/ 31 | !**/src/main/**/build/ 32 | !**/src/test/**/build/ 33 | 34 | -------------------------------------------------------------------------------- /astra.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Blockchain Explorer", 3 | "description": "Built using React and Next JS, Block Explorer gives the user real-time view of the latest blocks and ETH transactions.", 4 | "duration": "30 minutes", 5 | "skillLevel": "Beginner", 6 | "githubUrl": "https://github.com/datastax/block-explorer", 7 | "tags": [{ 8 | "name": "javascript" 9 | }, { 10 | "name": "Web3" 11 | }, { 12 | "name": "NextJS" 13 | }], 14 | "category": "apps", 15 | "priority": 3, 16 | "heroImage": "https://github.com/datastax/block-explorer/blob/master/hero.png" 17 | } 18 | -------------------------------------------------------------------------------- /next-sitemap.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next-sitemap').IConfig} */ 2 | const siteUrl = 'https://eth-explorer.datastax.com'; 3 | module.exports = { 4 | siteUrl, 5 | generateRobotsTxt: true, 6 | exclude: [ 7 | '/blocks-sitemap-index.xml', 8 | '/transactions-sitemap-index.xml', 9 | '/server-sitemaps/blocks/*tsx', 10 | '/server-sitemaps/transactions/*tsx', 11 | ], 12 | robotsTxtOptions: { 13 | additionalSitemaps: [ 14 | `${siteUrl}/blocks-sitemap-index.xml`, 15 | `${siteUrl}/transactions-sitemap-index.xml`, 16 | ], 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /components/shared/Chip/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ChipProps } from 'types'; 3 | import { CustomChip } from './styles'; 4 | 5 | const Chip = ({ 6 | label, 7 | bgcolor, 8 | border, 9 | titlecolor, 10 | icon, 11 | cursor = 'default', 12 | }: ChipProps) => { 13 | return ( 14 | 23 | ); 24 | }; 25 | 26 | export default Chip; 27 | -------------------------------------------------------------------------------- /constants/index.ts: -------------------------------------------------------------------------------- 1 | const GRAPHQL_ENDPOINT = 2 | process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT || 3 | 'https://krypton-etl.herokuapp.com/graphql'; 4 | 5 | const API_ACCESS_TOKEN = process.env.API_ACCESS_TOKEN; 6 | 7 | const SITE_URL = 'https://eth-explorer.datastax.com'; 8 | 9 | const SITEMAP_SIZE = 30000; 10 | 11 | enum PAGINATION_EVENT { 12 | PREV = 'previous', 13 | NEXT = 'next', 14 | } 15 | 16 | export { 17 | GRAPHQL_ENDPOINT, 18 | SITE_URL, 19 | API_ACCESS_TOKEN, 20 | SITEMAP_SIZE, 21 | PAGINATION_EVENT, 22 | }; 23 | export * from './routes'; 24 | export * from './stubs'; 25 | -------------------------------------------------------------------------------- /pages/index.tsx: -------------------------------------------------------------------------------- 1 | import Hero from '@components/Home/Hero'; 2 | import SummaryBlocks from '@components/Home/SummaryBlocks'; 3 | import type { NextPage } from 'next'; 4 | import LatestData from '@components/Home/LatestData'; 5 | import { useState } from 'react'; 6 | 7 | const Home: NextPage = () => { 8 | const [latestBlocksGroup, setLatestBlocksGroup] = useState(); 9 | return ( 10 | <> 11 | 12 | 13 | 14 | 15 | ); 16 | }; 17 | 18 | export default Home; 19 | -------------------------------------------------------------------------------- /utils/sessionStorage.ts: -------------------------------------------------------------------------------- 1 | const writeToSessionStorage = (key: string, value: string) => { 2 | typeof window !== 'undefined' && sessionStorage.setItem(key, value); 3 | }; 4 | 5 | const readFromSessionStorage = (key: string): string | null => { 6 | if (typeof window !== 'undefined') { 7 | return sessionStorage.getItem(key); 8 | } 9 | return null; 10 | }; 11 | 12 | const deleteFromSessionStorage = (key: string) => { 13 | typeof window !== 'undefined' && sessionStorage.removeItem(key); 14 | }; 15 | 16 | export { 17 | writeToSessionStorage, 18 | readFromSessionStorage, 19 | deleteFromSessionStorage, 20 | }; 21 | -------------------------------------------------------------------------------- /components/Layout/styles.ts: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/system'; 2 | import colors from '@styles/ThemeProvider/colors'; 3 | import { Box } from '@mui/material'; 4 | const MainContainer = styled(Box)({ 5 | background: colors.surfaceCard, 6 | width: '100%', 7 | }); 8 | 9 | const Wrapper = styled(Box)(({ theme }) => ({ 10 | maxWidth: '1440px', 11 | margin: 'auto', 12 | padding: '40px 44px', 13 | [theme.breakpoints.down('lg')]: { 14 | padding: '40px 34px', 15 | }, 16 | [theme.breakpoints.down('md')]: { 17 | padding: '40px 24px', 18 | }, 19 | [theme.breakpoints.down('sm')]: { 20 | padding: '40px 15px', 21 | }, 22 | })); 23 | 24 | export { MainContainer, Wrapper }; 25 | -------------------------------------------------------------------------------- /pages/api/getLatestBlockGroup.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client'; 2 | import client from 'lib/graphql/apolloClient'; 3 | import { Query } from 'lib/graphql/generated/generate'; 4 | import { GET_LATEST_BLOCKS_GROUP } from 'lib/graphql/queries'; 5 | import { NextApiRequest, NextApiResponse } from 'next'; 6 | 7 | export default async function handler( 8 | req: NextApiRequest, 9 | res: NextApiResponse 10 | ) { 11 | if (!req?.headers['referer']) { 12 | res.status(403).send({ message: 'UNAUTHORIZED' }); 13 | } 14 | const { data, error } = await client.query({ 15 | query: gql` 16 | ${GET_LATEST_BLOCKS_GROUP} 17 | `, 18 | }); 19 | res.json({ data, error }); 20 | } 21 | -------------------------------------------------------------------------------- /components/shared/CustomSkeleton/index.tsx: -------------------------------------------------------------------------------- 1 | import { Skeleton } from '@mui/material'; 2 | import colors from '@styles/ThemeProvider/colors'; 3 | import React from 'react'; 4 | 5 | interface CustomSkeletonProps { 6 | rows: number; 7 | } 8 | 9 | const CustomSkeleton = ({ rows }: CustomSkeletonProps) => { 10 | return ( 11 | <> 12 | {[...Array(rows)].map((_, index) => ( 13 | 19 | ))} 20 | 21 | ); 22 | }; 23 | 24 | export default CustomSkeleton; 25 | -------------------------------------------------------------------------------- /components/InternalTxnsTab/index.tsx: -------------------------------------------------------------------------------- 1 | import { Typography } from '@mui/material'; 2 | import colors from '@styles/ThemeProvider/colors'; 3 | import { InternalTxnTitle } from 'constants/stubs'; 4 | import { InternalTxnsTabData } from 'types'; 5 | import TxnsTable from './Table'; 6 | 7 | interface props { 8 | data: InternalTxnsTabData[]; 9 | } 10 | 11 | const InternalTxns = ({ data }: props) => { 12 | return ( 13 | <> 14 | 15 | Internal Transactions 16 | 17 | 18 | 19 | ); 20 | }; 21 | export default InternalTxns; 22 | -------------------------------------------------------------------------------- /pages/api/getDashboardAnalytics.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client'; 2 | import client from 'lib/graphql/apolloClient'; 3 | import { Query } from 'lib/graphql/generated/generate'; 4 | import { GET_DASHBOARD_ANALYTICS } from 'lib/graphql/queries'; 5 | import { NextApiRequest, NextApiResponse } from 'next'; 6 | 7 | export default async function handler( 8 | req: NextApiRequest, 9 | res: NextApiResponse 10 | ) { 11 | if (!req?.headers['referer']) { 12 | res.status(403).send({ message: 'UNAUTHORIZED' }); 13 | } 14 | const { data, error } = await client.query({ 15 | query: gql` 16 | ${GET_DASHBOARD_ANALYTICS} 17 | `, 18 | }); 19 | 20 | res.json({ data, error }); 21 | } 22 | -------------------------------------------------------------------------------- /pages/api/getDashboardAnalyticsHeader.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client'; 2 | import client from 'lib/graphql/apolloClient'; 3 | import { Query } from 'lib/graphql/generated/generate'; 4 | import { GET_DASHBOARD_ANALYTICS_HEADER } from 'lib/graphql/queries'; 5 | import { NextApiRequest, NextApiResponse } from 'next'; 6 | 7 | export default async function handler( 8 | req: NextApiRequest, 9 | res: NextApiResponse 10 | ) { 11 | if (!req?.headers['referer']) { 12 | res.status(403).send({ message: 'UNAUTHORIZED' }); 13 | } 14 | const { data, error } = await client.query({ 15 | query: gql` 16 | ${GET_DASHBOARD_ANALYTICS_HEADER} 17 | `, 18 | }); 19 | 20 | res.json({ data, error }); 21 | } 22 | -------------------------------------------------------------------------------- /components/shared/Tabs/CustomTabsPanel/index.tsx: -------------------------------------------------------------------------------- 1 | import { Typography, Box } from '@mui/material'; 2 | 3 | interface TabPanelProps { 4 | children?: React.ReactNode; 5 | index: number; 6 | value: number; 7 | } 8 | 9 | const TabPanel = ({ children, index, value, ...other }: TabPanelProps) => { 10 | return ( 11 | 24 | ); 25 | }; 26 | 27 | export default TabPanel; 28 | -------------------------------------------------------------------------------- /components/shared/Hero/styles.ts: -------------------------------------------------------------------------------- 1 | import { Box, styled } from '@mui/material'; 2 | import colors from '@styles/ThemeProvider/colors'; 3 | 4 | const MainHeading = styled(Box)({ 5 | fontWeight: '600', 6 | fontSize: '32px', 7 | lineHeight: '38px', 8 | color: colors.neutral100, 9 | }); 10 | const SubHeading = styled('span')({ 11 | fontWeight: '600', 12 | fontSize: '28px', 13 | lineHeight: '38px', 14 | color: colors.neutral300, 15 | }); 16 | const Container = styled(Box)({ 17 | display: 'flex', 18 | flexDirection: 'row', 19 | justifyContent: 'space-between', 20 | padding: '40px 0px 25px', 21 | }); 22 | const PaginationContainer = styled('span')({ 23 | marginLeft: '15px', 24 | }); 25 | 26 | export { MainHeading, Container, SubHeading, PaginationContainer }; 27 | -------------------------------------------------------------------------------- /styles/ThemeProvider/colors.ts: -------------------------------------------------------------------------------- 1 | const colors = { 2 | actionPrimary: '#05D8C3', 3 | actionSecondary: '#AB92FF', 4 | actionTertiary: '#EB82DA', 5 | blackberry: '#381232', 6 | semanticRed: '#FF5449', 7 | surfaceCard: 'linear-gradient(180deg, #121212 0%, #1D2025 100%)', 8 | neutral900: '#0A0A0A', 9 | neutral100: '#FFFFFF', 10 | neutral300: '#A2A2A3', 11 | nightRider: '#2E2E2E', 12 | neutral90: '#E6E1E6', 13 | nordic: '#182B2C', 14 | buttonShaddow: 15 | '0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px rgba(0, 0, 0, 0.14), 0px 1px 5px rgba(0, 0, 0, 0.12)', 16 | neutral700: '#1E1F23', 17 | borderPrimary: '#2E2E2E', 18 | darkTextSecondary: '#FFFFFFB2', 19 | neutral500: '#6D6F71', 20 | actionSecondaryHover: '#D1C4FF', 21 | }; 22 | export default colors; 23 | -------------------------------------------------------------------------------- /pages/api/getNextBlock.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client'; 2 | import client from 'lib/graphql/apolloClient'; 3 | import { Query } from 'lib/graphql/generated/generate'; 4 | import { GET_NEXT_BLOCK } from 'lib/graphql/queries'; 5 | import { NextApiRequest, NextApiResponse } from 'next'; 6 | 7 | export default async function handler( 8 | req: NextApiRequest, 9 | res: NextApiResponse 10 | ) { 11 | if (!req?.headers['referer']) { 12 | res.status(403).send({ message: 'UNAUTHORIZED' }); 13 | } 14 | const { blockGroup, blockNumber } = req?.body; 15 | const { data, error } = await client.query({ 16 | query: gql` 17 | ${GET_NEXT_BLOCK} 18 | `, 19 | variables: { 20 | blockGroup, 21 | blockNumber, 22 | }, 23 | }); 24 | 25 | res.json({ data, error }); 26 | } 27 | -------------------------------------------------------------------------------- /pages/api/getPreviousBlock.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client'; 2 | import client from 'lib/graphql/apolloClient'; 3 | import { Query } from 'lib/graphql/generated/generate'; 4 | import { GET_PREVIOUS_BLOCK } from 'lib/graphql/queries'; 5 | import { NextApiRequest, NextApiResponse } from 'next'; 6 | 7 | export default async function handler( 8 | req: NextApiRequest, 9 | res: NextApiResponse 10 | ) { 11 | if (!req?.headers['referer']) { 12 | res.status(403).send({ message: 'UNAUTHORIZED' }); 13 | } 14 | const { blockGroup, blockNumber } = req?.body; 15 | const { data, error } = await client.query({ 16 | query: gql` 17 | ${GET_PREVIOUS_BLOCK} 18 | `, 19 | variables: { 20 | blockGroup, 21 | blockNumber, 22 | }, 23 | }); 24 | 25 | res.json({ data, error }); 26 | } 27 | -------------------------------------------------------------------------------- /pages/server-sitemap-index.xml.tsx: -------------------------------------------------------------------------------- 1 | import { getServerSideSitemapIndex } from 'next-sitemap'; 2 | import { GetServerSidePropsContext } from 'next'; 3 | import { SITEMAP_SIZE, SITE_URL } from '@constants'; 4 | import { getLatestBlockGroup, getLatestEthBlockNumber } from 'utils'; 5 | 6 | export async function getServerSideProps(context: GetServerSidePropsContext) { 7 | const blockGroup = await getLatestBlockGroup(); 8 | const latestBlockNumber = await getLatestEthBlockNumber(blockGroup); 9 | 10 | const urlsList = []; 11 | for (let index = 1; index <= latestBlockNumber; index += SITEMAP_SIZE) { 12 | urlsList.push(`${SITE_URL}/server-sitemaps/${index}.xml`); 13 | } 14 | 15 | return getServerSideSitemapIndex(context, urlsList); 16 | } 17 | 18 | export default function SitemapIndex() { 19 | return null; 20 | } 21 | -------------------------------------------------------------------------------- /pages/blocks-sitemap-index.xml.tsx: -------------------------------------------------------------------------------- 1 | import { getServerSideSitemapIndex } from 'next-sitemap'; 2 | import { GetServerSidePropsContext } from 'next'; 3 | import { SITEMAP_SIZE, SITE_URL } from '@constants'; 4 | import { getLatestBlockGroup, getLatestEthBlockNumber } from 'utils'; 5 | 6 | export async function getServerSideProps(context: GetServerSidePropsContext) { 7 | const blockGroup = await getLatestBlockGroup(); 8 | const latestBlockNumber = await getLatestEthBlockNumber(blockGroup); 9 | 10 | const urlsList = []; 11 | for (let index = 1; index <= latestBlockNumber; index += SITEMAP_SIZE) { 12 | urlsList.push(`${SITE_URL}/server-sitemaps/blocks/${index}.xml`); 13 | } 14 | 15 | return getServerSideSitemapIndex(context, urlsList); 16 | } 17 | 18 | export default function SitemapIndex() { 19 | return null; 20 | } 21 | -------------------------------------------------------------------------------- /components/Home/Hero/styles.ts: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/system'; 2 | import colors from '@styles/ThemeProvider/colors'; 3 | import { Box, Typography } from '@mui/material'; 4 | import theme from '@styles/ThemeProvider/theme'; 5 | 6 | const TitleText = styled(Typography)({ 7 | fontWeight: 600, 8 | fontSize: '56px', 9 | [theme.breakpoints.down('lg')]: { 10 | fontSize: '52px', 11 | }, 12 | [theme.breakpoints.down('md')]: { 13 | fontSize: '48px', 14 | }, 15 | [theme.breakpoints.down('smA')]: { 16 | fontSize: '40px', 17 | }, 18 | [theme.breakpoints.down('sm')]: { 19 | fontSize: '28px', 20 | }, 21 | lineHeight: '65.53px', 22 | color: colors.neutral100, 23 | }); 24 | 25 | const SearchContainer = styled(Box)({ 26 | display: 'flex', 27 | marginTop: '32px', 28 | }); 29 | 30 | export { TitleText, SearchContainer }; 31 | -------------------------------------------------------------------------------- /components/TransactionDetail/TransactionHero/PaginationButton/styles.ts: -------------------------------------------------------------------------------- 1 | import { Button } from '@mui/material'; 2 | import { styled } from '@mui/system'; 3 | import colors from '@styles/ThemeProvider/colors'; 4 | import ArrowBackIosNewIcon from '@mui/icons-material/ArrowBackIosNew'; 5 | import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos'; 6 | const CustomPagingButton = styled(Button)({ 7 | backgroundColor: colors.nordic, 8 | color: colors.neutral100, 9 | border: `1px solid ${colors.actionPrimary}`, 10 | height: '32px', 11 | }); 12 | 13 | const ArrowBackStyle = styled(ArrowBackIosNewIcon)({ 14 | color: colors.neutral100, 15 | height: '10px', 16 | }); 17 | const ArrowForwardStyle = styled(ArrowForwardIosIcon)({ 18 | color: colors.neutral100, 19 | height: '10px', 20 | }); 21 | export { CustomPagingButton, ArrowBackStyle, ArrowForwardStyle }; 22 | -------------------------------------------------------------------------------- /components/shared/Tabs/CustomTabs/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Tabs } from '@mui/material'; 3 | import { TabProps } from '@types'; 4 | import { CustomTab } from './styles'; 5 | 6 | interface TabsProps { 7 | tabsList: TabProps[]; 8 | onChange: ( 9 | event: React.SyntheticEvent, 10 | tabIndex: number 11 | ) => void | undefined; 12 | tabIndex: number; 13 | } 14 | 15 | const CustomTabs = ({ tabsList, onChange, tabIndex }: TabsProps) => { 16 | return ( 17 | 18 | {tabsList.map((tab) => ( 19 | 25 | ))} 26 | 27 | ); 28 | }; 29 | 30 | export default CustomTabs; 31 | -------------------------------------------------------------------------------- /codegen.ts: -------------------------------------------------------------------------------- 1 | import { CodegenConfig } from '@graphql-codegen/cli'; 2 | 3 | const NEXT_PUBLIC_GRAPHQL_ENDPOINT: string = process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT || ''; 4 | const API_ACCESS_TOKEN: string = process.env.API_ACCESS_TOKEN || ''; 5 | 6 | const config: CodegenConfig = { 7 | overwrite: true, 8 | schema: [{ 9 | [NEXT_PUBLIC_GRAPHQL_ENDPOINT]: { 10 | headers: { 11 | 'x-cassandra-token': API_ACCESS_TOKEN 12 | } 13 | } 14 | }], 15 | documents: './lib/graphql/*.graphql', 16 | generates: { 17 | 'lib/graphql/generated/generate.tsx': { 18 | plugins: ['typescript', 'typescript-operations', 'typescript-react-apollo'], 19 | config: { 20 | withHooks: true, 21 | withHOC: false, 22 | withComponent: false, 23 | hooksImportFrom: '@apollo/react-hooks', 24 | }, 25 | } 26 | }, 27 | }; 28 | export default config; -------------------------------------------------------------------------------- /components/shared/Footer/index.tsx: -------------------------------------------------------------------------------- 1 | import { productPageUrl } from '@constants' 2 | import { Stack } from '@mui/material'; 3 | import colors from '@styles/ThemeProvider/colors'; 4 | import { Wrapper, Container, StyledTypography } from './styles'; 5 | 6 | const Footer = () => { 7 | return ( 8 | 9 | 10 | 11 | 12 | DataStax © {new Date().getFullYear()} 13 | 14 | 15 | 🚀️ Powered By Astra -{' '} 16 | window.open(productPageUrl, '_blank')}> 17 | See How It’s Done 18 | 19 | 20 | 21 | 22 | 23 | ); 24 | }; 25 | 26 | export default Footer; 27 | -------------------------------------------------------------------------------- /components/shared/HTMLParser/index.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import React from 'react'; 3 | import ReactHtmlParser, { HTMLReactParserOptions } from 'html-react-parser'; 4 | import { ColouredText } from '@components/TransactionDetail/TransactionLogs/styles'; 5 | 6 | interface HTMLParserProps { 7 | rawString: string; 8 | } 9 | 10 | const HTMLParser = ({ rawString }: HTMLParserProps): JSX.Element => { 11 | const parserOptions: HTMLReactParserOptions = { 12 | replace: (domNode: any) => { 13 | if (domNode?.name === 'colouredtext') { 14 | return ( 15 | 16 | {domNode?.children[0]?.data} 17 | 18 | ); 19 | } 20 | }, 21 | }; 22 | return ReactHtmlParser(rawString, parserOptions) as JSX.Element; 23 | }; 24 | 25 | export default HTMLParser; 26 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | - name: setup 3 | before: | 4 | printf 'export PATH="$HOME%s:$PATH"\n' "/.astra/cli" >> $HOME/.bashrc 5 | printf 'unset JAVA_TOOL_OPTIONS\n' >> $HOME/.bashrc 6 | curl -Ls "https://dtsx.io/get-astra-cli" | bash >> ./install.log 7 | command: | 8 | unset JAVA_TOOL_OPTIONS 9 | source /home/gitpod/.astra/cli/astra-init.sh 10 | cd /workspace/workshop-astra-block/block-explorer 11 | clear 12 | ports: 13 | - port: 8080 14 | onOpen: open-browser 15 | visibility: public 16 | 17 | github: 18 | prebuilds: 19 | master: true 20 | branches: true 21 | pullRequests: true 22 | pullRequestsFromForks: false 23 | addCheck: true 24 | addComment: false 25 | addBadge: true 26 | addLabel: false 27 | 28 | vscode: 29 | extensions: 30 | - datastax.astra-for-vs-code 31 | - vscjava.vscode-java-pack 32 | - Pivotal.vscode-boot-dev-pack 33 | -------------------------------------------------------------------------------- /pages/api/getLatestTransactionsList.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client'; 2 | import client from 'lib/graphql/apolloClient'; 3 | import { Query } from 'lib/graphql/generated/generate'; 4 | import { GET_LATEST_TRANSACTIONS } from 'lib/graphql/queries'; 5 | import { NextApiRequest, NextApiResponse } from 'next'; 6 | 7 | export default async function handler( 8 | req: NextApiRequest, 9 | res: NextApiResponse 10 | ) { 11 | if (!req?.headers['referer']) { 12 | res.status(403).send({ message: 'UNAUTHORIZED' }); 13 | } 14 | const { blockHash, pageSize } = req?.body; 15 | const { data, error } = await client.query({ 16 | query: gql` 17 | ${GET_LATEST_TRANSACTIONS} 18 | `, 19 | variables: { 20 | filter: { 21 | block_hash: { 22 | eq: blockHash, 23 | }, 24 | }, 25 | options: { 26 | pageSize, 27 | }, 28 | }, 29 | }); 30 | 31 | res.json({ data, error }); 32 | } 33 | -------------------------------------------------------------------------------- /pages/api/getLatestBlocksList.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client'; 2 | import client from 'lib/graphql/apolloClient'; 3 | import { Query } from 'lib/graphql/generated/generate'; 4 | import { GET_LATEST_ETH_BLOCKS } from 'lib/graphql/queries'; 5 | import { NextApiRequest, NextApiResponse } from 'next'; 6 | 7 | export default async function handler( 8 | req: NextApiRequest, 9 | res: NextApiResponse 10 | ) { 11 | if (!req?.headers['referer']) { 12 | res.status(403).send({ message: 'UNAUTHORIZED' }); 13 | } 14 | const { blockGroup, pageSize } = req?.body; 15 | const { data, error } = await client.query({ 16 | query: gql` 17 | ${GET_LATEST_ETH_BLOCKS} 18 | `, 19 | variables: { 20 | filter: { 21 | blocks_group: { 22 | eq: blockGroup, 23 | }, 24 | }, 25 | options: { 26 | pageSize: pageSize, 27 | }, 28 | }, 29 | }); 30 | 31 | res.json({ data, error }); 32 | } 33 | -------------------------------------------------------------------------------- /lib/graphql/apolloClient.ts: -------------------------------------------------------------------------------- 1 | import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client'; 2 | import { setContext } from '@apollo/client/link/context'; 3 | import { API_ACCESS_TOKEN, GRAPHQL_ENDPOINT } from '@constants'; 4 | 5 | const httpLink = createHttpLink({ 6 | uri: GRAPHQL_ENDPOINT, 7 | }); 8 | 9 | const authLink = setContext((_, { headers }) => { 10 | return { 11 | headers: { 12 | ...headers, 13 | 'x-cassandra-token': API_ACCESS_TOKEN, 14 | }, 15 | }; 16 | }); 17 | 18 | const client = new ApolloClient({ 19 | uri: GRAPHQL_ENDPOINT, 20 | link: authLink.concat(httpLink), 21 | cache: new InMemoryCache({ 22 | addTypename: false, 23 | }), 24 | defaultOptions: { 25 | query: { 26 | fetchPolicy: 'no-cache', 27 | errorPolicy: 'all', 28 | }, 29 | watchQuery: { 30 | fetchPolicy: 'no-cache', 31 | errorPolicy: 'ignore', 32 | }, 33 | }, 34 | }); 35 | 36 | export default client; 37 | -------------------------------------------------------------------------------- /components/shared/DataBox/styles.ts: -------------------------------------------------------------------------------- 1 | import { Button, styled } from '@mui/material'; 2 | import colors from '@styles/ThemeProvider/colors'; 3 | import theme from '@styles/ThemeProvider/theme'; 4 | 5 | const InputBox = styled('div')({ 6 | border: `1px solid ${colors.neutral500}`, 7 | borderRadius: '5px', 8 | padding: '10px', 9 | [theme.breakpoints.down('smA')]: { 10 | width: '500px', 11 | }, 12 | wordBreak: 'break-word', 13 | width: '100%', 14 | color: colors.neutral300, 15 | display: 'flex', 16 | justifyContent: 'space-between', 17 | alignContent: 'center', 18 | alignItems: 'center', 19 | overflowX: 'scroll', 20 | transition: 'all 1s ease-in', 21 | }); 22 | 23 | const CustomButton = styled(Button)({ 24 | display: 'flex', 25 | alignSelf: 'flex-start', 26 | marginLeft: '10px', 27 | '&:disabled': { 28 | background: colors.neutral300, 29 | color: colors.neutral100, 30 | }, 31 | }); 32 | 33 | export { InputBox, CustomButton }; 34 | -------------------------------------------------------------------------------- /components/shared/Footer/styles.ts: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/system'; 2 | import colors from '@styles/ThemeProvider/colors'; 3 | import { Box, Theme, Typography } from '@mui/material'; 4 | 5 | interface StyledTypographyProps { 6 | theme?: Theme; 7 | fontColor?: string; 8 | } 9 | 10 | const Container = styled(Box)({ 11 | background: colors.neutral900, 12 | width: '100%', 13 | }); 14 | 15 | const Wrapper = styled(Box)({ 16 | height: '56px', 17 | maxWidth: '1440px', 18 | display: 'flex', 19 | alignItems: 'center', 20 | margin: 'auto', 21 | padding: '0px 44px', 22 | }); 23 | 24 | const StyledTypography = styled(Typography)( 25 | ({ fontColor }: StyledTypographyProps) => ({ 26 | color: fontColor, 27 | fontWeight: 500, 28 | fontSize: '11px', 29 | lineHeight: '16px', 30 | span: { 31 | color: colors.actionTertiary, 32 | cursor: 'pointer', 33 | }, 34 | }) 35 | ); 36 | 37 | export { Container, Wrapper, StyledTypography }; 38 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "baseUrl": ".", 18 | "paths": { 19 | "@components/*": ["components/*"], 20 | "@pages/*": ["pages/*"], 21 | "@styles/*": ["styles/*"], 22 | "@utils": ["utils/"], 23 | "@hooks/*": ["hooks/*"], 24 | "@types": ["types/"], 25 | "@constants": ["constants/"], 26 | "@lib/*": ["lib/*/"] 27 | } 28 | }, 29 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "codegen.js"], 30 | "exclude": ["node_modules", "**/*/generate.tsx"] 31 | } 32 | -------------------------------------------------------------------------------- /components/TransactionDetail/TransactionHero/PaginationButton/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | CustomPagingButton, 4 | ArrowBackStyle, 5 | ArrowForwardStyle, 6 | } from './styles'; 7 | import { ButtonGroup } from '@mui/material'; 8 | interface PaginationProps { 9 | setPreviousConsecutiveState?: () => void; 10 | setNextConsecutiveState?: () => void; 11 | } 12 | 13 | const PaginationButton = ({ 14 | setPreviousConsecutiveState, 15 | setNextConsecutiveState, 16 | }: PaginationProps) => { 17 | return ( 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | ); 29 | }; 30 | 31 | export default PaginationButton; 32 | -------------------------------------------------------------------------------- /pages/api/getLatestEthBlock.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client'; 2 | import client from 'lib/graphql/apolloClient'; 3 | import { Query } from 'lib/graphql/generated/generate'; 4 | import { GET_LATEST_ETH_BLOCK } from 'lib/graphql/queries'; 5 | import { NextApiRequest, NextApiResponse } from 'next'; 6 | 7 | export default async function handler( 8 | req: NextApiRequest, 9 | res: NextApiResponse 10 | ) { 11 | if (!req?.headers['referer']) { 12 | res.status(403).send({ message: 'UNAUTHORIZED' }); 13 | } 14 | const { blockGroup, pageState, pageSize } = req?.body; 15 | const { data, error } = await client.query({ 16 | query: gql` 17 | ${GET_LATEST_ETH_BLOCK} 18 | `, 19 | variables: { 20 | filter: { 21 | blocks_group: { 22 | eq: blockGroup, 23 | }, 24 | }, 25 | options: { 26 | pageState: pageState, 27 | pageSize: pageSize, 28 | }, 29 | }, 30 | }); 31 | 32 | res.json({ data, error }); 33 | } 34 | -------------------------------------------------------------------------------- /components/Home/SummaryBlock/styles.ts: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/system'; 2 | import { Card, Typography } from '@mui/material'; 3 | import colors from 'styles/ThemeProvider/colors'; 4 | import theme from '@styles/ThemeProvider/theme'; 5 | 6 | const StyledCard = styled(Card)(() => ({ 7 | padding: '32px 0px 32px 32px', 8 | margin: '0px 0px 24px 0px', 9 | display: 'flex', 10 | background: colors.surfaceCard, 11 | border: `1px solid ${colors.nightRider}`, 12 | borderRadius: '6px', 13 | width: '100%', 14 | [theme.breakpoints.down('mdB')]: { 15 | padding: '32px 0px 32px 10px', 16 | }, 17 | })); 18 | 19 | const StyledTypograph = styled(Typography)({ 20 | color: colors.neutral100, 21 | fontSize: '16px', 22 | lineHeight: '24px', 23 | wordWrap: 'break-word', 24 | span: { 25 | color: colors.semanticRed, 26 | marginLeft: '8px', 27 | }, 28 | [theme.breakpoints.down('mdB')]: { 29 | fontSize: '14px', 30 | }, 31 | }); 32 | 33 | export { StyledCard, StyledTypograph }; 34 | -------------------------------------------------------------------------------- /pages/api/getInternalTransactionsByBlock.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client'; 2 | import client from 'lib/graphql/apolloClient'; 3 | import { Query } from 'lib/graphql/generated/generate'; 4 | import { GET_INTERNAL_TRANSACTIONS_OF_BLOCK } from 'lib/graphql/queries'; 5 | import { NextApiRequest, NextApiResponse } from 'next'; 6 | 7 | export default async function handler( 8 | req: NextApiRequest, 9 | res: NextApiResponse 10 | ) { 11 | if (!req?.headers['referer']) { 12 | res.status(403).send({ message: 'UNAUTHORIZED' }); 13 | } 14 | const { blockNumber, pageState, pageSize } = req?.body; 15 | const { data, error } = await client.query({ 16 | query: gql` 17 | ${GET_INTERNAL_TRANSACTIONS_OF_BLOCK} 18 | `, 19 | variables: { 20 | filter: { 21 | block_number: { eq: blockNumber }, 22 | }, 23 | options: { 24 | pageState: pageState, 25 | pageSize: pageSize, 26 | }, 27 | }, 28 | }); 29 | 30 | res.json({ data, error }); 31 | } 32 | -------------------------------------------------------------------------------- /pages/api/getPaginatedBlocks.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client'; 2 | import client from 'lib/graphql/apolloClient'; 3 | import { Query } from 'lib/graphql/generated/generate'; 4 | import { Get_PAGINATED_BLOCKS_QUERY } from 'lib/graphql/queries'; 5 | import { NextApiRequest, NextApiResponse } from 'next'; 6 | 7 | export default async function handler( 8 | req: NextApiRequest, 9 | res: NextApiResponse 10 | ) { 11 | if (!req?.headers['referer']) { 12 | res.status(403).send({ message: 'UNAUTHORIZED' }); 13 | } 14 | const { blockGroup, pageState, pageSize } = req?.body; 15 | const { data, error } = await client.query({ 16 | query: gql` 17 | ${Get_PAGINATED_BLOCKS_QUERY} 18 | `, 19 | variables: { 20 | filter: { 21 | blocks_group: { 22 | eq: blockGroup, 23 | }, 24 | }, 25 | options: { 26 | pageState: pageState, 27 | pageSize: pageSize, 28 | }, 29 | }, 30 | }); 31 | 32 | res.json({ data, error }); 33 | } 34 | -------------------------------------------------------------------------------- /components/shared/DataBox/index.tsx: -------------------------------------------------------------------------------- 1 | import DecodedData from '@components/TransactionDetail/TransactionLogs/DecodedData'; 2 | import { Maybe } from 'graphql/jsutils/Maybe'; 3 | import { Scalars } from 'lib/graphql/generated/generate'; 4 | import React, { useState } from 'react'; 5 | import { InputBox, CustomButton } from './styles'; 6 | 7 | interface DataBoxProps { 8 | decodedData: Maybe; 9 | rawData: Maybe; 10 | } 11 | 12 | const DataBox = ({ decodedData, rawData }: DataBoxProps) => { 13 | const [isDecoded, setIsDecoded] = useState(false); 14 | return ( 15 | 16 | {isDecoded ? : rawData} 17 | setIsDecoded(!isDecoded)} 21 | disabled={Object.keys(JSON.parse(decodedData as string)).length < 1} 22 | > 23 | {isDecoded ? 'Hex' : 'Dec'} 24 | 25 | 26 | ); 27 | }; 28 | 29 | export default DataBox; 30 | -------------------------------------------------------------------------------- /components/shared/PaginationButton/styles.ts: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/system'; 2 | import { Button, ButtonGroup } from '@mui/material'; 3 | import colors from '@styles/ThemeProvider/colors'; 4 | import ArrowBackIosNewIcon from '@mui/icons-material/ArrowBackIosNew'; 5 | import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos'; 6 | const CustomButtonGroup = styled(ButtonGroup)({ 7 | height: '36px', 8 | }); 9 | 10 | const CustomButton = styled(Button)({ 11 | color: 'white', 12 | '&:disabled': { 13 | color: colors.neutral300, 14 | border: `1px solid ${colors.neutral300}`, 15 | }, 16 | }); 17 | 18 | interface WrapperProps { 19 | disabled: boolean; 20 | } 21 | 22 | const ArrowBackStyle = styled(ArrowBackIosNewIcon)( 23 | ({ disabled }: WrapperProps) => ({ 24 | color: disabled ? colors.neutral300 : colors.neutral100, 25 | height: '10px', 26 | }) 27 | ); 28 | const ArrowForwardStyle = styled(ArrowForwardIosIcon)( 29 | ({ disabled }: WrapperProps) => ({ 30 | color: disabled ? colors.neutral300 : colors.neutral100, 31 | height: '10px', 32 | }) 33 | ); 34 | 35 | export { CustomButtonGroup, ArrowBackStyle, ArrowForwardStyle, CustomButton }; 36 | -------------------------------------------------------------------------------- /pages/server-sitemaps/blocks/[startingBlock].tsx: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { NextPageContext } from 'next'; 3 | import { AxiosApiResponse } from 'types'; 4 | import { 5 | createSitemap, 6 | getLatestBlockGroup, 7 | getLatestEthBlockNumber, 8 | } from 'utils'; 9 | 10 | export async function getServerSideProps({ res, req, query }: NextPageContext) { 11 | const { startingBlock } = query; 12 | const host = req?.headers?.host; 13 | const isLocalhost = host === 'localhost:3000'; 14 | const latestBlockGroup = await getLatestBlockGroup(); 15 | const latestBlockNumber = await getLatestEthBlockNumber(latestBlockGroup); 16 | const response = await axios.post( 17 | `${isLocalhost ? 'http' : 'https'}://${host}/api/getBlocksSitemap`, 18 | { 19 | startingBlock: Number(startingBlock?.slice(0, -4)), 20 | latestBlockNumber, 21 | } 22 | ); 23 | const urlList = response?.data?.data; 24 | const sitemap = createSitemap(urlList); 25 | res?.setHeader('Content-Type', 'text/xml'); 26 | res?.write(sitemap); 27 | res?.end(); 28 | return { props: { results: { urlList } } }; 29 | } 30 | 31 | export default function ServerSitemap() { 32 | return null; 33 | } 34 | -------------------------------------------------------------------------------- /pages/server-sitemaps/transactions/[timestamp].tsx: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { SITEMAP_SIZE } from '@constants'; 3 | import { NextPageContext } from 'next'; 4 | import { AxiosApiResponse } from 'types'; 5 | import { createSitemap } from 'utils'; 6 | 7 | export async function getServerSideProps({ res, req, query }: NextPageContext) { 8 | const { timestamp } = query; 9 | const host = req?.headers?.host; 10 | const queryDetails = String(timestamp)?.split('*'); 11 | const isLocalhost = host === 'localhost:3000'; 12 | 13 | const response = await axios.post( 14 | `${isLocalhost ? 'http' : 'https'}://${host}/api/getTransactionsSitemap`, 15 | { 16 | date: queryDetails?.[0], 17 | size: SITEMAP_SIZE, 18 | blockNumber: queryDetails?.[1] 19 | ? Number(queryDetails?.[1]?.slice(0, -4)) 20 | : undefined, 21 | } 22 | ); 23 | 24 | const urlsList = response?.data?.data; 25 | const sitemap = createSitemap(urlsList); 26 | res?.setHeader('Content-Type', 'text/xml'); 27 | res?.write(sitemap); 28 | res?.end(); 29 | return { props: { results: { urlsList } } }; 30 | } 31 | 32 | export default function ServerSitemap() { 33 | return null; 34 | } 35 | -------------------------------------------------------------------------------- /components/TransactionDetail/TransactionHero/DropdownButton/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import Menu from '@mui/material/Menu'; 3 | import MenuItem from '@mui/material/MenuItem'; 4 | import PopupState, { bindTrigger, bindMenu } from 'material-ui-popup-state'; 5 | import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; 6 | import { CustomDropButton, TextStyle } from './styles'; 7 | import { DropButtonProps } from 'types'; 8 | export default function DropdownButton({ title }: DropButtonProps) { 9 | return ( 10 | 11 | {(popupState) => ( 12 | 13 | 14 | {title} 15 | 16 | 17 | 18 | Profile 19 | My account 20 | Logout 21 | 22 | 23 | )} 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /pages/api/getTransactionsSitemap.ts: -------------------------------------------------------------------------------- 1 | import { NextApiRequest, NextApiResponse } from 'next'; 2 | import { generateTransactionsHashRoutes, getTransactionsList } from 'utils'; 3 | import Compression from 'compression'; 4 | 5 | const compression = Compression({ 6 | threshold: 0, 7 | }); 8 | 9 | function runMiddleware( 10 | req: NextApiRequest, 11 | res: NextApiResponse, 12 | // eslint-disable-next-line @typescript-eslint/ban-types 13 | fn: Function 14 | ) { 15 | return new Promise((resolve, reject) => { 16 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 17 | fn(req, res, (result: any) => { 18 | if (result instanceof Error) { 19 | return reject(result); 20 | } 21 | 22 | return resolve(result); 23 | }); 24 | }); 25 | } 26 | 27 | export default async function handler( 28 | req: NextApiRequest, 29 | res: NextApiResponse 30 | ) { 31 | const { date, size, blockNumber } = req?.body; 32 | const transactions = await getTransactionsList(date, size, blockNumber); 33 | const data = generateTransactionsHashRoutes( 34 | transactions as Array<{ hash: string; block_number: string }> 35 | ); 36 | 37 | await runMiddleware(req, res, compression); 38 | res.json({ data }); 39 | } 40 | -------------------------------------------------------------------------------- /pages/api/getPaginatedTransactions.ts: -------------------------------------------------------------------------------- 1 | import { gql } from '@apollo/client'; 2 | import client from 'lib/graphql/apolloClient'; 3 | import { Query } from 'lib/graphql/generated/generate'; 4 | import { GET_PAGINATED_ETH_TRANSACTIONS } from 'lib/graphql/queries'; 5 | import { NextApiRequest, NextApiResponse } from 'next'; 6 | 7 | export default async function handler( 8 | req: NextApiRequest, 9 | res: NextApiResponse 10 | ) { 11 | if (!req?.headers['referer']) { 12 | res.status(403).send({ message: 'UNAUTHORIZED' }); 13 | } 14 | const { blockHash, pageState, pageSize, limit, transactionIndexExpression } = 15 | req?.body; 16 | const { data, error } = await client.query({ 17 | query: gql` 18 | ${GET_PAGINATED_ETH_TRANSACTIONS} 19 | `, 20 | variables: { 21 | filter: { 22 | block_hash: { 23 | eq: blockHash, 24 | }, 25 | ...(transactionIndexExpression && { 26 | transaction_index: transactionIndexExpression, 27 | }), 28 | }, 29 | options: { 30 | ...(pageState && { pageState }), 31 | ...(pageSize && { pageSize }), 32 | ...(limit && { limit }), 33 | }, 34 | }, 35 | }); 36 | 37 | res.json({ data, error }); 38 | } 39 | -------------------------------------------------------------------------------- /public/sitemap-0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | https://eth-explorer.datastax.com/2023-01-11T13:13:33.803Zdaily0.7 4 | https://eth-explorer.datastax.com/blocks/2023-01-11T13:13:33.803Zdaily0.7 5 | https://eth-explorer.datastax.com/internal-transactions/2023-01-11T13:13:33.803Zdaily0.7 6 | https://eth-explorer.datastax.com/server-sitemap-index.xml/2023-01-11T13:13:33.803Zdaily0.7 7 | https://eth-explorer.datastax.com/transactions/2023-01-11T13:13:33.803Zdaily0.7 8 | -------------------------------------------------------------------------------- /styles/ThemeProvider/theme.ts: -------------------------------------------------------------------------------- 1 | import { createTheme, Theme } from '@mui/material/styles'; 2 | import colors from '@styles/ThemeProvider/colors'; 3 | 4 | declare module '@mui/material/styles' { 5 | type DefaultTheme = Theme; 6 | } 7 | declare module '@mui/material/styles' { 8 | interface BreakpointOverrides { 9 | xs: true; 10 | xsA: true; 11 | xsB: true; 12 | sm: true; 13 | smA: true; 14 | md: true; 15 | xmd: true; 16 | mdA: true; 17 | xmdA: true; 18 | mdB: true; 19 | xmdB: true; 20 | xxmdB: true; 21 | lg: true; 22 | xl: true; 23 | } 24 | } 25 | 26 | const theme = createTheme({ 27 | breakpoints: { 28 | values: { 29 | xs: 0, 30 | xsA: 460, 31 | xsB: 550, 32 | sm: 600, 33 | smA: 680, 34 | md: 900, 35 | xmd: 1000, 36 | mdA: 1100, 37 | xmdA: 1160, 38 | mdB: 1200, 39 | xmdB: 1340, 40 | xxmdB: 1380, 41 | lg: 1440, 42 | xl: 1600, 43 | }, 44 | }, 45 | palette: { 46 | primary: { 47 | main: colors.actionPrimary, 48 | }, 49 | secondary: { 50 | main: colors.actionSecondary, 51 | }, 52 | error: { 53 | main: colors.semanticRed, 54 | }, 55 | }, 56 | }); 57 | export default theme; 58 | -------------------------------------------------------------------------------- /pages/api/getBlocksSitemap.ts: -------------------------------------------------------------------------------- 1 | import { NextApiRequest, NextApiResponse } from 'next'; 2 | import { ISitemapField } from 'next-sitemap'; 3 | import { generateBlockNumberRoutes } from 'utils'; 4 | import Compression from 'compression'; 5 | import { SITEMAP_SIZE } from '@constants'; 6 | 7 | const compression = Compression({ 8 | threshold: 0, 9 | }); 10 | 11 | function runMiddleware( 12 | req: NextApiRequest, 13 | res: NextApiResponse, 14 | // eslint-disable-next-line @typescript-eslint/ban-types 15 | fn: Function 16 | ) { 17 | return new Promise((resolve, reject) => { 18 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 19 | fn(req, res, (result: any) => { 20 | if (result instanceof Error) { 21 | return reject(result); 22 | } 23 | 24 | return resolve(result); 25 | }); 26 | }); 27 | } 28 | 29 | export default async function handler( 30 | req: NextApiRequest, 31 | res: NextApiResponse 32 | ) { 33 | const { startingBlock, latestBlockNumber } = req?.body; 34 | const endingBlock = Number(startingBlock) + SITEMAP_SIZE; 35 | const data: ISitemapField[] = generateBlockNumberRoutes( 36 | startingBlock, 37 | endingBlock, 38 | latestBlockNumber 39 | ); 40 | 41 | await runMiddleware(req, res, compression); 42 | res.json({ data }); 43 | } 44 | -------------------------------------------------------------------------------- /components/TransactionDetail/TransactionLogs/DecodeRow/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { Row } from '../styles'; 3 | import { SelectChangeEvent, Typography, MenuItem } from '@mui/material'; 4 | import colors from '@styles/ThemeProvider/colors'; 5 | import { CustomSelect } from './styles'; 6 | 7 | type dataDisplayType = 'dec' | 'hex'; 8 | 9 | interface DecodeRowProps { 10 | data: { 11 | dec: string; 12 | hex: string; 13 | }; 14 | } 15 | 16 | const DecodeRow = ({ data }: DecodeRowProps) => { 17 | const [displayType, setDisplayType] = useState( 18 | 'hex' 19 | ); 20 | 21 | const handleChange = (event: SelectChangeEvent) => { 22 | setDisplayType(event.target.value as string); 23 | }; 24 | return ( 25 | 26 | 32 | hex 33 | dec 34 | 35 | 36 | {data[displayType as dataDisplayType]} 37 | 38 | 39 | ); 40 | }; 41 | 42 | export default DecodeRow; 43 | -------------------------------------------------------------------------------- /pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { AppProps } from 'next/app'; 3 | import { ThemeProvider } from '@mui/material/styles'; 4 | import CssBaseline from '@mui/material/CssBaseline'; 5 | import theme from '@styles/ThemeProvider/theme'; 6 | import Layout from '@components/Layout'; 7 | import { ApolloProvider } from '@apollo/client'; 8 | import Script from 'next/script'; 9 | import { Client } from '@lib/graphql'; 10 | import '@styles/globals.css'; 11 | 12 | const App = (props: AppProps) => { 13 | const { Component, pageProps } = props; 14 | return ( 15 | 16 | 17 | 30 | 31 | 32 | 33 | 34 | 35 | ); 36 | }; 37 | 38 | export default App; 39 | -------------------------------------------------------------------------------- /components/shared/CopyClipboard/CopyClipboard.tsx: -------------------------------------------------------------------------------- 1 | import { CopyAll } from '@components/shared/Icons'; 2 | import { ClickAwayListener, Tooltip } from '@mui/material'; 3 | import { useState } from 'react'; 4 | import { CopyClipboardProps } from 'types'; 5 | import { copyToClipboard } from 'utils'; 6 | import { Button } from './styles'; 7 | 8 | const CopyClipboard = ({ data }: CopyClipboardProps) => { 9 | const [open, setOpen] = useState(false); 10 | 11 | const handleTooltipClose = () => { 12 | setOpen(false); 13 | }; 14 | 15 | const handleTooltipOpen = () => { 16 | setOpen(true); 17 | }; 18 | return ( 19 | 20 | 32 | 41 | 42 | 43 | ); 44 | }; 45 | 46 | export default CopyClipboard; 47 | -------------------------------------------------------------------------------- /components/TransactionDetail/TransactionLogs/DecodedData/index.tsx: -------------------------------------------------------------------------------- 1 | import { Typography } from '@mui/material'; 2 | import colors from '@styles/ThemeProvider/colors'; 3 | import React from 'react'; 4 | import DecodeRow from '../DecodeRow'; 5 | import { ColouredText, Row } from '../styles'; 6 | 7 | interface DecodedDataProps { 8 | data: string | undefined | null; 9 | } 10 | const DecodedData = ({ data }: DecodedDataProps) => { 11 | if (!data) return null; 12 | 13 | const processedObject = JSON.parse(data); 14 | if (!processedObject || Object.keys(processedObject).length < 1) 15 | return
Nothing To Decode
; 16 | 17 | const processedData = () => { 18 | let UI: JSX.Element[]; 19 | if (Array.isArray(processedObject)) { 20 | UI = processedObject.map((dataObject, index) => ( 21 | 22 | )); 23 | } else { 24 | UI = Object.keys(processedObject).map((key) => ( 25 | 26 | 27 | {key} 28 | 29 | 30 | {processedObject[key]} 31 | 32 | 33 | )); 34 | } 35 | return UI; 36 | }; 37 | 38 | return
{processedData()}
; 39 | }; 40 | 41 | export default DecodedData; 42 | -------------------------------------------------------------------------------- /components/Layout/index.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head'; 2 | import React from 'react'; 3 | import Footer from '@components/shared/Footer'; 4 | import Header from '@components/shared/Header'; 5 | import { MainContainer, Wrapper } from './styles'; 6 | 7 | interface LayoutProps { 8 | children: React.ReactNode; 9 | } 10 | 11 | const Layout = ({ children }: LayoutProps) => { 12 | return ( 13 | <> 14 | 15 | Astra Block Explorer | View Realtime Ethereum Data 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | {children} 29 | 30 |