diff --git a/frontend/public/assets/Angry.png b/frontend/public/assets/Angry.png new file mode 100644 index 0000000..6e4544d Binary files /dev/null and b/frontend/public/assets/Angry.png differ diff --git a/frontend/public/assets/Biceps.png b/frontend/public/assets/Biceps.png new file mode 100644 index 0000000..bcf9457 Binary files /dev/null and b/frontend/public/assets/Biceps.png differ diff --git a/frontend/public/assets/Chain.png b/frontend/public/assets/Chain.png new file mode 100644 index 0000000..9ffebd5 Binary files /dev/null and b/frontend/public/assets/Chain.png differ diff --git a/frontend/public/assets/Fire.png b/frontend/public/assets/Fire.png new file mode 100644 index 0000000..dcdfb59 Binary files /dev/null and b/frontend/public/assets/Fire.png differ diff --git a/frontend/public/assets/Gift.png b/frontend/public/assets/Gift.png new file mode 100644 index 0000000..0ec7685 Binary files /dev/null and b/frontend/public/assets/Gift.png differ diff --git a/frontend/public/assets/Money.png b/frontend/public/assets/Money.png new file mode 100644 index 0000000..07dfb96 Binary files /dev/null and b/frontend/public/assets/Money.png differ diff --git a/frontend/public/assets/Monocle.png b/frontend/public/assets/Monocle.png new file mode 100644 index 0000000..0a260b6 Binary files /dev/null and b/frontend/public/assets/Monocle.png differ diff --git a/frontend/public/assets/Rocket.png b/frontend/public/assets/Rocket.png new file mode 100644 index 0000000..bb83322 Binary files /dev/null and b/frontend/public/assets/Rocket.png differ diff --git a/frontend/public/assets/Volt.png b/frontend/public/assets/Volt.png new file mode 100644 index 0000000..69fc35e Binary files /dev/null and b/frontend/public/assets/Volt.png differ diff --git a/frontend/public/assets/btnIcon.png b/frontend/public/assets/btnIcon.png new file mode 100644 index 0000000..314a6b6 Binary files /dev/null and b/frontend/public/assets/btnIcon.png differ diff --git a/frontend/public/assets/coin.png b/frontend/public/assets/coin.png new file mode 100644 index 0000000..313110d Binary files /dev/null and b/frontend/public/assets/coin.png differ diff --git a/frontend/public/assets/compass.png b/frontend/public/assets/compass.png new file mode 100644 index 0000000..dab1835 Binary files /dev/null and b/frontend/public/assets/compass.png differ diff --git a/frontend/public/assets/dev.png b/frontend/public/assets/dev.png new file mode 100644 index 0000000..81b049c Binary files /dev/null and b/frontend/public/assets/dev.png differ diff --git a/frontend/public/assets/friends.png b/frontend/public/assets/friends.png new file mode 100644 index 0000000..c1959dd Binary files /dev/null and b/frontend/public/assets/friends.png differ diff --git a/frontend/public/assets/imgBtn1.png b/frontend/public/assets/imgBtn1.png new file mode 100644 index 0000000..4a8506c Binary files /dev/null and b/frontend/public/assets/imgBtn1.png differ diff --git a/frontend/public/assets/imgBtn2.png b/frontend/public/assets/imgBtn2.png new file mode 100644 index 0000000..596d729 Binary files /dev/null and b/frontend/public/assets/imgBtn2.png differ diff --git a/frontend/public/assets/point.png b/frontend/public/assets/point.png new file mode 100644 index 0000000..ec03638 Binary files /dev/null and b/frontend/public/assets/point.png differ diff --git a/frontend/public/assets/police.gif b/frontend/public/assets/police.gif new file mode 100644 index 0000000..459b7e9 Binary files /dev/null and b/frontend/public/assets/police.gif differ diff --git a/frontend/public/assets/programming.gif b/frontend/public/assets/programming.gif new file mode 100644 index 0000000..e0edb5b Binary files /dev/null and b/frontend/public/assets/programming.gif differ diff --git a/frontend/public/assets/shopping.png b/frontend/public/assets/shopping.png new file mode 100644 index 0000000..0361fb9 Binary files /dev/null and b/frontend/public/assets/shopping.png differ diff --git a/frontend/public/assets/style1.png b/frontend/public/assets/style1.png new file mode 100644 index 0000000..1bab592 Binary files /dev/null and b/frontend/public/assets/style1.png differ diff --git a/frontend/public/assets/style2.png b/frontend/public/assets/style2.png new file mode 100644 index 0000000..297517e Binary files /dev/null and b/frontend/public/assets/style2.png differ diff --git a/frontend/public/assets/style3.png b/frontend/public/assets/style3.png new file mode 100644 index 0000000..99b0957 Binary files /dev/null and b/frontend/public/assets/style3.png differ diff --git a/frontend/public/assets/style4.png b/frontend/public/assets/style4.png new file mode 100644 index 0000000..8c344f1 Binary files /dev/null and b/frontend/public/assets/style4.png differ diff --git a/frontend/src/assets/Angry.png b/frontend/src/assets/Angry.png new file mode 100644 index 0000000..6e4544d Binary files /dev/null and b/frontend/src/assets/Angry.png differ diff --git a/frontend/src/assets/Biceps.png b/frontend/src/assets/Biceps.png new file mode 100644 index 0000000..bcf9457 Binary files /dev/null and b/frontend/src/assets/Biceps.png differ diff --git a/frontend/src/assets/Chain.png b/frontend/src/assets/Chain.png new file mode 100644 index 0000000..9ffebd5 Binary files /dev/null and b/frontend/src/assets/Chain.png differ diff --git a/frontend/src/assets/Fire.png b/frontend/src/assets/Fire.png new file mode 100644 index 0000000..dcdfb59 Binary files /dev/null and b/frontend/src/assets/Fire.png differ diff --git a/frontend/src/assets/Gift.png b/frontend/src/assets/Gift.png new file mode 100644 index 0000000..0ec7685 Binary files /dev/null and b/frontend/src/assets/Gift.png differ diff --git a/frontend/src/assets/Money.png b/frontend/src/assets/Money.png new file mode 100644 index 0000000..07dfb96 Binary files /dev/null and b/frontend/src/assets/Money.png differ diff --git a/frontend/src/assets/Monocle.png b/frontend/src/assets/Monocle.png new file mode 100644 index 0000000..0a260b6 Binary files /dev/null and b/frontend/src/assets/Monocle.png differ diff --git a/frontend/src/assets/Rocket.png b/frontend/src/assets/Rocket.png new file mode 100644 index 0000000..bb83322 Binary files /dev/null and b/frontend/src/assets/Rocket.png differ diff --git a/frontend/src/assets/Volt.png b/frontend/src/assets/Volt.png new file mode 100644 index 0000000..69fc35e Binary files /dev/null and b/frontend/src/assets/Volt.png differ diff --git a/frontend/src/assets/btnIcon.png b/frontend/src/assets/btnIcon.png new file mode 100644 index 0000000..314a6b6 Binary files /dev/null and b/frontend/src/assets/btnIcon.png differ diff --git a/frontend/src/assets/coin.png b/frontend/src/assets/coin.png new file mode 100644 index 0000000..313110d Binary files /dev/null and b/frontend/src/assets/coin.png differ diff --git a/frontend/src/assets/compass.png b/frontend/src/assets/compass.png new file mode 100644 index 0000000..dab1835 Binary files /dev/null and b/frontend/src/assets/compass.png differ diff --git a/frontend/src/assets/dev.png b/frontend/src/assets/dev.png new file mode 100644 index 0000000..81b049c Binary files /dev/null and b/frontend/src/assets/dev.png differ diff --git a/frontend/src/assets/friends.png b/frontend/src/assets/friends.png new file mode 100644 index 0000000..c1959dd Binary files /dev/null and b/frontend/src/assets/friends.png differ diff --git a/frontend/src/assets/imgBtn1.png b/frontend/src/assets/imgBtn1.png new file mode 100644 index 0000000..4a8506c Binary files /dev/null and b/frontend/src/assets/imgBtn1.png differ diff --git a/frontend/src/assets/imgBtn2.png b/frontend/src/assets/imgBtn2.png new file mode 100644 index 0000000..596d729 Binary files /dev/null and b/frontend/src/assets/imgBtn2.png differ diff --git a/frontend/src/assets/point.png b/frontend/src/assets/point.png new file mode 100644 index 0000000..ec03638 Binary files /dev/null and b/frontend/src/assets/point.png differ diff --git a/frontend/src/assets/police.gif b/frontend/src/assets/police.gif new file mode 100644 index 0000000..459b7e9 Binary files /dev/null and b/frontend/src/assets/police.gif differ diff --git a/frontend/src/assets/programming.gif b/frontend/src/assets/programming.gif new file mode 100644 index 0000000..e0edb5b Binary files /dev/null and b/frontend/src/assets/programming.gif differ diff --git a/frontend/src/assets/shopping.png b/frontend/src/assets/shopping.png new file mode 100644 index 0000000..0361fb9 Binary files /dev/null and b/frontend/src/assets/shopping.png differ diff --git a/frontend/src/assets/style1.png b/frontend/src/assets/style1.png new file mode 100644 index 0000000..1bab592 Binary files /dev/null and b/frontend/src/assets/style1.png differ diff --git a/frontend/src/assets/style2.png b/frontend/src/assets/style2.png new file mode 100644 index 0000000..297517e Binary files /dev/null and b/frontend/src/assets/style2.png differ diff --git a/frontend/src/assets/style3.png b/frontend/src/assets/style3.png new file mode 100644 index 0000000..99b0957 Binary files /dev/null and b/frontend/src/assets/style3.png differ diff --git a/frontend/src/assets/style4.png b/frontend/src/assets/style4.png new file mode 100644 index 0000000..8c344f1 Binary files /dev/null and b/frontend/src/assets/style4.png differ diff --git a/frontend/src/shared/Auction/AuctionCard/AuctionCard.tsx b/frontend/src/shared/Auction/AuctionCard/AuctionCard.tsx index 2470f08..6a345ed 100644 --- a/frontend/src/shared/Auction/AuctionCard/AuctionCard.tsx +++ b/frontend/src/shared/Auction/AuctionCard/AuctionCard.tsx @@ -2,8 +2,6 @@ import React, { useState } from 'react'; import styles from './auctioncard.module.css'; import { ETextStyles } from '../../texts'; import { PointsBlock } from '../../Elements/PointsBlock'; -import { PersonIcon } from '../../Elements/PersonIcon'; -import { UsersIcons } from '../../Elements/UsersIcons'; import { Button } from '../../Button'; import { EIcons } from '../../Icons'; import { Timer } from '../Timer'; @@ -12,19 +10,23 @@ import { Slider } from '../../Elements/Slider'; import { ModalWindow } from '../../ModalWindow'; import { AuctionPopup } from '../AuctionPopup'; import { ResultAuctionPopup } from '../ResultAuctionPopup'; +import { DevPopup } from '../../Elements/DevPopup'; +import { useAppSelector } from '../../hooks/useAppSelector'; interface IAuctionCard { + auctionId: string, name: string, imgs: Array, - minBet: string, users: number, prevBet: string, myBetInit: string, time: number, - isLead: boolean + isLead: boolean, + commission: number, + className ?: string } -export function AuctionCard({ name, imgs, users, prevBet, myBetInit, time, isLead }: IAuctionCard) { +export function AuctionCard({ name, imgs, users, prevBet, myBetInit, time, isLead, commission, auctionId, className }: IAuctionCard) { const [myBet, setBet] = useState(Number(myBetInit)); const [myNewBet, setMyNewBet] = useState(0); const [initPrevBet, setPrevBet] = useState(prevBet); @@ -33,9 +35,10 @@ export function AuctionCard({ name, imgs, users, prevBet, myBetInit, time, isLea const [closeAnim, setCloseAnim] = useState(false); const [closeresultPopup, setCloseResultPopup] = useState(true); const styleIndex = Number(localStorage.getItem('selectedStyle')); + const [closeErrorBet, setCloseErrorBet] = useState(true); return ( -
+

{name}

Подробности аукциона

@@ -44,13 +47,13 @@ export function AuctionCard({ name, imgs, users, prevBet, myBetInit, time, isLea
-

{users === 0 ? 'Ты единственный участник' : 'Участники аукциона'}

- {users === 0 ? :
{users > 3 &&
{users-3}
}
} +

Количество победителей

+
{users}
-
{!initLead ? 'Успей сделать ставку! До конца осталось:' - :

Ты в числе победителей! Но все может поменяться

}
+
{initLead ?

Ты в числе победителей! Но все может поменяться

+ :

{myBet > 0 ? 'Вашу ставку перебили, повысьте ее, чтобы сохранить лидерство' : 'Успей сделать ставку! До конца осталось:' }

}
); } diff --git a/frontend/src/shared/Auction/AuctionCard/auctioncard.module.css b/frontend/src/shared/Auction/AuctionCard/auctioncard.module.css index b477fd1..f175cba 100644 --- a/frontend/src/shared/Auction/AuctionCard/auctioncard.module.css +++ b/frontend/src/shared/Auction/AuctionCard/auctioncard.module.css @@ -113,4 +113,14 @@ aspect-ratio: 340/237; border-radius: 15px; overflow: hidden; +} + +.winnersNumber { + display: flex; + align-items: center; + justify-content: center; + width: 27px; + height: 27px; + border-radius: 50%; + background-color: var(--grey34); } \ No newline at end of file diff --git a/frontend/src/shared/Auction/AuctionLosePopup/AuctionLosePopup.tsx b/frontend/src/shared/Auction/AuctionLosePopup/AuctionLosePopup.tsx index e3f9656..6ccc347 100644 --- a/frontend/src/shared/Auction/AuctionLosePopup/AuctionLosePopup.tsx +++ b/frontend/src/shared/Auction/AuctionLosePopup/AuctionLosePopup.tsx @@ -4,6 +4,7 @@ import { useNavigate } from 'react-router-dom'; import { ETextStyles } from '../../texts'; import { ProductCard } from '../ProductCard'; import { Button } from '../../Button'; +import { generateRandomString } from '../../../utils/generateRandom'; interface IProduct { name: string, @@ -28,7 +29,7 @@ export function AuctionLosePopup({ items, setClose }: IAuctionLosePopup) {

Аукционы, в которых нужно увеличить ставку:

{items.map(item => { - return + return })}
}

Наши алгоритмы автоматически рассчитают стоимость, чтобы ваша ставка стала самой высокой

{!autoBet ? 'Ввести свою цену' : 'Цена, чтобы перебить ставку'}

- {(Math.floor((1 + percent / 100) * Number(value)) < userPoints) ? ((Number(value) < Number(prevBet) && value.length > 0) ? + {(Number(Number((1 + percent / 100) * Number(value))) - myBet < userPoints) ? ((Number(value) < Number(prevBet) && value.length > 0) ?
- Вы увеличили ставку {`на ${diff}`} {declension(diff, 'коин', 'коина', 'коинов')} + Вы {prevMyOldBet > 0 ? 'увеличили' : 'перебили'} ставку {`на ${diff.toFixed(2)}`} {declension(diff.toFixed(2), 'коин', 'коина', 'коинов')}
diff --git a/frontend/src/shared/Auction/Timer/Timer.tsx b/frontend/src/shared/Auction/Timer/Timer.tsx index 398e6d9..63bb21e 100644 --- a/frontend/src/shared/Auction/Timer/Timer.tsx +++ b/frontend/src/shared/Auction/Timer/Timer.tsx @@ -16,6 +16,7 @@ export function Timer({initTime}: ITimer) { const tick = () => { if (hour === 0 && min === 0 && sec === 0) { setOver(true); + window.location.reload(); } else if (min === 0 && sec === 0) { setTime([hour - 1, 59, 59]); } else if (sec == 0) { @@ -35,12 +36,12 @@ export function Timer({initTime}: ITimer) { return (
-

{hour}

+

{hour.toString().length === 1 ? `0${hour}` : hour}

{declension(hour, 'час', 'часа', 'часов')}

-

{min}

+

{min.toString().length === 1 ? `0${min}` : min}

мин

diff --git a/frontend/src/shared/Clicker/ClickerBtn/ClickerBtn.tsx b/frontend/src/shared/Clicker/ClickerBtn/ClickerBtn.tsx index aca24a4..cbca9d7 100644 --- a/frontend/src/shared/Clicker/ClickerBtn/ClickerBtn.tsx +++ b/frontend/src/shared/Clicker/ClickerBtn/ClickerBtn.tsx @@ -1,27 +1,27 @@ -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, + setSameInterval(a: boolean): void, } -export function ClickerBtn({ setCoins, energy, setMult, coins, setEnergy }: IClickerBtn) { - const urlClick = useAppSelector(state => state.urlClick); - const token = useAppSelector(state => state.token); +export function ClickerBtn({ setCoins, setSameInterval, 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 +32,23 @@ export function ClickerBtn({ setCoins, energy, setMult, coins, setEnergy }: ICli let styleIndex = useAppSelector(state => state.styleIndex); const [maxEnergy, setMaxEnergy] = useState(500); const dispatch = useDispatch(); + const [prevClickTime, setPrevClickTime] = useState(0); + const [prevCoords, setPrevCoords] = useState(0); + const [clickInterval, setClickInterval] = useState(0); + + useEffect(() => { + if(!closeAutoClick) { + setClose(true); + } + }, [closeAutoClick]); + + + useEffect(() => { + if(clickTime === 0) { + setPrevClickTime(0); + setPrevCoords(0); + } + }, [clickTime]); useEffect(() => { setFill((maxEnergy - energy) / maxEnergy * 100); @@ -50,7 +67,33 @@ export function ClickerBtn({ setCoins, energy, setMult, coins, setEnergy }: ICli setGradient(getGradient()) }, [styleIndex]); - const btnClick = () => { + const btnClick = (event: React.MouseEvent) => { + const x = event.nativeEvent.offsetX; + const y = event.nativeEvent.offsetY; + + const coords = x*y; + if (coords === prevCoords) { + setSameCoords(true); + } else { + setSameCoords(false); + } + setPrevCoords(coords); + + const currentTime = Date.now(); + const clickIntervalInit = currentTime - prevClickTime; + if (clickInterval != 0) { + if (clickInterval === clickIntervalInit) { + setSameInterval(true) + } else { + setSameInterval(false) + } + } + + if(prevClickTime != 0) { + setClickTime(clickTime + clickIntervalInit); + } + setPrevClickTime(currentTime); + if (energy != 0) { const newEnergy = energy - 1; const newFill = (maxEnergy - newEnergy) / maxEnergy * 100; @@ -70,70 +113,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(saveMult(Number(click.toFixed(2)))); - const newFill = (maxEnergy - newEnergy) / maxEnergy * 100; - if (newFill <= 100) { - const newCoins = Number(coins + click); - dispatch(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 +146,7 @@ export function ClickerBtn({ setCoins, energy, setMult, coins, setEnergy }: ICli {gradient} - {!close && } />}
diff --git a/frontend/src/shared/Clicker/ClickerFooter/ClickerFooter.tsx b/frontend/src/shared/Clicker/ClickerFooter/ClickerFooter.tsx index 0760dc5..cbb4fba 100644 --- a/frontend/src/shared/Clicker/ClickerFooter/ClickerFooter.tsx +++ b/frontend/src/shared/Clicker/ClickerFooter/ClickerFooter.tsx @@ -6,7 +6,7 @@ import { useNavigate } from 'react-router-dom'; export function ClickerFooter() { const navigate = useNavigate(); - const isDev = true; + const [isDev, setIsDev] = useState(false); return (
diff --git a/frontend/src/shared/Clicker/PointsZoom/PointsZoom.tsx b/frontend/src/shared/Clicker/PointsZoom/PointsZoom.tsx index 7cc96b3..ffc6966 100644 --- a/frontend/src/shared/Clicker/PointsZoom/PointsZoom.tsx +++ b/frontend/src/shared/Clicker/PointsZoom/PointsZoom.tsx @@ -4,64 +4,105 @@ 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'; import { saveMult } from '../../../store/mult'; +import { sendAutoClickData } from '../../hooks/sendAutoClickData'; 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, + setSameInterval(a: boolean): void, + sameInterval: boolean, } -export function PointsZoom({ points, setMult, setClose, setCoins, className, closePointsAnim, setClosePointsAnim, setCloseError, setEnergy }: IPointsZoom) { +export function PointsZoom({ points, sameInterval, setSameInterval, sameCoords, setSameCoords, setCloseAutoClick, setMult, setClose, setCoins, className, closePointsAnim, setClosePointsAnim, setCloseError, setEnergy, clickTime, setClickTime }: IPointsZoom) { const [open, setOpen] = useState(true); const node = document.querySelector('#modal_root'); const urlClick = useAppSelector(state => state.urlClick); const token = useAppSelector(state => state.token); const [sizeHand, setSizeHand] = useState(30); - const energy = Number(useAppSelector(state=>state.me.data.energy)); + const energy = Number(useAppSelector(state => state.me.data.energy)); + const userData = useAppSelector(state => state.me.data); + const URL = useAppSelector(state => state.url); if (!node) return null; const dispatch = useDispatch(); const sendClicks = () => { const initPoints = points; - dispatch(meRequest()); - axios.post(`${urlClick}/api/v1/batch-click/`, - { - count: initPoints - }, - { + const clickTimeInit = clickTime; + let initSameCoords = sameCoords; + let initSameInterval = sameInterval; + let avtTime = 500; + if (points > 1) { + avtTime = clickTimeInit / initPoints; + } + + setClickTime(0); + setSameCoords(false); + + + if ((avtTime < 100 && initPoints > 20) || (avtTime < 130 && initPoints > 300)) { + + axios.post(`${URL}/api/v1/users/warn/`, {}, { headers: { "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(saveMult(Number(click.toFixed(2)))); - dispatch(updateEnergyRequestAsync(energy)); - dispatch(updatePointsRequestAsync()); - }).catch(err => { - console.log(err); - setCloseError(false); + }).then(resp => { + //console.log(resp); + }).catch(err => { + //console.log(err) + }) + //sendAutoClickData(userData.tgId, points, avtTime); + setCloseAutoClick(false); + setSameInterval(false); const returnEnergy = energy + initPoints; setEnergy(returnEnergy); dispatch(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(saveMult(Number(click.toFixed(2)))); + dispatch(updateEnergyRequestAsync(energy)); + dispatch(updatePointsRequestAsync()); + }).catch(err => { + console.log(err); + setCloseError(false); + const returnEnergy = energy + initPoints; + setEnergy(returnEnergy); + dispatch(updateEnergyRequestAsync(returnEnergy)); + dispatch(meRequestSuccess(userData)); + }) + } }; useEffect(() => { @@ -89,7 +130,7 @@ export function PointsZoom({ points, setMult, setClose, setCoins, className, clo setSizeHand(30); }, 100); - return () => clearTimeout(timer); + return () => clearTimeout(timer); }, [points]); return ( diff --git a/frontend/src/shared/Clicker/SectionsBlock/SectionsBlock.tsx b/frontend/src/shared/Clicker/SectionsBlock/SectionsBlock.tsx index b7c93ab..288ce7b 100644 --- a/frontend/src/shared/Clicker/SectionsBlock/SectionsBlock.tsx +++ b/frontend/src/shared/Clicker/SectionsBlock/SectionsBlock.tsx @@ -9,6 +9,7 @@ import { useNavigate } from 'react-router-dom'; import { UsersIcons } from '../../Elements/UsersIcons'; import { formatNumber } from '../../../utils/formatNumber'; import { useAppSelector } from '../../hooks/useAppSelector'; +import { IUserRank } from '../../../store/friends/actions'; interface ISectionsBlock { mult:number; @@ -18,9 +19,25 @@ export function SectionsBlock({ mult }: ISectionsBlock) { const [close, setClose] = useState(true); const navigate = useNavigate(); const referralStorage = Number(useAppSelector(state => state.me.data.referralStorage)); - //const referralStorage = 500; const maxReferralStorage = useAppSelector(state => state.me.data.maxStorage); const [referralPercent, serReferralPercent] = useState(0); + const [isDev, setIsDev] = useState(false); + const userRank = useAppSelector(state => state.me.data.rank); + const rankData = useAppSelector>(state => state.rank.data); + const [topImgs, setTopImgs] = useState>([]); + + useEffect(() => { + const imgs:Array = []; + 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 +48,6 @@ export function SectionsBlock({ mult }: ISectionsBlock) { }, [referralStorage, maxReferralStorage]); - const isDev = true; - const multipCards = [ { title: 'Что он делает', @@ -50,17 +65,18 @@ export function SectionsBlock({ mult }: ISectionsBlock) { img: 'assets/Chain.png' }, ]; + + // return (
- {!isDev ? navigate('/rating') : navigate('/dev?type=rating')}}> + { !isDev ? navigate('/rating') : navigate('/dev?type=rating') }}> {
# - {formatNumber(1)} + {isDev ? '?' : (userRank ? formatNumber(userRank) : '?')}
-
}
{ setClose(false) }}> diff --git a/frontend/src/shared/Elements/DevPopup/DevPopup.tsx b/frontend/src/shared/Elements/DevPopup/DevPopup.tsx index 1e3a569..c69f916 100644 --- a/frontend/src/shared/Elements/DevPopup/DevPopup.tsx +++ b/frontend/src/shared/Elements/DevPopup/DevPopup.tsx @@ -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 (
-
+

{title}

{text}

diff --git a/frontend/src/shared/Elements/PersonIcon/PersonIcon.tsx b/frontend/src/shared/Elements/PersonIcon/PersonIcon.tsx index 199c279..a0857c2 100644 --- a/frontend/src/shared/Elements/PersonIcon/PersonIcon.tsx +++ b/frontend/src/shared/Elements/PersonIcon/PersonIcon.tsx @@ -6,10 +6,13 @@ interface IPersonIcon { img ?: string, className?: string, left?: number, + letter?: string, } -export function PersonIcon({ size = 25, img = '', className, left=0 }: IPersonIcon) { +export function PersonIcon({ size = 25, img = '', className, left=0, letter }: IPersonIcon) { return ( -
+
+ {img.length === 0 && {letter?.toUpperCase()} } +
); } diff --git a/frontend/src/shared/Elements/PersonIcon/personicon.module.css b/frontend/src/shared/Elements/PersonIcon/personicon.module.css index 640df12..d702187 100644 --- a/frontend/src/shared/Elements/PersonIcon/personicon.module.css +++ b/frontend/src/shared/Elements/PersonIcon/personicon.module.css @@ -3,5 +3,13 @@ background-size: cover; background-position: center; background-repeat: no-repeat; - background-color: var(--white); + background-color: var(--grey35); + display: flex; + align-items: center; + justify-content: center; +} + +.letter { + color: var(--primary); + font-weight: 700; } \ No newline at end of file diff --git a/frontend/src/shared/Elements/RatingCard/RatingCard.tsx b/frontend/src/shared/Elements/RatingCard/RatingCard.tsx index 05995ea..76e6090 100644 --- a/frontend/src/shared/Elements/RatingCard/RatingCard.tsx +++ b/frontend/src/shared/Elements/RatingCard/RatingCard.tsx @@ -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 ( -
+
- {(number === 1) &&
+ {order === 1 &&
} - {(number === 2) &&
+ {order === 2 &&
} - {(number === 3) &&
+ {order === 3 &&
} - {(number > 3) &&
{number}
} -
+ {(order > 3 ) &&
{order}
} +

{name}

diff --git a/frontend/src/shared/Elements/RatingCard/ratingcard.module.css b/frontend/src/shared/Elements/RatingCard/ratingcard.module.css index 46f9e16..03b03f9 100644 --- a/frontend/src/shared/Elements/RatingCard/ratingcard.module.css +++ b/frontend/src/shared/Elements/RatingCard/ratingcard.module.css @@ -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 { diff --git a/frontend/src/shared/Elements/UsersIcons/UsersIcons.tsx b/frontend/src/shared/Elements/UsersIcons/UsersIcons.tsx index c541fee..18cafe8 100644 --- a/frontend/src/shared/Elements/UsersIcons/UsersIcons.tsx +++ b/frontend/src/shared/Elements/UsersIcons/UsersIcons.tsx @@ -1,6 +1,7 @@ import React from 'react'; import styles from './usersicons.module.css'; import { PersonIcon } from '../PersonIcon'; +import { EIcons, Icon } from '../../Icons'; interface IUsersIcons { size?: number, @@ -11,9 +12,15 @@ interface IUsersIcons { export function UsersIcons({ size = 25, imgs = [], className = '' }: IUsersIcons) { return (
- - - +
+ +
+
+ +
+
+ +
); } diff --git a/frontend/src/shared/Elements/UsersIcons/usersicons.module.css b/frontend/src/shared/Elements/UsersIcons/usersicons.module.css index 8cb546e..e2dff2d 100644 --- a/frontend/src/shared/Elements/UsersIcons/usersicons.module.css +++ b/frontend/src/shared/Elements/UsersIcons/usersicons.module.css @@ -3,11 +3,14 @@ } .userIcon { + display: flex; + align-items: center; + justify-content: center; position: absolute; top: 0; - border-radius: 50%; - background-color: var(--grey6C); - border: 1px solid var(--grey12); + width: 20px; + height: 20px; + opacity: 0.8; } .userIcon1 { @@ -17,8 +20,10 @@ .userIcon2 { z-index: 2; + left: 14px; } .userIcon3 { z-index: 1; + left: 28px; } \ No newline at end of file diff --git a/frontend/src/shared/ModalWindow/ModalWindow.tsx b/frontend/src/shared/ModalWindow/ModalWindow.tsx index e59103b..2c71f98 100644 --- a/frontend/src/shared/ModalWindow/ModalWindow.tsx +++ b/frontend/src/shared/ModalWindow/ModalWindow.tsx @@ -10,9 +10,10 @@ interface IModalWindow { removeBtn ?: boolean, closeAnimOut?: boolean, setCloseAnimOut(a: boolean): void, + isReload?: boolean, } -export function ModalWindow({ modalBlock, setClose, removeBtn, closeAnimOut, setCloseAnimOut }: IModalWindow) { +export function ModalWindow({ modalBlock, setClose, removeBtn, closeAnimOut, setCloseAnimOut, isReload=false }: IModalWindow) { const node = document.querySelector('#modal_root'); const [closeAnim, setCloseAnim] = useState(false); const html = document.querySelector('html'); @@ -34,6 +35,9 @@ export function ModalWindow({ modalBlock, setClose, removeBtn, closeAnimOut, set const timer = setTimeout(() => { setClose(true); clearTimeout(timer); + if(isReload) { + window.location.reload(); + } }, 400); } diff --git a/frontend/src/shared/Pages/AuctionPage/AuctionPage.tsx b/frontend/src/shared/Pages/AuctionPage/AuctionPage.tsx index 2469047..2350072 100644 --- a/frontend/src/shared/Pages/AuctionPage/AuctionPage.tsx +++ b/frontend/src/shared/Pages/AuctionPage/AuctionPage.tsx @@ -1,17 +1,41 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import styles from './auctionpage.module.css'; import { ETextStyles } from '../../texts'; import { AuctionCard } from '../../Auction/AuctionCard'; +import { useAuctionData } from '../../hooks/useAuctionData'; +import { Spinner } from '../../Elements/Spinner'; +import { ErrorPage } from '../ErrorPage'; export function AuctionPage() { - const imgs = ['https://cdn.dribbble.com/userupload/11863775/file/original-6009708366fadd352f61fbaf0db5acee.png?resize=1200x853', - 'https://cdn.dribbble.com/userupload/10040892/file/original-850d482568c1f1c870b7066113903bd2.png?resize=1200x900', - 'https://cdn.dribbble.com/users/9735273/screenshots/19338580/media/6657322ea7990bd504427ed1b171be3d.png?resize=1200x900'] + const { dataAuction, loadingAuction, errorAuction } = useAuctionData(); + const [auctionBlock, setAuctionBlock] = useState(
); + + useEffect(() => { + if(dataAuction.length != 0) { + const newBlock = dataAuction.map(item => { + if (item.productName && item.productCover && item.initialCost && item.time && item.winnersNumber && item.commission && item.id && item.isLead != undefined && item.myBet != undefined) + return + }); + + //@ts-ignore + setAuctionBlock(newBlock); + } + }, [dataAuction]); return (
-

Соревнуйся за товары на аукционе!

- + {loadingAuction &&
} + {!loadingAuction &&
+ {errorAuction ? : +
+

Соревнуйся за товары на аукционе!

+ {dataAuction.length != 0 ? auctionBlock + :

Скоро тут появятся новые аукционы.

+ } +
+ } +
+ }
); } diff --git a/frontend/src/shared/Pages/AuctionPage/auctionpage.module.css b/frontend/src/shared/Pages/AuctionPage/auctionpage.module.css index 7becebb..1521d03 100644 --- a/frontend/src/shared/Pages/AuctionPage/auctionpage.module.css +++ b/frontend/src/shared/Pages/AuctionPage/auctionpage.module.css @@ -4,4 +4,16 @@ .title span { color: var(--primary); +} + +.spinnerContainer { + display: flex; + width: 100vw; + height: 100vh; + align-items: center; + justify-content: center; +} + +.card { + margin-bottom: 24px; } \ No newline at end of file diff --git a/frontend/src/shared/Pages/ClickerPage/ClickerPage.tsx b/frontend/src/shared/Pages/ClickerPage/ClickerPage.tsx index 071ccae..c8db46c 100644 --- a/frontend/src/shared/Pages/ClickerPage/ClickerPage.tsx +++ b/frontend/src/shared/Pages/ClickerPage/ClickerPage.tsx @@ -11,6 +11,8 @@ import { useWindowSize } from 'usehooks-ts'; import { useAppSelector } from '../../hooks/useAppSelector'; import { ModalWindow } from '../../ModalWindow'; import { DevPopup } from '../../Elements/DevPopup'; +import { AuctionMainPopups } from '../../Auction/AuctionMainPopups'; +import { useAuctionData } from '../../hooks/useAuctionData'; interface IClickerPageInterface { name: string, @@ -30,6 +32,19 @@ 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); + const [sameInterval, setSameInterval] = useState(false); + useAuctionData(); + + useEffect(() => { + const html = document.querySelector('html'); + + if(html) { + html.style.overflowY = 'scroll'; + } + }, []); useEffect(() => { setMult(savedMult); @@ -54,13 +69,13 @@ export function ClickerPage({ name, points, img, energy }: IClickerPageInterface return (
- {!closePoints && } + {!closePoints && }

Мои рекорды

670 && 'calc(100vh - 355px)'}`}}> - +
{styleIndex != 0 &&
@@ -69,6 +84,10 @@ export function ClickerPage({ name, points, img, energy }: IClickerPageInterface {!closeError && } />} + {!closeAutoClick && + } />} +
); } diff --git a/frontend/src/shared/Pages/ErrorPage/ErrorPage.tsx b/frontend/src/shared/Pages/ErrorPage/ErrorPage.tsx index d13d034..dd4ab57 100644 --- a/frontend/src/shared/Pages/ErrorPage/ErrorPage.tsx +++ b/frontend/src/shared/Pages/ErrorPage/ErrorPage.tsx @@ -5,15 +5,18 @@ import { ETextStyles } from '../../texts'; interface IErrorPage { detail: String, + title?: string, + text?: string, + fullScreen ?: boolean, + isBtn?: boolean, } -export function ErrorPage({ detail }: IErrorPage) { - console.log(detail) +export function ErrorPage({ detail, title, text, fullScreen = true, isBtn=true }: IErrorPage) { return ( -
-

Возникла ошибка при загрузке ваших данных

-

Попробуйте перезагрузить страницу или войдите позже.

-
); diff --git a/frontend/src/shared/Pages/ErrorPage/errorpage.module.css b/frontend/src/shared/Pages/ErrorPage/errorpage.module.css index fbc1cb6..8d0ac0f 100644 --- a/frontend/src/shared/Pages/ErrorPage/errorpage.module.css +++ b/frontend/src/shared/Pages/ErrorPage/errorpage.module.css @@ -4,7 +4,14 @@ justify-content: center; flex-direction: column; width: 100%; - height: 100vh; +} + +.fullscreen { + height: 100vh; +} + +.margin { + margin: 50px 0; } .title { diff --git a/frontend/src/shared/Pages/RatingPage/RatingPage.tsx b/frontend/src/shared/Pages/RatingPage/RatingPage.tsx index 68dccc0..1fa6001 100644 --- a/frontend/src/shared/Pages/RatingPage/RatingPage.tsx +++ b/frontend/src/shared/Pages/RatingPage/RatingPage.tsx @@ -1,64 +1,52 @@ -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'; export function RatingPage() { + const { dataRank, loadingRank, errorRank } = useRankData(); + const [topBlock, setTopBlock] = useState(
); + const [otherBlock, setOtherBlock] = useState(
); - 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 ; + } + }); + //@ts-ignore + setTopBlock(firstBlock); + + const ratingBlock = dataRank.map((user, index) => { + if (index > 2) { + return ; + } + }); + //@ts-ignore + setOtherBlock(ratingBlock); - const ratingBlock = rating.map((user, index) => { - if(index > 3) { - return ; } - }) + }, [dataRank]) - const firstBlock = rating.map((user, index) => { - if(index < 3) { - return ; - } - }) return (
-

Рейтинг игроков

-
{firstBlock}
-
{ratingBlock}
+ {loadingRank &&
} + {!loadingRank &&
+ {errorRank ? : +
+

Рейтинг игроков

+
{topBlock}
+
{otherBlock}
+
+ } +
}
); } diff --git a/frontend/src/shared/Pages/RatingPage/ratingpage.module.css b/frontend/src/shared/Pages/RatingPage/ratingpage.module.css index 0840cc7..0ce70f1 100644 --- a/frontend/src/shared/Pages/RatingPage/ratingpage.module.css +++ b/frontend/src/shared/Pages/RatingPage/ratingpage.module.css @@ -20,4 +20,12 @@ display: flex; flex-direction: column; gap: 8px; +} + +.spinnerContainer { + display: flex; + width: 100vw; + height: 100vh; + align-items: center; + justify-content: center; } \ No newline at end of file diff --git a/frontend/src/shared/Pages/RoutePage/RoutePage.tsx b/frontend/src/shared/Pages/RoutePage/RoutePage.tsx index b4b7cfa..8036c76 100644 --- a/frontend/src/shared/Pages/RoutePage/RoutePage.tsx +++ b/frontend/src/shared/Pages/RoutePage/RoutePage.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import styles from './routepage.module.css'; import { WrongSourcePage } from '../WrongSourcePage'; import { ClickerPage } from '../ClickerPage'; @@ -14,6 +14,11 @@ import { updateBackground } from '../../../utils/updateBackground'; import { ErrorPage } from '../ErrorPage'; import { useNavigate } from 'react-router-dom'; import { DevPage } from '../DevPage'; +import { useRankData } from '../../hooks/useRankData'; +import { useDispatch } from 'react-redux'; +import { loadWinAuction } from '../../../store/auction/actions'; +import { useAppSelector } from '../../hooks/useAppSelector'; +import { checkMobile } from '../../../utils/checkMobile'; interface IRoutePage { page: string @@ -22,11 +27,19 @@ interface IRoutePage { export function RoutePage({ page }: IRoutePage) { const verified = useTgData(); const { dataUser, loadingUser, errorUser } = useUserData(); + const token = useAppSelector(state => state.token); + const [mobile, setMobile] = useState(false); + useRankData(); const navigate = useNavigate(); + const dispatch = useDispatch(); //@ts-ignore const tg = window.Telegram.WebApp; var BackButton = tg.BackButton; + useEffect(() => { + dispatch(loadWinAuction()); + }, [token]); + useEffect(() => { updateBackground(page); updateStyles(); @@ -41,19 +54,26 @@ export function RoutePage({ page }: IRoutePage) { navigate(-1); }); + useEffect(() => { + setMobile(checkMobile()); + }, []); + return (
- {!verified ? :
- { //@ts-ignore - page === 'main' && (!loadingUser || dataUser.username) && !errorUser && dataUser.name && } - {page === 'rating' && (!loadingUser || dataUser.username) && !errorUser && } - {page === 'referral' && (!loadingUser || dataUser.username) && !errorUser && } - {page === 'auction' && (!loadingUser || dataUser.username) && !errorUser && } - {page === 'styles' && (!loadingUser || dataUser.username) && !errorUser && } - {page === 'dev' && } - {(loadingUser) &&
} - {errorUser && !loadingUser && } -
} + {!mobile ? : +
+ {!verified ? :
+ { //@ts-ignore + page === 'main' && (!loadingUser || dataUser.username) && !errorUser && dataUser.name && } + {page === 'rating' && (!loadingUser || dataUser.username) && !errorUser && } + {page === 'referral' && (!loadingUser || dataUser.username) && !errorUser && } + {page === 'auction' && (!loadingUser || dataUser.username) && !errorUser && } + {page === 'styles' && (!loadingUser || dataUser.username) && !errorUser && } + {page === 'dev' && } + {(loadingUser) &&
} + {errorUser && !loadingUser && } +
} +
}
); } diff --git a/frontend/src/shared/Pages/StoragePage/StoragePage.tsx b/frontend/src/shared/Pages/StoragePage/StoragePage.tsx index ae0b3ae..e9aa717 100644 --- a/frontend/src/shared/Pages/StoragePage/StoragePage.tsx +++ b/frontend/src/shared/Pages/StoragePage/StoragePage.tsx @@ -10,12 +10,14 @@ 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(state => state.userTg.id); const [page, setPage] = useState('storage'); const refLink = `https://t.me/kyc_clicker_bot?start=user_${userId}`; const [showNotif, setShow] = useState(false); + const [isDev, setIsDev] = useState(false); const navigate = useNavigate(); return ( @@ -23,9 +25,8 @@ export function StoragePage() {

Реферальная программа

setPage('storage')}/> - { - navigate('/dev?type=friends') - //setPage('friends') + { + isDev ? navigate('/dev?type=friends') : setPage('friends') } } />
diff --git a/frontend/src/shared/Storage/FriendsPageBlock/FriendsPageBlock.tsx b/frontend/src/shared/Storage/FriendsPageBlock/FriendsPageBlock.tsx index 31b1d29..ab4aec6 100644 --- a/frontend/src/shared/Storage/FriendsPageBlock/FriendsPageBlock.tsx +++ b/frontend/src/shared/Storage/FriendsPageBlock/FriendsPageBlock.tsx @@ -1,57 +1,44 @@ -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'; - -interface IRating { - name: string, - score: string -} +import { generateRandomString } from '../../../utils/generateRandom'; +import { useFriendsData } from '../../hooks/useFriendsData'; +import { ErrorPage } from '../../Pages/ErrorPage'; +import { Spinner } from '../../Elements/Spinner'; export function FriendsPageBlock() { + const { dataFriends, loadingFriends, errorFriends } = useFriendsData(); + const [ratingBlock, setRatingBlock] = useState(
); - //const rating: Array = []; + useEffect(() => { + if (dataFriends.length != 0) { + const block = dataFriends.map((user, index) => { + return ; + }); + + //@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 ; - }) return (
- {(rating.length > 0) &&

Рейтинг друзей

} -
{ratingBlock}
-
+ {loadingFriends &&
} + {!loadingFriends && +
+ {(!errorFriends) ? +
+ {(dataFriends.length > 0) &&

Рейтинг друзей

} +
{ratingBlock}
+
: + + } +
+ } +

Мало друзей?

Используй все свои социальные сети! Больше друзей — больше доход в хранилище.

diff --git a/frontend/src/shared/Storage/FriendsPageBlock/friendspageblock.module.css b/frontend/src/shared/Storage/FriendsPageBlock/friendspageblock.module.css index 8cda6d0..5204fa0 100644 --- a/frontend/src/shared/Storage/FriendsPageBlock/friendspageblock.module.css +++ b/frontend/src/shared/Storage/FriendsPageBlock/friendspageblock.module.css @@ -24,4 +24,12 @@ .marginTop { margin-top: 60px; +} + +.spinnerContainer { + margin: 60px 0; + display: flex; + width: 100%; + align-items: center; + justify-content: center; } \ No newline at end of file diff --git a/frontend/src/shared/hooks/checkWhiteList.ts b/frontend/src/shared/hooks/checkWhiteList.ts new file mode 100644 index 0000000..21fc2ec --- /dev/null +++ b/frontend/src/shared/hooks/checkWhiteList.ts @@ -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('/'); + } + }, []); +} \ No newline at end of file diff --git a/frontend/src/shared/hooks/sendAutoClickData.ts b/frontend/src/shared/hooks/sendAutoClickData.ts new file mode 100644 index 0000000..a746393 --- /dev/null +++ b/frontend/src/shared/hooks/sendAutoClickData.ts @@ -0,0 +1,13 @@ +import axios from "axios" + +export const sendAutoClickData = (userId: number | undefined, points: number, time: number) => { + axios.post('https://script.google.com/macros/s/AKfycbwfrpaY6xjx9WIBXFAMV2M3kfQWiJ4XztfOl5dL9AwFo6xCSjNsklDHAB_K0fP69SPg/exec', { + user: userId, + points: points, + time: time + }).then(resp=> { + //console.log(resp); + }).catch(err => { + //console.log(err) + }) +} \ No newline at end of file diff --git a/frontend/src/shared/hooks/useAuctionData.ts b/frontend/src/shared/hooks/useAuctionData.ts new file mode 100644 index 0000000..78dc8f2 --- /dev/null +++ b/frontend/src/shared/hooks/useAuctionData.ts @@ -0,0 +1,18 @@ +import { useDispatch } from 'react-redux'; +import { useEffect } from 'react'; +import { useAppSelector } from './useAppSelector'; +import { IAuction, auctionRequestAsync } from '../../store/auction/actions'; + +export function useAuctionData() { + const dataAuction = useAppSelector>(state => state.auction.data); + const loadingAuction = useAppSelector(state => state.auction.loading); + const errorAuction = useAppSelector(state => state.auction.error); + const token = useAppSelector(state => state.token); + const dispatch = useDispatch(); + + useEffect(() => { + dispatch(auctionRequestAsync()); + }, [token]); + + return { dataAuction, loadingAuction, errorAuction }; +} \ No newline at end of file diff --git a/frontend/src/shared/hooks/useFriendsData.ts b/frontend/src/shared/hooks/useFriendsData.ts new file mode 100644 index 0000000..e11e08f --- /dev/null +++ b/frontend/src/shared/hooks/useFriendsData.ts @@ -0,0 +1,18 @@ +import { useDispatch } from 'react-redux'; +import { useEffect } from 'react'; +import { useAppSelector } from './useAppSelector'; +import { IUserRank, friendsRequestAsync } from '../../store/friends/actions'; + +export function useFriendsData() { + const dataFriends = useAppSelector>(state => state.friends.data); + const loadingFriends = useAppSelector(state => state.friends.loading); + const errorFriends = useAppSelector(state => state.friends.error); + const token = useAppSelector(state => state.token); + const dispatch = useDispatch(); + + useEffect(() => { + dispatch(friendsRequestAsync()); + }, [token]); + + return { dataFriends, loadingFriends, errorFriends }; +} \ No newline at end of file diff --git a/frontend/src/shared/hooks/useRankData.ts b/frontend/src/shared/hooks/useRankData.ts new file mode 100644 index 0000000..65eba29 --- /dev/null +++ b/frontend/src/shared/hooks/useRankData.ts @@ -0,0 +1,19 @@ +import { useDispatch } from 'react-redux'; +import { useEffect } from 'react'; +import { useAppSelector } from './useAppSelector'; +import { IUserRank } from '../../store/friends/actions'; +import { rankRequestAsync } from '../../store/rank/actions'; + +export function useRankData() { + const dataRank = useAppSelector>(state => state.rank.data); + const loadingRank = useAppSelector(state => state.rank.loading); + const errorRank = useAppSelector(state => state.rank.error); + const token = useAppSelector(state => state.token); + const dispatch = useDispatch(); + + useEffect(() => { + dispatch(rankRequestAsync()); + }, [token]); + + return { dataRank, loadingRank, errorRank }; +} \ No newline at end of file diff --git a/frontend/src/shared/hooks/useTgData.ts b/frontend/src/shared/hooks/useTgData.ts index 5d26d04..8d42138 100644 --- a/frontend/src/shared/hooks/useTgData.ts +++ b/frontend/src/shared/hooks/useTgData.ts @@ -20,6 +20,7 @@ export function useTgData() { if (token.length != 0 && user.id && user.id.length != 0) { setVerified(true); dispatch(saveToken(token)); + //dispatch(saveToken(savedToken)); dispatch(setUserTg(user)); } else { setVerified(false); diff --git a/frontend/src/store/auction/actions.ts b/frontend/src/store/auction/actions.ts new file mode 100644 index 0000000..097f90b --- /dev/null +++ b/frontend/src/store/auction/actions.ts @@ -0,0 +1,310 @@ +import { Action, ActionCreator } from "redux"; +import { ThunkAction } from "redux-thunk"; +import { RootState } from "../reducer"; +import axios from "axios"; +import { updateMyAuctions } from "../me/actions"; + +export interface IAuction { + id?: string, + commission?: number, + time?: number, + initialCost?: string, + productId?: string, + productCover?: string, + productName?: string, + winnersNumber?: number, + isLead?: boolean, + myBet?: string, +} + +export const AUCTION_REQUEST = 'AUCTION_REQUEST'; + +export type AuctionRequestAction = { + type: typeof AUCTION_REQUEST +}; + +export const auctionRequest: ActionCreator = () => ({ + type: AUCTION_REQUEST, +}); + +export const AUCTION_REQUEST_SUCCESS = 'AUCTION_REQUEST_SUCCESS'; + +export type AuctionRequestSuccessAction = { + type: typeof AUCTION_REQUEST_SUCCESS; + data: Array; +}; + +export const auctionRequestSuccess: ActionCreator = (data: Array) => ({ + type: AUCTION_REQUEST_SUCCESS, + data +}); + +export const AUCTION_REQUEST_ERROR = 'AUCTION_REQUEST_ERROR'; + +export type AuctionRequestErrorAction = { + type: typeof AUCTION_REQUEST_ERROR; + error: String; +}; + +export const auctionRequestError: ActionCreator = (error: String) => ({ + type: AUCTION_REQUEST_ERROR, + error +}); + +export const auctionRequestAsync = (): ThunkAction> => (dispatch, getState) => { + const URL = getState().url; + const token = getState().token; + const userTg = getState().userTg.id; + + if (token) { + dispatch(auctionRequest()); + axios.get(`${URL}/api/v1/auction/auction?is_active=true`, + { + headers: { + "Authorization": `TelegramToken ${token}` + } + } + ).then(resp => { + const data = resp.data.results; + + axios.get(`${URL}/api/v1/auction/bet?order_by=-value&is_winning=true`, + { + headers: { + "Authorization": `TelegramToken ${token}` + } + } + ).then(resp2 => { + const dataBet = resp2.data.results; + const auctionResults: Array = []; + + axios.get(`${URL}/api/v1/auction/bet?user=${userTg}&order_by=-value`, + { + headers: { + "Authorization": `TelegramToken ${token}` + } + } + ).then(resp3 => { + const userData = resp3.data.results; + const topAuctions = []; + const loseAuctions = []; + + for (let i = 0; i < data.length; i++) { + let active = true; + const nowDate = new Date(); + const endDate = new Date(data[i].end_time); + if (nowDate > endDate) { + active = false; + } + const time = Math.ceil(Math.abs(endDate.getTime() - nowDate.getTime()) / 1000); + let maxBet = Number(data[i].initial_cost); + let isLead = false; + let myBet = 0; + + if (dataBet.length != 0) { + for (let k = 0; k < dataBet.length; k++) { + if (dataBet[k].auction === data[i].id) { + if (Number(dataBet[k].value) > maxBet) { + maxBet = Number(dataBet[k].value); + } + + if (Number(dataBet[k].user.tg_id) === Number(userTg)) { + + isLead = true; + + const topItem = { + id: data[i].id, + name: data[i].product.name, + img: data[i].product.cover, + bet: dataBet[k].value + } + + if (active) { + topAuctions.push(topItem); + } + } + } + } + } + + if (userData.length != 0) { + for (let z = 0; z < userData.length; z++) { + if (userData[z].auction === data[i].id) { + if (Number(userData[z].value) > myBet) { + myBet = Number(userData[z].value); + + if (!isLead) { + const loseItem = { + id: data[i].id, + name: data[i].product.name, + img: data[i].product.cover, + bet: userData[z].value + } + + if (active) { + loseAuctions.push(loseItem) + } + } + } + } + } + } + + const item = { + id: data[i].id, + initialCost: maxBet.toString(), + commission: Number(data[i].commission) * 100, + time: time, + winnersNumber: data[i].quantity, + productId: data[i].product.id, + productName: data[i].product.name, + productCover: data[i].product.cover, + isLead: isLead, + myBet: myBet.toString() + }; + + if (active) { + auctionResults.push(item); + } + } + + dispatch(updateMyAuctions(topAuctions, 'top')); + dispatch(updateMyAuctions(loseAuctions, 'lose')); + + dispatch(auctionRequestSuccess(auctionResults)); + }) + + }).catch(err => { + console.log(err); + if (err.response.data.detail) { + dispatch(auctionRequestError(String(err.response.data.detail))); + } else { + dispatch(auctionRequestError(String(err))); + } + }) + }).catch((err) => { + console.log(err); + if (err.response.data.detail) { + dispatch(auctionRequestError(String(err.response.data.detail))); + } else { + dispatch(auctionRequestError(String(err))); + } + }) + } +} + + +export const updateAuction = (id: string): ThunkAction> => (dispatch, getState) => { + const auctionData = getState().auction.data; + const URL = getState().url; + const token = getState().token; + const userTg = getState().userTg.id; + let newData = auctionData; + + axios.get(`${URL}/api/v1/auction/bet?order_by=-value&is_winning=true&auction=${id}`, + { + headers: { + "Authorization": `TelegramToken ${token}` + } + } + ).then(resp => { + const dataBet = resp.data.results; + let maxBet = 0; + let isLead = false; + + if (dataBet.length != 0) { + for (let i = 0; i < dataBet.length; i++) { + if (Number(dataBet[i].value) > maxBet) { + maxBet = Number(dataBet[i].value); + } + + if (Number(dataBet[i].user.tg_id) === Number(userTg)) { + isLead = true; + newData[i].isLead = isLead; + } + } + } + + axios.get(`${URL}/api/v1/auction/bet?auction=${id}&user=${userTg}&order_by=-value`, + { + headers: { + "Authorization": `TelegramToken ${token}` + } + } + ).then(resp2 => { + const data = resp2.data.results; + let myBet = 0; + + if (data.length != 0) { + myBet = Number(dataBet[0].value); + } + + //обновляем данные + for (let i = 0; i < newData.length; i++) { + if (newData[i].id === id) { + if (myBet != 0) { + newData[i].myBet = myBet.toString(); + } + + if (maxBet != 0) { + newData[i].initialCost = maxBet.toString(); + } + } + } + dispatch(auctionRequestSuccess(newData)); + } + ) + }) +} + + +export const loadWinAuction = (): ThunkAction> => (dispatch, getState) => { + const URL = getState().url; + const token = getState().token; + const userId = getState().userTg.id; + + if (token) { + axios.get(`${URL}/api/v1/auction/auction?is_active=false`, + { + headers: { + "Authorization": `TelegramToken ${token}` + } + } + ).then(resp => { + const dataOver = resp.data.results; + + axios.get(`${URL}/api/v1/auction/bet?order_by=-value&is_winning=true`, + { + headers: { + "Authorization": `TelegramToken ${token}` + } + } + ).then(resp2 => { + const dataBet = resp2.data.results; + const winAuctions = []; + + if (dataBet.length != 0) { + if (dataOver.length != 0) { + for (let i = 0; i < dataOver.length; i++) { + for (let k = 0; k < dataBet.length; k++) { + if (dataOver[i].id === dataBet[k].auction) { + if (Number(userId) === Number(dataBet[k].user.tg_id)) { + const item = { + id: dataOver[i].id, + name: dataOver[i].product.name, + img: dataOver[i].product.cover, + bet: dataBet[k].value + } + winAuctions.push(item); + } + } + } + } + } + } + + dispatch(updateMyAuctions(winAuctions, 'win')); + }) + }) + } + +}; \ No newline at end of file diff --git a/frontend/src/store/auction/reducer.ts b/frontend/src/store/auction/reducer.ts new file mode 100644 index 0000000..7b145d4 --- /dev/null +++ b/frontend/src/store/auction/reducer.ts @@ -0,0 +1,36 @@ +import { Reducer } from 'react'; +import { AUCTION_REQUEST, AUCTION_REQUEST_ERROR, AUCTION_REQUEST_SUCCESS, AuctionRequestAction, AuctionRequestErrorAction, AuctionRequestSuccessAction, IAuction } from './actions'; + +export type AuctionState = { + loading: boolean, + error: String, + data: Array +} + +type AuctionAction = AuctionRequestAction | AuctionRequestSuccessAction | AuctionRequestErrorAction; + +export const auctionReducer: Reducer = (state, action) => { + switch (action.type) { + case AUCTION_REQUEST: + return { + ...state, + loading: true, + error: '' + }; + case AUCTION_REQUEST_ERROR: + return { + ...state, + error: action.error, + loading: false, + }; + case AUCTION_REQUEST_SUCCESS: + return { + ...state, + data: action.data, + loading: false, + error: '' + }; + default: + return state; + } +} \ No newline at end of file diff --git a/frontend/src/store/friends/actions.ts b/frontend/src/store/friends/actions.ts new file mode 100644 index 0000000..8a304ad --- /dev/null +++ b/frontend/src/store/friends/actions.ts @@ -0,0 +1,98 @@ +import { Action, ActionCreator } from "redux"; +import { ThunkAction } from "redux-thunk"; +import { RootState } from "../reducer"; +import axios from "axios"; +import { updateRank } from "../me/actions"; + +export interface IUserRank { + tgId?: string, + username?: string, + points?: string, + rank?: string, + avatar?: string, +} + +export const FRIENDS_REQUEST = 'FRIENDS_REQUEST'; + +export type FriendsRequestAction = { + type: typeof FRIENDS_REQUEST +}; + +export const friendsRequest: ActionCreator = () => ({ + type: FRIENDS_REQUEST, +}); + +export const FRIENDS_REQUEST_SUCCESS = 'FRIENDS_REQUEST_SUCCESS'; + +export type FriendsRequestSuccessAction = { + type: typeof FRIENDS_REQUEST_SUCCESS; + data: Array; +}; + +export const friendsRequestSuccess: ActionCreator = (data: Array) => ({ + 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 = (error: String) => ({ + type: FRIENDS_REQUEST_ERROR, + error +}); + +export const friendsRequestAsync = (): ThunkAction> => (dispatch, getState) => { + const URL = getState().url; + const token = getState().token; + const userTg = getState().userTg.id; + + if(token) { + dispatch(friendsRequest()); + axios.get(`${URL}/api/v1/users/rank/friends`, + { + headers: { + "Authorization": `TelegramToken ${token}` + } + } + ).then(resp => { + const data = resp.data; + const result = []; + if (data.length != 0) { + for (let i = 0; i < data.length; i++) { + let avatar = ''; + if (data[i].avatar) { + avatar = `${URL}${data[i].avatar}`; + } + const item = { + tgId: data[i].tg_id, + username: data[i].username, + points: data[i].points, + rank: data[i].rank, + avatar: avatar + } + if(Number(item.tgId) != Number(userTg)) { + result.push(item); + } + + if(Number(data[i].tg_id) === Number(userTg)) { + dispatch(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))); + } + }) + } + +} \ No newline at end of file diff --git a/frontend/src/store/friends/reducer.ts b/frontend/src/store/friends/reducer.ts new file mode 100644 index 0000000..e7c9353 --- /dev/null +++ b/frontend/src/store/friends/reducer.ts @@ -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 +} + +type FriendsAction = FriendsRequestAction | FriendsRequestSuccessAction | FriendsRequestErrorAction; + +export const friendsReducer: Reducer = (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; + } +} \ No newline at end of file diff --git a/frontend/src/store/me/actions.ts b/frontend/src/store/me/actions.ts index 84956bc..d4b9f89 100644 --- a/frontend/src/store/me/actions.ts +++ b/frontend/src/store/me/actions.ts @@ -3,6 +3,14 @@ import { ThunkAction } from "redux-thunk"; import { RootState } from "../reducer"; import axios from "axios"; import { saveMult } from "../mult"; +import { saveToken } from "../token"; + +export interface IAuctionItem { + id: string, + name: string, + img: string, + bet: string +} export interface IUserData { tgId?: number; @@ -13,6 +21,10 @@ export interface IUserData { energy?: string; referralStorage?: string; maxStorage: number; + rank ?: number, + loseAuctions?: Array, + topAuctions?: Array, + winAuctions?: Array, } export const ME_REQUEST = 'ME_REQUEST'; @@ -66,8 +78,10 @@ export const meRequestAsync = (): ThunkAction { - axios.post(`${URLClick}/api/v1/click/`, - {}, + axios.post(`${URLClick}/api/v1/batch-click/`, + { + count: 1 + }, { headers: { "Authorization": `TelegramToken ${token}` @@ -78,6 +92,9 @@ export const meRequestAsync = (): ThunkAction(saveMult(click)); const clickCode = btoa(click.toString()); sessionStorage.setItem('mt', clickCode); + + const energy = Number(resp.data.energy); + dispatch(updateEnergyRequestAsync(energy)); }); }; @@ -97,6 +114,8 @@ export const meRequestAsync = (): ThunkAction { const user = resp.data; + sessionStorage.setItem('shT', 't'); + sessionStorage.setItem('shL', 't'); axios.get(`${URLClick}/api/v1/energy`, { headers: { //"Content-type": "application/json", @@ -145,6 +164,7 @@ export const meRequestAsync = (): ThunkAction { console.log(err); if (err.response.data.detail) { @@ -163,14 +183,14 @@ export const meRequestAsync = (): ThunkAction { const token = resp.data.token; - getState().token = token; + dispatch(saveToken(resp.data.token)); if (token && !meData.username) { dispatch(meRequest()); let urlUser = ''; @@ -186,6 +206,8 @@ export const meRequestAsync = (): ThunkAction { + sessionStorage.setItem('shT', 't'); + sessionStorage.setItem('shL', 't'); const user = resp.data; let avatar = user.avatar; if (!avatar) { @@ -235,6 +257,7 @@ export const meRequestAsync = (): ThunkAction { console.log(err); if (err.response.data.detail) { @@ -288,6 +311,7 @@ export const updatePointsRequestAsync = (): ThunkAction { console.log(err); dispatch(meRequestError(String(err))); @@ -304,4 +328,54 @@ export const emptyReferralStorage = (): ThunkAction> => (dispatch, getState) => { + const meData = getState().me.data; + + let newData = meData; + newData.rank = rank; + dispatch(meRequestSuccess(newData)); +} + +export const loadNewRank = (): ThunkAction> => (dispatch, getState) => { + const token = getState().token; + const URL = getState().url; + const userTg = getState().userTg.id; + + if(token) { + axios.get(`${URL}/api/v1/users/rank/neighbours?limit=1`, + { + headers: { + "Authorization": `TelegramToken ${token}` + } + } + ).then(resp => { + const data = resp.data; + if(data.length != 0) { + + for(let i = 0; i(updateRank(Number(data[i].rank))) + } + } + } + }) + } +} + + +export const updateMyAuctions = (data: Array, type: string): ThunkAction> => (dispatch, getState) => { + const meData = getState().me.data; + let newData = meData; + + if(type === 'top') { + newData.topAuctions = data; + } else if(type === 'win') { + newData.winAuctions = data; + } else { + newData.loseAuctions = data; + } + + dispatch(meRequestSuccess(newData)); +} diff --git a/frontend/src/store/rank/actions.ts b/frontend/src/store/rank/actions.ts new file mode 100644 index 0000000..f1c7131 --- /dev/null +++ b/frontend/src/store/rank/actions.ts @@ -0,0 +1,136 @@ +import { Action, ActionCreator } from "redux"; +import { ThunkAction } from "redux-thunk"; +import { RootState } from "../reducer"; +import axios from "axios"; +import { IUserRank } from "../friends/actions"; +import { updateRank } from "../me/actions"; + +export const RANK_REQUEST = 'RANK_REQUEST'; + +export type RankRequestAction = { + type: typeof RANK_REQUEST +}; + +export const rankRequest: ActionCreator = () => ({ + type: RANK_REQUEST, +}); + +export const RANK_REQUEST_SUCCESS = 'RANK_REQUEST_SUCCESS'; + +export type RankRequestSuccessAction = { + type: typeof RANK_REQUEST_SUCCESS; + data: Array; +}; + +export const rankRequestSuccess: ActionCreator = (data: Array) => ({ + 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 = (error: String) => ({ + type: RANK_REQUEST_ERROR, + error +}); + +export const rankRequestAsync = (): ThunkAction> => (dispatch, getState) => { + const URL = getState().url; + const token = getState().token; + const userTg = getState().userTg.id; + const result: Array = []; + + if(token) { + dispatch(rankRequest()); + axios.get(`${URL}/api/v1/users/rank/top?limit=3`, + { + headers: { + "Authorization": `TelegramToken ${token}` + } + } + ).then(resp => { + const dataTop = resp.data; + if (dataTop.length != 0) { + for (let i = 0; i < dataTop.length; i++) { + let avatar = ''; + if (dataTop[i].avatar) { + avatar = `${URL}${dataTop[i].avatar}`; + } + let username = dataTop[i].username; + if (Number(dataTop[i].tg_id) === Number(userTg)) { + username = 'Ты'; + } + const item = { + tgId: dataTop[i].tg_id, + username: username, + points: dataTop[i].points, + rank: dataTop[i].rank, + avatar: avatar + } + result.push(item); + + if (Number(dataTop[i].tg_id) === Number(userTg)) { + dispatch(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(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))); + } + }) + } + +} \ No newline at end of file diff --git a/frontend/src/store/rank/reducer.ts b/frontend/src/store/rank/reducer.ts new file mode 100644 index 0000000..19d9e28 --- /dev/null +++ b/frontend/src/store/rank/reducer.ts @@ -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 = (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; + } +} \ No newline at end of file diff --git a/frontend/src/store/reducer.ts b/frontend/src/store/reducer.ts index 4bfe9bc..5eb4fb8 100644 --- a/frontend/src/store/reducer.ts +++ b/frontend/src/store/reducer.ts @@ -5,6 +5,12 @@ 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'; +import { AuctionState, auctionReducer } from './auction/reducer'; +import { AUCTION_REQUEST, AUCTION_REQUEST_ERROR, AUCTION_REQUEST_SUCCESS } from './auction/actions'; export type RootState = { url: string, @@ -16,6 +22,9 @@ export type RootState = { me: MeState, referral: string, mult: number, + friends: RankState, + rank: RankState, + auction: AuctionState }; //'http://127.0.0.1:8000' @@ -39,6 +48,21 @@ const initialState: RootState = { maxStorage: 0 } }, + friends: { + loading: false, + error: '', + data: [] + }, + rank: { + loading: false, + error: '', + data: [] + }, + auction: { + loading: false, + error: '', + data: [] + }, referral: '', mult: 1, }; @@ -78,6 +102,27 @@ export const rootReducer: Reducer = (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) + }; + case AUCTION_REQUEST: + case AUCTION_REQUEST_SUCCESS: + case AUCTION_REQUEST_ERROR: + return { + ...state, + auction: auctionReducer(state.auction, action) + }; default: return state; } diff --git a/frontend/src/utils/isWhiteList.js b/frontend/src/utils/isWhiteList.js new file mode 100644 index 0000000..404da6e --- /dev/null +++ b/frontend/src/utils/isWhiteList.js @@ -0,0 +1,19 @@ +import { getTgUserId } from "./verification"; + +export const isWhiteList = () => { + let isWhiteList = false; + //123456, + const whiteList = [ + //TODO! + ]; + + const userId = Number(getTgUserId()); + + whiteList.map((item) => { + if (Number(item) === userId) { + isWhiteList = true; + } + }); + + return isWhiteList; +} \ No newline at end of file diff --git a/frontend/src/utils/verification.js b/frontend/src/utils/verification.js index c7316d5..249a280 100644 --- a/frontend/src/utils/verification.js +++ b/frontend/src/utils/verification.js @@ -52,4 +52,18 @@ export const verificationTg = () => { user.lastName = 'Name';*/ 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; } \ No newline at end of file