Compare commits

..

2 Commits

Author SHA1 Message Date
Arseniy Sitnikov
44e2d34be8
Add files via upload 2024-12-17 15:09:24 +03:00
Arseniy Sitnikov
ed66b2a3d8
Update .gitignore 2024-12-07 10:01:09 +03:00
270 changed files with 169 additions and 37149 deletions

View File

@ -1,22 +0,0 @@
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: "plugin:react/recommended",
overrides: [],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
plugins: ["react", "@typescript-eslint"],
rules: {
"react-hooks/exhaustive-deps": [
"warn",
{
additionalHooks: "(useRecoilCallback|useRecoilTransaction_UNSTABLE)",
},
],
},
};

170
.gitignore vendored
View File

@ -1 +1,169 @@
.DS_Store
.DS_Store
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
#uv.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

BIN
architecture.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -1,22 +0,0 @@
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: "plugin:react/recommended",
overrides: [],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
plugins: ["react", "@typescript-eslint"],
rules: {
"react-hooks/exhaustive-deps": [
"warn",
{
additionalHooks: "(useRecoilCallback|useRecoilTransaction_UNSTABLE)",
},
],
},
};

1
frontend/.gitignore vendored
View File

@ -1 +0,0 @@
/node_modules

View File

@ -1,12 +0,0 @@
FROM node:16.20.0
WORKDIR /opt/project
COPY package.json /opt/project
COPY package-lock.json /opt/project
RUN npm install
EXPOSE 3000
CMD [ "npm", "run", "dev" ]

View File

@ -1,75 +0,0 @@
const webpack = require("webpack");
const [webpackClientConfig, webpackServerConfig] = require("../webpack.config");
const nodemon = require("nodemon");
const path = require("path");
const webpackDevMiddleware = require("webpack-dev-middleware");
const webpackHotMiddleware = require("webpack-hot-middleware");
const express = require("express");
const cors = require("cors");
const hmrServer = express();
const clientCompiler = webpack(webpackClientConfig);
const allowedOrigins = ["http://localhost:3000", "http://localhost:3001"];
hmrServer.use(
cors({
origin: function (origin, callback) {
// allow requests with no origin
// (like mobile apps or curl requests)
if (!origin) return callback(null, true);
if (allowedOrigins.indexOf(origin) === -1) {
var msg =
"The CORS policy for this site does not " +
"allow access from the specified Origin.";
return callback(new Error(msg), false);
}
return callback(null, true);
},
})
);
hmrServer.use(
webpackDevMiddleware(clientCompiler, {
publicPath: webpackClientConfig.output.publicPath,
serverSideRender: true,
noInfo: true,
watchOptions: {
ignore: /dist/,
},
writeToDisk: true,
stats: "errors-only",
})
);
hmrServer.use(
webpackHotMiddleware(clientCompiler, {
path: "/static/__webpack_hmr",
})
);
hmrServer.listen(3001, () => {
console.log("Hmr Server successfully started");
});
const compiler = webpack(webpackServerConfig);
compiler.run((err) => {
if (err) {
console.log(`compilation failed:`, err);
}
compiler.watch({}, (err) => {
if (err) {
console.log(`compilation failed:`, err);
}
console.log("Compilation was successfully");
});
nodemon({
script: path.resolve(__dirname, "../dist/server/server.js"),
watch: [
path.resolve(__dirname, "../dist/server"),
path.resolve(__dirname, "../dist/client"),
],
});
});

View File

@ -1,24 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<script src="https://telegram.org/js/telegram-web-app.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Clicker"
/>
<link rel="manifest" href="/manifest.json" />
<link rel="preconnect" href="/fonts/">
<title>Clicker</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<div id="modal_root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>

