diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json index 5f8144fd4..4a47d0a5b 100644 --- a/frontend/.eslintrc.json +++ b/frontend/.eslintrc.json @@ -7,6 +7,9 @@ "react-hooks/exhaustive-deps": "warn", "@tanstack/query/exhaustive-deps": "error" }, + "parserOptions": { + "sourceType": "module" + }, "settings": { "react": { "version": "detect" diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index e2125efbf..8cae1a3fd 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -24,6 +24,7 @@ import { useCheckMobile } from './hooks/useCheckMobile'; import PositionHistory from './pages/position-history/PositionHistory'; import WithdrawAll from 'pages/spotnet/dashboard/withdraw-all/WithdrawAll'; import { DefiSpringPage } from 'pages/spotnet/defi-spring/DefiSpring'; +import { AddDeposit } from 'pages/add-deposit/AddDeposit'; function App() { const { setWalletId, removeWalletId } = useWalletStore(); @@ -100,7 +101,8 @@ function App() { } /> } /> } /> - } /> + } /> + } /> } /> } /> } /> diff --git a/frontend/src/components/layout/navigation-links/NavigationLinks.jsx b/frontend/src/components/layout/navigation-links/NavigationLinks.jsx index a5560f13f..e19b9fbda 100644 --- a/frontend/src/components/layout/navigation-links/NavigationLinks.jsx +++ b/frontend/src/components/layout/navigation-links/NavigationLinks.jsx @@ -7,10 +7,14 @@ const NavigationLinks = ({ onNavClick }) => ( (isActive ? 'active-link' : '')} onClick={onNavClick}> Home -
+
(isActive ? 'active-link' : '')} onClick={onNavClick}> Dashboard +
+ (isActive ? 'active-link' : '')} onClick={onNavClick}> + Form + {/*
*/} {/* (isActive ? 'active-link' : '')} onClick={onNavClick}> */} {/* Vault */} diff --git a/frontend/src/components/ui/token-selector/TokenSelector.jsx b/frontend/src/components/ui/token-selector/TokenSelector.jsx index f8e7ec04b..46c067558 100644 --- a/frontend/src/components/ui/token-selector/TokenSelector.jsx +++ b/frontend/src/components/ui/token-selector/TokenSelector.jsx @@ -2,6 +2,7 @@ import React from 'react'; import { ReactComponent as ETH } from 'assets/icons/ethereum.svg'; import { ReactComponent as USDC } from 'assets/icons/borrow_usdc.svg'; import { ReactComponent as STRK } from 'assets/icons/strk.svg'; +import './tokenSelector.css'; const Tokens = [ { id: 'ethOption', component: , label: 'ETH' }, @@ -10,27 +11,40 @@ const Tokens = [ ]; const TokenSelector = ({ selectedToken, setSelectedToken }) => { + const handleTokenChange = (token) => { + setSelectedToken(token.label); + }; + return ( -
- {Tokens.map((token) => ( -
-
- setSelectedToken(token?.label)} - /> - +
+ Select Token +
+ {Tokens.map((token) => ( +
handleTokenChange(token)} + > +
+ handleTokenChange(token)} + className="token-radio" + /> + +
-
- ))} + ))} +
); }; diff --git a/frontend/src/components/ui/token-selector/tokenSelector.css b/frontend/src/components/ui/token-selector/tokenSelector.css new file mode 100644 index 000000000..7c9634e82 --- /dev/null +++ b/frontend/src/components/ui/token-selector/tokenSelector.css @@ -0,0 +1,155 @@ +.token-selector-container { + display: flex; + flex-direction: column; + gap: 8px; +} + +.token-options { + display: flex; + justify-content: center; + align-items: center; + gap: 8px; +} + +.token-card-btn { + width: 100%; + text-align: center; + border: 1px solid var(--secondary); + border-radius: 8px; + padding: 8px; +} + +.token-card-btn.selected { + border-image: linear-gradient(to right, #74d6fd, #e01dee) 1; +} + +.token-container-deposit { + background: var(--dark-purple); + transition: background 1.3s ease; + padding: 1px; + height: 100%; +} + +.token-container:has(input[type='radio']:checked) { + background: var(--button-gradient); +} + +.token-icon-deposit { + display: flex; + align-items: center; + justify-content: center; + padding: 5px; + border-radius: 100px; + background-color: hsla(261, 49%, 15%, 1); +} + +.token-label { + display: flex; + flex-direction: column; + gap: 5px; + margin-top: 60px; +} + +.token-label input { + background-color: transparent; + border: 1px solid var(--light-purple); + border-radius: 50px; + padding: 20px 30px; + color: var(--gray); +} + +.token-select { + margin: 8px 0 8px 0; +} + +.token-amount { + margin: 20px 0 12px 0; +} + +.token-card-btn h5 { + margin-top: 9px; + font-size: 16px; + font-size: 16px; + color: var(--primary); + display: flex; + align-items: center; + justify-content: center; + gap: 6px; +} + +.token-card-btn svg { + width: 20px; + height: 20px; + width: 20px; + height: 20px; +} + +@media (max-width: 768px) { + .token-card-btn label { + width: 79.5px; + height: 36px; + padding: 4px 8px; + } +} + +.token-icon { + display: grid; + gap: 4px; +} + +.token-icon-deposit { + margin-right: 5px; + position: relative; + z-index: 1; +} + +.token-card-btn { + width: auto; + height: auto; +} + +.token-card-btn h5 { + margin: 0; + font-size: 14px; + gap: 0; +} + +.token-card-btn svg { + width: 15px; + height: 15px; +} + +.token-label input { + border-radius: 16px; + font-size: 14px; +} + +.token-container { + max-width: fit-content; + position: relative; +} + +.token-label { + margin-top: 0; +} + +.token-amount { + margin: 25px 0 12px 0; +} + +@media (min-width: 768px) { + .token-card-btn label { + width: 208.67px; + height: 40px; + padding: 4px 8px; + } +} + +input[type='radio'] { + display: none; + padding: 2px; + border: 1px solid #ccc; + border-radius: 4px; + width: 100%; + box-sizing: border-box; +} diff --git a/frontend/src/hooks/useAddDeposit.js b/frontend/src/hooks/useAddDeposit.js new file mode 100644 index 000000000..2481055a9 --- /dev/null +++ b/frontend/src/hooks/useAddDeposit.js @@ -0,0 +1,30 @@ +import { useMutation } from '@tanstack/react-query'; +import { axiosInstance } from 'utils/axios'; +import { notify } from 'components/layout/notifier/Notifier'; +import useDashboardData from './useDashboardData'; + +export const useAddDeposit = () => { + const { data: dashboardData } = useDashboardData(); + const mutation = useMutation({ + mutationFn: async ({ positionId, amount, tokenSymbol }) => { + if (!dashboardData?.position_id) { + return notify('No position found', 'error'); + } + + const { data } = await axiosInstance.post(`/api/add-extra-deposit/${positionId}`, { + position_id: dashboardData.position_id, + amount: parseFloat(amount), + token_symbol: tokenSymbol, + }); + return data; + }, + onSuccess: () => { + notify('Successfully deposited!', 'success'); + }, + onError: (error) => { + notify(error.response?.data?.message || 'Failed to process deposit', 'error'); + }, + }); + + return mutation; +}; diff --git a/frontend/src/pages/add-deposit/AddDeposit.jsx b/frontend/src/pages/add-deposit/AddDeposit.jsx new file mode 100644 index 000000000..eda7bcdb0 --- /dev/null +++ b/frontend/src/pages/add-deposit/AddDeposit.jsx @@ -0,0 +1,84 @@ +import React, { useState } from 'react'; +import { ReactComponent as HealthIcon } from 'assets/icons/health.svg'; +import { ReactComponent as EthIcon } from 'assets/icons/ethereum.svg'; +import { useAddDeposit } from 'hooks/useAddDeposit'; +import './addDeposit.css'; +import Card from 'components/ui/card/Card'; +import TokenSelector from 'components/ui/token-selector/TokenSelector'; +import { NUMBER_REGEX } from 'utils/regex'; + +export const AddDeposit = () => { + const [amount, setAmount] = useState('0'); + const [selectedToken, setSelectedToken] = useState('STRK'); + + const { mutate: addDeposit, isLoading } = useAddDeposit(); + + const handleAmountChange = (e) => { + const value = e.target.value; + if (NUMBER_REGEX.test(value)) { + setAmount(value); + } + }; + + const handleCancel = () => { + setAmount('0'); + setSelectedToken('STRK'); + }; + + const handleDeposit = () => { + addDeposit( + { + amount, + tokenSymbol: selectedToken, + }, + { + onSuccess: () => { + setAmount('0'); + setSelectedToken('STRK'); + }, + } + ); + }; + + return ( +
+
+

zkLend Deposit

+
+
+ } /> + } /> +
+
+

