autoclick add & add ranks
This commit is contained in:
parent
9e9fcc5f94
commit
16932959d5
BIN
frontend/src/.DS_Store
vendored
BIN
frontend/src/.DS_Store
vendored
Binary file not shown.
|
@ -1,27 +1,26 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import styles from './clickerbtn.module.css';
|
||||
import { ModalWindow } from '../../ModalWindow';
|
||||
import { ClickerPopup } from '../ClickerPopup';
|
||||
import { getGradient } from '../../../utils/getGradient';
|
||||
import { useAppSelector } from '../../hooks/useAppSelector';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { IUserData, updateEnergyRequestAsync } from '../../../store/me/actions';
|
||||
import axios from 'axios';
|
||||
import { DevPopup } from '../../Elements/DevPopup';
|
||||
import { saveMult } from '../../../store/mult';
|
||||
import { Spinner } from '../../Elements/Spinner';
|
||||
import { updateEnergyRequestAsync } from '../../../store/me/actions';
|
||||
|
||||
interface IClickerBtn {
|
||||
coins: number,
|
||||
setCoins(a: number): void,
|
||||
energy: number,
|
||||
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
|
||||
}
|
||||
|
||||
export function ClickerBtn({ setCoins, energy, setMult, coins, setEnergy }: IClickerBtn) {
|
||||
const urlClick = useAppSelector<string>(state => state.urlClick);
|
||||
const token = useAppSelector<string>(state => state.token);
|
||||
export function ClickerBtn({ setCoins, closeAutoClick, energy, setMult, coins, setEnergy, setClickTime, clickTime, setSameCoords }: IClickerBtn) {
|
||||
const [fill, setFill] = useState(0);
|
||||
const [size, setSize] = useState(240);
|
||||
const circumference = 2 * Math.PI * 125;
|
||||
|
@ -32,6 +31,22 @@ export function ClickerBtn({ setCoins, energy, setMult, coins, setEnergy }: ICli
|
|||
let styleIndex = useAppSelector<number>(state => state.styleIndex);
|
||||
const [maxEnergy, setMaxEnergy] = useState(500);
|
||||
const dispatch = useDispatch();
|
||||
const [prevClickTime, setPrevClickTime] = useState(0);
|
||||
const [prevCoords, setPrevCoords] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if(!closeAutoClick) {
|
||||
setClose(true);
|
||||
}
|
||||
}, [closeAutoClick]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if(clickTime === 0) {
|
||||
setPrevClickTime(0);
|
||||
setPrevCoords(0);
|
||||
}
|
||||
}, [clickTime]);
|
||||
|
||||
useEffect(() => {
|
||||
setFill((maxEnergy - energy) / maxEnergy * 100);
|
||||
|
@ -50,7 +65,25 @@ export function ClickerBtn({ setCoins, energy, setMult, coins, setEnergy }: ICli
|
|||
setGradient(getGradient())
|
||||
}, [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 clickInterval = currentTime - prevClickTime;
|
||||
if(prevClickTime != 0) {
|
||||
setClickTime(clickTime + clickInterval);
|
||||
}
|
||||
setPrevClickTime(currentTime);
|
||||
|
||||
if (energy != 0) {
|
||||
const newEnergy = energy - 1;
|
||||
const newFill = (maxEnergy - newEnergy) / maxEnergy * 100;
|
||||
|
@ -70,70 +103,11 @@ export function ClickerBtn({ setCoins, energy, setMult, coins, setEnergy }: ICli
|
|||
} else {
|
||||
setClose(false);
|
||||
}
|
||||
//sendClick();
|
||||
} else {
|
||||
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 = [
|
||||
{
|
||||
title: 'Ты большой молодец',
|
||||
|
@ -162,7 +136,7 @@ export function ClickerBtn({ setCoins, energy, setMult, coins, setEnergy }: ICli
|
|||
{gradient}
|
||||
</defs>
|
||||
</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}/>
|
||||
} />}
|
||||
</div>
|
||||
|
|
|
@ -4,7 +4,7 @@ import { formatNumber } from '../../../utils/formatNumber';
|
|||
import { ETextStyles } from '../../texts';
|
||||
import ReactDOM from 'react-dom';
|
||||
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 axios from 'axios';
|
||||
import { useAppSelector } from '../../hooks/useAppSelector';
|
||||
|
@ -12,56 +12,82 @@ import { saveMult } from '../../../store/mult';
|
|||
|
||||
interface IPointsZoom {
|
||||
points: number,
|
||||
setClose(a:boolean): void,
|
||||
className ?: string,
|
||||
setClose(a: boolean): void,
|
||||
className?: string,
|
||||
closePointsAnim: boolean,
|
||||
setClosePointsAnim(a: boolean): void,
|
||||
setCoins(a:number):void,
|
||||
setCoins(a: number): void,
|
||||
setCloseError(a: boolean): void,
|
||||
setEnergy(a: number): void,
|
||||
setMult(a: number): void,
|
||||
setClickTime(a: number): void,
|
||||
clickTime: number,
|
||||
setCloseAutoClick(a: boolean): void,
|
||||
sameCoords: boolean,
|
||||
setSameCoords(a: boolean): void,
|
||||
}
|
||||
|
||||
export function PointsZoom({ points, setMult, setClose, setCoins, className, closePointsAnim, setClosePointsAnim, setCloseError, setEnergy }: IPointsZoom) {
|
||||
export function PointsZoom({ points, sameCoords, setSameCoords, setCloseAutoClick, setMult, setClose, setCoins, className, closePointsAnim, setClosePointsAnim, setCloseError, setEnergy, clickTime, setClickTime }: IPointsZoom) {
|
||||
const [open, setOpen] = useState(true);
|
||||
const node = document.querySelector('#modal_root');
|
||||
const urlClick = useAppSelector<string>(state => state.urlClick);
|
||||
const token = useAppSelector<string>(state => state.token);
|
||||
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);
|
||||
if (!node) return null;
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const sendClicks = () => {
|
||||
const initPoints = points;
|
||||
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 clickTimeInit = clickTime;
|
||||
let initSameCoords = sameCoords;
|
||||
let avtTime = 500;
|
||||
if (points > 1) {
|
||||
avtTime = clickTimeInit / (initPoints - 1);
|
||||
}
|
||||
|
||||
//block function
|
||||
initSameCoords = false;
|
||||
|
||||
setClickTime(0);
|
||||
setSameCoords(false);
|
||||
|
||||
if (avtTime < 100 && initSameCoords && points > 30) {
|
||||
setCloseAutoClick(false);
|
||||
const returnEnergy = energy + initPoints;
|
||||
setEnergy(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(() => {
|
||||
|
|
|
@ -9,6 +9,8 @@ import { useNavigate } from 'react-router-dom';
|
|||
import { UsersIcons } from '../../Elements/UsersIcons';
|
||||
import { formatNumber } from '../../../utils/formatNumber';
|
||||
import { useAppSelector } from '../../hooks/useAppSelector';
|
||||
import { isWhiteList } from '../../../utils/isWhiteList';
|
||||
import { IUserRank } from '../../../store/friends/actions';
|
||||
|
||||
interface ISectionsBlock {
|
||||
mult:number;
|
||||
|
@ -18,9 +20,30 @@ export function SectionsBlock({ mult }: ISectionsBlock) {
|
|||
const [close, setClose] = useState(true);
|
||||
const navigate = useNavigate();
|
||||
const referralStorage = Number(useAppSelector<string | undefined>(state => state.me.data.referralStorage));
|
||||
//const referralStorage = 500;
|
||||
const maxReferralStorage = useAppSelector<number>(state => state.me.data.maxStorage);
|
||||
const [referralPercent, serReferralPercent] = useState(0);
|
||||
const [isDev, setIsDev] = useState(true);
|
||||
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 whiteList = isWhiteList();
|
||||
setIsDev(!whiteList)
|
||||
}, []);
|
||||
|
||||
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(() => {
|
||||
if(referralStorage >= maxReferralStorage) {
|
||||
|
@ -31,8 +54,6 @@ export function SectionsBlock({ mult }: ISectionsBlock) {
|
|||
|
||||
}, [referralStorage, maxReferralStorage]);
|
||||
|
||||
const isDev = true;
|
||||
|
||||
const multipCards = [
|
||||
{
|
||||
title: 'Что он делает',
|
||||
|
@ -54,13 +75,13 @@ export function SectionsBlock({ mult }: ISectionsBlock) {
|
|||
return (
|
||||
<div className={styles.sectionContainer}>
|
||||
<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 style={ETextStyles.InSb12120}>
|
||||
<span className={styles.rank1}>#</span>
|
||||
<span>{formatNumber(1)}</span>
|
||||
<span>{isDev ? '?' : (userRank ? formatNumber(userRank) : '?')}</span>
|
||||
</div>
|
||||
<UsersIcons size={16}/>
|
||||
<UsersIcons imgs={topImgs} size={16}/>
|
||||
</div>}
|
||||
</CardSection>
|
||||
<CardSection title='Множитель' onClick={() => { setClose(false) }}>
|
||||
|
|
|
@ -7,13 +7,14 @@ interface IDevPopup {
|
|||
setClose(a: boolean): void
|
||||
title: string,
|
||||
text: string,
|
||||
img?: string,
|
||||
}
|
||||
|
||||
export function DevPopup({ setClose, title, text }: IDevPopup) {
|
||||
export function DevPopup({ setClose, title, text, img }: IDevPopup) {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<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>
|
||||
<h2 className={styles.title} style={ETextStyles.RwSb24100}>{title}</h2>
|
||||
<p className={styles.text} style={ETextStyles.RwSb14120}>{text}</p>
|
||||
|
|
|
@ -3,28 +3,36 @@ import styles from './ratingcard.module.css';
|
|||
import { EIcons, Icon } from '../../Icons';
|
||||
import { PointsBlock } from '../PointsBlock';
|
||||
import { ETextStyles } from '../../texts';
|
||||
import { PersonIcon } from '../PersonIcon';
|
||||
|
||||
interface IRatingCard {
|
||||
number: number,
|
||||
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 (
|
||||
<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}>
|
||||
{(number === 1) && <div className={styles.medal}>
|
||||
{order === 1 && <div className={styles.medal}>
|
||||
<Icon icon={EIcons.MedalFirst}/>
|
||||
</div>}
|
||||
{(number === 2) && <div className={styles.medal}>
|
||||
{order === 2 && <div className={styles.medal}>
|
||||
<Icon icon={EIcons.MedalSecond} />
|
||||
</div>}
|
||||
{(number === 3) && <div className={styles.medal}>
|
||||
{order === 3 && <div className={styles.medal}>
|
||||
<Icon icon={EIcons.MedalThird} />
|
||||
</div>}
|
||||
{(number > 3) && <div className={styles.number} style={ETextStyles.InSb14120}>{number}</div>}
|
||||
<div className={styles.img}></div>
|
||||
{(order > 3 ) && <div className={styles.number} style={ETextStyles.InSb14120}>{order}</div>}
|
||||
<PersonIcon size={20} img={img} className={styles.img}/>
|
||||
<p style={ETextStyles.RwSb14120} className={styles.name}>{name}</p>
|
||||
</div>
|
||||
<PointsBlock points={score}/>
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
|
||||
.img {
|
||||
margin-right: 4px;
|
||||
width: 20px;
|
||||
/*width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 20px;
|
||||
background-color: var(--white);
|
||||
background-color: var(--white);*/
|
||||
}
|
||||
|
||||
.name {
|
||||
|
|
|
@ -11,9 +11,9 @@ interface IUsersIcons {
|
|||
export function UsersIcons({ size = 25, imgs = [], className = '' }: IUsersIcons) {
|
||||
return (
|
||||
<div className={`${styles.users} ${className}`} style={{height: `${size}px`, width: `${size*2.5}px`}}>
|
||||
<PersonIcon className={`${styles.userIcon} ${styles.userIcon1}`} size={size}/>
|
||||
<PersonIcon className={`${styles.userIcon} ${styles.userIcon2}`} size={size} left={size/1.4}/>
|
||||
<PersonIcon className={`${styles.userIcon} ${styles.userIcon3}`} size={size} left={2*size / 1.4} />
|
||||
<PersonIcon className={`${styles.userIcon} ${styles.userIcon1}`} size={size} img={imgs[0] ? imgs[0] : ''}/>
|
||||
<PersonIcon className={`${styles.userIcon} ${styles.userIcon2}`} size={size} left={size / 1.4} img={imgs[1] ? imgs[1] : ''} />
|
||||
<PersonIcon className={`${styles.userIcon} ${styles.userIcon3}`} size={size} left={2 * size / 1.4} img={imgs[2] ? imgs[2] : ''} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,9 @@ export function ClickerPage({ name, points, img, energy }: IClickerPageInterface
|
|||
const [closeError, setCloseError] = useState(true);
|
||||
const [animClose, setAnimClose] = useState(false);
|
||||
const [initEnergy, setInitEnergy] = useState(energy);
|
||||
const [clickTime, setClickTime] = useState(0);
|
||||
const [closeAutoClick, setCloseAutoClick] = useState(true);
|
||||
const [sameCoords, setSameCoords] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMult(savedMult);
|
||||
|
@ -54,13 +57,13 @@ export function ClickerPage({ name, points, img, energy }: IClickerPageInterface
|
|||
return (
|
||||
<div className={styles.container}>
|
||||
<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 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}/>
|
||||
<h1 style={ETextStyles.RwSb24100} className={styles.title}>Мои рекорды</h1>
|
||||
<SectionsBlock mult={mult}/>
|
||||
</div>
|
||||
<div className={styles.clicker} style={{height: `${height > 670 && 'calc(100vh - 355px)'}`}}>
|
||||
<ClickerBtn setEnergy={setInitEnergy} coins={coins} setCoins={setCoins} energy={initEnergy} setMult={setMult}/>
|
||||
<ClickerBtn closeAutoClick={closeAutoClick} sameCoords={sameCoords} setSameCoords={setSameCoords} clickTime={clickTime} setClickTime={setClickTime} setEnergy={setInitEnergy} coins={coins} setCoins={setCoins} energy={initEnergy} setMult={setMult}/>
|
||||
</div>
|
||||
<ClickerFooter />
|
||||
{styleIndex != 0 && <div>
|
||||
|
@ -69,6 +72,9 @@ export function ClickerPage({ name, points, img, energy }: IClickerPageInterface
|
|||
{!closeError && <ModalWindow removeBtn={true} setCloseAnimOut={setAnimClose} closeAnimOut={animClose} setClose={setCloseError} modalBlock={
|
||||
<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'/>
|
||||
} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,14 +5,16 @@ import { ETextStyles } from '../../texts';
|
|||
|
||||
interface IErrorPage {
|
||||
detail: String,
|
||||
title?: string,
|
||||
text?: string,
|
||||
fullScreen ?: boolean
|
||||
}
|
||||
|
||||
export function ErrorPage({ detail }: IErrorPage) {
|
||||
console.log(detail)
|
||||
export function ErrorPage({ detail, title, text, fullScreen=true }: IErrorPage) {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<h1 className={styles.title} style={ETextStyles.RwSb24100}>Возникла ошибка при загрузке ваших данных</h1>
|
||||
<p className={styles.text} style={ETextStyles.RwSb14120}>Попробуйте перезагрузить страницу или войдите позже.</p>
|
||||
<div className={`${styles.container} ${fullScreen ? styles.fullscreen : styles.margin}`}>
|
||||
<h1 className={styles.title} style={ETextStyles.RwSb24100}>{title ? title : 'Возникла ошибка при загрузке ваших данных'}</h1>
|
||||
<p className={styles.text} style={ETextStyles.RwSb14120}>{text ? text : 'Попробуйте перезагрузить страницу или войдите позже.'}</p>
|
||||
<Button text='Перезагрузить' stroke={true} onClick={() => window.location.reload()}/>
|
||||
{detail.length > 0 && <p className={styles.detail} style={ETextStyles.RwRg12120}>{detail}</p>}
|
||||
</div>
|
||||
|
|
|
@ -4,7 +4,14 @@
|
|||
justify-content: center;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.fullscreen {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.margin {
|
||||
margin: 50px 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
|
|
|
@ -1,64 +1,54 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import styles from './ratingpage.module.css';
|
||||
import { RatingCard } from '../../Elements/RatingCard';
|
||||
import { ETextStyles } from '../../texts';
|
||||
import { generateRandomString } from '../../../utils/generateRandom';
|
||||
import { useRankData } from '../../hooks/useRankData';
|
||||
import { Spinner } from '../../Elements/Spinner';
|
||||
import { ErrorPage } from '../ErrorPage';
|
||||
import { checkWhiteList } from '../../hooks/checkWhiteList';
|
||||
|
||||
export function RatingPage() {
|
||||
const { dataRank, loadingRank, errorRank } = useRankData();
|
||||
const [topBlock, setTopBlock] = useState(<div></div>);
|
||||
const [otherBlock, setOtherBlock] = useState(<div></div>);
|
||||
checkWhiteList();
|
||||
|
||||
const rating = [
|
||||
{
|
||||
name: 'Anficee',
|
||||
score: '1000000'
|
||||
},
|
||||
{
|
||||
name: 'Maria',
|
||||
score: '300000'
|
||||
},
|
||||
{
|
||||
name: 'Greg',
|
||||
score: '90000'
|
||||
},
|
||||
{
|
||||
name: 'Kate',
|
||||
score: '80000'
|
||||
},
|
||||
{
|
||||
name: 'Eva',
|
||||
score: '70000'
|
||||
},
|
||||
{
|
||||
name: 'Ты',
|
||||
score: '50000'
|
||||
},
|
||||
{
|
||||
name: 'Bill',
|
||||
score: '40000'
|
||||
},
|
||||
{
|
||||
name: 'Bradley',
|
||||
score: '30000'
|
||||
},
|
||||
];
|
||||
useEffect(() => {
|
||||
if (dataRank.length != 0) {
|
||||
const firstBlock = dataRank.map((user, index) => {
|
||||
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()} />;
|
||||
}
|
||||
});
|
||||
//@ts-ignore
|
||||
setTopBlock(firstBlock);
|
||||
|
||||
const ratingBlock = dataRank.map((user, index) => {
|
||||
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()} />;
|
||||
}
|
||||
});
|
||||
//@ts-ignore
|
||||
setOtherBlock(ratingBlock);
|
||||
|
||||
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 (
|
||||
<div className={styles.container}>
|
||||
<h1 className={styles.title} style={ETextStyles.RwSb30100}>Рейтинг игроков</h1>
|
||||
<div className={styles.winContainer}>{firstBlock}</div>
|
||||
<div className={styles.otherContainer}>{ratingBlock}</div>
|
||||
{loadingRank && <div className={styles.spinnerContainer}><Spinner color='#FFFFFF' size='40px' thickness='6px' className={styles.spinner} /></div>}
|
||||
{!loadingRank && <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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -21,3 +21,11 @@
|
|||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.spinnerContainer {
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
|
@ -14,6 +14,7 @@ import { updateBackground } from '../../../utils/updateBackground';
|
|||
import { ErrorPage } from '../ErrorPage';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { DevPage } from '../DevPage';
|
||||
import { useRankData } from '../../hooks/useRankData';
|
||||
|
||||
interface IRoutePage {
|
||||
page: string
|
||||
|
@ -22,6 +23,7 @@ interface IRoutePage {
|
|||
export function RoutePage({ page }: IRoutePage) {
|
||||
const verified = useTgData();
|
||||
const { dataUser, loadingUser, errorUser } = useUserData();
|
||||
useRankData();
|
||||
const navigate = useNavigate();
|
||||
//@ts-ignore
|
||||
const tg = window.Telegram.WebApp;
|
||||
|
|
|
@ -10,22 +10,28 @@ import { StoragePageBlock } from '../../Storage/StoragePageBlock';
|
|||
import { FriendsPageBlock } from '../../Storage/FriendsPageBlock';
|
||||
import { useAppSelector } from '../../hooks/useAppSelector';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { isWhiteList } from '../../../utils/isWhiteList';
|
||||
|
||||
export function StoragePage() {
|
||||
const userId = useAppSelector<string>(state => state.userTg.id);
|
||||
const [page, setPage] = useState('storage');
|
||||
const refLink = `https://t.me/sapphirecrown_bot?start=user_${userId}`;
|
||||
const [showNotif, setShow] = useState(false);
|
||||
const [isDev, setIsDev] = useState(true);
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
const whiteList = isWhiteList();
|
||||
setIsDev(!whiteList)
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 style={ETextStyles.RwSb30100} className={styles.title}>Реферальная программа</h1>
|
||||
<div className={styles.btnGroup}>
|
||||
<StorageBtn active={page === 'storage'} type={'storage'} onClick={() => setPage('storage')}/>
|
||||
<StorageBtn isDev={true} active={page === 'friends'} type={'friends'} onClick={() => {
|
||||
navigate('/dev?type=friends')
|
||||
//setPage('friends')
|
||||
<StorageBtn isDev={isDev} active={page === 'friends'} type={'friends'} onClick={() => {
|
||||
isDev ? navigate('/dev?type=friends') : setPage('friends')
|
||||
}
|
||||
} />
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import styles from './friendspageblock.module.css';
|
||||
import { ETextStyles } from '../../texts';
|
||||
import { RatingCard } from '../../Elements/RatingCard';
|
||||
import { generateRandomString } from '../../../utils/generateRandom';
|
||||
import { useFriendsData } from '../../hooks/useFriendsData';
|
||||
import { ErrorPage } from '../../Pages/ErrorPage';
|
||||
import { Spinner } from '../../Elements/Spinner';
|
||||
|
||||
interface IRating {
|
||||
name: string,
|
||||
|
@ -9,49 +13,38 @@ interface IRating {
|
|||
}
|
||||
|
||||
export function FriendsPageBlock() {
|
||||
const { dataFriends, loadingFriends, errorFriends } = useFriendsData();
|
||||
const [ratingBlock, setRatingBlock] = useState(<div></div>);
|
||||
const loading = true;
|
||||
|
||||
//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'} />;
|
||||
});
|
||||
|
||||
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'
|
||||
},
|
||||
];
|
||||
//@ts-ignore
|
||||
setRatingBlock(block);
|
||||
}
|
||||
|
||||
}, [dataFriends])
|
||||
|
||||
const ratingBlock = rating.map((user, index) => {
|
||||
return <RatingCard number={index + 1} name={user.name} score={user.score} />;
|
||||
})
|
||||
|
||||
return (
|
||||
<div>
|
||||
{(rating.length > 0) && <h2 style={ETextStyles.RwSb18120} className={styles.title}>Рейтинг друзей</h2>}
|
||||
<div className={styles.ranks}>{ratingBlock}</div>
|
||||
<div className={`${styles.content} ${(rating.length === 0) && styles.marginTop }`}>
|
||||
{loadingFriends && <div className={styles.spinnerContainer}><Spinner color='#FFFFFF' size='40px' thickness='6px' className={styles.spinner} /></div>}
|
||||
{!loadingFriends &&
|
||||
<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.RwSb14120} className={styles.descr}>Используй все свои социальные сети! Больше друзей — больше доход в хранилище.</p>
|
||||
</div>
|
||||
|
|
|
@ -25,3 +25,11 @@
|
|||
.marginTop {
|
||||
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
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('/');
|
||||
}
|
||||
}, []);
|
||||
}
|
24
frontend/src/shared/hooks/useFriendsData.ts
Normal file
24
frontend/src/shared/hooks/useFriendsData.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { useDispatch } from 'react-redux';
|
||||
import { useEffect } from 'react';
|
||||
import { useAppSelector } from './useAppSelector';
|
||||
import { IUserRank, friendsRequestAsync } from '../../store/friends/actions';
|
||||
import { isWhiteList } from '../../utils/isWhiteList';
|
||||
|
||||
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(() => {
|
||||
const whiteList = isWhiteList();
|
||||
|
||||
if(whiteList) {
|
||||
dispatch<any>(friendsRequestAsync());
|
||||
}
|
||||
|
||||
}, [token]);
|
||||
|
||||
return { dataFriends, loadingFriends, errorFriends };
|
||||
}
|
23
frontend/src/shared/hooks/useRankData.ts
Normal file
23
frontend/src/shared/hooks/useRankData.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
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';
|
||||
import { isWhiteList } from '../../utils/isWhiteList';
|
||||
|
||||
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(() => {
|
||||
const whiteList = isWhiteList();
|
||||
if(whiteList) {
|
||||
dispatch<any>(rankRequestAsync());
|
||||
}
|
||||
}, [token]);
|
||||
|
||||
return { dataRank, loadingRank, errorRank };
|
||||
}
|
|
@ -19,7 +19,8 @@ export function useTgData() {
|
|||
const [user, token]: [IUserTg, string] = verificationTg();
|
||||
if (token.length != 0 && user.id && user.id.length != 0) {
|
||||
setVerified(true);
|
||||
dispatch<any>(saveToken(token));
|
||||
//dispatch<any>(saveToken(token));
|
||||
dispatch<any>(saveToken(savedToken));
|
||||
dispatch<any>(setUserTg(user));
|
||||
} else {
|
||||
setVerified(false);
|
||||
|
|
97
frontend/src/store/friends/actions.ts
Normal file
97
frontend/src/store/friends/actions.ts
Normal file
|
@ -0,0 +1,97 @@
|
|||
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) {
|
||||
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
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,7 @@ import { ThunkAction } from "redux-thunk";
|
|||
import { RootState } from "../reducer";
|
||||
import axios from "axios";
|
||||
import { saveMult } from "../mult";
|
||||
import { saveToken } from "../token";
|
||||
|
||||
export interface IUserData {
|
||||
tgId?: number;
|
||||
|
@ -13,6 +14,7 @@ export interface IUserData {
|
|||
energy?: string;
|
||||
referralStorage?: string;
|
||||
maxStorage: number;
|
||||
rank ?: number
|
||||
}
|
||||
|
||||
export const ME_REQUEST = 'ME_REQUEST';
|
||||
|
@ -66,8 +68,10 @@ export const meRequestAsync = (): ThunkAction<void, RootState, unknown, Action<s
|
|||
}
|
||||
|
||||
const firstClick = (token: string) => {
|
||||
axios.post(`${URLClick}/api/v1/click/`,
|
||||
{},
|
||||
axios.post(`${URLClick}/api/v1/batch-click/`,
|
||||
{
|
||||
count: 1
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Authorization": `TelegramToken ${token}`
|
||||
|
@ -78,6 +82,9 @@ export const meRequestAsync = (): ThunkAction<void, RootState, unknown, Action<s
|
|||
dispatch<any>(saveMult(click));
|
||||
const clickCode = btoa(click.toString());
|
||||
sessionStorage.setItem('mt', clickCode);
|
||||
|
||||
const energy = Number(resp.data.energy);
|
||||
dispatch<any>(updateEnergyRequestAsync(energy));
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -170,7 +177,7 @@ export const meRequestAsync = (): ThunkAction<void, RootState, unknown, Action<s
|
|||
},
|
||||
).then((resp) => {
|
||||
const token = resp.data.token;
|
||||
getState().token = token;
|
||||
dispatch<any>(saveToken(resp.data.token));
|
||||
if (token && !meData.username) {
|
||||
dispatch(meRequest());
|
||||
let urlUser = '';
|
||||
|
@ -305,3 +312,11 @@ export const emptyReferralStorage = (): ThunkAction<void, RootState, unknown, Ac
|
|||
newData.points = (Number(newData.points) + referralPoints).toString();
|
||||
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));
|
||||
}
|
135
frontend/src/store/rank/actions.ts
Normal file
135
frontend/src/store/rank/actions.ts
Normal file
|
@ -0,0 +1,135 @@
|
|||
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) {
|
||||
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
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,10 @@ import { MeState, meReducer } from './me/reducer';
|
|||
import { ME_REQUEST, ME_REQUEST_ERROR, ME_REQUEST_SUCCESS } from './me/actions';
|
||||
import { SET_REFERRAL } from './referral';
|
||||
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';
|
||||
|
||||
export type RootState = {
|
||||
url: string,
|
||||
|
@ -16,6 +20,8 @@ export type RootState = {
|
|||
me: MeState,
|
||||
referral: string,
|
||||
mult: number,
|
||||
friends: RankState,
|
||||
rank: RankState,
|
||||
};
|
||||
|
||||
//'http://127.0.0.1:8000'
|
||||
|
@ -39,6 +45,16 @@ const initialState: RootState = {
|
|||
maxStorage: 0
|
||||
}
|
||||
},
|
||||
friends: {
|
||||
loading: false,
|
||||
error: '',
|
||||
data: []
|
||||
},
|
||||
rank: {
|
||||
loading: false,
|
||||
error: '',
|
||||
data: []
|
||||
},
|
||||
referral: '',
|
||||
mult: 1,
|
||||
};
|
||||
|
@ -78,6 +94,20 @@ export const rootReducer: Reducer<RootState> = (state = initialState, action) =>
|
|||
...state,
|
||||
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)
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
20
frontend/src/utils/isWhiteList.js
Normal file
20
frontend/src/utils/isWhiteList.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { getTgUserId } from "./verification";
|
||||
|
||||
export const isWhiteList = () => {
|
||||
let isWhiteList = false;
|
||||
//123456,
|
||||
const whiteList = [
|
||||
342495217, 6374536117, 322861155, 5219438370, 193428034, 402449803,
|
||||
406350282, 1083462027,
|
||||
];
|
||||
|
||||
const userId = Number(getTgUserId());
|
||||
|
||||
whiteList.map((item) => {
|
||||
if (Number(item) === userId) {
|
||||
isWhiteList = true;
|
||||
}
|
||||
});
|
||||
|
||||
return isWhiteList;
|
||||
}
|
|
@ -53,3 +53,17 @@ export const verificationTg = () => {
|
|||
|
||||
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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user