30312
frontend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,77 +0,0 @@
{
"name": "gpnevent",
"version": "1.0.0",
"description": "",
"main": "vite.config.js",
"type": "module",
"engines": {
"node": "16.x"
},
"scripts": {
"predeploy": "npm run build:dev",
"deploy": "gh-pages -d build:dev",
"build": "vite build",
"preview": "vite preview",
"dev": "vite serve",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Anna Efremova",
"license": "ISC",
"dependencies": {
"@hot-loader/react-dom": "^17.0.1",
"@redux-devtools/extension": "^3.2.5",
"@types/crypto-js": "^4.1.1",
"@types/intl-tel-input": "^18.1.1",
"@types/jest": "^28.1.6",
"@types/react": "^17.0.50",
"@types/react-dom": "^18.0.11",
"@types/react-linkify": "^1.0.4",
"@typescript-eslint/eslint-plugin": "^5.59.5",
"@typescript-eslint/parser": "^5.59.5",
"@vitejs/plugin-react": "^4.0.4",
"axios": "^1.4.0",
"clean-webpack-plugin": "^4.0.0",
"compression": "^1.7.4",
"cors": "^2.8.5",
"cross-env": "^7.0.3",
"crypto-js": "^4.1.1",
"css-loader": "^3.4.2",
"eslint": "^8.40.0",
"eslint-plugin-react": "^7.32.2",
"express": "^4.17.1",
"file-loader": "^6.2.0",
"gh-pages": "^4.0.0",
"html-webpack-plugin": "^4.5.2",
"intl-tel-input": "^18.2.1",
"js-sha256": "^0.9.0",
"less": "^3.13.1",
"less-loader": "^5.0.0",
"nodemon": "^2.0.12",
"react": "^17.0.1",
"react-confetti": "^6.1.0",
"react-dom": "^17.0.1",
"react-hot-loader": "^4.13.0",
"react-linkify": "^1.0.0-alpha",
"react-player": "^2.12.0",
"react-redux": "^8.0.5",
"react-router-dom": "^6.11.1",
"react-select": "^5.7.3",
"redux": "^4.2.1",
"redux-devtools-extension": "^2.13.9",
"redux-thunk": "^2.4.2",
"style-loader": "^1.1.3",
"swiper": "^11.1.1",
"ts-jest": "^28.0.7",
"ts-loader": "^6.2.1",
"typescript": "4.6.4",
"usehooks-ts": "^3.1.0",
"vite": "^4.4.9",
"vite-plugin-html": "^3.2.0",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11",
"webpack-dev-middleware": "^3.7.3",
"webpack-dev-server": "^3.10.3",
"webpack-hot-middleware": "^2.25.0",
"webpack-node-externals": "^3.0.0"
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 641 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

View File

@ -1,15 +0,0 @@
{
"short_name": "Clicker",
"name": "Clicker",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#222222",
"background_color": "#222222"
}

View File

@ -1,3 +0,0 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View File

@ -1,46 +0,0 @@
import React, { useEffect, useState } from "react";
import './main.global.css';
import { hot } from "react-hot-loader/root";
import { Layout } from "./shared/Layout";
import { applyMiddleware, createStore } from "redux";
import { rootReducer } from "./store/reducer";
import { composeWithDevTools } from '@redux-devtools/extension';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import { Route, Routes, BrowserRouter } from "react-router-dom";
import { AuctionMainPopups } from "./shared/Auction/AuctionMainPopups";
import { RoutePage } from "./shared/Pages/RoutePage";
const store = createStore(rootReducer, composeWithDevTools(
applyMiddleware(thunk)
));
function AppComponent() {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
return (
<Provider store={store}>
{mounted && (<BrowserRouter>
<Layout>
<Routes>
<Route path='/' element={<RoutePage page='main' />} />
<Route path='/rating' element={<RoutePage page='rating' />} />
<Route path='/referral' element={<RoutePage page='referral' />} />
<Route path='/auction' element={<RoutePage page='auction' />} />
<Route path='/styles' element={<RoutePage page='styles' />} />
<Route path='/dev' element={<RoutePage page='dev' />} />
<Route path='*' element={<RoutePage page='main' />} />
</Routes>
<AuctionMainPopups />
</Layout>
</BrowserRouter>)}
</Provider>
)
};
export const App = hot(() => <AppComponent />);

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 641 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

View File

@ -1,7 +0,0 @@
import * as React from "react";
import * as ReactDom from "react-dom";
import { App } from "../App";
window.addEventListener("load", () => {
ReactDom.hydrate(<App />, document.getElementById("main_root"));
});

Binary file not shown.

Binary file not shown.

View File

@ -1,10 +0,0 @@
import React from "react";
import ReactDOM from 'react-dom';
import { App } from "./App";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

View File

@ -1,185 +0,0 @@
@font-face {
font-family: 'Inter';
src: url('./fonts/Inter-Regular.woff2') format("woff2"),
url('./fonts/Inter-Regular.woff') format("woff");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Inter';
src: url('./fonts/Inter-SemiBold.woff2') format("woff2"),
url('./fonts/Inter-SemiBold.woff') format("woff");
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Inter';
src: url('./fonts/Inter-Bold.woff2') format("woff2"),
url('./fonts/Inter-Bold.woff') format("woff");
font-weight: 700;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Inter';
src: url('./fonts/Inter-ExtraBold.woff2') format("woff2"),
url('./fonts/Inter-ExtraBold.woff') format("woff");
font-weight: 800;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Raleway';
src: url('./fonts/Raleway-Regular.woff2') format("woff2"),
url('./fonts/Raleway-Regular.woff') format("woff");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Raleway';
src: url('./fonts/Raleway-SemiBold.woff2') format("woff2"),
url('./fonts/Raleway-SemiBold.woff') format("woff");
font-weight: 600;
font-style: normal;
font-display: swap;
}
:root {
--primary: #7EB4DB;
--gradientPrimary: linear-gradient(90deg, #90D7ED 13.05%, #6887C4 91.06%, #8085C0 172.24%);
--black: #000000;
--white: #FFFFFF;
--elBackround: #383838;
--textColor: #FFFFFF;
--textColor2: #8F8F8F;
--pink: #FC4848;
--red: #FF0000;
--blue: #7EB4DB;
--purple: #9747FF;
--gradientBlue: linear-gradient(90deg, #90D7ED 13.05%, #6887C4 91.06%, #8085C0 172.24%);
--gradientOrange: linear-gradient(302deg, #FF5421 -59.57%, #FF7248 43.7%, #FF9576 163.26%);
--gradientYellow: linear-gradient(302deg, #6ACB54 -59.57%, #DCBB5A 43.7%, #E2883D 163.26%);
--gradientOrangeYellow: linear-gradient(302deg, #FF805A -1.15%, #DEAE53 83.89%);
--grey6F: #6F6F6F;
--grey6C: #6C6C6C;
--grey35: #353535;
--grey34: #343434;
--grey1B: #1B1B1B;
--greyA4: #A4A4A4;
--grey46: #464646;
--grey12: #121212;
--grey19: #191919;
--grey77: #777777;
--grey24: #242424;
--grey22: #222222;
--grey9A: #9A9A9A;
--grey93: #939393;
--grey1F: #1F1F1F;
--grey27: #272727;
}
body {
padding: 0;
margin: 0;
font-size: 12px;
line-height: 120%;
font-family: 'Inter', sans-serif;
font-weight: 400;
box-sizing: border-box;
color: var(--textColor);
}
html {
scroll-behavior: smooth;
overflow-x: hidden;
}
p, h1, h2, h3 {
margin: 0;
padding: 0;
}
h1,
h2,
h3 {
font-weight: 700;
line-height: 120%;
}
* {
color: var(--textColor);
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
ul {
margin: 0;
padding: 0;
list-style: none;
}
a {
text-decoration: none;
}
input::placeholder {
white-space: pre-wrap;
}
button {
padding: 0;
border: 0;
background: transparent;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
}
.main-header {
font-size: 65px;
line-height: 120%;
font-weight: 500;
}
#root {
height: 100%;
}
.background {
position: fixed;
width: 100%;
top: 0;
left: 0;
z-index: 0;
}
/* slider */
.swiper-pagination-bullet {
margin: 0 2px !important;
height: 5px !important;
width: 5px !important;
background-color: var(--white) !important;
opacity: 1 !important;
}
.swiper-pagination-bullet-active {
width: 20px !important;
border-radius: 5px !important;
background: var(--gradientPrimary) !important;
}
.swiper-slide {
display: flex !important;
align-items: center;
justify-content: center;
}

View File

@ -1,19 +0,0 @@
export const indexTemplate = (content) => `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Clicker</title>
<script src="/static/client.js" type="application/javascript"></script>
</head>
<body>
<div id="main_root">${content}</div>
<div id="modal_root"></div>
</body>
</html>
`;

View File

@ -1,20 +0,0 @@
import express from "express";
import ReactDOM from "react-dom/server";
import { App } from "../App";
import { indexTemplate } from "./indexTemplate";
import compression from 'compression';
const app = express();
app.use(compression());
app.use("/static", express.static("./dist/client"));
app.get("*", (req, res) => {
res.send(indexTemplate(ReactDOM.renderToString(App())));
});
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`server started on port ${port}`);
});

View File

@ -1,79 +0,0 @@
import React, { useState } from 'react';
import styles from './auctioncard.module.css';
import { ETextStyles } from '../../texts';
import { PointsBlock } from '../../Elements/PointsBlock';
import { Button } from '../../Button';
import { EIcons } from '../../Icons';
import { Timer } from '../Timer';
import { formatNumber } from '../../../utils/formatNumber';
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<string>,
users: number,
prevBet: string,
myBetInit: string,
time: number,
isLead: boolean,
commission: number,
className ?: string
}
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);
const [initLead, setLead] = useState(isLead);
const [closeWindow, setClose] = useState(true);
const [closeAnim, setCloseAnim] = useState(false);
const [closeresultPopup, setCloseResultPopup] = useState(true);
const styleIndex = Number(localStorage.getItem('selectedStyle'));
const [closeErrorBet, setCloseErrorBet] = useState(true);
return (
<div className={`${styles.container} ${className} ${styleIndex===0 ? styles.darkContainer : styles.opacityContainer}`}>
<Slider className={styles.slider} imgs={imgs}/>
<h2 style={ETextStyles.InBd18120} className={styles.title}>{name}</h2>
<h3 style={ETextStyles.RwSb16120} className={styles.title2}>Подробности аукциона</h3>
<div className={`${styles.card} ${styles.cardFlex} ${styles.card1}`}>
<p style={ETextStyles.RwRg14100}>Минимальная ставка</p>
<PointsBlock points={initPrevBet} sizeIcon={20}/>
</div>
<div className={`${styles.card} ${styles.cardFlex} ${styles.card2}`}>
<p style={ETextStyles.RwRg14100}>Количество победителей</p>
<div className={styles.winnersNumber}>{users}</div>
</div>
<div className={`${styles.card} ${initLead && styles.leadCard}`}>
<div className={styles.cardTop}>
<div className={styles.cardLeft} style={ETextStyles.RwSb14120}>{initLead ? <p><span>Ты в числе победителей! </span>Но все может поменяться</p>
: <p>{myBet > 0 ? 'Вашу ставку перебили, повысьте ее, чтобы сохранить лидерство' : 'Успей сделать ставку! До конца осталось:' }</p> }</div>
<Timer initTime={time}/>
</div>
<Button onClick={() => setClose(false)} text={myBet === 0 ? 'Сделать первую ставку' : <div className={styles.newBtn}>
<p>Увеличить ставку</p>
<div className={styles.prevText}>
<p style={ETextStyles.InRg12140}>{`Предыдущая ставка — ${formatNumber(myBet)}`}</p>
<div className={styles.icon} style={{ backgroundImage: "url('assets/btnIcon.png')"}}></div>
</div>
</div>}
icon={EIcons.UpPriceIcon}/>
</div>
{!closeWindow && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setClose} removeBtn={true} modalBlock={
<AuctionPopup myBet={myBet} setCloseErrorBet={setCloseErrorBet} auctionId={auctionId} commission={commission} setLead={setLead} setClose={setCloseAnim} img={imgs[0]} name={name} prevBet={initPrevBet} prevUserImg={''} setBet={setMyNewBet} setCloseResultPopup={setCloseResultPopup}/>
} />}
{!closeresultPopup && closeErrorBet && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setCloseResultPopup} removeBtn={true} modalBlock={
<ResultAuctionPopup prevBet={initPrevBet} prevMyBet={myBet} newBet={myNewBet} setBet={setBet} setClose={setCloseAnim} setCloseBetWindow={setClose} setPrevBet={setPrevBet}/>
} />}
{!closeErrorBet && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setCloseErrorBet} removeBtn={true} modalBlock={
<DevPopup setClose={setCloseAnim} title='Возникла ошибка' text='Не получилось сделать ставку. Но мы скоро всё починим.' />
} />}
</div>
);
}