Pls make a deposit

+ + +
+ + + {selectedToken} + +
+ +
+ + +
+
+
+ ); +}; diff --git a/frontend/src/pages/add-deposit/addDeposit.css b/frontend/src/pages/add-deposit/addDeposit.css new file mode 100644 index 000000000..1fcdb081f --- /dev/null +++ b/frontend/src/pages/add-deposit/addDeposit.css @@ -0,0 +1,331 @@ +.deposit-wrapper { + background-size: cover; + background-position: center 39%; + min-height: 100vh; + display: flex; + justify-content: center; + align-items: flex-start; + padding: 1rem; + padding-top: 24px; + transition: all 0.2s ease-in-out; + padding-bottom: 4rem; +} + +.deposit-container { + display: flex; + flex-direction: column; + justify-content: center; + gap: 24px; + margin-left: 200px; + transition: all 0.3s ease-in-out; +} + +.deposit-title1 { + font-size: 24px; + font-weight: 600; + color: #ffffff; + text-align: center; +} + +.main-container-deposit { + width: 642px; + gap: 2px; + padding-top: 24px; + border-radius: 8px; + color: var(--primary); + text-align: center; + display: flex; + justify-content: center; + + flex-direction: column; + align-items: center; +} +.top-cards-deposit { + display: flex; + gap: 1.5rem; + width: 642px; + height: 101px; + justify-content: center; +} + +.deposit-title2 { + font-size: 20px; + font-weight: 400; + color: var(--primary); + text-align: center; + margin-top: 2rem; +} + +.card-header { + color: var(--stormy-gray); +} + +.card-icon { + margin-right: 5px; + width: 16px; + height: 16px; +} + +.main-card-deposit { + padding: 1.5rem; + height: auto; + display: flex; + flex-direction: column; + gap: 38px; + border: none; +} + +.deposit-token { + border: none; + border-radius: 8px; + background-color: white; +} + +.currency-deposit { + position: absolute; + color: var(--dark-gray); + right: 27%; + top: 18%; + transform: translateY(-50%); + opacity: 0.5; + font-size: 16px; + line-height: 20.83px; + z-index: 999999; +} + +.amount-input-deposit { + position: relative; + width: 100%; + max-width: 400px; + margin: 2rem auto; + text-align: center; + font-weight: 600; + font-size: 64px; +} + +.amount-field-deposit { + background: transparent; + border: none; + color: var(--gray); + font-size: 64px; + font-weight: 600; + outline: none; + text-align: center; + width: 100%; +} + +.amount-stack-card { + background: var(--footer-divider-bg); + border: var(--midnight-purple-border); + padding: 2rem; + border-radius: 8px; + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; +} + +.amount-stack-card-title-container { + text-align: center; + display: flex; + flex-direction: column; + align-items: center; +} + +.deposit-input-container { + padding: 8px 0; +} + +.deposit-input-title { + font-size: 16px; + color: var(--stormy-gray); + margin-bottom: 5px; +} + +.deposit-input { + width: 100%; + height: 60px; + background: transparent; + border: var(--midnight-purple-border); + border-radius: 8px; + border-radius: 8px; + padding: 16px; + color: var(--primary); + font-size: 16px; +} + +/* main card footer */ +.divider { + width: 100%; + height: 1.5px; + background: var(--footer-divider-bg); + margin: 1rem 0; +} + +.settings-fee-container { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + padding: 6px 0px 12px 0px; +} + +.fee-title { + color: var(--stormy-gray); + font-size: 12px; + font-weight: 400; +} + +.setting-circle { + width: 32px; + height: 32px; + background-color: var(--footer-divider-bg); + border-radius: 50%; + display: inline-block; + position: relative; + cursor: pointer; +} + +.setting-icon { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 16px; + height: 16px; +} + +.deposit-button::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-radius: 8px; + border-radius: 8px; + padding: 2px; + background: var(--blue-pink-gradient); + -webkit-mask: + linear-gradient(#fff 0 0) content-box, + linear-gradient(#fff 0 0); + mask: + linear-gradient(#fff 0 0) content-box, + linear-gradient(#fff 0 0); + -webkit-mask-composite: destination-out; + mask-composite: exclude; + z-index: -1; +} + +.mobile-screen-btns { + display: none; +} + +@media (max-width: 1024px) { + .deposit-container { + width: 642px; + margin-left: 0; + } +} + +@media (max-width: 768px) { + .deposit-container { + margin-left: 0px; + } + + .dep-button { + display: flex; + gap: 8px; + justify-content: center; + } + + .deposit-cancel-button { + position: relative; + font-weight: 600; + width: 167px; + height: 60px; + background: none; + color: var(--primary); + font-size: 16px; + cursor: pointer; + border-radius: 8px; + border: 1px solid; + border-color: #36294e; + border-radius: 8px; + padding: 16px 24px 16px 24px; + z-index: 1; + overflow: hidden; + } + + .deposit-button { + position: relative; + font-weight: 600; + width: 167px; + height: 60px; + background: none; + color: var(--primary); + font-size: 16px; + cursor: pointer; + border: none; + padding: 16px 24px 16px 24px; + z-index: 1; + overflow: hidden; + } +} + +@media (max-width: 680px) { + .top-cards-deposit { + width: 500px; + margin: 0px; + gap: 6px; + } + + .main-container-deposit { + width: 500px; + margin: auto; + padding-top: 0px; + } +} + +@media (max-width: 480px) { + .top-cards-deposit { + width: 380px; + /* gap: 8px; */ + height: 88px; + margin-top: -6px; + } +} + +@media (min-width: 768px) { + .deposit-button { + position: relative; + display: inline-block; + font-weight: 600; + width: 100%; + height: 60px; + background: none; + color: var(--primary); + font-size: 16px; + cursor: pointer; + border: none; + padding: 16px 24px 16px 24px; + z-index: 1; + overflow: hidden; + } + + .deposit-cancel-button { + position: relative; + display: none; + font-weight: 600; + width: 100%; + height: 60px; + background: none; + color: var(--primary); + font-size: 16px; + cursor: pointer; + border: none; + padding: 16px 24px 16px 24px; + z-index: 1; + overflow: hidden; + } +} diff --git a/frontend/src/pages/dashboard/Dashboard.jsx b/frontend/src/pages/dashboard/Dashboard.jsx index bf489ac50..fdadf825b 100644 --- a/frontend/src/pages/dashboard/Dashboard.jsx +++ b/frontend/src/pages/dashboard/Dashboard.jsx @@ -155,13 +155,13 @@ export default function Component({ telegramId }) { { id: 'deposit ', name: 'Add Deposit', - link: '/add-deposit', + link: '/dashboard/deposit', icon: depositIcon, }, { id: 'withdraw ', name: 'Withdraw All', - link: '/dashboard/withdraw-all', + link: '/dashboard/withdraw', icon: withdrawIcon, }, ]; diff --git a/frontend/src/pages/form/Form.jsx b/frontend/src/pages/form/Form.jsx index ac78fadab..9f5a595bb 100644 --- a/frontend/src/pages/form/Form.jsx +++ b/frontend/src/pages/form/Form.jsx @@ -98,7 +98,6 @@ const Form = () => {

Please submit your leverage details

- {

Estimated Health Factor Level:

{isHealthFactorLoading ? 'Loading...' : healthFactor}

-
- -
+
diff --git a/frontend/src/pages/form/form.css b/frontend/src/pages/form/form.css index e1f2c8377..e42b27e70 100644 --- a/frontend/src/pages/form/form.css +++ b/frontend/src/pages/form/form.css @@ -30,17 +30,6 @@ height: 64px; } -.token-card label { - border-radius: 100px; - padding: 2px 24px; - display: flex; - justify-content: center; - align-items: center; - background-color: var(--dark-purple); - cursor: pointer; - height: 100%; -} - .token-container { border-radius: 100px; background: var(--light-purple); @@ -49,10 +38,6 @@ height: 100%; } -.token-container:has(input[type='radio']:checked) { - background: var(--button-gradient); -} - .token-label { display: flex; flex-direction: column; @@ -77,32 +62,10 @@ font-size: 1rem; } -.token-select { - margin: 8px 0 8px 0; -} - .token-amount { margin: 20px 0 12px 0; } -.token-card h5 { - margin-top: 9px; - font-size: 16px; - font-size: 16px; - color: var(--primary); - display: flex; - align-items: center; - justify-content: center; - gap: 6px; -} - -.token-card svg { - width: 20px; - height: 20px; - width: 20px; - height: 20px; -} - .form-token { display: flex; justify-content: center; @@ -161,20 +124,6 @@ font-size: 21px; } -input[type='radio'] { - display: none; - padding: 2px; - border: 1px solid #ccc; - border-radius: 4px; - width: 100%; - box-sizing: border-box; -} - -.multiplier-item input[type='radio']:checked + label { - border-color: var(--brand); - box-shadow: 0 4px 20px var(--brand); -} - input[type='number']::-webkit-outer-spin-button, input[type='number']::-webkit-inner-spin-button { -webkit-appearance: none; @@ -204,20 +153,8 @@ input[type='number'].error { } .form-button { - width: 642px; - border: solid 5px transparent; - height: 60px; - border-radius: inherit; - font-size: 20px; - font-family: var(--text-font); - font-weight: 700; - color: var(--primary); - background-color: hsla(265, 65%, 8%, 1); -} - -.form-button-container { margin-top: 20px; - padding: 1px; + width: 100%; } .form-alert { @@ -275,22 +212,6 @@ input[type='number'].error { margin-bottom: 20px; } - .token-card { - width: auto; - height: auto; - } - - .token-card h5 { - margin: 0; - font-size: 14px; - gap: 0; - } - - .token-card svg { - width: 15px; - height: 15px; - } - .token-label input { border-radius: 16px; font-size: 14px; @@ -302,12 +223,6 @@ input[type='number'].error { padding: 4px 8px; } - .token-container { - border-radius: 12px; - max-width: fit-content; - position: relative; - } - .token-label { margin-top: 0; } diff --git a/frontend/src/utils/regex.js b/frontend/src/utils/regex.js new file mode 100644 index 000000000..1bf6dded7 --- /dev/null +++ b/frontend/src/utils/regex.js @@ -0,0 +1 @@ +export const NUMBER_REGEX = /^\d*\.?\d*$/;