auctions and bugs fixed about top imgs

This commit is contained in:
Arseniy Sitnikov 2024-12-13 02:46:21 +03:00
parent 07915ca426
commit 6ae11e83d6
26 changed files with 602 additions and 80 deletions

BIN
frontend/src/.DS_Store vendored

Binary file not shown.

BIN
frontend/src/shared/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -2,8 +2,6 @@ import React, { useState } from 'react';
import styles from './auctioncard.module.css'; import styles from './auctioncard.module.css';
import { ETextStyles } from '../../texts'; import { ETextStyles } from '../../texts';
import { PointsBlock } from '../../Elements/PointsBlock'; import { PointsBlock } from '../../Elements/PointsBlock';
import { PersonIcon } from '../../Elements/PersonIcon';
import { UsersIcons } from '../../Elements/UsersIcons';
import { Button } from '../../Button'; import { Button } from '../../Button';
import { EIcons } from '../../Icons'; import { EIcons } from '../../Icons';
import { Timer } from '../Timer'; import { Timer } from '../Timer';
@ -12,19 +10,23 @@ import { Slider } from '../../Elements/Slider';
import { ModalWindow } from '../../ModalWindow'; import { ModalWindow } from '../../ModalWindow';
import { AuctionPopup } from '../AuctionPopup'; import { AuctionPopup } from '../AuctionPopup';
import { ResultAuctionPopup } from '../ResultAuctionPopup'; import { ResultAuctionPopup } from '../ResultAuctionPopup';
import { DevPopup } from '../../Elements/DevPopup';
import { useAppSelector } from '../../hooks/useAppSelector';
interface IAuctionCard { interface IAuctionCard {
auctionId: string,
name: string, name: string,
imgs: Array<string>, imgs: Array<string>,
minBet: string,
users: number, users: number,
prevBet: string, prevBet: string,
myBetInit: string, myBetInit: string,
time: number, time: number,
isLead: boolean isLead: boolean,
commission: number,
className ?: string
} }
export function AuctionCard({ name, imgs, users, prevBet, myBetInit, time, isLead }: IAuctionCard) { export function AuctionCard({ name, imgs, users, prevBet, myBetInit, time, isLead, commission, auctionId, className }: IAuctionCard) {
const [myBet, setBet] = useState(Number(myBetInit)); const [myBet, setBet] = useState(Number(myBetInit));
const [myNewBet, setMyNewBet] = useState(0); const [myNewBet, setMyNewBet] = useState(0);
const [initPrevBet, setPrevBet] = useState(prevBet); const [initPrevBet, setPrevBet] = useState(prevBet);
@ -33,9 +35,10 @@ export function AuctionCard({ name, imgs, users, prevBet, myBetInit, time, isLea
const [closeAnim, setCloseAnim] = useState(false); const [closeAnim, setCloseAnim] = useState(false);
const [closeresultPopup, setCloseResultPopup] = useState(true); const [closeresultPopup, setCloseResultPopup] = useState(true);
const styleIndex = Number(localStorage.getItem('selectedStyle')); const styleIndex = Number(localStorage.getItem('selectedStyle'));
const [closeErrorBet, setCloseErrorBet] = useState(true);
return ( return (
<div className={`${styles.container} ${styleIndex===0 ? styles.darkContainer : styles.opacityContainer}`}> <div className={`${styles.container} ${className} ${styleIndex===0 ? styles.darkContainer : styles.opacityContainer}`}>
<Slider className={styles.slider} imgs={imgs}/> <Slider className={styles.slider} imgs={imgs}/>
<h2 style={ETextStyles.InBd18120} className={styles.title}>{name}</h2> <h2 style={ETextStyles.InBd18120} className={styles.title}>{name}</h2>
<h3 style={ETextStyles.RwSb16120} className={styles.title2}>Подробности аукциона</h3> <h3 style={ETextStyles.RwSb16120} className={styles.title2}>Подробности аукциона</h3>
@ -44,13 +47,13 @@ export function AuctionCard({ name, imgs, users, prevBet, myBetInit, time, isLea
<PointsBlock points={initPrevBet} sizeIcon={20}/> <PointsBlock points={initPrevBet} sizeIcon={20}/>
</div> </div>
<div className={`${styles.card} ${styles.cardFlex} ${styles.card2}`}> <div className={`${styles.card} ${styles.cardFlex} ${styles.card2}`}>
<p style={ETextStyles.RwRg14100}>{users === 0 ? 'Ты единственный участник' : 'Участники аукциона'}</p> <p style={ETextStyles.RwRg14100}>Количество победителей</p>
{users === 0 ? <PersonIcon /> : <div className={styles.usersBlock}><UsersIcons/> {users > 3 && <div className={styles.userCount} style={ETextStyles.InSb10120}>{users-3}</div>}</div>} <div className={styles.winnersNumber}>{users}</div>
</div> </div>
<div className={`${styles.card} ${initLead && styles.leadCard}`}> <div className={`${styles.card} ${initLead && styles.leadCard}`}>
<div className={styles.cardTop}> <div className={styles.cardTop}>
<div className={styles.cardLeft} style={ETextStyles.RwSb14120}>{!initLead ? 'Успей сделать ставку! До конца осталось:' <div className={styles.cardLeft} style={ETextStyles.RwSb14120}>{initLead ? <p><span>Ты в числе победителей! </span>Но все может поменяться</p>
: <p><span>Ты в числе победителей! </span>Но все может поменяться</p>}</div> : <p>{myBet > 0 ? 'Вашу ставку перебили, повысьте ее, чтобы сохранить лидерство' : 'Успей сделать ставку! До конца осталось:' }</p> }</div>
<Timer initTime={time}/> <Timer initTime={time}/>
</div> </div>
<Button onClick={() => setClose(false)} text={myBet === 0 ? 'Сделать первую ставку' : <div className={styles.newBtn}> <Button onClick={() => setClose(false)} text={myBet === 0 ? 'Сделать первую ставку' : <div className={styles.newBtn}>
@ -63,11 +66,14 @@ export function AuctionCard({ name, imgs, users, prevBet, myBetInit, time, isLea
icon={EIcons.UpPriceIcon}/> icon={EIcons.UpPriceIcon}/>
</div> </div>
{!closeWindow && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setClose} removeBtn={true} modalBlock={ {!closeWindow && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setClose} removeBtn={true} modalBlock={
<AuctionPopup setLead={setLead} setClose={setCloseAnim} img={imgs[0]} name={name} prevBet={initPrevBet} prevUserImg={''} setBet={setMyNewBet} setCloseResultPopup={setCloseResultPopup}/> <AuctionPopup myBet={myBet} setCloseErrorBet={setCloseErrorBet} auctionId={auctionId} commission={commission} setLead={setLead} setClose={setCloseAnim} img={imgs[0]} name={name} prevBet={initPrevBet} prevUserImg={''} setBet={setMyNewBet} setCloseResultPopup={setCloseResultPopup}/>
} />} } />}
{!closeresultPopup && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setCloseResultPopup} removeBtn={true} modalBlock={ {!closeresultPopup && closeErrorBet && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setCloseResultPopup} removeBtn={true} modalBlock={
<ResultAuctionPopup prevBet={initPrevBet} prevMyBet={myBet} newBet={myNewBet} setBet={setBet} setClose={setCloseAnim} setCloseBetWindow={setClose} setPrevBet={setPrevBet}/> <ResultAuctionPopup prevBet={initPrevBet} prevMyBet={myBet} newBet={myNewBet} setBet={setBet} setClose={setCloseAnim} setCloseBetWindow={setClose} setPrevBet={setPrevBet}/>
} />} } />}
{!closeErrorBet && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setCloseErrorBet} removeBtn={true} modalBlock={
<DevPopup setClose={setCloseAnim} title='Возникла ошибка' text='Не получилось сделать ставку. Но мы скоро всё починим.' />
} />}
</div> </div>
); );
} }

View File

@ -113,4 +113,14 @@
aspect-ratio: 340/237; aspect-ratio: 340/237;
border-radius: 15px; border-radius: 15px;
overflow: hidden; overflow: hidden;
}
.winnersNumber {
display: flex;
align-items: center;
justify-content: center;
width: 27px;
height: 27px;
border-radius: 50%;
background-color: var(--grey34);
} }

View File

@ -4,6 +4,7 @@ import { useNavigate } from 'react-router-dom';
import { ETextStyles } from '../../texts'; import { ETextStyles } from '../../texts';
import { ProductCard } from '../ProductCard'; import { ProductCard } from '../ProductCard';
import { Button } from '../../Button'; import { Button } from '../../Button';
import { generateRandomString } from '../../../utils/generateRandom';
interface IProduct { interface IProduct {
name: string, name: string,
@ -28,7 +29,7 @@ export function AuctionLosePopup({ items, setClose }: IAuctionLosePopup) {
<h3 className={styles.title2} style={ETextStyles.RwSb18120}>Аукционы, в&nbsp;которых нужно увеличить ставку:</h3> <h3 className={styles.title2} style={ETextStyles.RwSb18120}>Аукционы, в&nbsp;которых нужно увеличить ставку:</h3>
<div className={styles.cards}> <div className={styles.cards}>
{items.map(item => { {items.map(item => {
return <ProductCard name={item.name} img={item.img} bet={item.bet} /> return <ProductCard key={ generateRandomString() } name={item.name} img={item.img} bet={item.bet} />
})} })}
</div> </div>
<Button text='Увеличить ставку' onClick={() => { navigate('/auction'); setClose(true) }} /> <Button text='Увеличить ставку' onClick={() => { navigate('/auction'); setClose(true) }} />

View File

@ -1,39 +1,50 @@
import React, { useState } from 'react'; import React, { useEffect, useState } from 'react';
import styles from './auctionmainpopups.module.css'; import styles from './auctionmainpopups.module.css';
import { ModalWindow } from '../../ModalWindow'; import { ModalWindow } from '../../ModalWindow';
import { AuctionWinPopup } from '../AuctionWinPopup'; import { AuctionWinPopup } from '../AuctionWinPopup';
import { AuctionTopPopup } from '../AuctionTopPopup'; import { AuctionTopPopup } from '../AuctionTopPopup';
import { AuctionLosePopup } from '../AuctionLosePopup'; import { AuctionLosePopup } from '../AuctionLosePopup';
import { useAppSelector } from '../../hooks/useAppSelector';
import { IAuctionItem } from '../../../store/me/actions';
export function AuctionMainPopups() { export function AuctionMainPopups() {
const [closeWin, setCloseWin] = useState(true); const [closeWin, setCloseWin] = useState(true);
const [closeTop, setCloseTop] = useState(true); const [closeTop, setCloseTop] = useState(true);
const [closeLose, setCloseLose] = useState(true); const [closeLose, setCloseLose] = useState(true);
const [closeAnim, setCloseAnim] = useState(false); const [closeAnim, setCloseAnim] = useState(false);
const topAuctions = useAppSelector<Array<IAuctionItem> | undefined>(state=>state.me.data.topAuctions);
const loseAuctions = useAppSelector<Array<IAuctionItem> | undefined>(state => state.me.data.loseAuctions);
const items = [ useEffect(() => {
{ const show = sessionStorage.getItem('shT');
name: 'iPhone 15 Pro Max', if (show === 't' && closeTop) {
img: '', if (topAuctions && topAuctions.length != 0) {
bet: '788' sessionStorage.setItem('shT', 'f');
}, setCloseTop(false);
{ }
name: 'iPhone 13 Pro',
img: '',
bet: '200'
} }
]; }, [topAuctions]);
useEffect(() => {
const show = sessionStorage.getItem('shL');
if (show === 't' && closeLose) {
if (loseAuctions && loseAuctions.length != 0) {
sessionStorage.setItem('shL', 'f');
setCloseLose(false);
}
}
}, [loseAuctions]);
return ( return (
<div> <div>
{!closeWin && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setCloseWin} removeBtn={true} modalBlock={ {!closeWin && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setCloseWin} removeBtn={true} modalBlock={
<AuctionWinPopup name='iPhone 15 Pro Max ' img='' setClose={setCloseAnim}/> <AuctionWinPopup name='iPhone 15 Pro Max ' img='' setClose={setCloseAnim}/>
} />} } />}
{!closeTop && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setCloseTop} removeBtn={true} modalBlock={ {!closeTop && topAuctions != undefined && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setCloseTop} removeBtn={true} modalBlock={
<AuctionTopPopup items={items} setClose={setCloseAnim}/> <AuctionTopPopup items={topAuctions} setClose={setCloseAnim}/>
} />} } />}
{!closeLose && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setCloseLose} removeBtn={true} modalBlock={ {!closeLose && loseAuctions != undefined && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setCloseLose} removeBtn={true} modalBlock={
<AuctionLosePopup items={items} setClose={setCloseAnim} /> <AuctionLosePopup items={loseAuctions} setClose={setCloseAnim} />
} />} } />}
</div> </div>
); );

