import * as Uebersicht from "uebersicht"; import * as DataWidget from "./data-widget.jsx"; import * as DataWidgetLoader from "./data-widget-loader.jsx"; import * as Icons from "../icons/icons.jsx"; import useWidgetRefresh from "../../hooks/use-widget-refresh"; import useServerSocket from "../../hooks/use-server-socket"; import { useSimpleBarContext } from "../simple-bar-context.jsx"; import * as Utils from "../../utils"; export { cryptoStyles as styles } from "../../styles/components/data/crypto"; const { React } = Uebersicht; const DEFAULT_REFRESH_FREQUENCY = 5 * 60 * 1000; // Default refresh frequency set to 5 minutes /** * Crypto Widget Component * @returns {JSX.Element|null} The Crypto Widget component */ export const Widget = React.memo(() => { const { displayIndex, settings, pushMissive } = useSimpleBarContext(); const { widgets, cryptoWidgetOptions } = settings; const { cryptoWidget } = widgets; const { refreshFrequency, denomination, identifiers, precision, showOnDisplay, showIcon, } = cryptoWidgetOptions; // Calculate the refresh frequency using the provided or default value const refresh = React.useMemo( () => Utils.getRefreshFrequency(refreshFrequency, DEFAULT_REFRESH_FREQUENCY), [refreshFrequency], ); // Determine if the widget should be visible on the current display const visible = Utils.isVisibleOnDisplay(displayIndex, showOnDisplay) && cryptoWidget; const ref = React.useRef(); const denominatorToken = getDenominatorToken(denomination); // Memoize cleanedUpIdentifiers to prevent recreation on every render const cleanedUpIdentifiers = React.useMemo( () => identifiers.replace(/ /g, ""), [identifiers], ); // Memoize enumeratedIdentifiers to prevent recreation on every render const enumeratedIdentifiers = React.useMemo( () => cleanedUpIdentifiers.replace(/ /g, "").split(","), [cleanedUpIdentifiers], ); const [state, setState] = React.useState(); const [loading, setLoading] = React.useState(visible); // Reset the widget state const resetWidget = () => { setState(undefined); setLoading(false); }; /** * Fetches cryptocurrency prices from the CoinGecko API */ const getCrypto = React.useCallback(async () => { if (!visible) return; const response = await fetch( `https://api.coingecko.com/api/v3/simple/price?ids=${cleanedUpIdentifiers}&vs_currencies=${denomination}`, ); const result = await response.json(); const prices = enumeratedIdentifiers.map((id) => { const value = parseFloat(result[id][denomination]).toFixed(precision); return `${denominatorToken}${value}`; }); setState(prices); setLoading(false); }, [ visible, cleanedUpIdentifiers, denomination, enumeratedIdentifiers, precision, denominatorToken, ]); useServerSocket("crypto", visible, getCrypto, resetWidget, setLoading); useWidgetRefresh(visible, getCrypto, refresh); /** * Refreshes the cryptocurrency prices * @param {Event} e - The event object */ const refreshCrypto = (e) => { Utils.clickEffect(e); setLoading(true); getCrypto(); Utils.notification("Refreshing price from coingecko.com...", pushMissive); }; if (loading) return ; if (!state) return null; const classes = Utils.classNames("crypto"); return enumeratedIdentifiers.map((id, i) => ( openCrypto(e, pushMissive)} onRightClick={refreshCrypto} > {state[i]} )); }); Widget.displayName = "Crypto"; /** * Returns the icon component for a given cryptocurrency identifier * @param {string} identifier - The cryptocurrency identifier * @returns {JSX.Element} The icon component */ function getIcon(identifier) { if (identifier === "celo") return Icons.Celo; if (identifier === "ethereum") return Icons.Ethereum; if (identifier === "bitcoin") return Icons.Bitcoin; return Icons.Moon; } /** * Returns the symbol for a given denomination * @param {string} denomination - The denomination (e.g., "usd", "eur") * @returns {string} The symbol for the denomination */ function getDenominatorToken(denomination) { if (denomination === "usd") return "$"; if (denomination === "eur") return "€"; return ""; } /** * Opens the cryptocurrency price chart * @param {Event} e - The event object * @param {Function} pushMissive - The function to push a notification */ function openCrypto(e, pushMissive) { Utils.clickEffect(e); Utils.notification("Opening price chart from coingecko.com...", pushMissive); }