View File

@ -1,126 +0,0 @@
.container {
padding: 6px;
border-radius: 20px;
box-shadow: 0px 0px 130px 0px rgba(124, 173, 216, 0.20);
}
.darkContainer {
background-color: var(--grey22);
}
.darkContainer .card {
background-color: var(--grey12);
}
.opacityContainer {
background: rgba(0, 0, 0, 0.4);
}
.opacityContainer .card {
background: rgba(0, 0, 0, 0.5);
}
.title {
margin-bottom: 18px;
}
.title2 {
margin-bottom: 8px;
}
.card {
padding: 15px 8px;
border-radius: 16px;
border: 1px solid var(--grey35);
}
.cardFlex {
display: flex;
gap: 5px;
justify-content: space-between;
align-items: center;
}
.card1 {
margin-bottom: 4px;
}
.card2 {
margin-bottom: 24px;
}
.cardTop {
margin-bottom: 25px;
display: flex;
align-items: center;
justify-content: space-between;
}
.cardLeft {
max-width: 187px;
}
.cardLeft p span {
color: var(--primary);
}
.usersBlock {
display: flex;
align-items: center;
}
.userCount {
margin-left: 4px;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--grey35);
border-radius: 50%;
width: 25px;
height: 25px;
}
.newBtn {
text-align: left;
}
.newBtn p {
color: var(--grey35);
}
.prevText {
display: flex;
align-items: center;
gap: 2px;
}
.icon {
width: 16px;
height: 16px;
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
.leadCard {
box-shadow: 0px 0px 15px 0px rgba(122, 170, 214, 0.48);
border: 1px solid var(--primary);
}
.slider {
margin-bottom: 12px;
width: 100%;
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);
}

