diff --git a/frontend/src/components/MultiplierSelector.jsx b/frontend/src/components/MultiplierSelector.jsx index e439c01b..5ba11bf4 100644 --- a/frontend/src/components/MultiplierSelector.jsx +++ b/frontend/src/components/MultiplierSelector.jsx @@ -4,28 +4,45 @@ import sliderThumb from '../assets/icons/slider_thumb.svg'; import './multiplier.css'; const MultiplierSelector = ({ setSelectedMultiplier, selectedToken }) => { + const minMultiplier = 1.1; + const { data, isLoading, error } = useMaxMultiplier(); - const [actualValue, setActualValue] = useState(1.0); + const [actualValue, setActualValue] = useState(minMultiplier); const sliderRef = useRef(null); const isDragging = useRef(false); const maxMultiplier = useMemo(() => { - return Math.round(parseFloat(data?.[selectedToken])) || 5.0; + return data?.[selectedToken] || 5.0; }, [data, selectedToken]); + const marks = useMemo(() => { + const marksArray = []; + for (let i = Math.ceil(minMultiplier); i <= Math.floor(maxMultiplier); i++) { + marksArray.push(i); + } + marksArray.unshift(minMultiplier); + if (!marksArray.includes(maxMultiplier)) { + marksArray.push(maxMultiplier); + } + return marksArray; + }, [minMultiplier, maxMultiplier]); + const mapSliderToValue = useCallback( (sliderPosition) => { const rect = sliderRef.current.getBoundingClientRect(); const percentage = sliderPosition / rect.width; - const value = percentage * (maxMultiplier - 1) + 1; - return Math.max(1, Math.min(maxMultiplier, parseFloat(value.toFixed(1)))); + const value = percentage * (maxMultiplier - minMultiplier) + minMultiplier; + return Math.max(minMultiplier, Math.min(maxMultiplier, parseFloat(value.toFixed(1)))); }, - [maxMultiplier] + [maxMultiplier, minMultiplier] ); const calculateSliderPercentage = useCallback( - (value) => Math.min(((value - 1) / (maxMultiplier - 1)) * 100, 100), - [maxMultiplier] + (value) => { + const percentage = ((value - minMultiplier) / (maxMultiplier - minMultiplier)) * 100; + return Math.min(Math.max(percentage, 0), 100); + }, + [maxMultiplier, minMultiplier] ); const updateSliderValue = useCallback( @@ -40,7 +57,7 @@ const MultiplierSelector = ({ setSelectedMultiplier, selectedToken }) => { setActualValue(newValue); setSelectedMultiplier(newValue.toFixed(1)); }, - [mapSliderToValue, maxMultiplier, setSelectedMultiplier] + [mapSliderToValue, setSelectedMultiplier] ); const handleDrag = (e) => { @@ -80,9 +97,9 @@ const MultiplierSelector = ({ setSelectedMultiplier, selectedToken }) => { useEffect(() => { if (actualValue > maxMultiplier) { setActualValue(maxMultiplier); - setSelectedMultiplier(maxMultiplier.toFixed(2)); + setSelectedMultiplier(maxMultiplier.toFixed(1)); } else { - setSelectedMultiplier(actualValue.toFixed(2)); + setSelectedMultiplier(actualValue.toFixed(1)); } }, [maxMultiplier, actualValue, setSelectedMultiplier]); @@ -115,8 +132,16 @@ const MultiplierSelector = ({ setSelectedMultiplier, selectedToken }) => {
- {Array.from({ length: maxMultiplier }, (_, i) => i + 1).map((mark) => ( -
= mark && actualValue < mark + 1 ? 'active' : ''}`}> + {marks.map((mark, index) => ( +
{`x${mark}`}
diff --git a/frontend/src/components/multiplier.css b/frontend/src/components/multiplier.css index 9b7c4c87..16559c8c 100644 --- a/frontend/src/components/multiplier.css +++ b/frontend/src/components/multiplier.css @@ -70,14 +70,10 @@ border-color: #2c5475 transparent transparent transparent; } -.multiplier-slider-container { - margin: 15px 1px -10px 8px; - width: 97%; -} - .slider-with-tooltip { + margin: 15px 1px -10px 15px; position: relative; - width: 100%; + width: 96%; } .error-message { @@ -154,9 +150,18 @@ div.marker { /* Mobile */ @media (max-width: 768px) { .multiplier-slider-container { - margin: 10px 0px -10px 0; + margin: 10px 0px 0; width: 100%; - padding: 0px 9px; + padding: 0px; + } + + .slider-with-tooltip { + margin-left: 10px; + width: 94%; + } + + .mark-container { + margin-top: 10px; } .slider-container { diff --git a/frontend/src/components/ui/Button/button.css b/frontend/src/components/ui/Button/button.css index abab8400..3f39a7e5 100644 --- a/frontend/src/components/ui/Button/button.css +++ b/frontend/src/components/ui/Button/button.css @@ -40,12 +40,17 @@ color: white; padding: 16px 24px 16px 24px; background: linear-gradient(73.48deg, #e01dee 1.13%, #49abd2 51.27%); + transition: all 1 ease; } .button--primary:active { transform: translateY(1px); } +.button--primary:hover:not(:disabled) { + background: linear-gradient(73.48deg, #49abd2 1.13%, #e01dee 51.27%); +} + .button--secondary { position: relative; display: inline-block; diff --git a/frontend/src/hooks/useClosePosition.js b/frontend/src/hooks/useClosePosition.js index 287a4e4c..859cbfe2 100644 --- a/frontend/src/hooks/useClosePosition.js +++ b/frontend/src/hooks/useClosePosition.js @@ -30,7 +30,6 @@ export const useCheckPosition = () => { queryFn: async () => { if (!walletId) return { has_opened_position: false }; - console.log(walletId); const { data } = await axiosInstance.get('/api/has-user-opened-position', { params: { wallet_id: walletId }, }); diff --git a/frontend/src/hooks/useMaxMultiplier.js b/frontend/src/hooks/useMaxMultiplier.js index c81ca1ac..cc03e540 100644 --- a/frontend/src/hooks/useMaxMultiplier.js +++ b/frontend/src/hooks/useMaxMultiplier.js @@ -1,14 +1,12 @@ import { useQuery } from '@tanstack/react-query'; -import axios from 'axios'; import { ONE_HOUR_IN_MILLISECONDS } from '../utils/constants'; - -const backendUrl = process.env.REACT_APP_BACKEND_URL || 'http://0.0.0.0:8000'; +import { axiosInstance } from 'utils/axios'; export const useMaxMultiplier = () => { const { data, isPending, error } = useQuery({ queryKey: ['max-multiplier'], queryFn: async () => { - const response = await axios.get(`${backendUrl}/api/get-multipliers`); + const response = await axiosInstance.get(`/api/get-multipliers`); return response.data.multipliers; }, staleTime: ONE_HOUR_IN_MILLISECONDS, diff --git a/frontend/src/pages/forms/form.css b/frontend/src/pages/forms/form.css index 8f6aed46..034f79c3 100644 --- a/frontend/src/pages/forms/form.css +++ b/frontend/src/pages/forms/form.css @@ -68,6 +68,7 @@ display: flex; flex-direction: column; gap: 5px; + margin-top: 60px; } .token-label input { @@ -470,6 +471,12 @@ input[type='number'].error { .dot.active { background-color: var(--light-blue); } + + @media (max-width: 768px) { + .token-label { + margin-top: 0; + } + } } @media (max-width: 480px) { diff --git a/frontend/src/pages/spotnet/dashboard/Dashboard.jsx b/frontend/src/pages/spotnet/dashboard/Dashboard.jsx index 4749780e..0ec61a56 100644 --- a/frontend/src/pages/spotnet/dashboard/Dashboard.jsx +++ b/frontend/src/pages/spotnet/dashboard/Dashboard.jsx @@ -12,7 +12,7 @@ import { TrendingDown, TrendingUp } from 'lucide-react'; import Spinner from 'components/spinner/Spinner'; // import { ZETH_ADDRESS } from 'utils/constants'; import useDashboardData from 'hooks/useDashboardData'; -import { useClosePosition } from 'hooks/useClosePosition'; +import { useClosePosition, useCheckPosition } from 'hooks/useClosePosition'; import Button from 'components/ui/Button/Button'; import { useWalletStore } from 'stores/useWalletStore'; import { ActionModal } from 'components/ui/ActionModal'; @@ -30,8 +30,11 @@ export default function Component({ telegramId }) { isLoading: false, }; const { mutate: closePositionEvent, isLoading: isClosing, error: closePositionError } = useClosePosition(walletId); + const { data: positionData } = useCheckPosition(); const { subscribe } = useTelegramNotification(); + const hasOpenedPosition = positionData?.has_opened_position; + const handleSubscribe = () => subscribe({ telegramId, walletId }); const [cardData, setCardData] = useState([ @@ -243,12 +246,12 @@ export default function Component({ telegramId }) { size="lg" className="dashboard-btn" onClick={() => closePositionEvent()} - disabled={isClosing} + disabled={isClosing || !hasOpenedPosition} > {isClosing ? 'Closing...' : 'Redeem'} - {closePositionError &&
Error: {closePositionError.message}
} + {closePositionError &&
Error: {closePositionError.message}
}