View File

@ -1,15 +1,19 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import styles from './auctionpopup.module.css'; import styles from './auctionpopup.module.css';
import { ETextStyles } from '../../texts'; import { ETextStyles } from '../../texts';
import { PersonIcon } from '../../Elements/PersonIcon';
import { PointsBlock } from '../../Elements/PointsBlock';
import { Button } from '../../Button'; import { Button } from '../../Button';
import { EIcons } from '../../Icons'; import { EIcons } from '../../Icons';
import { declension } from '../../../utils/declension'; import { declension } from '../../../utils/declension';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ProductCard } from '../ProductCard'; import { ProductCard } from '../ProductCard';
import { useAppSelector } from '../../hooks/useAppSelector';
import { useDispatch } from 'react-redux';
import axios from 'axios';
import { updatePointsRequestAsync } from '../../../store/me/actions';
import { updateAuction } from '../../../store/auction/actions';
interface IAuctionPopup { interface IAuctionPopup {
auctionId: string,
setClose(a: boolean): void, setClose(a: boolean): void,
setLead(a: boolean): void, setLead(a: boolean): void,
img: string, img: string,
@ -17,16 +21,23 @@ interface IAuctionPopup {
prevBet: string, prevBet: string,
prevUserImg: string, prevUserImg: string,
setBet(a: number): void, setBet(a: number): void,
setCloseResultPopup(a: boolean): void setCloseResultPopup(a: boolean): void,
commission: number,
setCloseErrorBet(a: boolean): void,
myBet: number
} }
export function AuctionPopup({ setClose, img, name, prevBet, prevUserImg, setBet, setLead, setCloseResultPopup }: IAuctionPopup) { export function AuctionPopup({ setClose, setCloseErrorBet, auctionId, img, name, prevBet, prevUserImg, setBet, setLead, setCloseResultPopup, commission, myBet }: IAuctionPopup) {
const [value, setValue] = useState<string>(''); const [value, setValue] = useState<string>('');
const [disabled, setDis] = useState(true); const [disabled, setDis] = useState(true);
const [autoBet, setAutoBet] = useState(false); const [autoBet, setAutoBet] = useState(false);
const navigate = useNavigate(); const navigate = useNavigate();
const percent = 5; const [percent, setPercent] = useState(commission);
const userPoints = 1000; const userPoints = Number(useAppSelector<string | undefined>(state=>state.me.data.points));
const URL = useAppSelector<string>(state=>state.url);
const token = useAppSelector<string>(state => state.token);
const dispatch = useDispatch();
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => { const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
let newValue = event.target.value; let newValue = event.target.value;
@ -41,28 +52,43 @@ export function AuctionPopup({ setClose, img, name, prevBet, prevUserImg, setBet
} }
const newBet = () => { const newBet = () => {
setBet(Math.floor((1 + percent / 100) * Number(value))); const bet = Number(value);
setClose(true); setClose(true);
setLead(true);
const timer = setInterval(() => { if (token) {
setCloseResultPopup(false); axios.post(`${URL}/api/v1/auction/auction/${auctionId}/place-bet/?value=${bet}`, {},
clearTimeout(timer); {
}, 400); headers: {
"Authorization": `TelegramToken ${token}`
}
}
).then(resp => {
const data = resp.data;
dispatch<any>(updatePointsRequestAsync());
dispatch<any>(updateAuction(auctionId));
setBet(bet);
setLead(true);
const timer = setInterval(() => {
setCloseResultPopup(false);
clearTimeout(timer);
}, 400);
}).catch(err => {
setCloseErrorBet(false);
})
}
}; };
return ( return (
<div> <div>
<h2 className={styles.title} style={ETextStyles.RwSb24100}>Сделать ставку</h2> <h2 className={styles.title} style={ETextStyles.RwSb24100}>Сделать ставку</h2>
<ProductCard name={name} img={img} bet={prevBet} personImg={prevUserImg} className={styles.card} /> <ProductCard name={name} img={img} bet={prevBet} personImg={prevUserImg} className={styles.card} />
{!autoBet ? <Button onClick={() => { setAutoBet(true), setValue((Number(prevBet) + 5).toString()), setDis(false) }} text='Сразу перебить ставку' className={styles.btnFirst} icon={<div className={styles.icon} style={{ backgroundImage: "url('assets/Rocket.png')" }}></div>} /> : {!autoBet ? <Button onClick={() => { setAutoBet(true), setValue(Number(Number((1 + percent / 100) * Number(prevBet)).toFixed(2)).toString()), setDis(false) }} text='Сразу перебить ставку' className={styles.btnFirst} icon={<div className={styles.icon} style={{ backgroundImage: "url('assets/Rocket.png')" }}></div>} /> :
<button style={ETextStyles.InBd14120} className={styles.btnCancel} onClick={() => setClose(true)}>Не перебивать</button> <button style={ETextStyles.InBd14120} className={styles.btnCancel} onClick={() => setClose(true)}>Не перебивать</button>
} }
<p className={styles.descr} style={ETextStyles.RwRg10140}>Наши алгоритмы автоматически рассчитают стоимость, чтобы ваша ставка стала самой высокой</p> <p className={styles.descr} style={ETextStyles.RwRg10140}>Наши алгоритмы автоматически рассчитают стоимость, чтобы ваша ставка стала самой высокой</p>
<h3 className={styles.title2} style={ETextStyles.InSb14120}>{!autoBet ? 'Ввести свою цену' : 'Цена, чтобы перебить ставку'}</h3> <h3 className={styles.title2} style={ETextStyles.InSb14120}>{!autoBet ? 'Ввести свою цену' : 'Цена, чтобы перебить ставку'}</h3>
<input style={ETextStyles.InSb14120} className={styles.input} value={value} type="text" onChange={handleChange} inputMode="numeric" /> <input style={ETextStyles.InSb14120} className={styles.input} value={value} type="text" onChange={handleChange} inputMode="numeric" />
{(Math.floor((1 + percent / 100) * Number(value)) < userPoints) ? ((Number(value) < Number(prevBet) && value.length > 0) ? {(Number(Number((1 + percent / 100) * Number(value))) - myBet < userPoints) ? ((Number(value) < Number(prevBet) && value.length > 0) ?
<button className={styles.btnForbidden}> <button className={styles.btnForbidden}>
<p style={ETextStyles.InBd14120}>Ставка должна быть больше</p> <p style={ETextStyles.InBd14120}>Ставка должна быть больше</p>
<p style={ETextStyles.InRg12140} className={styles.textForbidden}>Нельзя сделать ставку меньше предыдущей</p> <p style={ETextStyles.InRg12140} className={styles.textForbidden}>Нельзя сделать ставку меньше предыдущей</p>
@ -70,7 +96,7 @@ export function AuctionPopup({ setClose, img, name, prevBet, prevUserImg, setBet
: <Button onClick={() => newBet()} disabled={disabled} text={disabled ? 'Перебить ставку' : <div className={styles.newBtn}> : <Button onClick={() => newBet()} disabled={disabled} text={disabled ? 'Перебить ставку' : <div className={styles.newBtn}>
<p>Перебить ставку</p> <p>Перебить ставку</p>
<div className={styles.btnText}> <div className={styles.btnText}>
<p style={ETextStyles.InRg12140}>{`${declension(value, 'коин', 'коина', 'коинов', true)} + ${percent}% = ${declension(Math.floor((1 + percent / 100) * Number(value)), 'коин', 'коина', 'коинов', true)}`}</p> <p style={ETextStyles.InRg12140}>{`${declension(value, 'коин', 'коина', 'коинов', true)} + ${percent}% = ${declension(Number(Number((1 + percent / 100) * Number(value)).toFixed(2)), 'коин', 'коина', 'коинов', true)}`}</p>
<div className={styles.icon} style={{ backgroundImage: "url('assets/btnIcon.png')" }}></div> <div className={styles.icon} style={{ backgroundImage: "url('assets/btnIcon.png')" }}></div>
</div> </div>
</div>} </div>}

View File

@ -4,6 +4,7 @@ import { ETextStyles } from '../../texts';
import { ProductCard } from '../ProductCard'; import { ProductCard } from '../ProductCard';
import { Button } from '../../Button'; import { Button } from '../../Button';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { generateRandomString } from '../../../utils/generateRandom';
interface IProduct { interface IProduct {
name: string, name: string,
@ -20,7 +21,7 @@ export function AuctionTopPopup({ items, setClose }: IAuctionTopPopup) {
const navigate = useNavigate(); const navigate = useNavigate();
return ( return (
<div> <div className='top'>
<div className={styles.iconBlock}> <div className={styles.iconBlock}>
<div className={styles.icon} style={{ backgroundImage: "url('assets/Fire.png')" }}></div> <div className={styles.icon} style={{ backgroundImage: "url('assets/Fire.png')" }}></div>
</div> </div>
@ -29,7 +30,7 @@ export function AuctionTopPopup({ items, setClose }: IAuctionTopPopup) {
<h3 className={styles.title2} style={ETextStyles.RwSb18120}>Аукционы, в которых вы лидируете:</h3> <h3 className={styles.title2} style={ETextStyles.RwSb18120}>Аукционы, в которых вы лидируете:</h3>
<div className={styles.cards}> <div className={styles.cards}>
{items.map(item => { {items.map(item => {
return <ProductCard name={item.name} img={item.img} bet={item.bet} /> return <ProductCard key={ generateRandomString() } name={item.name} img={item.img} bet={item.bet} />
})} })}
</div> </div>
<Button text='Продолжить кликать' onClick={() => { navigate('/'); setClose(true)}}/> <Button text='Продолжить кликать' onClick={() => { navigate('/'); setClose(true)}}/>

View File

@ -18,12 +18,17 @@ interface IResultAuctionPopup {
export function ResultAuctionPopup({ prevBet, prevMyBet, newBet, setBet, setClose, setCloseBetWindow, setPrevBet }: IResultAuctionPopup) { export function ResultAuctionPopup({ prevBet, prevMyBet, newBet, setBet, setClose, setCloseBetWindow, setPrevBet }: IResultAuctionPopup) {
const [diff, setDiff] = useState(0); const [diff, setDiff] = useState(0);
const [prevBetOld, setPrevBetOld] = useState(prevBet); const [prevBetOld, setPrevBetOld] = useState(prevBet);
const [prevMyOldBet, setPrevMyOld] = useState(prevMyBet);
useEffect(() => { useEffect(() => {
setDiff(newBet - prevMyBet); if (prevMyOldBet > 0) {
setDiff(newBet - prevMyOldBet);
} else {
setDiff(newBet - Number(prevBetOld));
}
setBet(newBet); setBet(newBet);
setPrevBet(newBet.toString()) setPrevBet(newBet.toString());
}, []); }, []);
const onClick = () => { const onClick = () => {
@ -40,7 +45,7 @@ export function ResultAuctionPopup({ prevBet, prevMyBet, newBet, setBet, setClos
<div className={styles.icon} style={{backgroundImage: 'url("assets/Money.png")'}}></div> <div className={styles.icon} style={{backgroundImage: 'url("assets/Money.png")'}}></div>
</div> </div>
<div className={styles.text} style={ETextStyles.InSb24100}> <div className={styles.text} style={ETextStyles.InSb24100}>
Вы <span>увеличили</span> ставку <span>{`на ${diff}`}</span> {declension(diff, 'коин', 'коина', 'коинов')} Вы <span>{prevMyOldBet > 0 ? 'увеличили' : 'перебили'}</span> ставку <span>{`на ${diff.toFixed(2)}`}</span> {declension(diff.toFixed(2), 'коин', 'коина', 'коинов')}
</div> </div>
<div className={styles.cards}> <div className={styles.cards}>
<div className={styles.card}> <div className={styles.card}>

View File

@ -40,7 +40,7 @@ export function Timer({initTime}: ITimer) {
</div> </div>
<div className={styles.dot}></div> <div className={styles.dot}></div>
<div className={styles.block}> <div className={styles.block}>
<p className={styles.value} style={ETextStyles.InSb14120}>{min}</p> <p className={styles.value} style={ETextStyles.InSb14120}>{min.toString().length === 1 ? `0${min}` : min}</p>
<p className={styles.text} style={ETextStyles.RwRg12120}>мин</p> <p className={styles.text} style={ETextStyles.RwRg12120}>мин</p>
</div> </div>
<div className={styles.dot}></div> <div className={styles.dot}></div>

View File

@ -17,10 +17,11 @@ interface IClickerBtn {
clickTime: number, clickTime: number,
sameCoords: boolean, sameCoords: boolean,
setSameCoords(a: boolean): void, setSameCoords(a: boolean): void,
closeAutoClick: boolean closeAutoClick: boolean,
setSameInterval(a: boolean): void,
} }
export function ClickerBtn({ setCoins, closeAutoClick, energy, setMult, coins, setEnergy, setClickTime, clickTime, setSameCoords }: IClickerBtn) { export function ClickerBtn({ setCoins, setSameInterval, closeAutoClick, energy, setMult, coins, setEnergy, setClickTime, clickTime, setSameCoords }: IClickerBtn) {
const [fill, setFill] = useState(0); const [fill, setFill] = useState(0);
const [size, setSize] = useState(240); const [size, setSize] = useState(240);
const circumference = 2 * Math.PI * 125; const circumference = 2 * Math.PI * 125;
@ -33,6 +34,7 @@ export function ClickerBtn({ setCoins, closeAutoClick, energy, setMult, coins, s
const dispatch = useDispatch(); const dispatch = useDispatch();
const [prevClickTime, setPrevClickTime] = useState(0); const [prevClickTime, setPrevClickTime] = useState(0);
const [prevCoords, setPrevCoords] = useState(0); const [prevCoords, setPrevCoords] = useState(0);
const [clickInterval, setClickInterval] = useState(0);
useEffect(() => { useEffect(() => {
if(!closeAutoClick) { if(!closeAutoClick) {
@ -78,9 +80,17 @@ export function ClickerBtn({ setCoins, closeAutoClick, energy, setMult, coins, s
setPrevCoords(coords); setPrevCoords(coords);
const currentTime = Date.now(); const currentTime = Date.now();
const clickInterval = currentTime - prevClickTime; const clickIntervalInit = currentTime - prevClickTime;
if (clickInterval != 0) {
if (clickInterval === clickIntervalInit) {
setSameInterval(true)
} else {
setSameInterval(false)
}
}
if(prevClickTime != 0) { if(prevClickTime != 0) {
setClickTime(clickTime + clickInterval); setClickTime(clickTime + clickIntervalInit);
} }
setPrevClickTime(currentTime); setPrevClickTime(currentTime);
@ -136,7 +146,7 @@ export function ClickerBtn({ setCoins, closeAutoClick, energy, setMult, coins, s
{gradient} {gradient}
</defs> </defs>
</svg> </svg>
{!close && !closeAutoClick && <ModalWindow setCloseAnimOut={setClose} removeBtn={true} setClose={setClose} modalBlock={ {!close && closeAutoClick && <ModalWindow setCloseAnimOut={setClose} removeBtn={true} setClose={setClose} modalBlock={
<ClickerPopup title='Кнопка перегрелась' cards={hotCards} setClose={setClose} isBtn={true}/> <ClickerPopup title='Кнопка перегрелась' cards={hotCards} setClose={setClose} isBtn={true}/>
} />} } />}
</div> </div>

View File

@ -1,12 +1,17 @@
import React, { useState } from 'react'; import React, { useEffect, useState } from 'react';
import styles from './clickerfooter.module.css'; import styles from './clickerfooter.module.css';
import { ClickerBtnFooter } from '../ClickerBtnFooter'; import { ClickerBtnFooter } from '../ClickerBtnFooter';
import { EIcons, Icon } from '../../Icons'; import { EIcons, Icon } from '../../Icons';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { isWhiteList } from '../../../utils/isWhiteList';
export function ClickerFooter() { export function ClickerFooter() {
const navigate = useNavigate(); const navigate = useNavigate();
const isDev = true; const [isDev, setIsDev] = useState(true);
useEffect(() => {
setIsDev(!isWhiteList());
}, []);
return ( return (
<div className={styles.container}> <div className={styles.container}>

View File

@ -26,9 +26,11 @@ interface IPointsZoom {
setCloseAutoClick(a: boolean): void, setCloseAutoClick(a: boolean): void,
sameCoords: boolean, sameCoords: boolean,
setSameCoords(a: boolean): void, setSameCoords(a: boolean): void,
setSameInterval(a: boolean): void,
sameInterval: boolean,
} }
export function PointsZoom({ points, sameCoords, setSameCoords, setCloseAutoClick, setMult, setClose, setCoins, className, closePointsAnim, setClosePointsAnim, setCloseError, setEnergy, clickTime, setClickTime }: IPointsZoom) { export function PointsZoom({ points, sameInterval, setSameInterval, sameCoords, setSameCoords, setCloseAutoClick, setMult, setClose, setCoins, className, closePointsAnim, setClosePointsAnim, setCloseError, setEnergy, clickTime, setClickTime }: IPointsZoom) {
const [open, setOpen] = useState(true); const [open, setOpen] = useState(true);
const node = document.querySelector('#modal_root'); const node = document.querySelector('#modal_root');
const urlClick = useAppSelector<string>(state => state.urlClick); const urlClick = useAppSelector<string>(state => state.urlClick);
@ -36,6 +38,7 @@ export function PointsZoom({ points, sameCoords, setSameCoords, setCloseAutoClic
const [sizeHand, setSizeHand] = useState(30); const [sizeHand, setSizeHand] = useState(30);
const energy = Number(useAppSelector<string | undefined>(state => state.me.data.energy)); const energy = Number(useAppSelector<string | undefined>(state => state.me.data.energy));
const userData = useAppSelector<IUserData>(state => state.me.data); const userData = useAppSelector<IUserData>(state => state.me.data);
const URL = useAppSelector<string>(state => state.url);
if (!node) return null; if (!node) return null;
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -43,6 +46,7 @@ export function PointsZoom({ points, sameCoords, setSameCoords, setCloseAutoClic
const initPoints = points; const initPoints = points;
const clickTimeInit = clickTime; const clickTimeInit = clickTime;
let initSameCoords = sameCoords; let initSameCoords = sameCoords;
let initSameInterval = sameInterval;
let avtTime = 500; let avtTime = 500;
if (points > 1) { if (points > 1) {
avtTime = clickTimeInit / (initPoints - 1); avtTime = clickTimeInit / (initPoints - 1);
@ -50,10 +54,21 @@ export function PointsZoom({ points, sameCoords, setSameCoords, setCloseAutoClic
setClickTime(0); setClickTime(0);
setSameCoords(false); setSameCoords(false);
if ((avtTime < 100 && initSameCoords) || (initSameInterval) && initPoints > 20) {
if (avtTime < 100 && initSameCoords && points > 40) { /*axios.post(`${URL}/api/v1/users/warn/`, {}, {
headers: {
"Authorization": `TelegramToken ${token}`
}
}).then(resp => {
console.log(resp);
}).catch(err => {
//console.log(err)
})*/
sendAutoClickData(userData.tgId, points, avtTime); sendAutoClickData(userData.tgId, points, avtTime);
setCloseAutoClick(false); setCloseAutoClick(false);
setSameInterval(false);
const returnEnergy = energy + initPoints; const returnEnergy = energy + initPoints;
setEnergy(returnEnergy); setEnergy(returnEnergy);
dispatch<any>(updateEnergyRequestAsync(returnEnergy)); dispatch<any>(updateEnergyRequestAsync(returnEnergy));

View File

@ -65,6 +65,8 @@ export function SectionsBlock({ mult }: ISectionsBlock) {
img: 'assets/Chain.png' img: 'assets/Chain.png'
}, },
]; ];
//<UsersIcons imgs={topImgs} size={16}/>
return ( return (
<div className={styles.sectionContainer}> <div className={styles.sectionContainer}>
@ -75,7 +77,6 @@ export function SectionsBlock({ mult }: ISectionsBlock) {
<span className={styles.rank1}>#</span> <span className={styles.rank1}>#</span>
<span>{isDev ? '?' : (userRank ? formatNumber(userRank) : '?')}</span> <span>{isDev ? '?' : (userRank ? formatNumber(userRank) : '?')}</span>
</div> </div>
<UsersIcons imgs={topImgs} size={16}/>
</div>} </div>}
</CardSection> </CardSection>
<CardSection title='Множитель' onClick={() => { setClose(false) }}> <CardSection title='Множитель' onClick={() => { setClose(false) }}>

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import styles from './usersicons.module.css'; import styles from './usersicons.module.css';
import { PersonIcon } from '../PersonIcon'; import { PersonIcon } from '../PersonIcon';
import { EIcons, Icon } from '../../Icons';
interface IUsersIcons { interface IUsersIcons {
size?: number, size?: number,
@ -11,9 +12,15 @@ interface IUsersIcons {
export function UsersIcons({ size = 25, imgs = [], className = '' }: IUsersIcons) { export function UsersIcons({ size = 25, imgs = [], className = '' }: IUsersIcons) {
return ( return (
<div className={`${styles.users} ${className}`} style={{height: `${size}px`, width: `${size*2.5}px`}}> <div className={`${styles.users} ${className}`} style={{height: `${size}px`, width: `${size*2.5}px`}}>
<PersonIcon className={`${styles.userIcon} ${styles.userIcon1}`} size={size} img={imgs[0] ? imgs[0] : ''}/> <div className={`${styles.userIcon} ${styles.userIcon1}`}>
<PersonIcon className={`${styles.userIcon} ${styles.userIcon2}`} size={size} left={size / 1.4} img={imgs[1] ? imgs[1] : ''} /> <Icon icon={EIcons.MedalFirst}/>
<PersonIcon className={`${styles.userIcon} ${styles.userIcon3}`} size={size} left={2 * size / 1.4} img={imgs[2] ? imgs[2] : ''} /> </div>
<div className={`${styles.userIcon} ${styles.userIcon2}`}>
<Icon icon={EIcons.MedalSecond} />
</div>
<div className={`${styles.userIcon} ${styles.userIcon3}`}>
<Icon icon={EIcons.MedalThird} />
</div>
</div> </div>
); );
} }

View File

@ -3,11 +3,14 @@
} }
.userIcon { .userIcon {
display: flex;
align-items: center;
justify-content: center;
position: absolute; position: absolute;
top: 0; top: 0;
border-radius: 50%; width: 20px;
background-color: var(--grey6C); height: 20px;
border: 1px solid var(--grey12); opacity: 0.8;
} }
.userIcon1 { .userIcon1 {
@ -17,8 +20,10 @@
.userIcon2 { .userIcon2 {
z-index: 2; z-index: 2;
left: 14px;
} }
.userIcon3 { .userIcon3 {
z-index: 1; z-index: 1;
left: 28px;
} }

View File

@ -10,9 +10,10 @@ interface IModalWindow {
removeBtn ?: boolean, removeBtn ?: boolean,
closeAnimOut?: boolean, closeAnimOut?: boolean,
setCloseAnimOut(a: boolean): void, setCloseAnimOut(a: boolean): void,
isReload?: boolean,
} }
export function ModalWindow({ modalBlock, setClose, removeBtn, closeAnimOut, setCloseAnimOut }: IModalWindow) { export function ModalWindow({ modalBlock, setClose, removeBtn, closeAnimOut, setCloseAnimOut, isReload=false }: IModalWindow) {
const node = document.querySelector('#modal_root'); const node = document.querySelector('#modal_root');
const [closeAnim, setCloseAnim] = useState(false); const [closeAnim, setCloseAnim] = useState(false);
const html = document.querySelector('html'); const html = document.querySelector('html');
@ -34,6 +35,9 @@ export function ModalWindow({ modalBlock, setClose, removeBtn, closeAnimOut, set
const timer = setTimeout(() => { const timer = setTimeout(() => {
setClose(true); setClose(true);
clearTimeout(timer); clearTimeout(timer);
if(isReload) {
window.location.reload();
}
}, 400); }, 400);
} }

View File

@ -1,17 +1,39 @@
import React, { useEffect } from 'react'; import React, { useEffect, useState } from 'react';
import styles from './auctionpage.module.css'; import styles from './auctionpage.module.css';
import { ETextStyles } from '../../texts'; import { ETextStyles } from '../../texts';
import { AuctionCard } from '../../Auction/AuctionCard'; import { AuctionCard } from '../../Auction/AuctionCard';
import { useAuctionData } from '../../hooks/useAuctionData';
import { Spinner } from '../../Elements/Spinner';
import { ErrorPage } from '../ErrorPage';
export function AuctionPage() { export function AuctionPage() {
const imgs = ['https://cdn.dribbble.com/userupload/11863775/file/original-6009708366fadd352f61fbaf0db5acee.png?resize=1200x853', const { dataAuction, loadingAuction, errorAuction } = useAuctionData();
'https://cdn.dribbble.com/userupload/10040892/file/original-850d482568c1f1c870b7066113903bd2.png?resize=1200x900', const [auctionBlock, setAuctionBlock] = useState( <div></div> );
'https://cdn.dribbble.com/users/9735273/screenshots/19338580/media/6657322ea7990bd504427ed1b171be3d.png?resize=1200x900']
useEffect(() => {
if(dataAuction.length != 0) {
const newBlock = dataAuction.map(item => {
if (item.productName && item.productCover && item.initialCost && item.time && item.winnersNumber && item.commission && item.id && item.isLead != undefined && item.myBet != undefined)
return <AuctionCard className={styles.card} auctionId={item.id} key={`${item.id}${JSON.stringify(dataAuction)}`} name={item.productName} imgs={[item.productCover]} users={item.winnersNumber} prevBet={item.initialCost} myBetInit={item.myBet} time={item.time} isLead={item.isLead} commission={item.commission}/>
});
//@ts-ignore
setAuctionBlock(newBlock);
}
}, [dataAuction]);
return ( return (
<div> <div>
<h1 className={styles.title} style={ETextStyles.RwSb26100}> <span>Соревнуйся за товары</span> на аукционе!</h1> {loadingAuction && <div className={styles.spinnerContainer}><Spinner color='#FFFFFF' size='40px' thickness='6px' className={styles.spinner} /></div>}
<AuctionCard name='iPhone 15 Pro Max, 256gb, Natural Titanium' imgs={imgs} minBet='200' users={23} prevBet='290' myBetInit='0' time={86400} isLead={false}/> {!loadingAuction && <div>
{errorAuction ? <ErrorPage fullScreen={true} title='Возникла ошибка загрузки аукционов' text='Перезагрузите страницу или попробуйте позже' detail={errorAuction} /> :
<div>
<h1 className={styles.title} style={ETextStyles.RwSb26100}> <span>Соревнуйся за товары</span> на аукционе!</h1>
{auctionBlock}
</div>
}
</div>
}
</div> </div>
); );
} }

View File

@ -4,4 +4,16 @@
.title span { .title span {
color: var(--primary); color: var(--primary);
}
.spinnerContainer {
display: flex;
width: 100vw;
height: 100vh;
align-items: center;
justify-content: center;
}
.card {
margin-bottom: 24px;
} }

View File

@ -11,6 +11,8 @@ import { useWindowSize } from 'usehooks-ts';
import { useAppSelector } from '../../hooks/useAppSelector'; import { useAppSelector } from '../../hooks/useAppSelector';
import { ModalWindow } from '../../ModalWindow'; import { ModalWindow } from '../../ModalWindow';
import { DevPopup } from '../../Elements/DevPopup'; import { DevPopup } from '../../Elements/DevPopup';
import { AuctionMainPopups } from '../../Auction/AuctionMainPopups';
import { useAuctionData } from '../../hooks/useAuctionData';
interface IClickerPageInterface { interface IClickerPageInterface {
name: string, name: string,
@ -33,6 +35,17 @@ export function ClickerPage({ name, points, img, energy }: IClickerPageInterface
const [clickTime, setClickTime] = useState(0); const [clickTime, setClickTime] = useState(0);
const [closeAutoClick, setCloseAutoClick] = useState(true); const [closeAutoClick, setCloseAutoClick] = useState(true);
const [sameCoords, setSameCoords] = useState(false); const [sameCoords, setSameCoords] = useState(false);
const [sameInterval, setSameInterval] = useState(false);
useAuctionData();
useEffect(() => {
const html = document.querySelector('html');
if(html) {
html.style.overflow = 'scroll';
}
}, []);
useEffect(() => { useEffect(() => {
setMult(savedMult); setMult(savedMult);
@ -57,13 +70,13 @@ export function ClickerPage({ name, points, img, energy }: IClickerPageInterface
return ( return (
<div className={styles.container}> <div className={styles.container}>
<div className={styles.records}> <div className={styles.records}>
{!closePoints && <PointsZoom sameCoords={sameCoords} setSameCoords={setSameCoords} setCloseAutoClick={setCloseAutoClick} setClickTime={setClickTime} clickTime={clickTime} setMult={setMult} setEnergy={setInitEnergy} setCloseError={setCloseError} setCoins={setCoins} points={coins} setClosePointsAnim={setClosePointsAnim} setClose={setClosePoints} className={styles.pointsAnim} closePointsAnim={closePointsAnim}/>} {!closePoints && <PointsZoom sameInterval={sameInterval} setSameInterval={setSameInterval} sameCoords={sameCoords} setSameCoords={setSameCoords} setCloseAutoClick={setCloseAutoClick} setClickTime={setClickTime} clickTime={clickTime} setMult={setMult} setEnergy={setInitEnergy} setCloseError={setCloseError} setCoins={setCoins} points={coins} setClosePointsAnim={setClosePointsAnim} setClose={setClosePoints} className={styles.pointsAnim} closePointsAnim={closePointsAnim}/>}
<Profile name={name} className={styles.profile} img={img}/> <Profile name={name} className={styles.profile} img={img}/>
<h1 style={ETextStyles.RwSb24100} className={styles.title}>Мои рекорды</h1> <h1 style={ETextStyles.RwSb24100} className={styles.title}>Мои рекорды</h1>
<SectionsBlock mult={mult}/> <SectionsBlock mult={mult}/>
</div> </div>
<div className={styles.clicker} style={{height: `${height > 670 && 'calc(100vh - 355px)'}`}}> <div className={styles.clicker} style={{height: `${height > 670 && 'calc(100vh - 355px)'}`}}>
<ClickerBtn closeAutoClick={closeAutoClick} sameCoords={sameCoords} setSameCoords={setSameCoords} clickTime={clickTime} setClickTime={setClickTime} setEnergy={setInitEnergy} coins={coins} setCoins={setCoins} energy={initEnergy} setMult={setMult}/> <ClickerBtn setSameInterval={setSameInterval} closeAutoClick={closeAutoClick} sameCoords={sameCoords} setSameCoords={setSameCoords} clickTime={clickTime} setClickTime={setClickTime} setEnergy={setInitEnergy} coins={coins} setCoins={setCoins} energy={initEnergy} setMult={setMult}/>
</div> </div>
<ClickerFooter /> <ClickerFooter />
{styleIndex != 0 && <div> {styleIndex != 0 && <div>
@ -75,6 +88,7 @@ export function ClickerPage({ name, points, img, energy }: IClickerPageInterface
{!closeAutoClick && <ModalWindow removeBtn={true} setCloseAnimOut={setAnimClose} closeAnimOut={animClose} setClose={setCloseAutoClick} modalBlock={ {!closeAutoClick && <ModalWindow removeBtn={true} setCloseAnimOut={setAnimClose} closeAnimOut={animClose} setClose={setCloseAutoClick} modalBlock={
<DevPopup setClose={setAnimClose} title='Кажется, вы используете автокликер...' text='Ваши клики не отправлены. Давайте играть честно.' img='assets/police.gif'/> <DevPopup setClose={setAnimClose} title='Кажется, вы используете автокликер...' text='Ваши клики не отправлены. Давайте играть честно.' img='assets/police.gif'/>
} />} } />}
<AuctionMainPopups/>
</div> </div>
); );
} }

View File

@ -0,0 +1,18 @@
import { useDispatch } from 'react-redux';
import { useEffect } from 'react';
import { useAppSelector } from './useAppSelector';
import { IAuction, auctionRequestAsync } from '../../store/auction/actions';
export function useAuctionData() {
const dataAuction = useAppSelector<Array<IAuction>>(state => state.auction.data);
const loadingAuction = useAppSelector<boolean>(state => state.auction.loading);
const errorAuction = useAppSelector<String>(state => state.auction.error);
const token = useAppSelector<string>(state => state.token);
const dispatch = useDispatch();
useEffect(() => {
dispatch<any>(auctionRequestAsync());
}, [token]);
return { dataAuction, loadingAuction, errorAuction };
}

View File

@ -0,0 +1,245 @@
import { Action, ActionCreator } from "redux";
import { ThunkAction } from "redux-thunk";
import { RootState } from "../reducer";
import axios from "axios";
import { updateMyAuctions } from "../me/actions";
export interface IAuction {
id?: string,
commission?: number,
time?: number,
initialCost?: string,
productId?: string,
productCover?: string,
productName?: string,
winnersNumber?: number,
isLead?: boolean,
myBet?: string,
}
export const AUCTION_REQUEST = 'AUCTION_REQUEST';
export type AuctionRequestAction = {
type: typeof AUCTION_REQUEST
};
export const auctionRequest: ActionCreator<AuctionRequestAction> = () => ({
type: AUCTION_REQUEST,
});
export const AUCTION_REQUEST_SUCCESS = 'AUCTION_REQUEST_SUCCESS';
export type AuctionRequestSuccessAction = {
type: typeof AUCTION_REQUEST_SUCCESS;
data: Array<IAuction>;
};
export const auctionRequestSuccess: ActionCreator<AuctionRequestSuccessAction> = (data: Array<IAuction>) => ({
type: AUCTION_REQUEST_SUCCESS,
data
});
export const AUCTION_REQUEST_ERROR = 'AUCTION_REQUEST_ERROR';
export type AuctionRequestErrorAction = {
type: typeof AUCTION_REQUEST_ERROR;
error: String;
};
export const auctionRequestError: ActionCreator<AuctionRequestErrorAction> = (error: String) => ({
type: AUCTION_REQUEST_ERROR,
error
});
export const auctionRequestAsync = (): ThunkAction<void, RootState, unknown, Action<string>> => (dispatch, getState) => {
const URL = getState().url;
const token = getState().token;
const userTg = getState().userTg.id;
if (token) {
axios.get(`${URL}/api/v1/auction/auction?is_active=true`,
{
headers: {
"Authorization": `TelegramToken ${token}`
}
}
).then(resp => {
const data = resp.data.results;
axios.get(`${URL}/api/v1/auction/bet?order_by=-value&is_winning=true`,
{
headers: {
"Authorization": `TelegramToken ${token}`
}
}
).then(resp2 => {
const dataBet = resp2.data.results;
const auctionResults: Array<IAuction> = [];
axios.get(`${URL}/api/v1/auction/bet?user=${userTg}&order_by=-value`,
{
headers: {
"Authorization": `TelegramToken ${token}`
}
}
).then(resp3 => {
const userData = resp3.data.results;
const topAuctions = [];
const loseAuctions = [];
for (let i = 0; i < data.length; i++) {
const nowDate = new Date();
const endDate = new Date(data[i].end_time);
const time = Math.ceil(Math.abs(endDate.getTime() - nowDate.getTime()) / 1000);
let maxBet = Number(data[i].initial_cost);
let isLead = false;
let myBet = 0;
if (dataBet.length != 0) {
for (let k = 0; k < dataBet.length; k++) {
if (dataBet[k].auction === data[i].id) {
if (Number(dataBet[k].value) > maxBet) {
maxBet = Number(dataBet[k].value);
}
if (Number(dataBet[k].user.tg_id) === Number(userTg)) {
isLead = true;
const topItem = {
name: data[i].product.name,
img: data[i].product.cover,
bet: dataBet[k].value
}
topAuctions.push(topItem);
}
}
}
}
if (userData.length != 0) {
for (let z = 0; z < userData.length; z++) {
if (userData[z].auction === data[i].id) {
if (Number(userData[z].value) > myBet) {
myBet = Number(userData[z].value);
if(!isLead) {
const loseItem = {
name: data[i].product.name,
img: data[i].product.cover,
bet: userData[z].value
}
loseAuctions.push(loseItem)
}
}
}
}
}
const item = {
id: data[i].id,
initialCost: maxBet.toString(),
commission: Number(data[i].commission) * 100,
time: time,
winnersNumber: data[i].quantity,
productId: data[i].product.id,
productName: data[i].product.name,
productCover: data[i].product.cover,
isLead: isLead,
myBet: myBet.toString()
};
auctionResults.push(item);
}
dispatch(updateMyAuctions(topAuctions, 'top'));
dispatch(updateMyAuctions(loseAuctions, 'lose'));
dispatch(auctionRequestSuccess(auctionResults));
})
}).catch(err => {
console.log(err);
if (err.response.data.detail) {
dispatch(auctionRequestError(String(err.response.data.detail)));
} else {
dispatch(auctionRequestError(String(err)));
}
})
}).catch((err) => {
console.log(err);
if (err.response.data.detail) {
dispatch(auctionRequestError(String(err.response.data.detail)));
} else {
dispatch(auctionRequestError(String(err)));
}
})
}
}
export const updateAuction = (id: string): ThunkAction<void, RootState, unknown, Action<string>> => (dispatch, getState) => {
const auctionData = getState().auction.data;
const URL = getState().url;
const token = getState().token;
const userTg = getState().userTg.id;
let newData = auctionData;
axios.get(`${URL}/api/v1/auction/bet?order_by=-value&is_winning=true&auction=${id}`,
{
headers: {
"Authorization": `TelegramToken ${token}`
}
}
).then(resp => {
const dataBet = resp.data.results;
let maxBet = 0;
let isLead = false;
if (dataBet.length != 0) {
for (let i = 0; i < dataBet.length; i++) {
if (Number(dataBet[i].value) > maxBet) {
maxBet = Number(dataBet[i].value);
}
if (Number(dataBet[i].user.tg_id) === Number(userTg)) {
isLead = true;
newData[i].isLead = isLead;
}
}
}
axios.get(`${URL}/api/v1/auction/bet?auction=${id}&user=${userTg}&order_by=-value`,
{
headers: {
"Authorization": `TelegramToken ${token}`
}
}
).then(resp2 => {
const data = resp2.data.results;
let myBet = 0;
if (data.length != 0) {
myBet = Number(dataBet[0].value);
}
//обновляем данные
for (let i = 0; i < newData.length; i++) {
if (newData[i].id === id) {
if (myBet != 0) {
newData[i].myBet = myBet.toString();
}
if (maxBet != 0) {
newData[i].initialCost = maxBet.toString();
}
}
}
dispatch(auctionRequestSuccess(newData));
}
)
})
}

View File

@ -0,0 +1,36 @@
import { Reducer } from 'react';
import { AUCTION_REQUEST, AUCTION_REQUEST_ERROR, AUCTION_REQUEST_SUCCESS, AuctionRequestAction, AuctionRequestErrorAction, AuctionRequestSuccessAction, IAuction } from './actions';
export type AuctionState = {
loading: boolean,
error: String,
data: Array<IAuction>
}
type AuctionAction = AuctionRequestAction | AuctionRequestSuccessAction | AuctionRequestErrorAction;
export const auctionReducer: Reducer<AuctionState, AuctionAction> = (state, action) => {
switch (action.type) {
case AUCTION_REQUEST:
return {
...state,
loading: true,
error: ''
};
case AUCTION_REQUEST_ERROR:
return {
...state,
error: action.error,
loading: false,
};
case AUCTION_REQUEST_SUCCESS:
return {
...state,
data: action.data,
loading: false,
error: ''
};
default:
return state;
}
}

View File

@ -5,6 +5,12 @@ import axios from "axios";
import { saveMult } from "../mult"; import { saveMult } from "../mult";
import { saveToken } from "../token"; import { saveToken } from "../token";
export interface IAuctionItem {
name: string,
img: string,
bet: string
}
export interface IUserData { export interface IUserData {
tgId?: number; tgId?: number;
username?: string; username?: string;
@ -14,7 +20,9 @@ export interface IUserData {
energy?: string; energy?: string;
referralStorage?: string; referralStorage?: string;
maxStorage: number; maxStorage: number;
rank ?: number rank ?: number,
loseAuctions?: Array<IAuctionItem>,
topAuctions?: Array<IAuctionItem>,
} }
export const ME_REQUEST = 'ME_REQUEST'; export const ME_REQUEST = 'ME_REQUEST';
@ -117,6 +125,8 @@ export const meRequestAsync = (): ThunkAction<void, RootState, unknown, Action<s
const savedToken = sessionStorage.getItem('tk'); const savedToken = sessionStorage.getItem('tk');
if (savedToken) { if (savedToken) {
if (savedToken != encodeToken) { if (savedToken != encodeToken) {
sessionStorage.setItem('shT', 't');
sessionStorage.setItem('shL', 't');
sessionStorage.setItem('tk', encodeToken); sessionStorage.setItem('tk', encodeToken);
firstClick(token); firstClick(token);
const energyCode = btoa(energy.toString()); const energyCode = btoa(energy.toString());
@ -170,7 +180,7 @@ export const meRequestAsync = (): ThunkAction<void, RootState, unknown, Action<s
}) })
} }
/*if (tgId && Url && !meData.username) { /*if (tgId && Url && !meData.username) {
axios.get(`${Url}/api/internal/users/get-token/123456`, { axios.get(`${Url}/api/internal/users/get-token/${tgId}`, {
headers: { headers: {
"Content-type": "application/json" "Content-type": "application/json"
} }
@ -211,6 +221,8 @@ export const meRequestAsync = (): ThunkAction<void, RootState, unknown, Action<s
const savedToken = sessionStorage.getItem('tk'); const savedToken = sessionStorage.getItem('tk');
if (savedToken) { if (savedToken) {
if (savedToken != encodeToken) { if (savedToken != encodeToken) {
sessionStorage.setItem('shT', 't');
sessionStorage.setItem('shL', 't');
sessionStorage.setItem('tk', encodeToken); sessionStorage.setItem('tk', encodeToken);
firstClick(token); firstClick(token);
const energyCode = btoa(energy.toString()); const energyCode = btoa(energy.toString());
@ -295,6 +307,7 @@ export const updatePointsRequestAsync = (): ThunkAction<void, RootState, unknown
const newData = meData; const newData = meData;
newData.points = points; newData.points = points;
dispatch(meRequestSuccess(newData)); dispatch(meRequestSuccess(newData));
dispatch(loadNewRank());
}).catch((err) => { }).catch((err) => {
console.log(err); console.log(err);
dispatch(meRequestError(String(err))); dispatch(meRequestError(String(err)));
@ -319,4 +332,44 @@ export const updateRank = (rank: number): ThunkAction<void, RootState, unknown,
let newData = meData; let newData = meData;
newData.rank = rank; newData.rank = rank;
dispatch(meRequestSuccess(newData)); dispatch(meRequestSuccess(newData));
} }
export const loadNewRank = (): ThunkAction<void, RootState, unknown, Action<string>> => (dispatch, getState) => {
const token = getState().token;
const URL = getState().url;
const userTg = getState().userTg.id;
if(token) {
axios.get(`${URL}/api/v1/users/rank/neighbours?limit=1`,
{
headers: {
"Authorization": `TelegramToken ${token}`
}
}
).then(resp => {
const data = resp.data;
if(data.length != 0) {
for(let i = 0; i<data.length; i++) {
if (Number(data[i].tg_id) === Number(userTg)) {
dispatch<any>(updateRank(Number(data[i].rank)))
}
}
}
})
}
}
export const updateMyAuctions = (data: Array<IAuctionItem>, type: string): ThunkAction<void, RootState, unknown, Action<string>> => (dispatch, getState) => {
const meData = getState().me.data;
let newData = meData;
if(type === 'top') {
newData.topAuctions = data;
} else {
newData.loseAuctions = data;
}
dispatch(meRequestSuccess(newData));
}

View File

@ -9,6 +9,8 @@ import { RankState, friendsReducer } from './friends/reducer';
import { FRIENDS_REQUEST, FRIENDS_REQUEST_ERROR, FRIENDS_REQUEST_SUCCESS } from './friends/actions'; import { FRIENDS_REQUEST, FRIENDS_REQUEST_ERROR, FRIENDS_REQUEST_SUCCESS } from './friends/actions';
import { RANK_REQUEST, RANK_REQUEST_ERROR, RANK_REQUEST_SUCCESS } from './rank/actions'; import { RANK_REQUEST, RANK_REQUEST_ERROR, RANK_REQUEST_SUCCESS } from './rank/actions';
import { rankReducer } from './rank/reducer'; import { rankReducer } from './rank/reducer';
import { AuctionState, auctionReducer } from './auction/reducer';
import { AUCTION_REQUEST, AUCTION_REQUEST_ERROR, AUCTION_REQUEST_SUCCESS } from './auction/actions';
export type RootState = { export type RootState = {
url: string, url: string,
@ -22,6 +24,7 @@ export type RootState = {
mult: number, mult: number,
friends: RankState, friends: RankState,
rank: RankState, rank: RankState,
auction: AuctionState
}; };
//'http://127.0.0.1:8000' //'http://127.0.0.1:8000'
@ -55,6 +58,11 @@ const initialState: RootState = {
error: '', error: '',
data: [] data: []
}, },
auction: {
loading: false,
error: '',
data: []
},
referral: '', referral: '',
mult: 1, mult: 1,
}; };
@ -108,6 +116,13 @@ export const rootReducer: Reducer<RootState> = (state = initialState, action) =>
...state, ...state,
rank: rankReducer(state.rank, action) rank: rankReducer(state.rank, action)
}; };
case AUCTION_REQUEST:
case AUCTION_REQUEST_SUCCESS:
case AUCTION_REQUEST_ERROR:
return {
...state,
auction: auctionReducer(state.auction, action)
};
default: default:
return state; return state;
} }

View File

@ -5,7 +5,7 @@ export const isWhiteList = () => {
//123456, //123456,
const whiteList = [ const whiteList = [
342495217, 6374536117, 322861155, 5219438370, 193428034, 402449803, 342495217, 6374536117, 322861155, 5219438370, 193428034, 402449803,
406350282 406350282, 1083462027
]; ];
const userId = Number(getTgUserId()); const userId = Number(getTgUserId());