import { Box, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography, Container, FormControlLabel, FormControl, Checkbox, Link, useMediaQuery, useTheme, } from "@mui/material"; import { useLocation } from "react-router-dom"; import { useEffect, useState, useMemo, useCallback } from "react"; import useSWR from 'swr'; import ReactGA from "react-ga4"; import SettingsIcon from '@mui/icons-material/Settings'; import Modal from "../../components/Modal/Modal"; import Paper from "../../components/Paper/Paper"; import PageTitle from "../../components/PageTitle/PageTitle"; import TokenStack from "../../components/TokenStack/TokenStack"; import GhostStyledIcon from "../../components/Icon/GhostIcon"; import Chip from "../../components/Chip/Chip"; import { PrimaryButton, TertiaryButton } from "../../components/Button"; import { Tab, Tabs } from "../../components/Tabs/Tabs"; import { useTokenSymbol } from "../../hooks/tokens"; import { useLocalStorage } from "../../hooks/localstorage"; import { useUnstableProvider } from "../../hooks/ghost"; import { shorten } from "../../helpers"; import { networkAvgBlockSpeed } from "../../constants"; import EraseModal from "./EraseModal"; import SettingsModal from "./SettingsModal"; import DexViewModal from "./DexViewModal"; import StakingViewModal from "./StakingViewModal"; import BridgeInModal from "./BridgeInModal"; const HistoryItem = ({ item, chainId, config, currentTime, eraseRecord, setViewModalOpen, isSmallScreen, finalityDelay }) => { const theme = useTheme(); const isVerySmallScreen = useMediaQuery("(max-width: 450px)"); const localString = new Date(item.submitted).toLocaleString(); const { symbol: ftsoSymbol } = useTokenSymbol(chainId, "FTSO") const chainInfo = useMemo(() => { const client = config?.getClient(); return { url: client?.chain?.blockExplorers?.default?.url, symbol: client?.chain?.nativeCurrency?.symbol, }; }, [config]); const chipStatus = useMemo(() => { const delay = Number(finalityDelay * networkAvgBlockSpeed(chainId)) * 1000; const width = isVerySmallScreen ? "21px" : "100px"; if (item.submitted + delay > currentTime) { return } return }, [item, currentTime, isVerySmallScreen, finalityDelay]) if (isSmallScreen || isVerySmallScreen) { return ( <> {localString} {shorten(item.txHash)} {item?.name ?? "Unknown"} {chipStatus} Erase View ) } return ( {item?.name ?? "Unknown"} {shorten(item.txHash, 7, -5)} {chipStatus} {localString} Erase View ) } const HistoryList = ({ chainId, storedTransactions, historyType, config, eraseRecord }) => { const isSmallScreen = useMediaQuery("(max-width: 900px)"); const [currentTime, setCurrentTime] = useState(Date.now()); const [viewModalOpen, setViewModalOpen] = useState(null); const { CONSTANTS } = useLocalStorage(); const { casperApi } = useUnstableProvider(); const { data: networkData, error, isLoading } = useSWR( casperApi ? ['networkData', casperApi, chainId] : null, async () => { const key = BigInt(chainId); const res = await casperApi.query.GhostNetworks.Networks.getValue(key); return res; }, { revalidateOnFocus: true } ); const finalityDelay = useMemo(() => { return networkData ? networkData.finality_delay : 420n; }, [networkData]); useEffect(() => { const intervalId = setInterval(() => { setCurrentTime(Date.now()); }, 1000); return () => clearInterval(intervalId); }, []); const historyContainer = useMemo(() => { if (isSmallScreen) { return ( {storedTransactions?.map((item, i) => { return ( eraseRecord(i)} setViewModalOpen={() => setViewModalOpen(i)} isSmallScreen={isSmallScreen} /> ) })} ) } else { return ( Transaction Status Submitted {storedTransactions?.map((item, i) => { return ( eraseRecord(i)} setViewModalOpen={() => setViewModalOpen(i)} isSmallScreen={isSmallScreen} /> ) })}
) } }, [isSmallScreen, storedTransactions, config]); return ( <> {viewModalOpen !== null && historyType === CONSTANTS.dex.key && ( setViewModalOpen(null)} isOpen={true} historyRecord={storedTransactions.at(viewModalOpen)} /> )} {viewModalOpen !== null && historyType === CONSTANTS.stake.key && ( setViewModalOpen(null)} isOpen={true} historyRecord={storedTransactions.at(viewModalOpen)} /> )} {viewModalOpen !== null && historyType === CONSTANTS.bridgeIn.key && ( setViewModalOpen(null)} isOpen={true} historyRecord={storedTransactions.at(viewModalOpen)} /> )} {historyContainer} ) } const History = ({ chainId, config, tryConnectInjected, address }) => { const isSmallScreen = useMediaQuery("(max-width: 650px)"); const isSemiSmallScreen = useMediaQuery("(max-width: 745px)"); const isVerySmallScreen = useMediaQuery("(max-width: 379px)"); const [historyTypeIndex, setHistoryTypeIndex] = useState(0); const [erasingIndex, setErasingIndex] = useState(null); const [settingsOpen, setSettingsOpen] = useState(false); const [erasingOpen, setErasingOpen] = useState(false); const location = useLocation(); useEffect(() => { ReactGA.send({ hitType: "pageview", page: location.pathname }); }, [location]); const { CONSTANTS, useStorageValue, setStorageValue, clearPendingHistory } = useLocalStorage(); const { data: storedHistoryTypes } = useStorageValue(chainId, address, CONSTANTS.historyPrefix, CONSTANTS.defaultHistoryTypes); const { data: storedTransactions } = useStorageValue(chainId, address, storedHistoryTypes[historyTypeIndex], []); const { data: pendingHistory } = useStorageValue(chainId, address, CONSTANTS.pendingHistoryPrefix, {}); const handleHistoryTypesChange = useCallback((values) => { setStorageValue(chainId, address, CONSTANTS.historyPrefix, values); }, [chainId, address]); const handleConfirmErase = useCallback(() => { if (erasingIndex !== null) { const updated = storedTransactions.filter((_, index) => index !== erasingIndex); setStorageValue(chainId, address, storedHistoryTypes[historyTypeIndex], updated); } else { setStorageValue(chainId, address, storedHistoryTypes[historyTypeIndex], []); } setErasingOpen(false); setErasingIndex(null); }, [storedTransactions, erasingIndex, chainId, address, historyTypeIndex]); useEffect(() => { clearPendingHistory(chainId, address, storedHistoryTypes.at(historyTypeIndex)); }, [storedHistoryTypes, historyTypeIndex]) return ( { setErasingOpen(false); setErasingIndex(null); }} submit={handleConfirmErase} isAll={erasingIndex === null} /> setSettingsOpen(false)} onChange={handleHistoryTypesChange} selectedValues={storedHistoryTypes} possibleValues={CONSTANTS.possibleHistoryTypes} /> setSettingsOpen(true)} /> } headerContent={ { const index = storedHistoryTypes.indexOf(selectedValue); if (index !== -1) setHistoryTypeIndex(index); }} TabIndicatorProps={{ style: { display: "none" } }} > {storedHistoryTypes.map((type, i) => { return ( {type} {pendingHistory && pendingHistory[type] > 0 && ( )} } /> ) })} setErasingOpen(true)} sx={{ maxWidth: isSemiSmallScreen ? "100%" : "350px" }} > Erase All Records } > { setErasingIndex(index); setErasingOpen(true); }} historyType={storedHistoryTypes[historyTypeIndex]} storedTransactions={storedTransactions} /> ); } export default History;