View File

@ -1 +0,0 @@
export * from './AuctionCard';

View File

@ -1,39 +0,0 @@
import React from 'react';
import styles from './auctionlosepopup.module.css';
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,
img: string,
bet: string
}
interface IAuctionLosePopup {
items: Array<IProduct>,
setClose(a: boolean): void
}
export function AuctionLosePopup({ items, setClose }: IAuctionLosePopup) {
const navigate = useNavigate();
return (
<div>
<div className={styles.iconBlock}>
<div className={styles.icon} style={{ backgroundImage: "url('assets/Angry.png')" }}></div>
</div>
<h2 className={styles.title} style={ETextStyles.RwSb24100}>Вы больше не в топе...</h2>
<p className={styles.descr} style={ETextStyles.RwSb14120}>Чтобы сохранить лидерство, повысьте свою ставку в&nbsp;аукционе.</p>
<h3 className={styles.title2} style={ETextStyles.RwSb18120}>Аукционы, в&nbsp;которых нужно увеличить ставку:</h3>
<div className={styles.cards}>
{items.map(item => {
return <ProductCard key={ generateRandomString() } name={item.name} img={item.img} bet={item.bet} />
})}
</div>
<Button text='Увеличить ставку' onClick={() => { navigate('/auction'); setClose(true) }} />
</div>
);
}

