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 (
+
+

+
+
Core Information
+ Core Version: {buildVersion}
+ {message}
+ Block Height: {height || ''}
+ Connected Peers: {numberOfConnections || ''}
+ Using gateway: {isUsingGateway?.toString()}
+
+
+
+ );
+ };
+
+ return (
+
+ {renderSyncStatusIcon()}
+
+ );
+};
+