diff --git a/frontend/src/.DS_Store b/frontend/src/.DS_Store index 926ef31..4eef03b 100644 Binary files a/frontend/src/.DS_Store and b/frontend/src/.DS_Store differ diff --git a/frontend/src/shared/.DS_Store b/frontend/src/shared/.DS_Store new file mode 100644 index 0000000..c4b26bf Binary files /dev/null and b/frontend/src/shared/.DS_Store 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..c373d51 100644 --- a/frontend/src/shared/Auction/Timer/Timer.tsx +++ b/frontend/src/shared/Auction/Timer/Timer.tsx @@ -40,7 +40,7 @@ export function Timer({initTime}: ITimer) {
-

{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 288d568..cbca9d7 100644 --- a/frontend/src/shared/Clicker/ClickerBtn/ClickerBtn.tsx +++ b/frontend/src/shared/Clicker/ClickerBtn/ClickerBtn.tsx @@ -17,10 +17,11 @@ interface IClickerBtn { clickTime: number, sameCoords: boolean, setSameCoords(a: boolean): void, - closeAutoClick: boolean + closeAutoClick: boolean, + setSameInterval(a: boolean): void, } -export function ClickerBtn({ setCoins, closeAutoClick, energy, setMult, coins, setEnergy, setClickTime, clickTime, setSameCoords }: IClickerBtn) { +export function ClickerBtn({ setCoins, setSameInterval, closeAutoClick, energy, setMult, coins, setEnergy, setClickTime, clickTime, setSameCoords }: IClickerBtn) { const [fill, setFill] = useState(0); const [size, setSize] = useState(240); const circumference = 2 * Math.PI * 125; @@ -33,6 +34,7 @@ export function ClickerBtn({ setCoins, closeAutoClick, energy, setMult, coins, s const dispatch = useDispatch(); const [prevClickTime, setPrevClickTime] = useState(0); const [prevCoords, setPrevCoords] = useState(0); + const [clickInterval, setClickInterval] = useState(0); useEffect(() => { if(!closeAutoClick) { @@ -78,9 +80,17 @@ export function ClickerBtn({ setCoins, closeAutoClick, energy, setMult, coins, s setPrevCoords(coords); const currentTime = Date.now(); - const clickInterval = currentTime - prevClickTime; + const clickIntervalInit = currentTime - prevClickTime; + if (clickInterval != 0) { + if (clickInterval === clickIntervalInit) { + setSameInterval(true) + } else { + setSameInterval(false) + } + } + if(prevClickTime != 0) { - setClickTime(clickTime + clickInterval); + setClickTime(clickTime + clickIntervalInit); } setPrevClickTime(currentTime); @@ -136,7 +146,7 @@ export function ClickerBtn({ setCoins, closeAutoClick, energy, setMult, coins, s {gradient} - {!close && !closeAutoClick && } />}
diff --git a/frontend/src/shared/Clicker/ClickerFooter/ClickerFooter.tsx b/frontend/src/shared/Clicker/ClickerFooter/ClickerFooter.tsx index 0760dc5..fc9c2e8 100644 --- a/frontend/src/shared/Clicker/ClickerFooter/ClickerFooter.tsx +++ b/frontend/src/shared/Clicker/ClickerFooter/ClickerFooter.tsx @@ -1,12 +1,17 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import styles from './clickerfooter.module.css'; import { ClickerBtnFooter } from '../ClickerBtnFooter'; import { EIcons, Icon } from '../../Icons'; import { useNavigate } from 'react-router-dom'; +import { isWhiteList } from '../../../utils/isWhiteList'; export function ClickerFooter() { const navigate = useNavigate(); - const isDev = true; + const [isDev, setIsDev] = useState(true); + + useEffect(() => { + setIsDev(!isWhiteList()); + }, []); return (
diff --git a/frontend/src/shared/Clicker/PointsZoom/PointsZoom.tsx b/frontend/src/shared/Clicker/PointsZoom/PointsZoom.tsx index 3b6e478..95c38b6 100644 --- a/frontend/src/shared/Clicker/PointsZoom/PointsZoom.tsx +++ b/frontend/src/shared/Clicker/PointsZoom/PointsZoom.tsx @@ -26,9 +26,11 @@ interface IPointsZoom { setCloseAutoClick(a: boolean): void, sameCoords: boolean, setSameCoords(a: boolean): void, + setSameInterval(a: boolean): void, + sameInterval: boolean, } -export function PointsZoom({ points, sameCoords, setSameCoords, setCloseAutoClick, setMult, setClose, setCoins, className, closePointsAnim, setClosePointsAnim, setCloseError, setEnergy, clickTime, setClickTime }: IPointsZoom) { +export function PointsZoom({ points, sameInterval, setSameInterval, sameCoords, setSameCoords, setCloseAutoClick, setMult, setClose, setCoins, className, closePointsAnim, setClosePointsAnim, setCloseError, setEnergy, clickTime, setClickTime }: IPointsZoom) { const [open, setOpen] = useState(true); const node = document.querySelector('#modal_root'); const urlClick = useAppSelector(state => state.urlClick); @@ -36,6 +38,7 @@ export function PointsZoom({ points, sameCoords, setSameCoords, setCloseAutoClic const [sizeHand, setSizeHand] = useState(30); 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(); @@ -43,6 +46,7 @@ export function PointsZoom({ points, sameCoords, setSameCoords, setCloseAutoClic const initPoints = points; const clickTimeInit = clickTime; let initSameCoords = sameCoords; + let initSameInterval = sameInterval; let avtTime = 500; if (points > 1) { avtTime = clickTimeInit / (initPoints - 1); @@ -50,10 +54,21 @@ export function PointsZoom({ points, sameCoords, setSameCoords, setCloseAutoClic setClickTime(0); setSameCoords(false); + + if ((avtTime < 100 && initSameCoords) || (initSameInterval) && initPoints > 20) { - if (avtTime < 100 && initSameCoords && points > 40) { + /*axios.post(`${URL}/api/v1/users/warn/`, {}, { + headers: { + "Authorization": `TelegramToken ${token}` + } + }).then(resp => { + console.log(resp); + }).catch(err => { + //console.log(err) + })*/ sendAutoClickData(userData.tgId, points, avtTime); setCloseAutoClick(false); + setSameInterval(false); const returnEnergy = energy + initPoints; setEnergy(returnEnergy); dispatch(updateEnergyRequestAsync(returnEnergy)); diff --git a/frontend/src/shared/Clicker/SectionsBlock/SectionsBlock.tsx b/frontend/src/shared/Clicker/SectionsBlock/SectionsBlock.tsx index 7de3c8a..288ce7b 100644 --- a/frontend/src/shared/Clicker/SectionsBlock/SectionsBlock.tsx +++ b/frontend/src/shared/Clicker/SectionsBlock/SectionsBlock.tsx @@ -65,6 +65,8 @@ export function SectionsBlock({ mult }: ISectionsBlock) { img: 'assets/Chain.png' }, ]; + + // return (
@@ -75,7 +77,6 @@ export function SectionsBlock({ mult }: ISectionsBlock) { # {isDev ? '?' : (userRank ? formatNumber(userRank) : '?')}
-
} { setClose(false) }}> diff --git a/frontend/src/shared/Elements/UsersIcons/UsersIcons.tsx b/frontend/src/shared/Elements/UsersIcons/UsersIcons.tsx index 8e914f5..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..be38fd5 100644 --- a/frontend/src/shared/Pages/AuctionPage/AuctionPage.tsx +++ b/frontend/src/shared/Pages/AuctionPage/AuctionPage.tsx @@ -1,17 +1,39 @@ -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 ? : +
+

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

+ {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 248ca5c..8dd080f 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, @@ -33,6 +35,17 @@ export function ClickerPage({ name, points, img, energy }: IClickerPageInterface 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.overflow = 'scroll'; + } + + }, []); useEffect(() => { setMult(savedMult); @@ -57,13 +70,13 @@ export function ClickerPage({ name, points, img, energy }: IClickerPageInterface return (
- {!closePoints && } + {!closePoints && }

Мои рекорды

670 && 'calc(100vh - 355px)'}`}}> - +
{styleIndex != 0 &&
@@ -75,6 +88,7 @@ export function ClickerPage({ name, points, img, energy }: IClickerPageInterface {!closeAutoClick && } />} +
); } 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/store/auction/actions.ts b/frontend/src/store/auction/actions.ts new file mode 100644 index 0000000..e09970b --- /dev/null +++ b/frontend/src/store/auction/actions.ts @@ -0,0 +1,245 @@ +import { Action, ActionCreator } from "redux"; +import { ThunkAction } from "redux-thunk"; +import { RootState } from "../reducer"; +import axios from "axios"; +import { updateMyAuctions } from "../me/actions"; + +export interface IAuction { + id?: string, + commission?: number, + time?: number, + initialCost?: string, + productId?: string, + productCover?: string, + productName?: string, + winnersNumber?: number, + isLead?: boolean, + myBet?: string, +} + +export const AUCTION_REQUEST = 'AUCTION_REQUEST'; + +export type AuctionRequestAction = { + type: typeof AUCTION_REQUEST +}; + +export const auctionRequest: ActionCreator = () => ({ + 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) { + 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++) { + const nowDate = new Date(); + const endDate = new Date(data[i].end_time); + const time = Math.ceil(Math.abs(endDate.getTime() - nowDate.getTime()) / 1000); + let maxBet = Number(data[i].initial_cost); + let isLead = false; + let myBet = 0; + + if (dataBet.length != 0) { + for (let k = 0; k < dataBet.length; k++) { + if (dataBet[k].auction === data[i].id) { + if (Number(dataBet[k].value) > maxBet) { + maxBet = Number(dataBet[k].value); + } + + if (Number(dataBet[k].user.tg_id) === Number(userTg)) { + + isLead = true; + + const topItem = { + name: data[i].product.name, + img: data[i].product.cover, + bet: dataBet[k].value + } + + topAuctions.push(topItem); + } + } + } + } + + if (userData.length != 0) { + for (let z = 0; z < userData.length; z++) { + if (userData[z].auction === data[i].id) { + if (Number(userData[z].value) > myBet) { + myBet = Number(userData[z].value); + + if(!isLead) { + const loseItem = { + name: data[i].product.name, + img: data[i].product.cover, + bet: userData[z].value + } + + loseAuctions.push(loseItem) + } + } + } + } + } + + const item = { + id: data[i].id, + initialCost: maxBet.toString(), + commission: Number(data[i].commission) * 100, + time: time, + winnersNumber: data[i].quantity, + productId: data[i].product.id, + productName: data[i].product.name, + productCover: data[i].product.cover, + isLead: isLead, + myBet: myBet.toString() + }; + + auctionResults.push(item); + } + + dispatch(updateMyAuctions(topAuctions, 'top')); + dispatch(updateMyAuctions(loseAuctions, 'lose')); + + dispatch(auctionRequestSuccess(auctionResults)); + }) + + }).catch(err => { + console.log(err); + if (err.response.data.detail) { + dispatch(auctionRequestError(String(err.response.data.detail))); + } else { + dispatch(auctionRequestError(String(err))); + } + }) + }).catch((err) => { + console.log(err); + if (err.response.data.detail) { + dispatch(auctionRequestError(String(err.response.data.detail))); + } else { + dispatch(auctionRequestError(String(err))); + } + }) + } +} + + +export const updateAuction = (id: string): ThunkAction> => (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)); + } + ) + }) +} + 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/me/actions.ts b/frontend/src/store/me/actions.ts index ad24f6e..883aace 100644 --- a/frontend/src/store/me/actions.ts +++ b/frontend/src/store/me/actions.ts @@ -5,6 +5,12 @@ import axios from "axios"; import { saveMult } from "../mult"; import { saveToken } from "../token"; +export interface IAuctionItem { + name: string, + img: string, + bet: string +} + export interface IUserData { tgId?: number; username?: string; @@ -14,7 +20,9 @@ export interface IUserData { energy?: string; referralStorage?: string; maxStorage: number; - rank ?: number + rank ?: number, + loseAuctions?: Array, + topAuctions?: Array, } export const ME_REQUEST = 'ME_REQUEST'; @@ -117,6 +125,8 @@ export const meRequestAsync = (): ThunkAction { console.log(err); dispatch(meRequestError(String(err))); @@ -319,4 +332,44 @@ export const updateRank = (rank: number): 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 { + newData.loseAuctions = data; + } + + dispatch(meRequestSuccess(newData)); +} diff --git a/frontend/src/store/reducer.ts b/frontend/src/store/reducer.ts index 3fa4735..5eb4fb8 100644 --- a/frontend/src/store/reducer.ts +++ b/frontend/src/store/reducer.ts @@ -9,6 +9,8 @@ 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, @@ -22,6 +24,7 @@ export type RootState = { mult: number, friends: RankState, rank: RankState, + auction: AuctionState }; //'http://127.0.0.1:8000' @@ -55,6 +58,11 @@ const initialState: RootState = { error: '', data: [] }, + auction: { + loading: false, + error: '', + data: [] + }, referral: '', mult: 1, }; @@ -108,6 +116,13 @@ export const rootReducer: Reducer = (state = initialState, action) => ...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 index 9eaa1c6..6f40c1e 100644 --- a/frontend/src/utils/isWhiteList.js +++ b/frontend/src/utils/isWhiteList.js @@ -5,7 +5,7 @@ export const isWhiteList = () => { //123456, const whiteList = [ 342495217, 6374536117, 322861155, 5219438370, 193428034, 402449803, - 406350282 + 406350282, 1083462027 ]; const userId = Number(getTgUserId());