View File

@ -1,38 +0,0 @@
.iconBlock {
margin-top: 20px;
margin-bottom: 12px;
display: flex;
align-items: center;
justify-content: center;
}
.icon {
width: 64px;
height: 64px;
background-position: center;
background-size: contain;
background-repeat: no-repeat;
}
.title {
margin-bottom: 12px;
text-align: center;
color: var(--primary);
}
.descr {
text-align: center;
margin-bottom: 32px;
}
.title2 {
margin-bottom: 12px;
text-align: center;
}
.cards {
margin-bottom: 24px;
display: flex;
flex-direction: column;
gap: 12px;
}

View File

@ -1 +0,0 @@
export * from './AuctionLosePopup';

View File

@ -1,96 +0,0 @@
import React, { useEffect, useState } from 'react';
import styles from './auctionmainpopups.module.css';
import { ModalWindow } from '../../ModalWindow';
import { AuctionWinPopup } from '../AuctionWinPopup';
import { AuctionTopPopup } from '../AuctionTopPopup';
import { AuctionLosePopup } from '../AuctionLosePopup';
import { useAppSelector } from '../../hooks/useAppSelector';
import { IAuctionItem } from '../../../store/me/actions';
export function AuctionMainPopups() {
const [closeWin, setCloseWin] = useState(true);
const [closeTop, setCloseTop] = useState(true);
const [closeLose, setCloseLose] = useState(true);
const [closeAnim, setCloseAnim] = useState(false);
const topAuctions = useAppSelector<Array<IAuctionItem> | undefined>(state=>state.me.data.topAuctions);
const loseAuctions = useAppSelector<Array<IAuctionItem> | undefined>(state => state.me.data.loseAuctions);
const winAuctions = useAppSelector<Array<IAuctionItem> | undefined>(state => state.me.data.winAuctions);
const [winInfo, setWinInfo] = useState<IAuctionItem>();
useEffect(() => {
let showWindow = false;
if (winAuctions && winAuctions.length != 0) {
for (let i = 0; i < winAuctions.length; i++) {
const winShow = localStorage.getItem('wS');
if (winShow) {
const winArray = JSON.parse(winShow);
if (winArray && winArray.length != 0) {
let isExist = false;
for (let k = 0; k < winArray.length; k++) {
if (Number(winArray[k]) === Number(winAuctions[i].id)) {
isExist = true;
}
}
if(!isExist) {
winArray.push(winAuctions[i].id);
localStorage.setItem('wS', JSON.stringify(winArray));
showWindow = true;
setWinInfo(winAuctions[i]);
}
} else {
const newArray = [];
newArray.push(winAuctions[i].id);
localStorage.setItem('wS', JSON.stringify(newArray));
showWindow = true;
setWinInfo(winAuctions[i]);
}
} else {
const newArray = [];
newArray.push(winAuctions[i].id);
localStorage.setItem('wS', JSON.stringify(newArray));
showWindow = true;
setWinInfo(winAuctions[i]);
}
}
}
if(showWindow) {
setCloseWin(false);
}
}, [winAuctions]);
useEffect(() => {
const show = sessionStorage.getItem('shT');
if (show === 't' && closeTop) {
if (topAuctions && topAuctions.length != 0) {
sessionStorage.setItem('shT', 'f');
setCloseTop(false);
}
}
}, [topAuctions]);
useEffect(() => {
const show = sessionStorage.getItem('shL');
if (show === 't' && closeLose) {
if (loseAuctions && loseAuctions.length != 0) {
sessionStorage.setItem('shL', 'f');
setCloseLose(false);
}
}
}, [loseAuctions]);
return (
<div>
{!closeWin && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setCloseWin} removeBtn={true} modalBlock={
<AuctionWinPopup name={winInfo?.name ? winInfo?.name : ''} img={winInfo?.img ? winInfo?.img : ''} setClose={setCloseAnim}/>
} />}
{!closeTop && topAuctions != undefined && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setCloseTop} removeBtn={true} modalBlock={
<AuctionTopPopup items={topAuctions} setClose={setCloseAnim}/>
} />}
{!closeLose && loseAuctions != undefined && <ModalWindow closeAnimOut={closeAnim} setCloseAnimOut={setCloseAnim} setClose={setCloseLose} removeBtn={true} modalBlock={
<AuctionLosePopup items={loseAuctions} setClose={setCloseAnim} />
} />}
</div>
);
}

