BIN
frontend/public/assets/Angry.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
frontend/public/assets/Biceps.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
frontend/public/assets/Chain.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
frontend/public/assets/Fire.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
frontend/public/assets/Gift.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
frontend/public/assets/Money.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
frontend/public/assets/Monocle.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
frontend/public/assets/Rocket.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
frontend/public/assets/Volt.png
Normal file
After Width: | Height: | Size: 641 B |
BIN
frontend/public/assets/btnIcon.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
frontend/public/assets/coin.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
frontend/public/assets/compass.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
frontend/public/assets/dev.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
frontend/public/assets/friends.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
frontend/public/assets/imgBtn1.png
Normal file
After Width: | Height: | Size: 2.8 MiB |
BIN
frontend/public/assets/imgBtn2.png
Normal file
After Width: | Height: | Size: 2.1 MiB |
BIN
frontend/public/assets/point.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
frontend/public/assets/police.gif
Normal file
After Width: | Height: | Size: 4.2 MiB |
BIN
frontend/public/assets/programming.gif
Normal file
After Width: | Height: | Size: 3.6 MiB |
BIN
frontend/public/assets/shopping.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
frontend/public/assets/style1.png
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
frontend/public/assets/style2.png
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
frontend/public/assets/style3.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
frontend/public/assets/style4.png
Normal file
After Width: | Height: | Size: 164 KiB |
BIN
frontend/src/assets/Angry.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
frontend/src/assets/Biceps.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
frontend/src/assets/Chain.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
frontend/src/assets/Fire.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
frontend/src/assets/Gift.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
frontend/src/assets/Money.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
frontend/src/assets/Monocle.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
frontend/src/assets/Rocket.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
frontend/src/assets/Volt.png
Normal file
After Width: | Height: | Size: 641 B |
BIN
frontend/src/assets/btnIcon.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
frontend/src/assets/coin.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
frontend/src/assets/compass.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
frontend/src/assets/dev.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
frontend/src/assets/friends.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
frontend/src/assets/imgBtn1.png
Normal file
After Width: | Height: | Size: 2.8 MiB |
BIN
frontend/src/assets/imgBtn2.png
Normal file
After Width: | Height: | Size: 2.1 MiB |
BIN
frontend/src/assets/point.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
frontend/src/assets/police.gif
Normal file
After Width: | Height: | Size: 4.2 MiB |
BIN
frontend/src/assets/programming.gif
Normal file
After Width: | Height: | Size: 3.6 MiB |
BIN
frontend/src/assets/shopping.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
frontend/src/assets/style1.png
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
frontend/src/assets/style2.png
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
frontend/src/assets/style3.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
frontend/src/assets/style4.png
Normal file
After Width: | Height: | Size: 164 KiB |
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
|
@ -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}>Аукционы, в которых нужно увеличить ставку:</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('/auction'); setClose(true) }} />
|
<Button text='Увеличить ставку' onClick={() => { navigate('/auction'); setClose(true) }} />
|
||||||
|
|
|
@ -1,39 +1,95 @@
|
||||||
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 winAuctions = useAppSelector<Array<IAuctionItem> | undefined>(state => state.me.data.winAuctions);
|
||||||
|
const [winInfo, setWinInfo] = useState<IAuctionItem>();
|
||||||
|
|
||||||
const items = [
|
useEffect(() => {
|
||||||
{
|
let showWindow = false;
|
||||||
name: 'iPhone 15 Pro Max',
|
if (winAuctions && winAuctions.length != 0) {
|
||||||
img: '',
|
for (let i = 0; i < winAuctions.length; i++) {
|
||||||
bet: '788'
|
const winShow = localStorage.getItem('wS');
|
||||||
},
|
if (winShow) {
|
||||||
{
|
const winArray = JSON.parse(winShow);
|
||||||
name: 'iPhone 13 Pro',
|
if (winArray && winArray.length != 0) {
|
||||||
img: '',
|
let isExist = false;
|
||||||
bet: '200'
|
for (let k = 0; k < winArray.length; k++) {
|
||||||
|
if (Number(winArray[k]) === Number(winAuctions[i].id)) {
|
||||||
|
isExist = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!isExist) {
|
||||||
|
winArray.push(winAuctions[i].id);
|
||||||
|
localStorage.setItem('wS', JSON.stringify(winArray));
|
||||||
|
showWindow = true;
|
||||||
|
setWinInfo(winAuctions[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const newArray = [];
|
||||||
|
newArray.push(winAuctions[i].id);
|
||||||
|
localStorage.setItem('wS', JSON.stringify(newArray));
|
||||||
|
showWindow = true;
|
||||||
|
setWinInfo(winAuctions[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const newArray = [];
|
||||||
|
newArray.push(winAuctions[i].id);
|
||||||
|
localStorage.setItem('wS', JSON.stringify(newArray));
|
||||||
|
showWindow = true;
|
||||||
|
setWinInfo(winAuctions[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
|
||||||
|
if(showWindow) {
|
||||||
|
setCloseWin(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [winAuctions]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const show = sessionStorage.getItem('shT');
|
||||||
|
if (show === 't' && closeTop) {
|
||||||
|
if (topAuctions && topAuctions.length != 0) {
|
||||||
|
sessionStorage.setItem('shT', 'f');
|
||||||
|
setCloseTop(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [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={winInfo?.name ? winInfo?.name : ''} img={winInfo?.img ? winInfo?.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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>}
|
||||||
|
|
|
@ -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)}}/>
|
||||||
|
|
|
@ -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}>
|
||||||
|
|
|
@ -16,6 +16,7 @@ export function Timer({initTime}: ITimer) {
|
||||||
const tick = () => {
|
const tick = () => {
|
||||||
if (hour === 0 && min === 0 && sec === 0) {
|
if (hour === 0 && min === 0 && sec === 0) {
|
||||||
setOver(true);
|
setOver(true);
|
||||||
|
window.location.reload();
|
||||||
} else if (min === 0 && sec === 0) {
|
} else if (min === 0 && sec === 0) {
|
||||||
setTime([hour - 1, 59, 59]);
|
setTime([hour - 1, 59, 59]);
|
||||||
} else if (sec == 0) {
|
} else if (sec == 0) {
|
||||||
|
@ -35,12 +36,12 @@ export function Timer({initTime}: ITimer) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className={styles.block}>
|
<div className={styles.block}>
|
||||||
<p className={styles.value} style={ETextStyles.InSb14120}>{hour}</p>
|
<p className={styles.value} style={ETextStyles.InSb14120}>{hour.toString().length === 1 ? `0${hour}` : hour}</p>
|
||||||
<p className={styles.text} style={ETextStyles.RwRg12120}>{declension(hour, 'час', 'часа', 'часов')}</p>
|
<p className={styles.text} style={ETextStyles.RwRg12120}>{declension(hour, 'час', 'часа', 'часов')}</p>
|
||||||
</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>
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import styles from './clickerbtn.module.css';
|
import styles from './clickerbtn.module.css';
|
||||||
import { ModalWindow } from '../../ModalWindow';
|
import { ModalWindow } from '../../ModalWindow';
|
||||||
import { ClickerPopup } from '../ClickerPopup';
|
import { ClickerPopup } from '../ClickerPopup';
|
||||||
import { getGradient } from '../../../utils/getGradient';
|
import { getGradient } from '../../../utils/getGradient';
|
||||||
import { useAppSelector } from '../../hooks/useAppSelector';
|
import { useAppSelector } from '../../hooks/useAppSelector';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { IUserData, updateEnergyRequestAsync } from '../../../store/me/actions';
|
import { updateEnergyRequestAsync } from '../../../store/me/actions';
|
||||||
import axios from 'axios';
|
|
||||||
import { DevPopup } from '../../Elements/DevPopup';
|
|
||||||
import { saveMult } from '../../../store/mult';
|
|
||||||
import { Spinner } from '../../Elements/Spinner';
|
|
||||||
|
|
||||||
interface IClickerBtn {
|
interface IClickerBtn {
|
||||||
coins: number,
|
coins: number,
|
||||||
setCoins(a: number): void,
|
setCoins(a: number): void,
|
||||||
energy: number,
|
energy: number,
|
||||||
setMult(a: number): void,
|
setMult(a: number): void,
|
||||||
setEnergy(a: number): void
|
setEnergy(a: number): void,
|
||||||
|
setClickTime(a: number): void,
|
||||||
|
clickTime: number,
|
||||||
|
sameCoords: boolean,
|
||||||
|
setSameCoords(a: boolean): void,
|
||||||
|
closeAutoClick: boolean,
|
||||||
|
setSameInterval(a: boolean): void,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ClickerBtn({ setCoins, energy, setMult, coins, setEnergy }: IClickerBtn) {
|
export function ClickerBtn({ setCoins, setSameInterval, closeAutoClick, energy, setMult, coins, setEnergy, setClickTime, clickTime, setSameCoords }: IClickerBtn) {
|
||||||
const urlClick = useAppSelector<string>(state => state.urlClick);
|
|
||||||
const token = useAppSelector<string>(state => state.token);
|
|
||||||
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;
|
||||||
|
@ -32,6 +32,23 @@ export function ClickerBtn({ setCoins, energy, setMult, coins, setEnergy }: ICli
|
||||||
let styleIndex = useAppSelector<number>(state => state.styleIndex);
|
let styleIndex = useAppSelector<number>(state => state.styleIndex);
|
||||||
const [maxEnergy, setMaxEnergy] = useState(500);
|
const [maxEnergy, setMaxEnergy] = useState(500);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
const [prevClickTime, setPrevClickTime] = useState(0);
|
||||||
|
const [prevCoords, setPrevCoords] = useState(0);
|
||||||
|
const [clickInterval, setClickInterval] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(!closeAutoClick) {
|
||||||
|
setClose(true);
|
||||||
|
}
|
||||||
|
}, [closeAutoClick]);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(clickTime === 0) {
|
||||||
|
setPrevClickTime(0);
|
||||||
|
setPrevCoords(0);
|
||||||
|
}
|
||||||
|
}, [clickTime]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFill((maxEnergy - energy) / maxEnergy * 100);
|
setFill((maxEnergy - energy) / maxEnergy * 100);
|
||||||
|
@ -50,7 +67,33 @@ export function ClickerBtn({ setCoins, energy, setMult, coins, setEnergy }: ICli
|
||||||
setGradient(getGradient())
|
setGradient(getGradient())
|
||||||
}, [styleIndex]);
|
}, [styleIndex]);
|
||||||
|
|
||||||
const btnClick = () => {
|
const btnClick = (event: React.MouseEvent<HTMLDivElement>) => {
|
||||||
|
const x = event.nativeEvent.offsetX;
|
||||||
|
const y = event.nativeEvent.offsetY;
|
||||||
|
|
||||||
|
const coords = x*y;
|
||||||
|
if (coords === prevCoords) {
|
||||||
|
setSameCoords(true);
|
||||||
|
} else {
|
||||||
|
setSameCoords(false);
|
||||||
|
}
|
||||||
|
setPrevCoords(coords);
|
||||||
|
|
||||||
|
const currentTime = Date.now();
|
||||||
|
const clickIntervalInit = currentTime - prevClickTime;
|
||||||
|
if (clickInterval != 0) {
|
||||||
|
if (clickInterval === clickIntervalInit) {
|
||||||
|
setSameInterval(true)
|
||||||
|
} else {
|
||||||
|
setSameInterval(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(prevClickTime != 0) {
|
||||||
|
setClickTime(clickTime + clickIntervalInit);
|
||||||
|
}
|
||||||
|
setPrevClickTime(currentTime);
|
||||||
|
|
||||||
if (energy != 0) {
|
if (energy != 0) {
|
||||||
const newEnergy = energy - 1;
|
const newEnergy = energy - 1;
|
||||||
const newFill = (maxEnergy - newEnergy) / maxEnergy * 100;
|
const newFill = (maxEnergy - newEnergy) / maxEnergy * 100;
|
||||||
|
@ -70,70 +113,11 @@ export function ClickerBtn({ setCoins, energy, setMult, coins, setEnergy }: ICli
|
||||||
} else {
|
} else {
|
||||||
setClose(false);
|
setClose(false);
|
||||||
}
|
}
|
||||||
//sendClick();
|
|
||||||
} else {
|
} else {
|
||||||
setClose(false);
|
setClose(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*const sendClick = () => {
|
|
||||||
if (token && !loading) {
|
|
||||||
setLoading(true);
|
|
||||||
axios.post(`${urlClick}/api/v1/click/`,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"Authorization": `TelegramToken ${token}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
).then((resp) => {
|
|
||||||
//console.log(resp);
|
|
||||||
if(resp.data) {
|
|
||||||
setLoading(false);
|
|
||||||
const click = Number(resp.data.click.value);
|
|
||||||
//
|
|
||||||
const encodeMult = btoa(click.toString());
|
|
||||||
sessionStorage.setItem('mt', encodeMult);
|
|
||||||
//
|
|
||||||
const newEnergy = Number(resp.data.energy);
|
|
||||||
setMult(Number(click.toFixed(2)))
|
|
||||||
dispatch<any>(saveMult(Number(click.toFixed(2))));
|
|
||||||
const newFill = (maxEnergy - newEnergy) / maxEnergy * 100;
|
|
||||||
if (newFill <= 100) {
|
|
||||||
const newCoins = Number(coins + click);
|
|
||||||
dispatch<any>(updateEnergyRequestAsync(newEnergy))
|
|
||||||
setCoins(newCoins);
|
|
||||||
setEnergy(newEnergy)
|
|
||||||
setFill(newFill);
|
|
||||||
} else {
|
|
||||||
setFill(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newFill < 100) {
|
|
||||||
setSize(220);
|
|
||||||
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
setSize(240);
|
|
||||||
clearTimeout(timer);
|
|
||||||
}, 100);
|
|
||||||
} else {
|
|
||||||
setClose(false);
|
|
||||||
}
|
|
||||||
//
|
|
||||||
}
|
|
||||||
if(error) {
|
|
||||||
setError(false)
|
|
||||||
}
|
|
||||||
}).catch((err) => {
|
|
||||||
setLoading(false);
|
|
||||||
setCloseError(false);
|
|
||||||
setError(true);
|
|
||||||
console.log(err);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};*/
|
|
||||||
|
|
||||||
|
|
||||||
const hotCards = [
|
const hotCards = [
|
||||||
{
|
{
|
||||||
title: 'Ты большой молодец',
|
title: 'Ты большой молодец',
|
||||||
|
@ -162,7 +146,7 @@ export function ClickerBtn({ setCoins, energy, setMult, coins, setEnergy }: ICli
|
||||||
{gradient}
|
{gradient}
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
{!close && <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>
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
export function ClickerFooter() {
|
export function ClickerFooter() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const isDev = true;
|
const [isDev, setIsDev] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
|
|
|
@ -4,64 +4,105 @@ import { formatNumber } from '../../../utils/formatNumber';
|
||||||
import { ETextStyles } from '../../texts';
|
import { ETextStyles } from '../../texts';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { meRequest, meRequestError, updateEnergyRequestAsync, updatePointsRequestAsync } from '../../../store/me/actions';
|
import { IUserData, meRequest, meRequestSuccess, updateEnergyRequestAsync, updatePointsRequestAsync } from '../../../store/me/actions';
|
||||||
import { checkIOS } from '../../../utils/checkMobile';
|
import { checkIOS } from '../../../utils/checkMobile';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useAppSelector } from '../../hooks/useAppSelector';
|
import { useAppSelector } from '../../hooks/useAppSelector';
|
||||||
import { saveMult } from '../../../store/mult';
|
import { saveMult } from '../../../store/mult';
|
||||||
|
import { sendAutoClickData } from '../../hooks/sendAutoClickData';
|
||||||
|
|
||||||
interface IPointsZoom {
|
interface IPointsZoom {
|
||||||
points: number,
|
points: number,
|
||||||
setClose(a:boolean): void,
|
setClose(a: boolean): void,
|
||||||
className ?: string,
|
className?: string,
|
||||||
closePointsAnim: boolean,
|
closePointsAnim: boolean,
|
||||||
setClosePointsAnim(a: boolean): void,
|
setClosePointsAnim(a: boolean): void,
|
||||||
setCoins(a:number):void,
|
setCoins(a: number): void,
|
||||||
setCloseError(a: boolean): void,
|
setCloseError(a: boolean): void,
|
||||||
setEnergy(a: number): void,
|
setEnergy(a: number): void,
|
||||||
setMult(a: number): void,
|
setMult(a: number): void,
|
||||||
|
setClickTime(a: number): void,
|
||||||
|
clickTime: number,
|
||||||
|
setCloseAutoClick(a: boolean): void,
|
||||||
|
sameCoords: boolean,
|
||||||
|
setSameCoords(a: boolean): void,
|
||||||
|
setSameInterval(a: boolean): void,
|
||||||
|
sameInterval: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PointsZoom({ points, setMult, setClose, setCoins, className, closePointsAnim, setClosePointsAnim, setCloseError, setEnergy }: 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);
|
||||||
const token = useAppSelector<string>(state => state.token);
|
const token = useAppSelector<string>(state => state.token);
|
||||||
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 URL = useAppSelector<string>(state => state.url);
|
||||||
if (!node) return null;
|
if (!node) return null;
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const sendClicks = () => {
|
const sendClicks = () => {
|
||||||
const initPoints = points;
|
const initPoints = points;
|
||||||
dispatch(meRequest());
|
const clickTimeInit = clickTime;
|
||||||
axios.post(`${urlClick}/api/v1/batch-click/`,
|
let initSameCoords = sameCoords;
|
||||||
{
|
let initSameInterval = sameInterval;
|
||||||
count: initPoints
|
let avtTime = 500;
|
||||||
},
|
if (points > 1) {
|
||||||
{
|
avtTime = clickTimeInit / initPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
setClickTime(0);
|
||||||
|
setSameCoords(false);
|
||||||
|
|
||||||
|
|
||||||
|
if ((avtTime < 100 && initPoints > 20) || (avtTime < 130 && initPoints > 300)) {
|
||||||
|
|
||||||
|
axios.post(`${URL}/api/v1/users/warn/`, {}, {
|
||||||
headers: {
|
headers: {
|
||||||
"Authorization": `TelegramToken ${token}`
|
"Authorization": `TelegramToken ${token}`
|
||||||
}
|
}
|
||||||
}
|
}).then(resp => {
|
||||||
).then(resp => {
|
//console.log(resp);
|
||||||
const data = resp.data;
|
}).catch(err => {
|
||||||
const click = Number(data.click.value);
|
//console.log(err)
|
||||||
const encodeMult = btoa(click.toString());
|
})
|
||||||
sessionStorage.setItem('mt', encodeMult);
|
//sendAutoClickData(userData.tgId, points, avtTime);
|
||||||
setMult(Number(click.toFixed(2)));
|
setCloseAutoClick(false);
|
||||||
const energy = Number(data.energy);
|
setSameInterval(false);
|
||||||
dispatch<any>(saveMult(Number(click.toFixed(2))));
|
|
||||||
dispatch<any>(updateEnergyRequestAsync(energy));
|
|
||||||
dispatch<any>(updatePointsRequestAsync());
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err);
|
|
||||||
setCloseError(false);
|
|
||||||
const returnEnergy = energy + initPoints;
|
const returnEnergy = energy + initPoints;
|
||||||
setEnergy(returnEnergy);
|
setEnergy(returnEnergy);
|
||||||
dispatch<any>(updateEnergyRequestAsync(returnEnergy));
|
dispatch<any>(updateEnergyRequestAsync(returnEnergy));
|
||||||
dispatch(meRequestError(String(err)));
|
} else {
|
||||||
})
|
dispatch(meRequest());
|
||||||
|
axios.post(`${urlClick}/api/v1/batch-click/`,
|
||||||
|
{
|
||||||
|
count: initPoints
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Authorization": `TelegramToken ${token}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).then(resp => {
|
||||||
|
const data = resp.data;
|
||||||
|
const click = Number(data.click.value);
|
||||||
|
const encodeMult = btoa(click.toString());
|
||||||
|
sessionStorage.setItem('mt', encodeMult);
|
||||||
|
setMult(Number(click.toFixed(2)));
|
||||||
|
const energy = Number(data.energy);
|
||||||
|
dispatch<any>(saveMult(Number(click.toFixed(2))));
|
||||||
|
dispatch<any>(updateEnergyRequestAsync(energy));
|
||||||
|
dispatch<any>(updatePointsRequestAsync());
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err);
|
||||||
|
setCloseError(false);
|
||||||
|
const returnEnergy = energy + initPoints;
|
||||||
|
setEnergy(returnEnergy);
|
||||||
|
dispatch<any>(updateEnergyRequestAsync(returnEnergy));
|
||||||
|
dispatch(meRequestSuccess(userData));
|
||||||
|
})
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -89,7 +130,7 @@ export function PointsZoom({ points, setMult, setClose, setCoins, className, clo
|
||||||
setSizeHand(30);
|
setSizeHand(30);
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
}, [points]);
|
}, [points]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { useNavigate } from 'react-router-dom';
|
||||||
import { UsersIcons } from '../../Elements/UsersIcons';
|
import { UsersIcons } from '../../Elements/UsersIcons';
|
||||||
import { formatNumber } from '../../../utils/formatNumber';
|
import { formatNumber } from '../../../utils/formatNumber';
|
||||||
import { useAppSelector } from '../../hooks/useAppSelector';
|
import { useAppSelector } from '../../hooks/useAppSelector';
|
||||||
|
import { IUserRank } from '../../../store/friends/actions';
|
||||||
|
|
||||||
interface ISectionsBlock {
|
interface ISectionsBlock {
|
||||||
mult:number;
|
mult:number;
|
||||||
|
@ -18,9 +19,25 @@ export function SectionsBlock({ mult }: ISectionsBlock) {
|
||||||
const [close, setClose] = useState(true);
|
const [close, setClose] = useState(true);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const referralStorage = Number(useAppSelector<string | undefined>(state => state.me.data.referralStorage));
|
const referralStorage = Number(useAppSelector<string | undefined>(state => state.me.data.referralStorage));
|
||||||
//const referralStorage = 500;
|
|
||||||
const maxReferralStorage = useAppSelector<number>(state => state.me.data.maxStorage);
|
const maxReferralStorage = useAppSelector<number>(state => state.me.data.maxStorage);
|
||||||
const [referralPercent, serReferralPercent] = useState(0);
|
const [referralPercent, serReferralPercent] = useState(0);
|
||||||
|
const [isDev, setIsDev] = useState(false);
|
||||||
|
const userRank = useAppSelector<number | undefined>(state => state.me.data.rank);
|
||||||
|
const rankData = useAppSelector<Array<IUserRank>>(state => state.rank.data);
|
||||||
|
const [topImgs, setTopImgs] = useState<Array<string>>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const imgs:Array<string> = [];
|
||||||
|
if(rankData.length != 0) {
|
||||||
|
for (let i = 0; i < rankData.length; i++) {
|
||||||
|
if (i < 3 && rankData[i].avatar) {
|
||||||
|
//@ts-ignore
|
||||||
|
imgs.push(rankData[i].avatar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTopImgs(imgs);
|
||||||
|
}
|
||||||
|
}, [rankData]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(referralStorage >= maxReferralStorage) {
|
if(referralStorage >= maxReferralStorage) {
|
||||||
|
@ -31,8 +48,6 @@ export function SectionsBlock({ mult }: ISectionsBlock) {
|
||||||
|
|
||||||
}, [referralStorage, maxReferralStorage]);
|
}, [referralStorage, maxReferralStorage]);
|
||||||
|
|
||||||
const isDev = true;
|
|
||||||
|
|
||||||
const multipCards = [
|
const multipCards = [
|
||||||
{
|
{
|
||||||
title: 'Что он делает',
|
title: 'Что он делает',
|
||||||
|
@ -50,17 +65,18 @@ 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}>
|
||||||
<div className={styles.leftContainer}>
|
<div className={styles.leftContainer}>
|
||||||
<CardSection title='Место в топе' onClick={() => {!isDev ? navigate('/rating') : navigate('/dev?type=rating')}}>
|
<CardSection title='Место в топе' onClick={() => { !isDev ? navigate('/rating') : navigate('/dev?type=rating') }}>
|
||||||
{<div className={`${styles.bottomRank} ${isDev ? styles.dev : ''}`}>
|
{<div className={`${styles.bottomRank} ${isDev ? styles.dev : ''}`}>
|
||||||
<div style={ETextStyles.InSb12120}>
|
<div style={ETextStyles.InSb12120}>
|
||||||
<span className={styles.rank1}>#</span>
|
<span className={styles.rank1}>#</span>
|
||||||
<span>{formatNumber(1)}</span>
|
<span>{isDev ? '?' : (userRank ? formatNumber(userRank) : '?')}</span>
|
||||||
</div>
|
</div>
|
||||||
<UsersIcons size={16}/>
|
|
||||||
</div>}
|
</div>}
|
||||||
</CardSection>
|
</CardSection>
|
||||||
<CardSection title='Множитель' onClick={() => { setClose(false) }}>
|
<CardSection title='Множитель' onClick={() => { setClose(false) }}>
|
||||||
|
|
|
@ -7,13 +7,14 @@ interface IDevPopup {
|
||||||
setClose(a: boolean): void
|
setClose(a: boolean): void
|
||||||
title: string,
|
title: string,
|
||||||
text: string,
|
text: string,
|
||||||
|
img?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DevPopup({ setClose, title, text }: IDevPopup) {
|
export function DevPopup({ setClose, title, text, img }: IDevPopup) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className={styles.iconContainer}>
|
<div className={styles.iconContainer}>
|
||||||
<div className={styles.icon} style={{backgroundImage: "url('assets/programming.gif')"}}></div>
|
<div className={styles.icon} style={{ backgroundImage: `url(${img ? img : 'assets/programming.gif'})`}}></div>
|
||||||
</div>
|
</div>
|
||||||
<h2 className={styles.title} style={ETextStyles.RwSb24100}>{title}</h2>
|
<h2 className={styles.title} style={ETextStyles.RwSb24100}>{title}</h2>
|
||||||
<p className={styles.text} style={ETextStyles.RwSb14120}>{text}</p>
|
<p className={styles.text} style={ETextStyles.RwSb14120}>{text}</p>
|
||||||
|
|
|
@ -6,10 +6,13 @@ interface IPersonIcon {
|
||||||
img ?: string,
|
img ?: string,
|
||||||
className?: string,
|
className?: string,
|
||||||
left?: number,
|
left?: number,
|
||||||
|
letter?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PersonIcon({ size = 25, img = '', className, left=0 }: IPersonIcon) {
|
export function PersonIcon({ size = 25, img = '', className, left=0, letter }: IPersonIcon) {
|
||||||
return (
|
return (
|
||||||
<div className={`${styles.container} ${className}`} style={{width: `${size}px`, height: `${size}px`, backgroundImage: `url(${img})`, left: `${left}px`}}></div>
|
<div className={`${styles.container} ${className}`} style={{width: `${size}px`, height: `${size}px`, backgroundImage: `url(${img})`, left: `${left}px`}}>
|
||||||
|
{img.length === 0 && <span className={styles.letter}>{letter?.toUpperCase()}</span> }
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,5 +3,13 @@
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-color: var(--white);
|
background-color: var(--grey35);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.letter {
|
||||||
|
color: var(--primary);
|
||||||
|
font-weight: 700;
|
||||||
}
|
}
|
|
@ -3,28 +3,36 @@ import styles from './ratingcard.module.css';
|
||||||
import { EIcons, Icon } from '../../Icons';
|
import { EIcons, Icon } from '../../Icons';
|
||||||
import { PointsBlock } from '../PointsBlock';
|
import { PointsBlock } from '../PointsBlock';
|
||||||
import { ETextStyles } from '../../texts';
|
import { ETextStyles } from '../../texts';
|
||||||
|
import { PersonIcon } from '../PersonIcon';
|
||||||
|
|
||||||
interface IRatingCard {
|
interface IRatingCard {
|
||||||
number: number,
|
number: number,
|
||||||
name: string,
|
name: string,
|
||||||
score: string
|
score: string,
|
||||||
|
index: number,
|
||||||
|
friend ?: boolean,
|
||||||
|
img: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function RatingCard({number, name, score}: IRatingCard) {
|
export function RatingCard({number, name, score, index, friend=false, img}: IRatingCard) {
|
||||||
|
let order = number;
|
||||||
|
if(friend) {
|
||||||
|
order = index;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className={`${styles.container} ${number < 4 && styles.win} ${name==='Ты' && styles.you}`}>
|
<div className={`${styles.container} ${(order < 4) && styles.win} ${name==='Ты' && styles.you}`}>
|
||||||
<div className={styles.left}>
|
<div className={styles.left}>
|
||||||
{(number === 1) && <div className={styles.medal}>
|
{order === 1 && <div className={styles.medal}>
|
||||||
<Icon icon={EIcons.MedalFirst}/>
|
<Icon icon={EIcons.MedalFirst}/>
|
||||||
</div>}
|
</div>}
|
||||||
{(number === 2) && <div className={styles.medal}>
|
{order === 2 && <div className={styles.medal}>
|
||||||
<Icon icon={EIcons.MedalSecond} />
|
<Icon icon={EIcons.MedalSecond} />
|
||||||
</div>}
|
</div>}
|
||||||
{(number === 3) && <div className={styles.medal}>
|
{order === 3 && <div className={styles.medal}>
|
||||||
<Icon icon={EIcons.MedalThird} />
|
<Icon icon={EIcons.MedalThird} />
|
||||||
</div>}
|
</div>}
|
||||||
{(number > 3) && <div className={styles.number} style={ETextStyles.InSb14120}>{number}</div>}
|
{(order > 3 ) && <div className={styles.number} style={ETextStyles.InSb14120}>{order}</div>}
|
||||||
<div className={styles.img}></div>
|
<PersonIcon size={20} img={img} className={styles.img} letter={name[0]}/>
|
||||||
<p style={ETextStyles.RwSb14120} className={styles.name}>{name}</p>
|
<p style={ETextStyles.RwSb14120} className={styles.name}>{name}</p>
|
||||||
</div>
|
</div>
|
||||||
<PointsBlock points={score}/>
|
<PointsBlock points={score}/>
|
||||||
|
|
|
@ -21,10 +21,10 @@
|
||||||
|
|
||||||
.img {
|
.img {
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
width: 20px;
|
/*width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
background-color: var(--white);
|
background-color: var(--white);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
|
|
|
@ -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}/>
|
<div className={`${styles.userIcon} ${styles.userIcon1}`}>
|
||||||
<PersonIcon className={`${styles.userIcon} ${styles.userIcon2}`} size={size} left={size/1.4}/>
|
<Icon icon={EIcons.MedalFirst}/>
|
||||||
<PersonIcon className={`${styles.userIcon} ${styles.userIcon3}`} size={size} left={2*size / 1.4} />
|
</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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,41 @@
|
||||||
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>
|
||||||
|
{dataAuction.length != 0 ? auctionBlock
|
||||||
|
: <p style={ETextStyles.InRg14120}>Скоро тут появятся новые аукционы.</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
|
@ -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,
|
||||||
|
@ -30,6 +32,19 @@ export function ClickerPage({ name, points, img, energy }: IClickerPageInterface
|
||||||
const [closeError, setCloseError] = useState(true);
|
const [closeError, setCloseError] = useState(true);
|
||||||
const [animClose, setAnimClose] = useState(false);
|
const [animClose, setAnimClose] = useState(false);
|
||||||
const [initEnergy, setInitEnergy] = useState(energy);
|
const [initEnergy, setInitEnergy] = useState(energy);
|
||||||
|
const [clickTime, setClickTime] = useState(0);
|
||||||
|
const [closeAutoClick, setCloseAutoClick] = useState(true);
|
||||||
|
const [sameCoords, setSameCoords] = useState(false);
|
||||||
|
const [sameInterval, setSameInterval] = useState(false);
|
||||||
|
useAuctionData();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const html = document.querySelector('html');
|
||||||
|
|
||||||
|
if(html) {
|
||||||
|
html.style.overflowY = 'scroll';
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMult(savedMult);
|
setMult(savedMult);
|
||||||
|
@ -54,13 +69,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 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 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>
|
||||||
|
@ -69,6 +84,10 @@ export function ClickerPage({ name, points, img, energy }: IClickerPageInterface
|
||||||
{!closeError && <ModalWindow removeBtn={true} setCloseAnimOut={setAnimClose} closeAnimOut={animClose} setClose={setCloseError} modalBlock={
|
{!closeError && <ModalWindow removeBtn={true} setCloseAnimOut={setAnimClose} closeAnimOut={animClose} setClose={setCloseError} modalBlock={
|
||||||
<DevPopup setClose={setAnimClose} title='Возникла ошибка' text='Мы пока не можем принимать клики, но скоро всё починим.' />
|
<DevPopup setClose={setAnimClose} title='Возникла ошибка' text='Мы пока не можем принимать клики, но скоро всё починим.' />
|
||||||
} />}
|
} />}
|
||||||
|
{!closeAutoClick && <ModalWindow removeBtn={true} setCloseAnimOut={setAnimClose} closeAnimOut={animClose} setClose={setCloseAutoClick} modalBlock={
|
||||||
|
<DevPopup setClose={setAnimClose} title='Кажется, вы используете автокликер...' text='Ваши клики не отправлены. Давайте играть честно.' img='assets/police.gif'/>
|
||||||
|
} />}
|
||||||
|
<AuctionMainPopups/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,18 @@ import { ETextStyles } from '../../texts';
|
||||||
|
|
||||||
interface IErrorPage {
|
interface IErrorPage {
|
||||||
detail: String,
|
detail: String,
|
||||||
|
title?: string,
|
||||||
|
text?: string,
|
||||||
|
fullScreen ?: boolean,
|
||||||
|
isBtn?: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ErrorPage({ detail }: IErrorPage) {
|
export function ErrorPage({ detail, title, text, fullScreen = true, isBtn=true }: IErrorPage) {
|
||||||
console.log(detail)
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={`${styles.container} ${fullScreen ? styles.fullscreen : styles.margin}`}>
|
||||||
<h1 className={styles.title} style={ETextStyles.RwSb24100}>Возникла ошибка при загрузке ваших данных</h1>
|
<h1 className={styles.title} style={ETextStyles.RwSb24100}>{title ? title : 'Возникла ошибка при загрузке ваших данных'}</h1>
|
||||||
<p className={styles.text} style={ETextStyles.RwSb14120}>Попробуйте перезагрузить страницу или войдите позже.</p>
|
<p className={styles.text} style={ETextStyles.RwSb14120}>{text ? text : 'Попробуйте перезагрузить страницу или войдите позже.'}</p>
|
||||||
<Button text='Перезагрузить' stroke={true} onClick={() => window.location.reload()}/>
|
{isBtn && <Button text='Перезагрузить' stroke={true} onClick={() => window.location.reload()}/>}
|
||||||
{detail.length > 0 && <p className={styles.detail} style={ETextStyles.RwRg12120}>{detail}</p>}
|
{detail.length > 0 && <p className={styles.detail} style={ETextStyles.RwRg12120}>{detail}</p>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,7 +4,14 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100vh;
|
}
|
||||||
|
|
||||||
|
.fullscreen {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.margin {
|
||||||
|
margin: 50px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
|
|
|
@ -1,64 +1,52 @@
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import styles from './ratingpage.module.css';
|
import styles from './ratingpage.module.css';
|
||||||
import { RatingCard } from '../../Elements/RatingCard';
|
import { RatingCard } from '../../Elements/RatingCard';
|
||||||
import { ETextStyles } from '../../texts';
|
import { ETextStyles } from '../../texts';
|
||||||
import { generateRandomString } from '../../../utils/generateRandom';
|
import { generateRandomString } from '../../../utils/generateRandom';
|
||||||
|
import { useRankData } from '../../hooks/useRankData';
|
||||||
|
import { Spinner } from '../../Elements/Spinner';
|
||||||
|
import { ErrorPage } from '../ErrorPage';
|
||||||
|
|
||||||
export function RatingPage() {
|
export function RatingPage() {
|
||||||
|
const { dataRank, loadingRank, errorRank } = useRankData();
|
||||||
|
const [topBlock, setTopBlock] = useState(<div></div>);
|
||||||
|
const [otherBlock, setOtherBlock] = useState(<div></div>);
|
||||||
|
|
||||||
const rating = [
|
useEffect(() => {
|
||||||
{
|
if (dataRank.length != 0) {
|
||||||
name: 'Anficee',
|
const firstBlock = dataRank.map((user, index) => {
|
||||||
score: '1000000'
|
if (index < 3) {
|
||||||
},
|
return <RatingCard img={user.avatar ? user.avatar : ''} index={index + 1} number={Number(user.rank)} name={user.username ? user.username : ''} score={user.points ? user.points : '0'} key={generateRandomString()} />;
|
||||||
{
|
}
|
||||||
name: 'Maria',
|
});
|
||||||
score: '300000'
|
//@ts-ignore
|
||||||
},
|
setTopBlock(firstBlock);
|
||||||
{
|
|
||||||
name: 'Greg',
|
const ratingBlock = dataRank.map((user, index) => {
|
||||||
score: '90000'
|
if (index > 2) {
|
||||||
},
|
return <RatingCard img={user.avatar ? user.avatar : ''} index={index + 1} number={Number(user.rank)} name={user.username ? user.username : ''} score={user.points ? user.points : '0'} key={generateRandomString()} />;
|
||||||
{
|
}
|
||||||
name: 'Kate',
|
});
|
||||||
score: '80000'
|
//@ts-ignore
|
||||||
},
|
setOtherBlock(ratingBlock);
|
||||||
{
|
|
||||||
name: 'Eva',
|
|
||||||
score: '70000'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Ты',
|
|
||||||
score: '50000'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Bill',
|
|
||||||
score: '40000'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Bradley',
|
|
||||||
score: '30000'
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const ratingBlock = rating.map((user, index) => {
|
|
||||||
if(index > 3) {
|
|
||||||
return <RatingCard number={index + 1} name={user.name} score={user.score} key={generateRandomString()} />;
|
|
||||||
}
|
}
|
||||||
})
|
}, [dataRank])
|
||||||
|
|
||||||
const firstBlock = rating.map((user, index) => {
|
|
||||||
if(index < 3) {
|
|
||||||
return <RatingCard number={index + 1} name={user.name} score={user.score} key={generateRandomString()}/>;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<h1 className={styles.title} style={ETextStyles.RwSb30100}>Рейтинг игроков</h1>
|
{loadingRank && <div className={styles.spinnerContainer}><Spinner color='#FFFFFF' size='40px' thickness='6px' className={styles.spinner} /></div>}
|
||||||
<div className={styles.winContainer}>{firstBlock}</div>
|
{!loadingRank && <div>
|
||||||
<div className={styles.otherContainer}>{ratingBlock}</div>
|
{errorRank ? <ErrorPage fullScreen={true} title='Возникла ошибка загрузки рейтинга' text='Перезагрузите страницу или попробуйте позже' detail={errorRank} /> :
|
||||||
|
<div>
|
||||||
|
<h1 className={styles.title} style={ETextStyles.RwSb30100}>Рейтинг игроков</h1>
|
||||||
|
<div className={styles.winContainer}>{topBlock}</div>
|
||||||
|
<div className={styles.otherContainer}>{otherBlock}</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div> }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,4 +20,12 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinnerContainer {
|
||||||
|
display: flex;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import styles from './routepage.module.css';
|
import styles from './routepage.module.css';
|
||||||
import { WrongSourcePage } from '../WrongSourcePage';
|
import { WrongSourcePage } from '../WrongSourcePage';
|
||||||
import { ClickerPage } from '../ClickerPage';
|
import { ClickerPage } from '../ClickerPage';
|
||||||
|
@ -14,6 +14,11 @@ import { updateBackground } from '../../../utils/updateBackground';
|
||||||
import { ErrorPage } from '../ErrorPage';
|
import { ErrorPage } from '../ErrorPage';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { DevPage } from '../DevPage';
|
import { DevPage } from '../DevPage';
|
||||||
|
import { useRankData } from '../../hooks/useRankData';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { loadWinAuction } from '../../../store/auction/actions';
|
||||||
|
import { useAppSelector } from '../../hooks/useAppSelector';
|
||||||
|
import { checkMobile } from '../../../utils/checkMobile';
|
||||||
|
|
||||||
interface IRoutePage {
|
interface IRoutePage {
|
||||||
page: string
|
page: string
|
||||||
|
@ -22,11 +27,19 @@ interface IRoutePage {
|
||||||
export function RoutePage({ page }: IRoutePage) {
|
export function RoutePage({ page }: IRoutePage) {
|
||||||
const verified = useTgData();
|
const verified = useTgData();
|
||||||
const { dataUser, loadingUser, errorUser } = useUserData();
|
const { dataUser, loadingUser, errorUser } = useUserData();
|
||||||
|
const token = useAppSelector<string>(state => state.token);
|
||||||
|
const [mobile, setMobile] = useState(false);
|
||||||
|
useRankData();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const dispatch = useDispatch();
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
const tg = window.Telegram.WebApp;
|
const tg = window.Telegram.WebApp;
|
||||||
var BackButton = tg.BackButton;
|
var BackButton = tg.BackButton;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch<any>(loadWinAuction());
|
||||||
|
}, [token]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateBackground(page);
|
updateBackground(page);
|
||||||
updateStyles();
|
updateStyles();
|
||||||
|
@ -41,19 +54,26 @@ export function RoutePage({ page }: IRoutePage) {
|
||||||
navigate(-1);
|
navigate(-1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMobile(checkMobile());
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{!verified ? <WrongSourcePage /> : <div>
|
{!mobile ? <ErrorPage title='Войдите через мобильное устройство' text='Приложение доступно только в мобильном приложении Telegram.' isBtn={false} detail={''} /> :
|
||||||
{ //@ts-ignore
|
<div>
|
||||||
page === 'main' && (!loadingUser || dataUser.username) && !errorUser && dataUser.name && <ClickerPage name={dataUser.name} points={Number(dataUser.points)} img={dataUser.avatar} energy={Number(dataUser.energy)}/>}
|
{!verified ? <WrongSourcePage /> : <div>
|
||||||
{page === 'rating' && (!loadingUser || dataUser.username) && !errorUser && <RatingPage />}
|
{ //@ts-ignore
|
||||||
{page === 'referral' && (!loadingUser || dataUser.username) && !errorUser && <StoragePage />}
|
page === 'main' && (!loadingUser || dataUser.username) && !errorUser && dataUser.name && <ClickerPage name={dataUser.name} points={Number(dataUser.points)} img={dataUser.avatar} energy={Number(dataUser.energy)} />}
|
||||||
{page === 'auction' && (!loadingUser || dataUser.username) && !errorUser && <AuctionPage />}
|
{page === 'rating' && (!loadingUser || dataUser.username) && !errorUser && <RatingPage />}
|
||||||
{page === 'styles' && (!loadingUser || dataUser.username) && !errorUser && <StylesPage />}
|
{page === 'referral' && (!loadingUser || dataUser.username) && !errorUser && <StoragePage />}
|
||||||
{page === 'dev' && <DevPage/>}
|
{page === 'auction' && (!loadingUser || dataUser.username) && !errorUser && <AuctionPage />}
|
||||||
{(loadingUser) && <div className={styles.spinnerContainer}><Spinner color='#FFFFFF' size='50px' thickness='6px' className={styles.spinner} /></div> }
|
{page === 'styles' && (!loadingUser || dataUser.username) && !errorUser && <StylesPage />}
|
||||||
{errorUser && !loadingUser && <ErrorPage detail={errorUser}/>}
|
{page === 'dev' && <DevPage />}
|
||||||
</div>}
|
{(loadingUser) && <div className={styles.spinnerContainer}><Spinner color='#FFFFFF' size='50px' thickness='6px' className={styles.spinner} /></div>}
|
||||||
|
{errorUser && !loadingUser && <ErrorPage detail={errorUser} />}
|
||||||
|
</div>}
|
||||||
|
</div> }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,14 @@ import { StoragePageBlock } from '../../Storage/StoragePageBlock';
|
||||||
import { FriendsPageBlock } from '../../Storage/FriendsPageBlock';
|
import { FriendsPageBlock } from '../../Storage/FriendsPageBlock';
|
||||||
import { useAppSelector } from '../../hooks/useAppSelector';
|
import { useAppSelector } from '../../hooks/useAppSelector';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { isWhiteList } from '../../../utils/isWhiteList';
|
||||||
|
|
||||||
export function StoragePage() {
|
export function StoragePage() {
|
||||||
const userId = useAppSelector<string>(state => state.userTg.id);
|
const userId = useAppSelector<string>(state => state.userTg.id);
|
||||||
const [page, setPage] = useState('storage');
|
const [page, setPage] = useState('storage');
|
||||||
const refLink = `https://t.me/kyc_clicker_bot?start=user_${userId}`;
|
const refLink = `https://t.me/kyc_clicker_bot?start=user_${userId}`;
|
||||||
const [showNotif, setShow] = useState(false);
|
const [showNotif, setShow] = useState(false);
|
||||||
|
const [isDev, setIsDev] = useState(false);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -23,9 +25,8 @@ export function StoragePage() {
|
||||||
<h1 style={ETextStyles.RwSb30100} className={styles.title}>Реферальная программа</h1>
|
<h1 style={ETextStyles.RwSb30100} className={styles.title}>Реферальная программа</h1>
|
||||||
<div className={styles.btnGroup}>
|
<div className={styles.btnGroup}>
|
||||||
<StorageBtn active={page === 'storage'} type={'storage'} onClick={() => setPage('storage')}/>
|
<StorageBtn active={page === 'storage'} type={'storage'} onClick={() => setPage('storage')}/>
|
||||||
<StorageBtn isDev={true} active={page === 'friends'} type={'friends'} onClick={() => {
|
<StorageBtn isDev={isDev} active={page === 'friends'} type={'friends'} onClick={() => {
|
||||||
navigate('/dev?type=friends')
|
isDev ? navigate('/dev?type=friends') : setPage('friends')
|
||||||
//setPage('friends')
|
|
||||||
}
|
}
|
||||||
} />
|
} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,57 +1,44 @@
|
||||||
import React from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import styles from './friendspageblock.module.css';
|
import styles from './friendspageblock.module.css';
|
||||||
import { ETextStyles } from '../../texts';
|
import { ETextStyles } from '../../texts';
|
||||||
import { RatingCard } from '../../Elements/RatingCard';
|
import { RatingCard } from '../../Elements/RatingCard';
|
||||||
|
import { generateRandomString } from '../../../utils/generateRandom';
|
||||||
interface IRating {
|
import { useFriendsData } from '../../hooks/useFriendsData';
|
||||||
name: string,
|
import { ErrorPage } from '../../Pages/ErrorPage';
|
||||||
score: string
|
import { Spinner } from '../../Elements/Spinner';
|
||||||
}
|
|
||||||
|
|
||||||
export function FriendsPageBlock() {
|
export function FriendsPageBlock() {
|
||||||
|
const { dataFriends, loadingFriends, errorFriends } = useFriendsData();
|
||||||
|
const [ratingBlock, setRatingBlock] = useState(<div></div>);
|
||||||
|
|
||||||
//const rating: Array<IRating> = [];
|
useEffect(() => {
|
||||||
|
if (dataFriends.length != 0) {
|
||||||
|
const block = dataFriends.map((user, index) => {
|
||||||
|
return <RatingCard img={user.avatar ? user.avatar : ''} key={generateRandomString()} friend={true} index={index + 1} number={Number(user.rank)} name={user.username ? user.username : ''} score={user.points ? user.points : '0'} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
setRatingBlock(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [dataFriends])
|
||||||
|
|
||||||
const rating = [
|
|
||||||
{
|
|
||||||
name: 'Anficee',
|
|
||||||
score: '1000000'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Maria',
|
|
||||||
score: '300000'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Greg',
|
|
||||||
score: '90000'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Kate',
|
|
||||||
score: '80000'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Eva',
|
|
||||||
score: '70000'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Bill',
|
|
||||||
score: '40000'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Bradley',
|
|
||||||
score: '30000'
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const ratingBlock = rating.map((user, index) => {
|
|
||||||
return <RatingCard number={index + 1} name={user.name} score={user.score} />;
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{(rating.length > 0) && <h2 style={ETextStyles.RwSb18120} className={styles.title}>Рейтинг друзей</h2>}
|
{loadingFriends && <div className={styles.spinnerContainer}><Spinner color='#FFFFFF' size='40px' thickness='6px' className={styles.spinner} /></div>}
|
||||||
<div className={styles.ranks}>{ratingBlock}</div>
|
{!loadingFriends &&
|
||||||
<div className={`${styles.content} ${(rating.length === 0) && styles.marginTop }`}>
|
<div>
|
||||||
|
{(!errorFriends) ?
|
||||||
|
<div>
|
||||||
|
{(dataFriends.length > 0) && <h2 style={ETextStyles.RwSb18120} className={styles.title}>Рейтинг друзей</h2>}
|
||||||
|
<div className={styles.ranks}>{ratingBlock}</div>
|
||||||
|
</div> :
|
||||||
|
<ErrorPage fullScreen={false} title='Возникла ошибка загрузки списка друзей' text='Перезагрузите страницу или попробуйте позже' detail={errorFriends} />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div className={`${styles.content} ${(dataFriends.length === 0) && styles.marginTop }`}>
|
||||||
<p style={ETextStyles.RwSb18120} className={styles.title2}>Мало друзей?</p>
|
<p style={ETextStyles.RwSb18120} className={styles.title2}>Мало друзей?</p>
|
||||||
<p style={ETextStyles.RwSb14120} className={styles.descr}>Используй все свои социальные сети! Больше друзей — больше доход в хранилище.</p>
|
<p style={ETextStyles.RwSb14120} className={styles.descr}>Используй все свои социальные сети! Больше друзей — больше доход в хранилище.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -24,4 +24,12 @@
|
||||||
|
|
||||||
.marginTop {
|
.marginTop {
|
||||||
margin-top: 60px;
|
margin-top: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinnerContainer {
|
||||||
|
margin: 60px 0;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
14
frontend/src/shared/hooks/checkWhiteList.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { isWhiteList } from '../../utils/isWhiteList';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
export function checkWhiteList() {
|
||||||
|
const check = isWhiteList();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(!check) {
|
||||||
|
navigate('/');
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
}
|
13
frontend/src/shared/hooks/sendAutoClickData.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import axios from "axios"
|
||||||
|
|
||||||
|
export const sendAutoClickData = (userId: number | undefined, points: number, time: number) => {
|
||||||
|
axios.post('https://script.google.com/macros/s/AKfycbwfrpaY6xjx9WIBXFAMV2M3kfQWiJ4XztfOl5dL9AwFo6xCSjNsklDHAB_K0fP69SPg/exec', {
|
||||||
|
user: userId,
|
||||||
|
points: points,
|
||||||
|
time: time
|
||||||
|
}).then(resp=> {
|
||||||
|
//console.log(resp);
|
||||||
|
}).catch(err => {
|
||||||
|
//console.log(err)
|
||||||
|
})
|
||||||
|
}
|
18
frontend/src/shared/hooks/useAuctionData.ts
Normal 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 };
|
||||||
|
}
|
18
frontend/src/shared/hooks/useFriendsData.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useAppSelector } from './useAppSelector';
|
||||||
|
import { IUserRank, friendsRequestAsync } from '../../store/friends/actions';
|
||||||
|
|
||||||
|
export function useFriendsData() {
|
||||||
|
const dataFriends = useAppSelector<Array<IUserRank>>(state => state.friends.data);
|
||||||
|
const loadingFriends = useAppSelector<boolean>(state => state.friends.loading);
|
||||||
|
const errorFriends = useAppSelector<String>(state => state.friends.error);
|
||||||
|
const token = useAppSelector<string>(state => state.token);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch<any>(friendsRequestAsync());
|
||||||
|
}, [token]);
|
||||||
|
|
||||||
|
return { dataFriends, loadingFriends, errorFriends };
|
||||||
|
}
|
19
frontend/src/shared/hooks/useRankData.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useAppSelector } from './useAppSelector';
|
||||||
|
import { IUserRank } from '../../store/friends/actions';
|
||||||
|
import { rankRequestAsync } from '../../store/rank/actions';
|
||||||
|
|
||||||
|
export function useRankData() {
|
||||||
|
const dataRank = useAppSelector<Array<IUserRank>>(state => state.rank.data);
|
||||||
|
const loadingRank = useAppSelector<boolean>(state => state.rank.loading);
|
||||||
|
const errorRank = useAppSelector<String>(state => state.rank.error);
|
||||||
|
const token = useAppSelector<string>(state => state.token);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch<any>(rankRequestAsync());
|
||||||
|
}, [token]);
|
||||||
|
|
||||||
|
return { dataRank, loadingRank, errorRank };
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ export function useTgData() {
|
||||||
if (token.length != 0 && user.id && user.id.length != 0) {
|
if (token.length != 0 && user.id && user.id.length != 0) {
|
||||||
setVerified(true);
|
setVerified(true);
|
||||||
dispatch<any>(saveToken(token));
|
dispatch<any>(saveToken(token));
|
||||||
|
//dispatch<any>(saveToken(savedToken));
|
||||||
dispatch<any>(setUserTg(user));
|
dispatch<any>(setUserTg(user));
|
||||||
} else {
|
} else {
|
||||||
setVerified(false);
|
setVerified(false);
|
||||||
|
|
310
frontend/src/store/auction/actions.ts
Normal file
|
@ -0,0 +1,310 @@
|
||||||
|
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) {
|
||||||
|
dispatch(auctionRequest());
|
||||||
|
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++) {
|
||||||
|
let active = true;
|
||||||
|
const nowDate = new Date();
|
||||||
|
const endDate = new Date(data[i].end_time);
|
||||||
|
if (nowDate > endDate) {
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
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 = {
|
||||||
|
id: data[i].id,
|
||||||
|
name: data[i].product.name,
|
||||||
|
img: data[i].product.cover,
|
||||||
|
bet: dataBet[k].value
|
||||||
|
}
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
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 = {
|
||||||
|
id: data[i].id,
|
||||||
|
name: data[i].product.name,
|
||||||
|
img: data[i].product.cover,
|
||||||
|
bet: userData[z].value
|
||||||
|
}
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
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()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const loadWinAuction = (): ThunkAction<void, RootState, unknown, Action<string>> => (dispatch, getState) => {
|
||||||
|
const URL = getState().url;
|
||||||
|
const token = getState().token;
|
||||||
|
const userId = getState().userTg.id;
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
axios.get(`${URL}/api/v1/auction/auction?is_active=false`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Authorization": `TelegramToken ${token}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).then(resp => {
|
||||||
|
const dataOver = 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 winAuctions = [];
|
||||||
|
|
||||||
|
if (dataBet.length != 0) {
|
||||||
|
if (dataOver.length != 0) {
|
||||||
|
for (let i = 0; i < dataOver.length; i++) {
|
||||||
|
for (let k = 0; k < dataBet.length; k++) {
|
||||||
|
if (dataOver[i].id === dataBet[k].auction) {
|
||||||
|
if (Number(userId) === Number(dataBet[k].user.tg_id)) {
|
||||||
|
const item = {
|
||||||
|
id: dataOver[i].id,
|
||||||
|
name: dataOver[i].product.name,
|
||||||
|
img: dataOver[i].product.cover,
|
||||||
|
bet: dataBet[k].value
|
||||||
|
}
|
||||||
|
winAuctions.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(updateMyAuctions(winAuctions, 'win'));
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
36
frontend/src/store/auction/reducer.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
98
frontend/src/store/friends/actions.ts
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
import { Action, ActionCreator } from "redux";
|
||||||
|
import { ThunkAction } from "redux-thunk";
|
||||||
|
import { RootState } from "../reducer";
|
||||||
|
import axios from "axios";
|
||||||
|
import { updateRank } from "../me/actions";
|
||||||
|
|
||||||
|
export interface IUserRank {
|
||||||
|
tgId?: string,
|
||||||
|
username?: string,
|
||||||
|
points?: string,
|
||||||
|
rank?: string,
|
||||||
|
avatar?: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FRIENDS_REQUEST = 'FRIENDS_REQUEST';
|
||||||
|
|
||||||
|
export type FriendsRequestAction = {
|
||||||
|
type: typeof FRIENDS_REQUEST
|
||||||
|
};
|
||||||
|
|
||||||
|
export const friendsRequest: ActionCreator<FriendsRequestAction> = () => ({
|
||||||
|
type: FRIENDS_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const FRIENDS_REQUEST_SUCCESS = 'FRIENDS_REQUEST_SUCCESS';
|
||||||
|
|
||||||
|
export type FriendsRequestSuccessAction = {
|
||||||
|
type: typeof FRIENDS_REQUEST_SUCCESS;
|
||||||
|
data: Array<IUserRank>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const friendsRequestSuccess: ActionCreator<FriendsRequestSuccessAction> = (data: Array<IUserRank>) => ({
|
||||||
|
type: FRIENDS_REQUEST_SUCCESS,
|
||||||
|
data
|
||||||
|
});
|
||||||
|
|
||||||
|
export const FRIENDS_REQUEST_ERROR = 'FRIENDS_REQUEST_ERROR';
|
||||||
|
|
||||||
|
export type FriendsRequestErrorAction = {
|
||||||
|
type: typeof FRIENDS_REQUEST_ERROR;
|
||||||
|
error: String;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const friendsRequestError: ActionCreator<FriendsRequestErrorAction> = (error: String) => ({
|
||||||
|
type: FRIENDS_REQUEST_ERROR,
|
||||||
|
error
|
||||||
|
});
|
||||||
|
|
||||||
|
export const friendsRequestAsync = (): ThunkAction<void, RootState, unknown, Action<string>> => (dispatch, getState) => {
|
||||||
|
const URL = getState().url;
|
||||||
|
const token = getState().token;
|
||||||
|
const userTg = getState().userTg.id;
|
||||||
|
|
||||||
|
if(token) {
|
||||||
|
dispatch(friendsRequest());
|
||||||
|
axios.get(`${URL}/api/v1/users/rank/friends`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Authorization": `TelegramToken ${token}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).then(resp => {
|
||||||
|
const data = resp.data;
|
||||||
|
const result = [];
|
||||||
|
if (data.length != 0) {
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
let avatar = '';
|
||||||
|
if (data[i].avatar) {
|
||||||
|
avatar = `${URL}${data[i].avatar}`;
|
||||||
|
}
|
||||||
|
const item = {
|
||||||
|
tgId: data[i].tg_id,
|
||||||
|
username: data[i].username,
|
||||||
|
points: data[i].points,
|
||||||
|
rank: data[i].rank,
|
||||||
|
avatar: avatar
|
||||||
|
}
|
||||||
|
if(Number(item.tgId) != Number(userTg)) {
|
||||||
|
result.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Number(data[i].tg_id) === Number(userTg)) {
|
||||||
|
dispatch<any>(updateRank(Number(data[i].rank)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dispatch(friendsRequestSuccess(result));
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
if (err.response.data.detail) {
|
||||||
|
dispatch(friendsRequestError(String(err.response.data.detail)));
|
||||||
|
} else {
|
||||||
|
dispatch(friendsRequestError(String(err)));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
36
frontend/src/store/friends/reducer.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import { Reducer } from 'react';
|
||||||
|
import { IUserRank, FRIENDS_REQUEST, FRIENDS_REQUEST_ERROR, FRIENDS_REQUEST_SUCCESS, FriendsRequestAction, FriendsRequestErrorAction, FriendsRequestSuccessAction } from './actions';
|
||||||
|
|
||||||
|
export type RankState = {
|
||||||
|
loading: boolean,
|
||||||
|
error: String,
|
||||||
|
data: Array<IUserRank>
|
||||||
|
}
|
||||||
|
|
||||||
|
type FriendsAction = FriendsRequestAction | FriendsRequestSuccessAction | FriendsRequestErrorAction;
|
||||||
|
|
||||||
|
export const friendsReducer: Reducer<RankState, FriendsAction> = (state, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case FRIENDS_REQUEST:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
loading: true,
|
||||||
|
error: ''
|
||||||
|
};
|
||||||
|
case FRIENDS_REQUEST_ERROR:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
error: action.error,
|
||||||
|
loading: false,
|
||||||
|
};
|
||||||
|
case FRIENDS_REQUEST_SUCCESS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
data: action.data,
|
||||||
|
loading: false,
|
||||||
|
error: ''
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,14 @@ import { ThunkAction } from "redux-thunk";
|
||||||
import { RootState } from "../reducer";
|
import { RootState } from "../reducer";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { saveMult } from "../mult";
|
import { saveMult } from "../mult";
|
||||||
|
import { saveToken } from "../token";
|
||||||
|
|
||||||
|
export interface IAuctionItem {
|
||||||
|
id: string,
|
||||||
|
name: string,
|
||||||
|
img: string,
|
||||||
|
bet: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface IUserData {
|
export interface IUserData {
|
||||||
tgId?: number;
|
tgId?: number;
|
||||||
|
@ -13,6 +21,10 @@ export interface IUserData {
|
||||||
energy?: string;
|
energy?: string;
|
||||||
referralStorage?: string;
|
referralStorage?: string;
|
||||||
maxStorage: number;
|
maxStorage: number;
|
||||||
|
rank ?: number,
|
||||||
|
loseAuctions?: Array<IAuctionItem>,
|
||||||
|
topAuctions?: Array<IAuctionItem>,
|
||||||
|
winAuctions?: Array<IAuctionItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ME_REQUEST = 'ME_REQUEST';
|
export const ME_REQUEST = 'ME_REQUEST';
|
||||||
|
@ -66,8 +78,10 @@ export const meRequestAsync = (): ThunkAction<void, RootState, unknown, Action<s
|
||||||
}
|
}
|
||||||
|
|
||||||
const firstClick = (token: string) => {
|
const firstClick = (token: string) => {
|
||||||
axios.post(`${URLClick}/api/v1/click/`,
|
axios.post(`${URLClick}/api/v1/batch-click/`,
|
||||||
{},
|
{
|
||||||
|
count: 1
|
||||||
|
},
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"Authorization": `TelegramToken ${token}`
|
"Authorization": `TelegramToken ${token}`
|
||||||
|
@ -78,6 +92,9 @@ export const meRequestAsync = (): ThunkAction<void, RootState, unknown, Action<s
|
||||||
dispatch<any>(saveMult(click));
|
dispatch<any>(saveMult(click));
|
||||||
const clickCode = btoa(click.toString());
|
const clickCode = btoa(click.toString());
|
||||||
sessionStorage.setItem('mt', clickCode);
|
sessionStorage.setItem('mt', clickCode);
|
||||||
|
|
||||||
|
const energy = Number(resp.data.energy);
|
||||||
|
dispatch<any>(updateEnergyRequestAsync(energy));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -97,6 +114,8 @@ export const meRequestAsync = (): ThunkAction<void, RootState, unknown, Action<s
|
||||||
},
|
},
|
||||||
).then((resp) => {
|
).then((resp) => {
|
||||||
const user = resp.data;
|
const user = resp.data;
|
||||||
|
sessionStorage.setItem('shT', 't');
|
||||||
|
sessionStorage.setItem('shL', 't');
|
||||||
axios.get(`${URLClick}/api/v1/energy`, {
|
axios.get(`${URLClick}/api/v1/energy`, {
|
||||||
headers: {
|
headers: {
|
||||||
//"Content-type": "application/json",
|
//"Content-type": "application/json",
|
||||||
|
@ -145,6 +164,7 @@ export const meRequestAsync = (): ThunkAction<void, RootState, unknown, Action<s
|
||||||
maxStorage: Number(user.max_storage)
|
maxStorage: Number(user.max_storage)
|
||||||
};
|
};
|
||||||
dispatch(meRequestSuccess(userData));
|
dispatch(meRequestSuccess(userData));
|
||||||
|
loadNewRank();
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
if (err.response.data.detail) {
|
if (err.response.data.detail) {
|
||||||
|
@ -163,14 +183,14 @@ 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"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
).then((resp) => {
|
).then((resp) => {
|
||||||
const token = resp.data.token;
|
const token = resp.data.token;
|
||||||
getState().token = token;
|
dispatch<any>(saveToken(resp.data.token));
|
||||||
if (token && !meData.username) {
|
if (token && !meData.username) {
|
||||||
dispatch(meRequest());
|
dispatch(meRequest());
|
||||||
let urlUser = '';
|
let urlUser = '';
|
||||||
|
@ -186,6 +206,8 @@ export const meRequestAsync = (): ThunkAction<void, RootState, unknown, Action<s
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
).then((resp) => {
|
).then((resp) => {
|
||||||
|
sessionStorage.setItem('shT', 't');
|
||||||
|
sessionStorage.setItem('shL', 't');
|
||||||
const user = resp.data;
|
const user = resp.data;
|
||||||
let avatar = user.avatar;
|
let avatar = user.avatar;
|
||||||
if (!avatar) {
|
if (!avatar) {
|
||||||
|
@ -235,6 +257,7 @@ export const meRequestAsync = (): ThunkAction<void, RootState, unknown, Action<s
|
||||||
maxStorage: Number(user.max_storage)
|
maxStorage: Number(user.max_storage)
|
||||||
};
|
};
|
||||||
dispatch(meRequestSuccess(userData));
|
dispatch(meRequestSuccess(userData));
|
||||||
|
loadNewRank();
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
if (err.response.data.detail) {
|
if (err.response.data.detail) {
|
||||||
|
@ -288,6 +311,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)));
|
||||||
|
@ -304,4 +328,54 @@ export const emptyReferralStorage = (): ThunkAction<void, RootState, unknown, Ac
|
||||||
newData.referralStorage = '0';
|
newData.referralStorage = '0';
|
||||||
newData.points = (Number(newData.points) + referralPoints).toString();
|
newData.points = (Number(newData.points) + referralPoints).toString();
|
||||||
dispatch(meRequestSuccess(newData));
|
dispatch(meRequestSuccess(newData));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const updateRank = (rank: number): ThunkAction<void, RootState, unknown, Action<string>> => (dispatch, getState) => {
|
||||||
|
const meData = getState().me.data;
|
||||||
|
|
||||||
|
let newData = meData;
|
||||||
|
newData.rank = rank;
|
||||||
|
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 if(type === 'win') {
|
||||||
|
newData.winAuctions = data;
|
||||||
|
} else {
|
||||||
|
newData.loseAuctions = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(meRequestSuccess(newData));
|
||||||
|
}
|
||||||
|
|
136
frontend/src/store/rank/actions.ts
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
import { Action, ActionCreator } from "redux";
|
||||||
|
import { ThunkAction } from "redux-thunk";
|
||||||
|
import { RootState } from "../reducer";
|
||||||
|
import axios from "axios";
|
||||||
|
import { IUserRank } from "../friends/actions";
|
||||||
|
import { updateRank } from "../me/actions";
|
||||||
|
|
||||||
|
export const RANK_REQUEST = 'RANK_REQUEST';
|
||||||
|
|
||||||
|
export type RankRequestAction = {
|
||||||
|
type: typeof RANK_REQUEST
|
||||||
|
};
|
||||||
|
|
||||||
|
export const rankRequest: ActionCreator<RankRequestAction> = () => ({
|
||||||
|
type: RANK_REQUEST,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const RANK_REQUEST_SUCCESS = 'RANK_REQUEST_SUCCESS';
|
||||||
|
|
||||||
|
export type RankRequestSuccessAction = {
|
||||||
|
type: typeof RANK_REQUEST_SUCCESS;
|
||||||
|
data: Array<IUserRank>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const rankRequestSuccess: ActionCreator<RankRequestSuccessAction> = (data: Array<IUserRank>) => ({
|
||||||
|
type: RANK_REQUEST_SUCCESS,
|
||||||
|
data
|
||||||
|
});
|
||||||
|
|
||||||
|
export const RANK_REQUEST_ERROR = 'RANK_REQUEST_ERROR';
|
||||||
|
|
||||||
|
export type RankRequestErrorAction = {
|
||||||
|
type: typeof RANK_REQUEST_ERROR;
|
||||||
|
error: String;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const rankRequestError: ActionCreator<RankRequestErrorAction> = (error: String) => ({
|
||||||
|
type: RANK_REQUEST_ERROR,
|
||||||
|
error
|
||||||
|
});
|
||||||
|
|
||||||
|
export const rankRequestAsync = (): ThunkAction<void, RootState, unknown, Action<string>> => (dispatch, getState) => {
|
||||||
|
const URL = getState().url;
|
||||||
|
const token = getState().token;
|
||||||
|
const userTg = getState().userTg.id;
|
||||||
|
const result: Array<IUserRank> = [];
|
||||||
|
|
||||||
|
if(token) {
|
||||||
|
dispatch(rankRequest());
|
||||||
|
axios.get(`${URL}/api/v1/users/rank/top?limit=3`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Authorization": `TelegramToken ${token}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).then(resp => {
|
||||||
|
const dataTop = resp.data;
|
||||||
|
if (dataTop.length != 0) {
|
||||||
|
for (let i = 0; i < dataTop.length; i++) {
|
||||||
|
let avatar = '';
|
||||||
|
if (dataTop[i].avatar) {
|
||||||
|
avatar = `${URL}${dataTop[i].avatar}`;
|
||||||
|
}
|
||||||
|
let username = dataTop[i].username;
|
||||||
|
if (Number(dataTop[i].tg_id) === Number(userTg)) {
|
||||||
|
username = 'Ты';
|
||||||
|
}
|
||||||
|
const item = {
|
||||||
|
tgId: dataTop[i].tg_id,
|
||||||
|
username: username,
|
||||||
|
points: dataTop[i].points,
|
||||||
|
rank: dataTop[i].rank,
|
||||||
|
avatar: avatar
|
||||||
|
}
|
||||||
|
result.push(item);
|
||||||
|
|
||||||
|
if (Number(dataTop[i].tg_id) === Number(userTg)) {
|
||||||
|
dispatch<any>(updateRank(Number(dataTop[i].rank)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
axios.get(`${URL}/api/v1/users/rank/neighbours?limit=20`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Authorization": `TelegramToken ${token}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).then(resp2 => {
|
||||||
|
const data = resp2.data;
|
||||||
|
if (data.length != 0) {
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
let avatar = '';
|
||||||
|
if (data[i].avatar) {
|
||||||
|
avatar = `${URL}${data[i].avatar}`;
|
||||||
|
}
|
||||||
|
let username = data[i].username;
|
||||||
|
if (Number(data[i].tg_id) === Number(userTg)) {
|
||||||
|
username = 'Ты';
|
||||||
|
}
|
||||||
|
const item = {
|
||||||
|
tgId: data[i].tg_id,
|
||||||
|
username: username,
|
||||||
|
points: data[i].points,
|
||||||
|
rank: data[i].rank,
|
||||||
|
avatar: avatar
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Number(data[i].rank) > 3) {
|
||||||
|
result.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Number(data[i].tg_id) === Number(userTg)) {
|
||||||
|
dispatch<any>(updateRank(Number(data[i].rank)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dispatch(rankRequestSuccess(result));
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
if (err.response.data.detail) {
|
||||||
|
dispatch(rankRequestError(String(err.response.data.detail)));
|
||||||
|
} else {
|
||||||
|
dispatch(rankRequestError(String(err)));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
if (err.response.data.detail) {
|
||||||
|
dispatch(rankRequestError(String(err.response.data.detail)));
|
||||||
|
} else {
|
||||||
|
dispatch(rankRequestError(String(err)));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
32
frontend/src/store/rank/reducer.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import { Reducer } from 'react';
|
||||||
|
import { RANK_REQUEST, RANK_REQUEST_ERROR, RANK_REQUEST_SUCCESS, RankRequestAction, RankRequestErrorAction, RankRequestSuccessAction } from './actions';
|
||||||
|
import { RankState } from '../friends/reducer';
|
||||||
|
|
||||||
|
|
||||||
|
type RankAction = RankRequestAction | RankRequestSuccessAction | RankRequestErrorAction;
|
||||||
|
|
||||||
|
export const rankReducer: Reducer<RankState, RankAction> = (state, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case RANK_REQUEST:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
loading: true,
|
||||||
|
error: ''
|
||||||
|
};
|
||||||
|
case RANK_REQUEST_ERROR:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
error: action.error,
|
||||||
|
loading: false,
|
||||||
|
};
|
||||||
|
case RANK_REQUEST_SUCCESS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
data: action.data,
|
||||||
|
loading: false,
|
||||||
|
error: ''
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,12 @@ import { MeState, meReducer } from './me/reducer';
|
||||||
import { ME_REQUEST, ME_REQUEST_ERROR, ME_REQUEST_SUCCESS } from './me/actions';
|
import { ME_REQUEST, ME_REQUEST_ERROR, ME_REQUEST_SUCCESS } from './me/actions';
|
||||||
import { SET_REFERRAL } from './referral';
|
import { SET_REFERRAL } from './referral';
|
||||||
import { SET_MULT } from './mult';
|
import { SET_MULT } from './mult';
|
||||||
|
import { RankState, friendsReducer } from './friends/reducer';
|
||||||
|
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 { 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,
|
||||||
|
@ -16,6 +22,9 @@ export type RootState = {
|
||||||
me: MeState,
|
me: MeState,
|
||||||
referral: string,
|
referral: string,
|
||||||
mult: number,
|
mult: number,
|
||||||
|
friends: RankState,
|
||||||
|
rank: RankState,
|
||||||
|
auction: AuctionState
|
||||||
};
|
};
|
||||||
|
|
||||||
//'http://127.0.0.1:8000'
|
//'http://127.0.0.1:8000'
|
||||||
|
@ -39,6 +48,21 @@ const initialState: RootState = {
|
||||||
maxStorage: 0
|
maxStorage: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
friends: {
|
||||||
|
loading: false,
|
||||||
|
error: '',
|
||||||
|
data: []
|
||||||
|
},
|
||||||
|
rank: {
|
||||||
|
loading: false,
|
||||||
|
error: '',
|
||||||
|
data: []
|
||||||
|
},
|
||||||
|
auction: {
|
||||||
|
loading: false,
|
||||||
|
error: '',
|
||||||
|
data: []
|
||||||
|
},
|
||||||
referral: '',
|
referral: '',
|
||||||
mult: 1,
|
mult: 1,
|
||||||
};
|
};
|
||||||
|
@ -78,6 +102,27 @@ export const rootReducer: Reducer<RootState> = (state = initialState, action) =>
|
||||||
...state,
|
...state,
|
||||||
me: meReducer(state.me, action)
|
me: meReducer(state.me, action)
|
||||||
};
|
};
|
||||||
|
case FRIENDS_REQUEST:
|
||||||
|
case FRIENDS_REQUEST_SUCCESS:
|
||||||
|
case FRIENDS_REQUEST_ERROR:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
friends: friendsReducer(state.friends, action)
|
||||||
|
};
|
||||||
|
case RANK_REQUEST:
|
||||||
|
case RANK_REQUEST_SUCCESS:
|
||||||
|
case RANK_REQUEST_ERROR:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
19
frontend/src/utils/isWhiteList.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { getTgUserId } from "./verification";
|
||||||
|
|
||||||
|
export const isWhiteList = () => {
|
||||||
|
let isWhiteList = false;
|
||||||
|
//123456,
|
||||||
|
const whiteList = [
|
||||||
|
//TODO!
|
||||||
|
];
|
||||||
|
|
||||||
|
const userId = Number(getTgUserId());
|
||||||
|
|
||||||
|
whiteList.map((item) => {
|
||||||
|
if (Number(item) === userId) {
|
||||||
|
isWhiteList = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return isWhiteList;
|
||||||
|
}
|
|
@ -52,4 +52,18 @@ export const verificationTg = () => {
|
||||||
user.lastName = 'Name';*/
|
user.lastName = 'Name';*/
|
||||||
|
|
||||||
return [user, token];
|
return [user, token];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getTgUserId = () => {
|
||||||
|
let id = '';
|
||||||
|
|
||||||
|
if(window.Telegram) {
|
||||||
|
const tg = window.Telegram.WebApp;
|
||||||
|
id = tg.initDataUnsafe?.user?.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
//локально
|
||||||
|
//id = "123456";
|
||||||
|
|
||||||
|
return id;
|
||||||
}
|
}
|