From 6a20e77613167e78b5a7d847836d3172a24741ac Mon Sep 17 00:00:00 2001 From: Ruben Gutierrez Date: Fri, 25 Nov 2022 10:10:20 -0400 Subject: [PATCH 1/5] add syncing toast --- __test__/components/infoCard.test.tsx | 8 +++++ components/Header/Header.tsx | 5 +-- components/InfoCard/InfoCard.tsx | 44 +++++++++++++++++++++++ components/SearchBar/SearchBar.tsx | 1 - generated/index.tsx | 51 ++++++++++++++++++++++++++- graphql/queries.ts | 8 +++++ i18n/en.ts | 3 ++ i18n/es.ts | 3 ++ 8 files changed, 119 insertions(+), 4 deletions(-) diff --git a/__test__/components/infoCard.test.tsx b/__test__/components/infoCard.test.tsx index a181ae7..7feca06 100644 --- a/__test__/components/infoCard.test.tsx +++ b/__test__/components/infoCard.test.tsx @@ -20,6 +20,14 @@ jest.mock('../../generated', () => ({ data: { version }, } }), + useGetSyncQuery: jest.fn(() => { + return { + data: { + lastSynced: 100, + }, + refetch: jest.fn(), + } + }), })) jest.mock('binance-api-node', () => { diff --git a/components/Header/Header.tsx b/components/Header/Header.tsx index bd5e6c0..3c8c214 100644 --- a/components/Header/Header.tsx +++ b/components/Header/Header.tsx @@ -5,11 +5,12 @@ import { useEffect, useState } from 'react' import { Col, Dropdown, DropdownButton, InputGroup, Row } from 'react-bootstrap' import LanguageIcon from '../../assets/img/language.svg' import { useFormatIntl } from '../../hooks/useFormatIntl' +import withApollo from '../../lib/withApollo' import { getTitle } from '../../utils/pagetitile' import InfoCard from '../InfoCard/InfoCard' import Searchbar from '../SearchBar/SearchBar' -export const Header = () => { +export const Header = withApollo(() => { const { format } = useFormatIntl() const [title, setTitle] = useState('') const router = useRouter() @@ -60,4 +61,4 @@ export const Header = () => { ) -} +}) diff --git a/components/InfoCard/InfoCard.tsx b/components/InfoCard/InfoCard.tsx index c7fdb0f..463a2c5 100644 --- a/components/InfoCard/InfoCard.tsx +++ b/components/InfoCard/InfoCard.tsx @@ -3,9 +3,11 @@ import { get } from 'lodash' import Image from 'next/future/image' import { useRouter } from 'next/router' import { useState, useEffect } from 'react' +import { toast } from 'react-toastify' import time from '../../assets/img/bxs_time.svg' import coin from '../../assets/img/ph_coin-vertical-fill.svg' import { useGetLastBlockQuery, GetLastBlockQuery, useVersionQuery, VersionQuery } from '../../generated' +import { useGetSyncQuery } from '../../generated/index' import { useFormatIntl } from '../../hooks/useFormatIntl' import { getTimeAgo } from '../../lib/utils' import withApollo from '../../lib/withApollo' @@ -17,6 +19,10 @@ function InfoCard() { const { data } = useGetLastBlockQuery({ variables: { skip: 0, take: 1 } }) const blocks = get(data, 'getBlocks', []) as GetLastBlockQuery['getBlocks'] const { data: versionData } = useVersionQuery() + const { data: syncData, refetch } = useGetSyncQuery() + const [sync, setSync] = useState() + const [isSyncing, setIsSyncing] = useState(false) + const [syncingFromBlock, setSyncingFromBlock] = useState(0) const version = get(versionData, 'version', []) as VersionQuery['version'] const token = 'DOT' @@ -32,6 +38,44 @@ function InfoCard() { console.log(err) }) }, []) + + useEffect(() => { + if (syncData) { + setSync(syncData?.getSync) + if (!syncingFromBlock) setSyncingFromBlock(syncData?.getSync?.lastSynced) + } + }, [syncData, syncingFromBlock]) + + useEffect(() => { + if (sync) { + if (sync?.status) { + if (sync?.status?.toLocaleLowerCase().includes('syncing')) { + setIsSyncing(true) + toast.info(`${format('syncing')} ${syncingFromBlock}...`, { + position: 'bottom-right', + isLoading: true, + closeButton: false, + draggable: false, + autoClose: false, + closeOnClick: false, + toastId: 'syncing', + }) + + setTimeout(() => { + refetch() + }, 60000) + } else if (isSyncing) { + toast.dismiss() + toast.success(format('all_block_synced'), { + position: 'bottom-right', + closeOnClick: false, + toastId: 'synced', + }) + } + } + } + }, [sync, isSyncing, syncingFromBlock]) + return ( <>
diff --git a/components/SearchBar/SearchBar.tsx b/components/SearchBar/SearchBar.tsx index 85b2930..35868ac 100644 --- a/components/SearchBar/SearchBar.tsx +++ b/components/SearchBar/SearchBar.tsx @@ -16,7 +16,6 @@ function Searchbar() { } const handleKeyPress = (e: any) => { - console.log('presiona') if (e.key === 'Enter') { handleSubmit() } diff --git a/generated/index.tsx b/generated/index.tsx index b7b1f38..8e8e8d9 100644 --- a/generated/index.tsx +++ b/generated/index.tsx @@ -96,6 +96,7 @@ export type Query = { getContracts: Array; getEvent: Event; getEvents: Array; + getSync: Sync; getTransaction: Transaction; getTransactions: Array; getTransactionsByContract: Array; @@ -167,6 +168,14 @@ export type QueryGetTransactionsByContractArgs = { take?: InputMaybe; }; +export type Sync = { + __typename?: 'Sync'; + id: Scalars['Float']; + lastSynced: Scalars['Float']; + status: Scalars['String']; + timestamp: Scalars['String']; +}; + export type Transaction = { __typename?: 'Transaction'; args?: Maybe; @@ -305,6 +314,11 @@ export type DecodeEventMutationVariables = Exact<{ export type DecodeEventMutation = { __typename?: 'Mutation', decodeEvent: string }; +export type GetSyncQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetSyncQuery = { __typename?: 'Query', getSync: { __typename?: 'Sync', lastSynced: number, status: string } }; + export const GetBlocksDocument = gql` query getBlocks($skip: Int!, $take: Int!, $orderByNumber: Boolean, $orderAsc: Boolean) { @@ -935,4 +949,39 @@ export function useDecodeEventMutation(baseOptions?: Apollo.MutationHookOptions< } export type DecodeEventMutationHookResult = ReturnType; export type DecodeEventMutationResult = Apollo.MutationResult; -export type DecodeEventMutationOptions = Apollo.BaseMutationOptions; \ No newline at end of file +export type DecodeEventMutationOptions = Apollo.BaseMutationOptions; +export const GetSyncDocument = gql` + query getSync { + getSync { + lastSynced + status + } +} + `; + +/** + * __useGetSyncQuery__ + * + * To run a query within a React component, call `useGetSyncQuery` and pass it any options that fit your needs. + * When your component renders, `useGetSyncQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetSyncQuery({ + * variables: { + * }, + * }); + */ +export function useGetSyncQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(GetSyncDocument, options); + } +export function useGetSyncLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(GetSyncDocument, options); + } +export type GetSyncQueryHookResult = ReturnType; +export type GetSyncLazyQueryHookResult = ReturnType; +export type GetSyncQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/graphql/queries.ts b/graphql/queries.ts index 92d5931..8a669e4 100644 --- a/graphql/queries.ts +++ b/graphql/queries.ts @@ -210,3 +210,11 @@ export const DECODE_EVENT_MUTATION = gql` decodeEvent(contractAddress: $contractAddress, id: $id) } ` +export const GET_SYNC_QUERY = gql` + query getSync { + getSync { + lastSynced + status + } + } +` diff --git a/i18n/en.ts b/i18n/en.ts index a9c83a6..11a7199 100644 --- a/i18n/en.ts +++ b/i18n/en.ts @@ -97,4 +97,7 @@ export const en = { english: 'English', spanish: 'Spanish', + + syncing: 'Syncing from block', + all_block_synced: 'All blocks synced', } diff --git a/i18n/es.ts b/i18n/es.ts index 112ed39..23a95a8 100644 --- a/i18n/es.ts +++ b/i18n/es.ts @@ -97,4 +97,7 @@ export const es = { english: 'Inglés', spanish: 'Español', + + syncing: 'Sincronizando desde bloque', + all_block_synced: 'Todos los bloques fueron sincronizados', } From 2e9f86d9bc40dadbbca97d301481e68575437b15 Mon Sep 17 00:00:00 2001 From: Ruben Gutierrez Date: Fri, 25 Nov 2022 12:18:47 -0400 Subject: [PATCH 2/5] change logic + update tests --- __test__/components/infoCard.test.tsx | 5 ++++- components/InfoCard/InfoCard.tsx | 13 ++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/__test__/components/infoCard.test.tsx b/__test__/components/infoCard.test.tsx index 7feca06..fcbf895 100644 --- a/__test__/components/infoCard.test.tsx +++ b/__test__/components/infoCard.test.tsx @@ -23,7 +23,10 @@ jest.mock('../../generated', () => ({ useGetSyncQuery: jest.fn(() => { return { data: { - lastSynced: 100, + getSync: { + status: 'syncing', + lastSynced: 100, + }, }, refetch: jest.fn(), } diff --git a/components/InfoCard/InfoCard.tsx b/components/InfoCard/InfoCard.tsx index 463a2c5..33a4920 100644 --- a/components/InfoCard/InfoCard.tsx +++ b/components/InfoCard/InfoCard.tsx @@ -20,7 +20,6 @@ function InfoCard() { const blocks = get(data, 'getBlocks', []) as GetLastBlockQuery['getBlocks'] const { data: versionData } = useVersionQuery() const { data: syncData, refetch } = useGetSyncQuery() - const [sync, setSync] = useState() const [isSyncing, setIsSyncing] = useState(false) const [syncingFromBlock, setSyncingFromBlock] = useState(0) const version = get(versionData, 'version', []) as VersionQuery['version'] @@ -41,15 +40,11 @@ function InfoCard() { useEffect(() => { if (syncData) { - setSync(syncData?.getSync) + const data = syncData.getSync if (!syncingFromBlock) setSyncingFromBlock(syncData?.getSync?.lastSynced) - } - }, [syncData, syncingFromBlock]) - useEffect(() => { - if (sync) { - if (sync?.status) { - if (sync?.status?.toLocaleLowerCase().includes('syncing')) { + if (data?.status) { + if (data?.status?.toLocaleLowerCase().includes('syncing') && syncingFromBlock) { setIsSyncing(true) toast.info(`${format('syncing')} ${syncingFromBlock}...`, { position: 'bottom-right', @@ -74,7 +69,7 @@ function InfoCard() { } } } - }, [sync, isSyncing, syncingFromBlock]) + }, [syncData, syncingFromBlock]) return ( <> From a12c033849fd943ab7cb3025b8c25e404598fc0b Mon Sep 17 00:00:00 2001 From: Ruben Gutierrez Date: Fri, 25 Nov 2022 16:38:23 -0400 Subject: [PATCH 3/5] improve coverage --- __test__/pages/contract-transactions.test.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/__test__/pages/contract-transactions.test.tsx b/__test__/pages/contract-transactions.test.tsx index ad96412..fc30ab9 100644 --- a/__test__/pages/contract-transactions.test.tsx +++ b/__test__/pages/contract-transactions.test.tsx @@ -1,10 +1,10 @@ import '@testing-library/jest-dom' import { fireEvent, render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import { contractTransactionsMocks } from '../../_mocks/contracts-mocks' -import ContractTransactions from '../../pages/contracts/transactions/[address]' import { IntlProvider } from 'react-intl' +import { contractTransactionsMocks } from '../../_mocks/contracts-mocks' import { messages } from '../../pages/_app' +import ContractTransactions from '../../pages/contracts/transactions/[address]' userEvent.setup() @@ -90,6 +90,14 @@ describe('Contract transactions', () => { expect(tbody.children.length).toBe(5) }) + it('should show first page', async () => { + const prevBtn = await screen.getByTestId('prev-btn') + await fireEvent.click(prevBtn) + + const tbody = await screen.getByTestId('tbody') + expect(tbody.children.length).toBe(5) + }) + it('should order by timestap', async () => { const timeHeader = await screen.getByText('Time') From bb34c5c98e41b590993ab41a7a1c90ea6849434a Mon Sep 17 00:00:00 2001 From: Ruben Gutierrez Date: Fri, 25 Nov 2022 16:46:45 -0400 Subject: [PATCH 4/5] improve coverage --- __test__/pages/blocks.test.tsx | 1 + __test__/pages/contracts.test.tsx | 1 + __test__/pages/transactions.test.tsx | 1 + 3 files changed, 3 insertions(+) diff --git a/__test__/pages/blocks.test.tsx b/__test__/pages/blocks.test.tsx index c5bc7d9..c27db9a 100644 --- a/__test__/pages/blocks.test.tsx +++ b/__test__/pages/blocks.test.tsx @@ -26,6 +26,7 @@ jest.mock('../../generated', () => ({ data: { getBlocks: getBlocks.slice(variables?.skip || 0, variables?.skip + variables?.take || 10), }, + loading: true, } }), })) diff --git a/__test__/pages/contracts.test.tsx b/__test__/pages/contracts.test.tsx index b7ed815..fec1bca 100644 --- a/__test__/pages/contracts.test.tsx +++ b/__test__/pages/contracts.test.tsx @@ -22,6 +22,7 @@ jest.mock('../../generated', () => ({ data: { getContracts: getContracts.slice(variables?.skip || 0, variables?.skip + variables?.take || 10), }, + loading: true, } }), })) diff --git a/__test__/pages/transactions.test.tsx b/__test__/pages/transactions.test.tsx index 7c66fc1..78505f1 100644 --- a/__test__/pages/transactions.test.tsx +++ b/__test__/pages/transactions.test.tsx @@ -22,6 +22,7 @@ jest.mock('../../generated', () => ({ data: { getTransactions: getTransactions.slice(variables?.skip || 0, variables?.skip + variables?.take || 10), }, + loading: true, } }), })) From 9d47cb8740896986b7120375b206d751ac2459b1 Mon Sep 17 00:00:00 2001 From: Ruben Gutierrez Date: Fri, 25 Nov 2022 16:58:49 -0400 Subject: [PATCH 5/5] update package version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d01abd0..3c6ea5e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ink-substrate-explorer-frontend", - "version": "1.0.3", + "version": "1.0.4", "description": "Ink Explorer is an application that provides Ink contracts related information on Substrate based blockchains.", "author": "Blockcoders ", "license": "MIT",