diff --git a/frontend/jest.config.js b/frontend/jest.config.js index d704a6fd..bb18538e 100644 --- a/frontend/jest.config.js +++ b/frontend/jest.config.js @@ -5,6 +5,7 @@ module.exports = { }, moduleNameMapper: { '\\.svg$': '/test/__mocks__/svgMock.js', + '\\.css$': '/test/__mocks__/styleMock.js', '^src/(.*)$': ['/src/$1'], }, transformIgnorePatterns: [ diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 07c236a6..6aca0e2f 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -13,14 +13,13 @@ import { getTelegramUserWalletId } from 'services/telegram'; import Documentation from 'pages/spotnet/documentation/Documentation'; import Withdraw from 'pages/vault/withdraw/Withdraw'; import { useWalletStore } from 'stores/useWalletStore'; -import { Notifier } from 'components/Notifier/Notifier'; +import { Notifier, notify } from 'components/Notifier/Notifier'; import { useConnectWallet } from 'hooks/useConnectWallet'; import OverviewPage from 'pages/spotnet/overview/Overview'; import { ActionModal } from 'components/ui/ActionModal'; import Stake from 'pages/vault/stake/Stake'; import { TELEGRAM_BOT_LINK } from 'utils/constants'; import { useCheckMobile } from 'hooks/useCheckMobile'; -import { notifyError } from 'utils/notification'; import PositionHistory from 'pages/spotnet/position_history/PositionHistory'; @@ -72,7 +71,7 @@ function App() { }) .catch((error) => { console.error('Error getting Telegram user wallet ID:', error); - notifyError('Error loading wallet'); + notify('Error loading wallet', "error"); window.Telegram.WebApp.ready(); }); } diff --git a/frontend/src/components/LendingForm.js b/frontend/src/components/LendingForm.js index 3289f18c..d2749392 100644 --- a/frontend/src/components/LendingForm.js +++ b/frontend/src/components/LendingForm.js @@ -1,10 +1,10 @@ import React, { useCallback, useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { getTokenBalances, sendTransaction } from 'services/wallet'; -import { notifyError } from 'utils/notification'; import { axiosInstance } from 'utils/axios'; import Button from 'components/ui/Button/Button'; import { useWalletStore } from 'stores /useWalletStore'; +import { notify } from './Notifier/Notifier'; const LendingForm = () => { @@ -29,7 +29,7 @@ const navigate = useNavigate(); setBalances(tokenBalances); } catch (error) { console.error('Failed to fetch balances:', error); - notifyError('Failed to fetch token balances. Please try again.'); + notify('Failed to fetch token balances. Please try again.', "error"); } }, [walletId]); diff --git a/frontend/src/components/MultiplierSelector.jsx b/frontend/src/components/MultiplierSelector.jsx index 5ba11bf4..82dac369 100644 --- a/frontend/src/components/MultiplierSelector.jsx +++ b/frontend/src/components/MultiplierSelector.jsx @@ -6,7 +6,7 @@ import './multiplier.css'; const MultiplierSelector = ({ setSelectedMultiplier, selectedToken }) => { const minMultiplier = 1.1; - const { data, isLoading, error } = useMaxMultiplier(); + const { data, isLoading } = useMaxMultiplier(); const [actualValue, setActualValue] = useState(minMultiplier); const sliderRef = useRef(null); const isDragging = useRef(false); @@ -104,7 +104,6 @@ const MultiplierSelector = ({ setSelectedMultiplier, selectedToken }) => { }, [maxMultiplier, actualValue, setSelectedMultiplier]); if (isLoading) return
Loading multiplier data...
; - if (error) return
Error loading multiplier data: {error.message}
; return (
diff --git a/frontend/src/components/Notifier/Notifier.jsx b/frontend/src/components/Notifier/Notifier.jsx index ea6a3573..6072e57c 100644 --- a/frontend/src/components/Notifier/Notifier.jsx +++ b/frontend/src/components/Notifier/Notifier.jsx @@ -2,14 +2,27 @@ import React from 'react'; import { ToastContainer, toast } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; -const notify = (message) => toast(message); +const defaultStyles = { + success: { backgroundColor: 'green', color: 'white' }, + error: { backgroundColor: 'red', color: 'white' }, + warning: { backgroundColor: 'orange', color: 'white' }, + info: { backgroundColor: 'blue', color: 'white' }, +}; + +const ToastWithLink = (message, link, linkMessage) => ( +
+ {message} {linkMessage} +
+); + +const notify = (message, type='info', autoClose=3000) => toast(message, { type, autoClose, style: defaultStyles[type] || defaultStyles.info }); const Notifier = () => { return (
- +
); }; -export { Notifier, notify }; +export { Notifier, notify, ToastWithLink}; diff --git a/frontend/src/components/SlideBarFour.jsx b/frontend/src/components/SlideBarFour.jsx index afb5aa54..f40e0f8c 100644 --- a/frontend/src/components/SlideBarFour.jsx +++ b/frontend/src/components/SlideBarFour.jsx @@ -1,6 +1,7 @@ import React, { useState, useCallback, useMemo } from 'react'; import { useMaxMultiplier } from 'hooks/useMaxMultiplier'; import './slider-three.css'; +import { notify } from 'components/Notifier/Notifier'; const StepSlider = ({ min = 0, max = 10, step = 1, defaultValue = 1, setSelectedMultiplier, selectedToken }) => { const { data, isLoading, error } = useMaxMultiplier(); @@ -34,7 +35,7 @@ const StepSlider = ({ min = 0, max = 10, step = 1, defaultValue = 1, setSelected }, [value, maxMultiplier, TOTAL_MARKS]); if (isLoading) return
Loading multiplier data...
; - if (error) return
Error loading multiplier data: {error.message}
; + if (error) return notify(error.message, 'error'); const currentMark = getCurrentMark(); diff --git a/frontend/src/components/WalletSection.jsx b/frontend/src/components/WalletSection.jsx index 0dc94869..394562dd 100644 --- a/frontend/src/components/WalletSection.jsx +++ b/frontend/src/components/WalletSection.jsx @@ -74,7 +74,7 @@ const WalletSection = ({ onConnectWallet, onLogout }) => { onLogout(); }} > - Log out + Disconnect
)} diff --git a/frontend/src/components/collateral/Collateral.jsx b/frontend/src/components/collateral/Collateral.jsx index ef50530e..7714705e 100644 --- a/frontend/src/components/collateral/Collateral.jsx +++ b/frontend/src/components/collateral/Collateral.jsx @@ -14,7 +14,7 @@ function Collateral({ data, startSum, currentSum, getCurrentSumColor }) { {data[0]?.currencyName || 'N/A'} - Balance: + Position Balance: {data[0]?.balance ? Number(data[0].balance).toFixed(8) : '0.00'} diff --git a/frontend/src/hooks/useClosePosition.js b/frontend/src/hooks/useClosePosition.js index 859cbfe2..8df35d34 100644 --- a/frontend/src/hooks/useClosePosition.js +++ b/frontend/src/hooks/useClosePosition.js @@ -2,6 +2,7 @@ import { useMutation, useQuery } from '@tanstack/react-query'; import { axiosInstance } from 'utils/axios'; import { closePosition } from 'services/transaction'; import { useWalletStore } from 'stores/useWalletStore'; +import { notify } from 'components/Notifier/Notifier'; export const useClosePosition = () => { const { walletId } = useWalletStore(); @@ -18,6 +19,7 @@ export const useClosePosition = () => { }, onError: (error) => { console.error('Error during closePositionEvent', error); + notify(`Error during closePositionEvent: ${error.message}`, 'error') }, }); }; diff --git a/frontend/src/hooks/useConnectWallet.js b/frontend/src/hooks/useConnectWallet.js index 61e7519a..576ffff9 100644 --- a/frontend/src/hooks/useConnectWallet.js +++ b/frontend/src/hooks/useConnectWallet.js @@ -1,6 +1,6 @@ import { useMutation } from '@tanstack/react-query'; +import { notify } from 'components/Notifier/Notifier'; import { connectWallet, checkForCRMToken } from 'services/wallet'; -import { notifyError } from 'utils/notification'; export const useConnectWallet = (setWalletId) => { return useMutation({ @@ -22,7 +22,7 @@ export const useConnectWallet = (setWalletId) => { }, onError: (error) => { console.error('Wallet connection failed:', error); - notifyError('Failed to connect wallet. Please try again.'); + notify('Failed to connect wallet. Please try again.', "error"); }, }); }; \ No newline at end of file diff --git a/frontend/src/hooks/useMaxMultiplier.js b/frontend/src/hooks/useMaxMultiplier.js index cc03e540..3d8f7eeb 100644 --- a/frontend/src/hooks/useMaxMultiplier.js +++ b/frontend/src/hooks/useMaxMultiplier.js @@ -1,9 +1,10 @@ import { useQuery } from '@tanstack/react-query'; import { ONE_HOUR_IN_MILLISECONDS } from '../utils/constants'; import { axiosInstance } from 'utils/axios'; +import { notify } from 'components/Notifier/Notifier'; export const useMaxMultiplier = () => { - const { data, isPending, error } = useQuery({ + const { data, isPending } = useQuery({ queryKey: ['max-multiplier'], queryFn: async () => { const response = await axiosInstance.get(`/api/get-multipliers`); @@ -11,7 +12,8 @@ export const useMaxMultiplier = () => { }, staleTime: ONE_HOUR_IN_MILLISECONDS, refetchInterval: ONE_HOUR_IN_MILLISECONDS, + onError: (error) => notify(`Error using multiplier: ${error.message}`, 'error') }); - return { data, isLoading: isPending, error }; + return { data, isLoading: isPending }; }; diff --git a/frontend/src/hooks/useTelegramNotification.js b/frontend/src/hooks/useTelegramNotification.js index ec0e51b5..883261b7 100644 --- a/frontend/src/hooks/useTelegramNotification.js +++ b/frontend/src/hooks/useTelegramNotification.js @@ -1,6 +1,6 @@ import { useMutation } from "@tanstack/react-query"; import { subscribeToNotification, generateTelegramLink } from "services/telegram"; -import { notifyError, notifySuccess } from "utils/notification"; +import { notify } from "components/Notifier/Notifier"; const useTelegramNotification = () => { const mutation = useMutation({ @@ -14,10 +14,10 @@ const useTelegramNotification = () => { return await subscribeToNotification(telegramId, walletId); }, onSuccess: () => { - notifySuccess("Subscribed to notifications successfully!"); + notify("Subscribed to notifications successfully!", "success"); }, onError: (error) => { - notifyError(error?.message || "Failed to subscribe. Please try again."); + notify(error?.message || "Failed to subscribe. Please try again.", "error"); }, }); diff --git a/frontend/src/pages/forms/Form.jsx b/frontend/src/pages/forms/Form.jsx index 8a0d817f..659f4d73 100644 --- a/frontend/src/pages/forms/Form.jsx +++ b/frontend/src/pages/forms/Form.jsx @@ -7,7 +7,6 @@ import BalanceCards from 'components/BalanceCards'; import MultiplierSelector from 'components/MultiplierSelector'; import { handleTransaction } from 'services/transaction'; import Spinner from 'components/spinner/Spinner'; -import { ReactComponent as AlertHexagon } from 'assets/icons/alert_hexagon.svg'; import './form.css'; import { createPortal } from 'react-dom'; import useLockBodyScroll from 'hooks/useLockBodyScroll'; @@ -19,6 +18,7 @@ import { useCheckPosition } from 'hooks/useClosePosition'; import { useNavigate } from 'react-router-dom'; import { ActionModal } from 'components/ui/ActionModal'; import { useHealthFactor } from 'hooks/useHealthRatio'; +import { notify } from 'components/Notifier/Notifier'; const Form = () => { const navigate = useNavigate(); @@ -26,9 +26,7 @@ const Form = () => { const [tokenAmount, setTokenAmount] = useState(''); const [selectedToken, setSelectedToken] = useState('ETH'); const [selectedMultiplier, setSelectedMultiplier] = useState(''); - const [error, setError] = useState(''); const [loading, setLoading] = useState(false); - const [alertMessage, setAlertMessage] = useState(''); const [successful, setSuccessful] = useState(false); useLockBodyScroll(successful); @@ -70,19 +68,17 @@ const Form = () => { } if (tokenAmount === '' || selectedToken === '' || selectedMultiplier === '') { - setAlertMessage('Please fill the form'); + notify("Please fill the form", 'error') return; } - setAlertMessage(''); - const formData = { wallet_id: connectedWalletId, token_symbol: selectedToken, amount: tokenAmount, multiplier: selectedMultiplier, }; - await handleTransaction(connectedWalletId, formData, setError, setTokenAmount, setLoading, setSuccessful); + await handleTransaction(connectedWalletId, formData, setTokenAmount, setLoading, setSuccessful); }; const handleCloseModal = () => { @@ -117,11 +113,6 @@ const Form = () => {

Please submit your leverage details

- {alertMessage && ( -

- {alertMessage} -

- )} @@ -132,13 +123,11 @@ const Form = () => { />
- {error &&

{error}

} setTokenAmount(e.target.value)} - className={error ? 'error' : ''} />
diff --git a/frontend/src/pages/spotnet/dashboard/Dashboard.jsx b/frontend/src/pages/spotnet/dashboard/Dashboard.jsx index 5a4475ec..ce6a7304 100644 --- a/frontend/src/pages/spotnet/dashboard/Dashboard.jsx +++ b/frontend/src/pages/spotnet/dashboard/Dashboard.jsx @@ -12,7 +12,6 @@ import Button from 'components/ui/Button/Button'; import { useWalletStore } from 'stores/useWalletStore'; import { ActionModal } from 'components/ui/ActionModal'; import useTelegramNotification from 'hooks/useTelegramNotification'; -import { ReactComponent as AlertHexagon } from 'assets/icons/alert_hexagon.svg'; import Borrow from 'components/borrow/Borrow'; import { ReactComponent as CollateralIcon } from 'assets/icons/collateral_dynamic.svg'; import Collateral from 'components/collateral/Collateral'; @@ -30,7 +29,7 @@ export default function Component({ telegramId }) { data: { health_ratio: '1.5', current_sum: '0.05', start_sum: '0.04', borrowed: '10.0' }, isLoading: false, }; - const { mutate: closePositionEvent, isLoading: isClosing, error: closePositionError } = useClosePosition(walletId); + const { mutate: closePositionEvent, isLoading: isClosing } = useClosePosition(walletId); const { data: positionData } = useCheckPosition(); const { subscribe } = useTelegramNotification(); @@ -189,11 +188,6 @@ export default function Component({ telegramId }) { > {isClosing ? 'Closing...' : 'Redeem'} - {closePositionError && ( -
- Error: {closePositionError.message} -
- )}