autoclick add & add ranks

This commit is contained in:
Arseniy Sitnikov 2024-12-12 23:01:22 +03:00
parent 9e9fcc5f94
commit 16932959d5
29 changed files with 718 additions and 225 deletions

BIN
frontend/src/.DS_Store vendored

Binary file not shown.

View File

@ -1,27 +1,26 @@
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
} }
export function ClickerBtn({ setCoins, energy, setMult, coins, setEnergy }: IClickerBtn) { export function ClickerBtn({ setCoins, 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 +31,22 @@ 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);
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 +65,25 @@ 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 clickInterval = currentTime - prevClickTime;
if(prevClickTime != 0) {
setClickTime(clickTime + clickInterval);
}
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 +103,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 +136,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>

View File

@ -4,7 +4,7 @@ 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';
@ -12,56 +12,82 @@ import { saveMult } from '../../../store/mult';
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,
} }
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 [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);
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 avtTime = 500;
count: initPoints if (points > 1) {
}, avtTime = clickTimeInit / (initPoints - 1);
{ }
headers: {
"Authorization": `TelegramToken ${token}` //block function
} initSameCoords = false;
}
).then(resp => { setClickTime(0);
const data = resp.data; setSameCoords(false);
const click = Number(data.click.value);
const encodeMult = btoa(click.toString()); if (avtTime < 100 && initSameCoords && points > 30) {
sessionStorage.setItem('mt', encodeMult); setCloseAutoClick(false);
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; 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 +115,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 (

View File

@ -9,6 +9,8 @@ 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 { isWhiteList } from '../../../utils/isWhiteList';
import { IUserRank } from '../../../store/friends/actions';
interface ISectionsBlock { interface ISectionsBlock {
mult:number; mult:number;
@ -18,9 +20,30 @@ 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(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(() => { useEffect(() => {
if(referralStorage >= maxReferralStorage) { if(referralStorage >= maxReferralStorage) {
@ -31,8 +54,6 @@ export function SectionsBlock({ mult }: ISectionsBlock) {
}, [referralStorage, maxReferralStorage]); }, [referralStorage, maxReferralStorage]);
const isDev = true;
const multipCards = [ const multipCards = [
{ {
title: 'Что он делает', title: 'Что он делает',
@ -54,13 +75,13 @@ export function SectionsBlock({ mult }: ISectionsBlock) {
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}/> <UsersIcons imgs={topImgs} size={16}/>
</div>} </div>}
</CardSection> </CardSection>
<CardSection title='Множитель' onClick={() => { setClose(false) }}> <CardSection title='Множитель' onClick={() => { setClose(false) }}>

View File

@ -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>

View File

@ -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}/>
<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}/>

View File

@ -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 {

View File

@ -11,9 +11,9 @@ 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}/> <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}/> <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} /> <PersonIcon className={`${styles.userIcon} ${styles.userIcon3}`} size={size} left={2 * size / 1.4} img={imgs[2] ? imgs[2] : ''} />
</div> </div>
); );
} }

View File

@ -30,6 +30,9 @@ 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);
useEffect(() => { useEffect(() => {
setMult(savedMult); setMult(savedMult);
@ -54,13 +57,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 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 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 +72,9 @@ 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'/>
} />}
</div> </div>
); );
} }

View File

@ -5,14 +5,16 @@ import { ETextStyles } from '../../texts';
interface IErrorPage { interface IErrorPage {
detail: String, detail: String,
title?: string,
text?: string,
fullScreen ?: boolean
} }
export function ErrorPage({ detail }: IErrorPage) { export function ErrorPage({ detail, title, text, fullScreen=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()}/> <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>

View File

@ -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 {

View File

@ -1,64 +1,54 @@
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';
import { checkWhiteList } from '../../hooks/checkWhiteList';
export function RatingPage() { export function RatingPage() {
const { dataRank, loadingRank, errorRank } = useRankData();
const [topBlock, setTopBlock] = useState(<div></div>);
const [otherBlock, setOtherBlock] = useState(<div></div>);
checkWhiteList();
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>
); );
} }

View File

@ -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;
} }

View File

@ -14,6 +14,7 @@ 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';
interface IRoutePage { interface IRoutePage {
page: string page: string
@ -22,6 +23,7 @@ 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();
useRankData();
const navigate = useNavigate(); const navigate = useNavigate();
//@ts-ignore //@ts-ignore
const tg = window.Telegram.WebApp; const tg = window.Telegram.WebApp;

View File

@ -10,22 +10,28 @@ 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/sapphirecrown_bot?start=user_${userId}`; const refLink = `https://t.me/sapphirecrown_bot?start=user_${userId}`;
const [showNotif, setShow] = useState(false); const [showNotif, setShow] = useState(false);
const [isDev, setIsDev] = useState(true);
const navigate = useNavigate(); const navigate = useNavigate();
useEffect(() => {
const whiteList = isWhiteList();
setIsDev(!whiteList)
}, []);
return ( return (
<div> <div>
<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>

View File

@ -1,7 +1,11 @@
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';
import { useFriendsData } from '../../hooks/useFriendsData';
import { ErrorPage } from '../../Pages/ErrorPage';
import { Spinner } from '../../Elements/Spinner';
interface IRating { interface IRating {
name: string, name: string,
@ -9,49 +13,38 @@ interface IRating {
} }
export function FriendsPageBlock() { 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'} />;
});
//@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}>Используй все свои социальные сети! Больше друзей&nbsp;&mdash; больше доход в&nbsp;хранилище.</p> <p style={ETextStyles.RwSb14120} className={styles.descr}>Используй все свои социальные сети! Больше друзей&nbsp;&mdash; больше доход в&nbsp;хранилище.</p>
</div> </div>

View File

@ -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;
} }

View 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('/');
}
}, []);
}

View 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 };
}

View 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 };
}

View File

@ -19,7 +19,8 @@ export function useTgData() {
const [user, token]: [IUserTg, string] = verificationTg(); const [user, token]: [IUserTg, string] = verificationTg();
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);

View 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)));
}
})
}
}

View 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;
}
}

View File

@ -3,6 +3,7 @@ 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 IUserData { export interface IUserData {
tgId?: number; tgId?: number;
@ -13,6 +14,7 @@ export interface IUserData {
energy?: string; energy?: string;
referralStorage?: string; referralStorage?: string;
maxStorage: number; maxStorage: number;
rank ?: number
} }
export const ME_REQUEST = 'ME_REQUEST'; export const ME_REQUEST = 'ME_REQUEST';
@ -66,8 +68,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 +82,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));
}); });
}; };
@ -170,7 +177,7 @@ export const meRequestAsync = (): ThunkAction<void, RootState, unknown, Action<s
}, },
).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 = '';
@ -304,4 +311,12 @@ 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));
} }

View 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)));
}
})
}
}

View 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;
}
}

View File

@ -5,6 +5,10 @@ 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';
export type RootState = { export type RootState = {
url: string, url: string,
@ -16,6 +20,8 @@ export type RootState = {
me: MeState, me: MeState,
referral: string, referral: string,
mult: number, mult: number,
friends: RankState,
rank: RankState,
}; };
//'http://127.0.0.1:8000' //'http://127.0.0.1:8000'
@ -39,6 +45,16 @@ const initialState: RootState = {
maxStorage: 0 maxStorage: 0
} }
}, },
friends: {
loading: false,
error: '',
data: []
},
rank: {
loading: false,
error: '',
data: []
},
referral: '', referral: '',
mult: 1, mult: 1,
}; };
@ -78,6 +94,20 @@ 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)
};
default: default:
return state; return state;
} }

View 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;
}

View File

@ -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;
} }