Skip to content

Commit

Permalink
Merge pull request #239 from wheval/fix/create-position-mobile-version
Browse files Browse the repository at this point in the history
fix: implement position for mobile screen
  • Loading branch information
djeck1432 authored Nov 26, 2024
2 parents 1da7014 + 95ed392 commit 41e9980
Show file tree
Hide file tree
Showing 13 changed files with 676 additions and 1,000 deletions.
463 changes: 14 additions & 449 deletions frontend/package-lock.json

Large diffs are not rendered by default.

Binary file added frontend/public/mobilebackground.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions frontend/src/assets/icons/slider_thumb.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion frontend/src/assets/icons/strk.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 28 additions & 10 deletions frontend/src/components/BalanceCards.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { ReactComponent as STRK } from '../assets/icons/strk.svg';
import { ReactComponent as DAI } from '../assets/icons/dai.svg';
import { useMatchMedia } from 'hooks/useMatchMedia';
import { getBalances } from '../services/wallet';
import useScrollTracker from 'hooks/useScrollTracker';
import PaginationDots from './PaginationDots';

const BalanceCards = ({ walletId }) => {
const [balances, setBalances] = useState([
Expand All @@ -15,37 +17,53 @@ const BalanceCards = ({ walletId }) => {
]);

const isMobile = useMatchMedia('(max-width: 768px)');
const { scrollRef, activeIndex, setActiveIndex } = useScrollTracker();

const handleDotClick = (index) => {
setActiveIndex(index);
const balanceContainer = scrollRef.current;
const containerWidth = balanceContainer.offsetWidth;
const scrollAmount = index * containerWidth;

balanceContainer.scrollTo({ left: scrollAmount, behavior: "smooth" });
};


useEffect(() => {
getBalances(walletId, setBalances);
}, [walletId]);

return (
<div className="balance-container">
<div className='balance-card'>
<div className="balance-container" ref={scrollRef}>
{balances.map((balance) =>
isMobile ? (
<div className="balance-item" key={balance.title}>
<label htmlFor="icon" className="balance-title">
{balance.icon}
</label>
<div className="title-container">
<label htmlFor={balance.title}>{balance.title} Balance:</label>
<label htmlFor={balance.title}>{balance.balance}</label>
<label htmlFor="icon" className="balance-title">
<span className="token-icon">{balance.icon}</span>
</label>
<label htmlFor={balance.title}>{balance.title} Balance</label>
</div>
<label htmlFor={balance.title}>{balance.balance}</label>
</div>
) : (
<div className="balance-item" key={balance.title}>
<label htmlFor={balance.title} className={'balance-title'}>
<p className='balance-icon-wrapper'>
{balance.icon}
</p>
<span>{balance.title} Balance</span>
<span className="token-icon blend">{balance.icon}</span>
{balance.title} Balance
</label>
<label htmlFor={balance.title}>{balance.balance}</label>
</div>
)
)}
</div>
<PaginationDots
balances={balances}
activeIndex={activeIndex}
onDotClick={handleDotClick}
/>
</div>
);
};

Expand Down
183 changes: 125 additions & 58 deletions frontend/src/components/MultiplierSelector.jsx
Original file line number Diff line number Diff line change
@@ -1,75 +1,142 @@
import React, { useState, useCallback, useMemo } from 'react';
import React, { useMemo, useCallback, useState, useRef, useEffect } from 'react';
import { useMaxMultiplier } from 'hooks/useMaxMultiplier';
import sliderThumb from '../assets/icons/slider_thumb.svg';
import './multiplier.css';

const MultiplierSelector = ({ min = 0, max = 10, step = 1, defaultValue = 1, setSelectedMultiplier, selectedToken }) => {
const { data, isLoading, error } = useMaxMultiplier();
const [value, setValue] = useState(defaultValue);
const MultiplierSelector = ({ setSelectedMultiplier, selectedToken }) => {
const { data, isLoading, error } = useMaxMultiplier();
const [actualValue, setActualValue] = useState(1.0);
const sliderRef = useRef(null);
const isDragging = useRef(false);

const maxMultiplier = useMemo(() => {
return Math.round(parseFloat((data?.[selectedToken]))) || 5.0;
}, [data, selectedToken]);

const maxMultiplier = useMemo(() => {
return data?.[selectedToken] || 11.0;
}, [data, selectedToken]);

const handleMultiplierChange = useCallback((e) => {
setValue(Number(e.target.value));
setSelectedMultiplier(value);
}, [setSelectedMultiplier, value]);
const mapSliderToValue = useCallback(
(sliderPosition) => {
const value = sliderPosition ;
return Math.max(1, Math.min(maxMultiplier, value));
},
[maxMultiplier]
);

const steps = Array.from(
{ length: Math.floor((max - min) / step) + 1 },
(_, i) => min + (i * step)
);
const calculateSliderPercentage = useCallback(
(value) => Math.min(((value - 1) / (maxMultiplier - 1)) * 100, 100),
[maxMultiplier]
);

console.log(maxMultiplier);
const TOTAL_MARKS = 11;
const updateSliderValue = useCallback(
(clientX) => {
const slider = sliderRef.current;
if (!slider) return;

const getTrackPercentage = useCallback(() => {
return ((value - min + 0.15) / (max - min + 0.25)) * 100;
}, [value, min, max]);
const rect = slider.getBoundingClientRect();
const x = Math.max(0, Math.min(clientX - rect.left, rect.width));
const position = Math.round((x / rect.width) * (maxMultiplier - 1) + 1);
const newValue = mapSliderToValue(position);

if (isLoading) return <div className="slider-skeleton">Loading multiplier data...</div>;
if (error) return <div className="error-message">Error loading multiplier data: {error.message}</div>;
setActualValue(newValue);
setSelectedMultiplier(newValue.toFixed(1));
},
[mapSliderToValue, maxMultiplier, setSelectedMultiplier]
);

return (
<div className="step-slider-container">
<div className="slider-labels">
<span>Min</span>
<span>Max</span>
</div>
<div className="slider-wrapper">
const handleDrag = (e) => {
if (!isDragging.current) return;
const clientX = e.type.startsWith('touch') ? e.touches[0].clientX : e.clientX;
updateSliderValue(clientX);
};

const handleMouseDown = (e) => {
isDragging.current = true;
updateSliderValue(e.clientX);
};

const handleTouchStart = (e) => {
isDragging.current = true;
updateSliderValue(e.touches[0].clientX);
};

const handleDragEnd = () => {
isDragging.current = false;
};

useEffect(() => {
document.addEventListener('mousemove', handleDrag);
document.addEventListener('mouseup', handleDragEnd);
document.addEventListener('touchmove', handleDrag);
document.addEventListener('touchend', handleDragEnd);

return () => {
document.removeEventListener('mousemove', handleDrag);
document.removeEventListener('mouseup', handleDragEnd);
document.removeEventListener('touchmove', handleDrag);
document.removeEventListener('touchend', handleDragEnd);
};
}, [handleDrag]);

useEffect(() => {
if (actualValue > maxMultiplier) {
setActualValue(maxMultiplier);
setSelectedMultiplier(maxMultiplier.toFixed(2));
} else {
setSelectedMultiplier(actualValue.toFixed(2));
}
}, [maxMultiplier, actualValue, setSelectedMultiplier]);

if (isLoading) return <div className="slider-skeleton">Loading multiplier data...</div>;
if (error) return <div className="error-message">Error loading multiplier data: {error.message}</div>;

return (
<div className="multiplier-card">
<div className="slider-container">
<div className="slider-labels">
<span className="slider-label">Min</span>
<span className="slider-label">Max</span>
</div>
<div className="slider-with-tooltip">
<div className="multiplier-slider-container">
<div
className="slider"
ref={sliderRef}
onMouseDown={handleMouseDown}
onTouchStart={handleTouchStart}
>
<div className="slider-track">
<div
className="slider-track-fill"
style={{ 'width': `${getTrackPercentage()}%` }}
/>
<input
type="range"
min={min}
max={max}
step={step}
value={value}
onChange={handleMultiplierChange}
className="step-slider"
/>
<div className="step-markers">
{steps.map((stepValue) => (
<div
key={stepValue}
className={`step-mark ${stepValue === value ? 'active' : ''}`}
/>
))}
</div>
<div className="step-multipliers">
{Array.from({ length: TOTAL_MARKS }).map((_, index) => (
<div
key={index}
className={`step-multiplier ${index === value ? 'active' : ''}`}
>x{index}</div>
))}
</div>
className="slider-range"
style={{
width: `${calculateSliderPercentage(actualValue)}%`,
}}
></div>
</div>
<div
className="slider-thumb"
style={{
left: `${calculateSliderPercentage(actualValue)}%`,
}}
>
<img src={sliderThumb} alt="slider thumb" draggable="false" />
</div>
</div>
</div>
<div className="mark-container">
{Array.from({ length: maxMultiplier}, (_, i) => i + 1).map((mark) => (
<div
key={mark}
className={`mark-item ${mark === actualValue ? 'active' : ''}`}
>
<div className="marker" />
<span className="mark-label">{`x${mark}`}</span>
</div>
))}
</div>
</div>
);
</div>
</div>
);
};

export default MultiplierSelector;
18 changes: 18 additions & 0 deletions frontend/src/components/PaginationDots.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const PaginationDots = ({ balances, activeIndex, onDotClick }) => {
const numberOfDots = Math.ceil(balances.length / 2);

return (
<div className="pagination">
{Array.from({ length: numberOfDots }).map((_, index) => (
<div
key={index}
className={`dot ${activeIndex === index ? "active" : ""}`}
onClick={() => onDotClick(index)}
></div>
))}
</div>
);
};

export default PaginationDots;

42 changes: 21 additions & 21 deletions frontend/src/components/TokenSelector.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,30 @@ const Tokens = [
{ id: 'daiOption', component: <DAI />, label: 'DAI' },
];

const TokenSelector = ({ setSelectedToken, currentToken }) => {
const handleSelectedToken = (token) => {
setSelectedToken(token);
}
return (
<div className="form-token">
{Tokens.map((token) => (
<div className="token-card flex" key={token.id}>
<input
type="radio"
id={token.id}
name="token-options"
value={token.label}
onChange={() => handleSelectedToken(token.label)}
/>
<label htmlFor={token.id} className={token.label === currentToken ? 'strk-token' : ''}>

const TokenSelector = ({ selectedToken, setSelectedToken }) => {

return <div className='form-token'>
{Tokens.map((token) => (
<div className='token-card' key={token?.id}>
<div className="token-container">
<input
type='radio'
id={token.id}
checked={selectedToken === token.label}
name='token-options'
value={token.label}
onChange={() => setSelectedToken(token?.label)}
/>
<label htmlFor={token?.id}>
<h5>
<span className='token'>{token.component}</span> {token.label}
<span className="token-icon">{token?.component}</span> {token?.label}
</h5>
</label>
</div>
))}
</div>
)
</div>
))}
</div>
};

export default TokenSelector;
export default TokenSelector;
Loading

0 comments on commit 41e9980

Please sign in to comment.