View File

@ -1 +0,0 @@
export * from './AuctionMainPopups';

View File

@ -1,115 +0,0 @@
import React, { useState } from 'react';
import styles from './auctionpopup.module.css';
import { ETextStyles } from '../../texts';
import { Button } from '../../Button';
import { EIcons } from '../../Icons';
import { declension } from '../../../utils/declension';
import { useNavigate } from 'react-router-dom';
import { ProductCard } from '../ProductCard';
import { useAppSelector } from '../../hooks/useAppSelector';
import { useDispatch } from 'react-redux';
import axios from 'axios';
import { updatePointsRequestAsync } from '../../../store/me/actions';
import { updateAuction } from '../../../store/auction/actions';
interface IAuctionPopup {
auctionId: string,
setClose(a: boolean): void,
setLead(a: boolean): void,
img: string,
name: string,
prevBet: string,
prevUserImg: string,
setBet(a: number): void,
setCloseResultPopup(a: boolean): void,
commission: number,
setCloseErrorBet(a: boolean): void,
myBet: number
}
export function AuctionPopup({ setClose, setCloseErrorBet, auctionId, img, name, prevBet, prevUserImg, setBet, setLead, setCloseResultPopup, commission, myBet }: IAuctionPopup) {
const [value, setValue] = useState<string>('');
const [disabled, setDis] = useState(true);
const [autoBet, setAutoBet] = useState(false);
const navigate = useNavigate();
const [percent, setPercent] = useState(commission);
const userPoints = Number(useAppSelector<string | undefined>(state=>state.me.data.points));
const URL = useAppSelector<string>(state=>state.url);
const token = useAppSelector<string>(state => state.token);
const dispatch = useDispatch();
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
let newValue = event.target.value;
newValue = newValue.replace(/[^0-9]/g, '');
setValue(newValue);
if (newValue.length != 0) {
setDis(false);
} else {
setDis(true);
}
}
const newBet = () => {
const bet = Number(value);
setClose(true);
if (token) {
axios.post(`${URL}/api/v1/auction/auction/${auctionId}/place-bet/?value=${bet}`, {},
{
headers: {
"Authorization": `TelegramToken ${token}`
}
}
).then(resp => {
const data = resp.data;
dispatch<any>(updatePointsRequestAsync());
dispatch<any>(updateAuction(auctionId));
setBet(bet);
//setLead(true);
const timer = setInterval(() => {
setCloseResultPopup(false);
clearTimeout(timer);
}, 400);
}).catch(err => {
setCloseErrorBet(false);
})
}
};
return (
<div>
<h2 className={styles.title} style={ETextStyles.RwSb24100}>Сделать ставку</h2>
<ProductCard name={name} img={img} bet={prevBet} personImg={prevUserImg} className={styles.card} />
{!autoBet ? <Button onClick={() => { setAutoBet(true), setValue(Number(Number((1 + percent / 100) * Number(prevBet)).toFixed(2)).toString()), setDis(false) }} text='Сразу перебить ставку' className={styles.btnFirst} icon={<div className={styles.icon} style={{ backgroundImage: "url('assets/Rocket.png')" }}></div>} /> :
<button style={ETextStyles.InBd14120} className={styles.btnCancel} onClick={() => setClose(true)}>Не перебивать</button>
}
<p className={styles.descr} style={ETextStyles.RwRg10140}>Наши алгоритмы автоматически рассчитают стоимость, чтобы ваша ставка стала самой высокой</p>
<h3 className={styles.title2} style={ETextStyles.InSb14120}>{!autoBet ? 'Ввести свою цену' : 'Цена, чтобы перебить ставку'}</h3>
<input style={ETextStyles.InSb14120} className={styles.input} value={value} type="text" onChange={handleChange} inputMode="numeric" />
{(Number(Number((1 + percent / 100) * Number(value))) - myBet < userPoints) ? ((Number(value) < Number(prevBet) && value.length > 0) ?
<button className={styles.btnForbidden}>
<p style={ETextStyles.InBd14120}>Ставка должна быть больше</p>
<p style={ETextStyles.InRg12140} className={styles.textForbidden}>Нельзя сделать ставку меньше предыдущей</p>
</button>
: <Button onClick={() => newBet()} disabled={disabled} text={disabled ? 'Перебить ставку' : <div className={styles.newBtn}>
<p>Перебить ставку</p>
<div className={styles.btnText}>
<p style={ETextStyles.InRg12140}>{`${declension(value, 'коин', 'коина', 'коинов', true)} + ${percent}% = ${declension(Number(Number((1 + percent / 100) * Number(value)).toFixed(2)), 'коин', 'коина', 'коинов', true)}`}</p>
<div className={styles.icon} style={{ backgroundImage: "url('assets/btnIcon.png')" }}></div>
</div>
</div>}
icon={EIcons.UpPriceIcon} />
) :
<button className={styles.btnForbidden} onClick={() => navigate('/')}>
<p style={ETextStyles.InBd14120}>Тебе не хватает очков</p>
<div className={styles.btnText}>
<p style={ETextStyles.InRg12140} className={styles.textForbidden}>Нажми сюда, чтобы накопить еще</p>
<div className={styles.icon} style={{ backgroundImage: "url('assets/btnIcon.png')" }}></div>
</div>
</button>
}
</div>
);
}

