diff --git a/src/App.tsx b/src/App.tsx index ddc752d..c9df7fc 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -116,6 +116,7 @@ import { NotAuthenticated } from "./ExtStates/NotAuthenticated"; import { openIndexedDB, showSaveFilePicker } from "./components/Apps/useQortalMessageListener"; import { fileToBase64 } from "./utils/fileReading"; import { handleGetFileFromIndexedDB } from "./utils/indexedDB"; +import { CoreSyncStatus } from "./components/CoreSyncStatus"; type extStates = @@ -1458,6 +1459,8 @@ function App() { }} /> )} + + ); diff --git a/src/assets/syncStatus/synced.png b/src/assets/syncStatus/synced.png new file mode 100644 index 0000000..f944bad Binary files /dev/null and b/src/assets/syncStatus/synced.png differ diff --git a/src/assets/syncStatus/synced_minting.png b/src/assets/syncStatus/synced_minting.png new file mode 100644 index 0000000..567e784 Binary files /dev/null and b/src/assets/syncStatus/synced_minting.png differ diff --git a/src/assets/syncStatus/syncing.png b/src/assets/syncStatus/syncing.png new file mode 100644 index 0000000..82d39bb Binary files /dev/null and b/src/assets/syncStatus/syncing.png differ diff --git a/src/components/CoreSyncStatus.css b/src/components/CoreSyncStatus.css new file mode 100644 index 0000000..00b03e1 --- /dev/null +++ b/src/components/CoreSyncStatus.css @@ -0,0 +1,59 @@ + .lineHeight { + line-height: 33%; + } + + .tooltip { + display: inline-block; + position: relative; + text-align: left; + } + + .tooltip .bottom { + min-width: 200px; + max-width: 250px; + top: 35px; + right: 0px; + /* transform: translate(-50%, 0); */ + padding: 10px 10px; + color: var(--black); + background-color: var(--bg-2); + font-weight: normal; + font-size: 13px; + border-radius: 8px; + position: absolute; + z-index: 99999999; + box-sizing: border-box; + box-shadow: 0 1px 8px rgba(0, 0, 0, 0.5); + border: 1px solid var(--black); + visibility: hidden; + opacity: 0; + transition: opacity 0.2s; + } + + .tooltip:hover .bottom { + visibility: visible; + opacity: 1; + z-index: 100; + } + + .tooltip .bottom i { + position: absolute; + bottom: 100%; + left: 50%; + margin-left: -12px; + width: 24px; + height: 12px; + overflow: hidden; + } + + .tooltip .bottom i::after { + content: ''; + position: absolute; + width: 12px; + height: 12px; + left: 50%; + transform: translate(-50%, 50%) rotate(45deg); + background-color: var(--white); + border: 1px solid var(--black); + box-shadow: 0 1px 8px rgba(0, 0, 0, 0.5); + } \ No newline at end of file diff --git a/src/components/CoreSyncStatus.tsx b/src/components/CoreSyncStatus.tsx new file mode 100644 index 0000000..08bd0f6 --- /dev/null +++ b/src/components/CoreSyncStatus.tsx @@ -0,0 +1,105 @@ +import React, { useEffect, useState } from 'react'; +import syncedImg from '../assets/syncStatus/synced.png' +import syncedMintingImg from '../assets/syncStatus/synced.png' +import syncingImg from '../assets/syncStatus/synced.png' +import { getBaseApiReact } from '../App'; +import './CoreSyncStatus.css' +export const CoreSyncStatus = () => { + const [nodeInfos, setNodeInfos] = useState({}); + const [coreInfos, setCoreInfos] = useState({}); + const [isUsingGateway, setIsUsingGateway] = useState(false); + + useEffect(() => { + const getNodeInfos = async () => { + + + try { + setIsUsingGateway(!!getBaseApiReact()?.includes('ext-node.qortal.link')) + const url = `${getBaseApiReact()}/admin/status`; + const response = await fetch(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + const data = await response.json(); + setNodeInfos(data); + } catch (error) { + console.error('Request failed', error); + } + }; + + const getCoreInfos = async () => { + + + try { + const url = `${getBaseApiReact()}/admin/info`; + const response = await fetch(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + const data = await response.json(); + setCoreInfos(data); + } catch (error) { + console.error('Request failed', error); + } + }; + + getNodeInfos(); + getCoreInfos(); + + const interval = setInterval(() => { + getNodeInfos(); + getCoreInfos(); + }, 30000); + + return () => clearInterval(interval); + }, []); + + const renderSyncStatusIcon = () => { + const { isSynchronizing = false, syncPercent = 0, isMintingPossible = false, height = 0, numberOfConnections = 0 } = nodeInfos; + const buildVersion = coreInfos?.buildVersion ? coreInfos?.buildVersion.substring(0, 12) : ''; + + let imagePath = '/img/syncing.png'; + let message = `Synchronizing` + if (isSynchronizing === true && syncPercent === 99) { + imagePath = syncedImg + } else if (isSynchronizing && !isMintingPossible && syncPercent === 100) { + imagePath = syncingImg; + message = `Synchronized (Not Minting)` + } else if (!isSynchronizing && !isMintingPossible && syncPercent === 100) { + imagePath = syncingImg; + message = `Synchronized (Not Minting)` + } else if (isSynchronizing && isMintingPossible && syncPercent === 100) { + imagePath = syncedMintingImg; + message = `Synchronized (Minting)` + } else if (!isSynchronizing && isMintingPossible && syncPercent === 100) { + imagePath = syncedMintingImg; + message = `Synchronized (Minting)` + } + + return ( +
+ sync status +
+

Core Information

+

Core Version: {buildVersion}

+

{message}

+

Block Height: {height || ''}

+

Connected Peers: {numberOfConnections || ''}

+

Using gateway: {isUsingGateway?.toString()}

+ +
+
+ ); + }; + + return ( +
+ {renderSyncStatusIcon()} +
+ ); +}; +