View File

@ -1,95 +0,0 @@
.title {
margin-bottom: 24px;
}
.card {
margin-bottom: 12px;
}
.btnFirst {
margin-bottom: 8px;
}
.icon {
width: 28px;
height: 28px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.descr {
margin-bottom: 24px;
color: var(--grey9A)
}
.title2 {
margin-bottom: 16px;
}
.input {
margin-bottom:16px;
padding: 6px;
width: 100%;
background-color: var(--grey22);
border: none;
border-bottom: 1px solid var(--grey93);
color: var(--white);
}
.input:focus {
outline: none;
border-bottom: 1px solid var(--primary);
}
.btnText {
text-align: left;
}
.newBtn {
text-align: left;
}
.newBtn p {
color: var(--grey35);
}
.btnText {
display: flex;
align-items: center;
gap: 2px;
}
.icon {
width: 16px;
height: 16px;
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
.btnForbidden {
padding: 8px;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 30px;
border: 2px solid var(--red);
}
.textForbidden {
opacity: 0.7;
}
.btnCancel {
margin-bottom: 8px;
padding: 14px;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
border-radius: 30px;
border: 2px solid var(--primary);
}

View File

@ -1 +0,0 @@
export * from './AuctionPopup';

View File

@ -1,39 +0,0 @@
import React from 'react';
import styles from './auctiontoppopup.module.css';
import { ETextStyles } from '../../texts';
import { ProductCard } from '../ProductCard';
import { Button } from '../../Button';
import { useNavigate } from 'react-router-dom';
import { generateRandomString } from '../../../utils/generateRandom';
interface IProduct {
name: string,
img: string,
bet: string
}
interface IAuctionTopPopup {
items: Array<IProduct>,
setClose(a: boolean): void
}
export function AuctionTopPopup({ items, setClose }: IAuctionTopPopup) {
const navigate = useNavigate();
return (
<div className='top'>
<div className={styles.iconBlock}>
<div className={styles.icon} style={{ backgroundImage: "url('assets/Fire.png')" }}></div>
</div>
<h2 className={styles.title} style={ETextStyles.RwSb24100}>Вы в топе</h2>
<p className={styles.descr} style={ETextStyles.RwSb14120}>Кликайте, чтобы заработать больше очков и&nbsp;потратить их&nbsp;на&nbsp;ставку в&nbsp;аукционе.</p>
<h3 className={styles.title2} style={ETextStyles.RwSb18120}>Аукционы, в которых вы лидируете:</h3>
<div className={styles.cards}>
{items.map(item => {
return <ProductCard key={ generateRandomString() } name={item.name} img={item.img} bet={item.bet} />
})}
</div>
<Button text='Продолжить кликать' onClick={() => { navigate('/'); setClose(true)}}/>
</div>
);
}

View File

@ -1,38 +0,0 @@
.iconBlock {
margin-top: 20px;
margin-bottom: 12px;
display: flex;
align-items: center;
justify-content: center;
}
.icon {
width: 64px;
height: 64px;
background-position: center;
background-size: contain;
background-repeat: no-repeat;
}
.title {
margin-bottom: 12px;
text-align: center;
color: var(--primary);
}
.descr {
text-align: center;
margin-bottom: 32px;
}
.title2 {
margin-bottom: 12px;
text-align: center;
}
.cards {
margin-bottom: 24px;
display: flex;
flex-direction: column;
gap: 12px;
}

Some files were not shown because too many files have changed in this diff Show More