mirror of
https://github.com/BlackWallTeam/frontend.git
synced 2024-11-21 16:26:34 +03:00
add all
This commit is contained in:
parent
f3e676e163
commit
6f345babf6
117
package-lock.json
generated
117
package-lock.json
generated
|
@ -18,12 +18,14 @@
|
|||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"antd": "^5.2.1",
|
||||
"axios": "^1.3.3",
|
||||
"chart.js": "^4.2.1",
|
||||
"mapbox-gl": "^2.12.1",
|
||||
"react": "^18.2.0",
|
||||
"react-chartjs-2": "^5.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-redux": "^8.0.5",
|
||||
"react-router-dom": "^6.8.1",
|
||||
"react-scripts": "5.0.1",
|
||||
"redux": "^4.2.1",
|
||||
"typescript": "^4.9.5",
|
||||
|
@ -3323,6 +3325,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.2.tgz",
|
||||
"integrity": "sha512-t54ONhl/h75X94SWsHGQ4G/ZrCEguKSRQr7DrjTciJXW0YU1QhlwYeycvK5JgkzlxmvrK7wq1NB/PLtHxoiDcA==",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-babel": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
|
||||
|
@ -5162,6 +5172,29 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.3.tgz",
|
||||
"integrity": "sha512-eYq77dYIFS77AQlhzEL937yUBSepBfPIe8FcgEDN35vMNZKMrs81pgnyrQpwfy4NF4b4XWX1Zgx7yX+25w8QJA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios/node_modules/form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/axobject-query": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz",
|
||||
|
@ -14298,6 +14331,11 @@
|
|||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"node_modules/psl": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
|
||||
|
@ -15267,6 +15305,36 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "6.8.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.1.tgz",
|
||||
"integrity": "sha512-Jgi8BzAJQ8MkPt8ipXnR73rnD7EmZ0HFFb7jdQU24TynGW1Ooqin2KVDN9voSC+7xhqbbCd2cjGUepb6RObnyg==",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "6.8.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.1.tgz",
|
||||
"integrity": "sha512-67EXNfkQgf34P7+PSb6VlBuaacGhkKn3kpE51+P6zYSG2kiRoumXEL6e27zTa9+PGF2MNXbgIUHTVlleLbIcHQ==",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.3.2",
|
||||
"react-router": "6.8.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-scripts": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
|
||||
|
@ -20454,6 +20522,11 @@
|
|||
"reselect": "^4.1.7"
|
||||
}
|
||||
},
|
||||
"@remix-run/router": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.2.tgz",
|
||||
"integrity": "sha512-t54ONhl/h75X94SWsHGQ4G/ZrCEguKSRQr7DrjTciJXW0YU1QhlwYeycvK5JgkzlxmvrK7wq1NB/PLtHxoiDcA=="
|
||||
},
|
||||
"@rollup/plugin-babel": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
|
||||
|
@ -21845,6 +21918,28 @@
|
|||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.6.3.tgz",
|
||||
"integrity": "sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.3.tgz",
|
||||
"integrity": "sha512-eYq77dYIFS77AQlhzEL937yUBSepBfPIe8FcgEDN35vMNZKMrs81pgnyrQpwfy4NF4b4XWX1Zgx7yX+25w8QJA==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"axobject-query": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz",
|
||||
|
@ -28312,6 +28407,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"psl": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
|
||||
|
@ -28975,6 +29075,23 @@
|
|||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
|
||||
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A=="
|
||||
},
|
||||
"react-router": {
|
||||
"version": "6.8.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.1.tgz",
|
||||
"integrity": "sha512-Jgi8BzAJQ8MkPt8ipXnR73rnD7EmZ0HFFb7jdQU24TynGW1Ooqin2KVDN9voSC+7xhqbbCd2cjGUepb6RObnyg==",
|
||||
"requires": {
|
||||
"@remix-run/router": "1.3.2"
|
||||
}
|
||||
},
|
||||
"react-router-dom": {
|
||||
"version": "6.8.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.1.tgz",
|
||||
"integrity": "sha512-67EXNfkQgf34P7+PSb6VlBuaacGhkKn3kpE51+P6zYSG2kiRoumXEL6e27zTa9+PGF2MNXbgIUHTVlleLbIcHQ==",
|
||||
"requires": {
|
||||
"@remix-run/router": "1.3.2",
|
||||
"react-router": "6.8.1"
|
||||
}
|
||||
},
|
||||
"react-scripts": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
|
||||
|
|
|
@ -13,12 +13,14 @@
|
|||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"antd": "^5.2.1",
|
||||
"axios": "^1.3.3",
|
||||
"chart.js": "^4.2.1",
|
||||
"mapbox-gl": "^2.12.1",
|
||||
"react": "^18.2.0",
|
||||
"react-chartjs-2": "^5.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-redux": "^8.0.5",
|
||||
"react-router-dom": "^6.8.1",
|
||||
"react-scripts": "5.0.1",
|
||||
"redux": "^4.2.1",
|
||||
"typescript": "^4.9.5",
|
||||
|
|
54
public/200.html
Normal file
54
public/200.html
Normal file
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<style>
|
||||
*::-webkit-scrollbar{
|
||||
display: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
BIN
public/location_pin.png
Normal file
BIN
public/location_pin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
104
public/points.geojson
Normal file
104
public/points.geojson
Normal file
|
@ -0,0 +1,104 @@
|
|||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
39.08647667577779,
|
||||
45.0039321850457
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
39.04491379939927,
|
||||
45.03243514655392
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
38.97323072498696,
|
||||
45.06542932356558
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
38.95386129652343,
|
||||
45.10189657981991
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
38.97872396028441,
|
||||
45.13042706066193
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
38.96503174898015,
|
||||
45.01385308177049
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
39.112531237076155,
|
||||
45.04610100871051
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
39.11927597081987,
|
||||
45.0588865314364
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
38.94055848744463,
|
||||
45.045496678942584
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -416,6 +416,105 @@
|
|||
],
|
||||
"type": "Polygon"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
39.08647667577779,
|
||||
45.0039321850457
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
39.04491379939927,
|
||||
45.03243514655392
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
38.97323072498696,
|
||||
45.06542932356558
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
38.95386129652343,
|
||||
45.10189657981991
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
38.97872396028441,
|
||||
45.13042706066193
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
38.96503174898015,
|
||||
45.01385308177049
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
39.112531237076155,
|
||||
45.04610100871051
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
39.11927597081987,
|
||||
45.0588865314364
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
38.94055848744463,
|
||||
45.045496678942584
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
import React from 'react';
|
||||
import { Sidebar } from './components/Sidebar';
|
||||
import { TheMap } from './components/TheMap';
|
||||
import {Provider} from 'react-redux'
|
||||
import {Provider} from 'react-redux';
|
||||
import {RouterProvider} from 'react-router-dom'
|
||||
import router from './router'
|
||||
import store from './store';
|
||||
import 'antd/dist/reset.css';
|
||||
|
||||
|
@ -10,8 +12,7 @@ function App() {
|
|||
return (
|
||||
<div className="App">
|
||||
<Provider store={store}>
|
||||
<TheMap />
|
||||
<Sidebar />
|
||||
<RouterProvider router={router}></RouterProvider>
|
||||
</Provider>
|
||||
</div>
|
||||
);
|
||||
|
|
62
src/components/CardChart/index.tsx
Normal file
62
src/components/CardChart/index.tsx
Normal file
|
@ -0,0 +1,62 @@
|
|||
import 'chart.js/auto';
|
||||
|
||||
import react, {useRef} from 'react'
|
||||
|
||||
import { Line } from "react-chartjs-2";
|
||||
|
||||
interface IChart{
|
||||
data: number[],
|
||||
days: number[]
|
||||
}
|
||||
|
||||
export const CardChart: react.FC<IChart> = (props) => {
|
||||
const ref = useRef();
|
||||
const data = {
|
||||
labels: props.days,
|
||||
datasets: [
|
||||
{
|
||||
data: props.data,
|
||||
fill: true,
|
||||
backgroundColor: 'rgba(75,192,192,0.2)',
|
||||
borderColor: 'rgba(75,192,192,1)'
|
||||
},
|
||||
],
|
||||
|
||||
};
|
||||
return <div style={{width: 340,
|
||||
height: 170,}}>
|
||||
<Line
|
||||
data={data}
|
||||
ref={ref}
|
||||
style={{
|
||||
width: 340,
|
||||
height: 170,
|
||||
transform: 'translateX(-10px)'
|
||||
}}
|
||||
options={{
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
title: {
|
||||
text: "руб",
|
||||
display: true
|
||||
}
|
||||
},
|
||||
x: {
|
||||
title: {
|
||||
text: "Дней до сдачи",
|
||||
display: true
|
||||
}
|
||||
}
|
||||
},
|
||||
responsive: true,
|
||||
maintainAspectRatio: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}></Line>
|
||||
</div>
|
||||
}
|
65
src/components/PrimaryCard/index.tsx
Normal file
65
src/components/PrimaryCard/index.tsx
Normal file
|
@ -0,0 +1,65 @@
|
|||
import react from 'react'
|
||||
import {Card, Checkbox, Typography} from 'antd'
|
||||
import './style.css'
|
||||
import { CardChart } from '../CardChart';
|
||||
|
||||
interface IPrimaryCard{
|
||||
prices: {
|
||||
days: number,
|
||||
price: number
|
||||
}[],
|
||||
community: string;
|
||||
status: string;
|
||||
risk: string;
|
||||
floor: string;
|
||||
area: number;
|
||||
days_to_be_done: number;
|
||||
developer: string;
|
||||
increase_procent: string;
|
||||
days_for_increase: number;
|
||||
}
|
||||
|
||||
export const PrimaryCard: react.FC<IPrimaryCard> = (props) => {
|
||||
|
||||
var deal_text = (deal_type: string) => {
|
||||
if (deal_type == 'bad') return {
|
||||
status: 'Сделка плохая',
|
||||
color: 'red'
|
||||
}
|
||||
if (deal_type == 'riskey') return {
|
||||
status: 'Сделка рискованная',
|
||||
color: 'black'
|
||||
}
|
||||
if (deal_type == 'good') return {
|
||||
status: 'Сделка хорошая',
|
||||
color: 'green'
|
||||
}
|
||||
}
|
||||
var mapped_price = props.prices.map((e) => e.price);
|
||||
var mapped_days = props.prices.map((e) => e.days);
|
||||
|
||||
return <Card title={props.community} style={{width: 400}}>
|
||||
<div className="container">
|
||||
<div className='ch-b__text'>
|
||||
<Checkbox checked={props.status == 'short'}/>
|
||||
<Typography.Text>Шорт</Typography.Text>
|
||||
</div>
|
||||
<Typography.Text>
|
||||
Застрощик: <strong>{props.developer}</strong>
|
||||
</Typography.Text>
|
||||
<Typography.Text>
|
||||
Дней до сдачи: <strong>{props.days_to_be_done}</strong>
|
||||
</Typography.Text>
|
||||
<Typography.Text>
|
||||
Рекомендация: <strong style={{color: deal_text(props.risk)?.color as any}}>
|
||||
{deal_text(props.risk)?.status}
|
||||
</strong>
|
||||
</Typography.Text>
|
||||
<Typography.Text>Предполагаемая прибыль <strong>{props.increase_procent}%</strong></Typography.Text>
|
||||
<Typography.Text>Этаж: <strong>{props.floor}</strong></Typography.Text>
|
||||
<Typography.Text>Площадь: <strong>{props.area} кв.м</strong></Typography.Text>
|
||||
<Typography.Text>Ждать прибыли: <strong>{props.days_for_increase} дней (дня)</strong></Typography.Text>
|
||||
<CardChart data={mapped_price} days={mapped_days}/>
|
||||
</div>
|
||||
</Card>
|
||||
}
|
9
src/components/PrimaryCard/style.css
Normal file
9
src/components/PrimaryCard/style.css
Normal file
|
@ -0,0 +1,9 @@
|
|||
.ch-b__text{
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
.container{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
52
src/components/SecondaryCard/index.tsx
Normal file
52
src/components/SecondaryCard/index.tsx
Normal file
|
@ -0,0 +1,52 @@
|
|||
import react from 'react'
|
||||
import {Card, Typography} from 'antd';
|
||||
import './style.css'
|
||||
|
||||
interface ISecondaryCard {
|
||||
link: string;
|
||||
floor: number;
|
||||
rooms_count: number;
|
||||
area: number;
|
||||
year_of_construction: number;
|
||||
living_meters: number;
|
||||
kitchen_meters: number;
|
||||
pred_price: number;
|
||||
diff: number;
|
||||
marker: string;
|
||||
}
|
||||
|
||||
export const SecondaryCard: react.FC<ISecondaryCard> = (props) => {
|
||||
var color = 'green';
|
||||
if (props.marker == 'underpriced') color = 'red';
|
||||
|
||||
return <Card>
|
||||
<div className='sec__container'>
|
||||
<div className="stat-item">
|
||||
<div className="colored" style={{backgroundColor: `${color}!important`}}></div>
|
||||
<Typography.Link
|
||||
href={props.link} strong
|
||||
>Ссылка на квартиру
|
||||
</Typography.Link>
|
||||
</div>
|
||||
<Typography.Text>
|
||||
Этаж: <strong>{props.floor}</strong>
|
||||
</Typography.Text>
|
||||
<Typography.Text>
|
||||
Количество комнат: <strong>{props.rooms_count}</strong>
|
||||
</Typography.Text>
|
||||
<Typography.Text>
|
||||
Площадь: <strong>{props.area} кв.м</strong>
|
||||
</Typography.Text>
|
||||
<Typography.Text>
|
||||
Год постройки: <strong>{props.year_of_construction} г.</strong>
|
||||
</Typography.Text>
|
||||
<Typography.Text>
|
||||
Предсказанная цена: <strong>{props.pred_price.toFixed(0)} р</strong>
|
||||
</Typography.Text>
|
||||
<Typography.Text>
|
||||
Процент отклонения: <strong>{(props.diff * -1).toFixed(1)}%</strong>
|
||||
</Typography.Text>
|
||||
</div>
|
||||
|
||||
</Card>
|
||||
}
|
16
src/components/SecondaryCard/style.css
Normal file
16
src/components/SecondaryCard/style.css
Normal file
|
@ -0,0 +1,16 @@
|
|||
.sec__container{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.stat-item{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px
|
||||
}
|
||||
|
||||
.colored{
|
||||
background-color: red;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 1000px;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -4,10 +4,116 @@ import * as mapboxgl from 'mapbox-gl';
|
|||
import 'mapbox-gl/dist/mapbox-gl.css';
|
||||
import { useDispatch } from 'react-redux/es/exports';
|
||||
import { setActive, setName } from '../../store/slices/sidebarSlice';
|
||||
|
||||
import './style.css'
|
||||
(mapboxgl as any).accessToken = 'pk.eyJ1IjoiaWxpYXZhcyIsImEiOiJjazcwdXU0dHkwMGViM21ta3VxaHB2YWNqIn0.yHEDUiatwp4dy4MM3ywnOQ';
|
||||
|
||||
|
||||
const points = {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
39.08647667577779,
|
||||
45.0039321850457
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
39.04491379939927,
|
||||
45.03243514655392
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
38.97323072498696,
|
||||
45.06542932356558
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
38.95386129652343,
|
||||
45.10189657981991
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
38.97872396028441,
|
||||
45.13042706066193
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
38.96503174898015,
|
||||
45.01385308177049
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
39.112531237076155,
|
||||
45.04610100871051
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
39.11927597081987,
|
||||
45.0588865314364
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"coordinates": [
|
||||
38.94055848744463,
|
||||
45.045496678942584
|
||||
],
|
||||
"type": "Point"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
export const TheMap: react.FC = () => {
|
||||
const mapContainer = useRef(null);
|
||||
const map = useRef(null as any);
|
||||
|
@ -49,6 +155,36 @@ export const TheMap: react.FC = () => {
|
|||
'line-width': 2
|
||||
}
|
||||
});
|
||||
|
||||
map.current.loadImage('/location_pin.png', (error: any, image: any) => {
|
||||
if (error) throw error;
|
||||
map.current.addImage('point_icon', image)
|
||||
map.current.addSource('building_points', {
|
||||
type: 'geojson',
|
||||
data: '/points.geojson'
|
||||
})
|
||||
map.current.addLayer({
|
||||
'id': 'building_points_geojson',
|
||||
'type': 'symbol',
|
||||
'source': 'building_points',
|
||||
'layout': {
|
||||
'icon-image': 'point_icon',
|
||||
|
||||
}
|
||||
})
|
||||
map.current.on('click', 'building_points_geojson', (e: any) => {
|
||||
console.log(e.features[0].properties.name)
|
||||
dispatch(setActive(true));
|
||||
dispatch(setName(e.features[0].properties.name))
|
||||
});
|
||||
map.current.on('mouseenter', 'building_points_geojson', () => {
|
||||
map.current.getCanvas().style.cursor = 'pointer';
|
||||
});
|
||||
map.current.on('mouseleave', 'building_points_geojson', () => {
|
||||
map.current.getCanvas().style.cursor = '';
|
||||
});
|
||||
})
|
||||
|
||||
map.current.on('click', 'buildings-layer', (e: any) => {
|
||||
console.log(e.features[0].properties.name)
|
||||
dispatch(setActive(true));
|
||||
|
|
0
src/components/TheMap/style.css
Normal file
0
src/components/TheMap/style.css
Normal file
11
src/pages/MapPage/index.tsx
Normal file
11
src/pages/MapPage/index.tsx
Normal file
|
@ -0,0 +1,11 @@
|
|||
import react from 'react'
|
||||
import { TheMap } from '../../components/TheMap'
|
||||
import { Sidebar } from '../../components/Sidebar'
|
||||
|
||||
export const MapPage: react.FC = () => {
|
||||
|
||||
return <>
|
||||
<TheMap />
|
||||
<Sidebar />
|
||||
</>
|
||||
}
|
112
src/pages/SearchPage/index.tsx
Normal file
112
src/pages/SearchPage/index.tsx
Normal file
|
@ -0,0 +1,112 @@
|
|||
import react from 'react'
|
||||
import {Switch, Typography, Slider, Button, Divider} from 'antd';
|
||||
import './style.css'
|
||||
import axios from 'axios';
|
||||
import { PrimaryCard } from '../../components/PrimaryCard';
|
||||
import { SecondaryCard } from '../../components/SecondaryCard';
|
||||
|
||||
var secondary_url = 'https://dev.akarpov.ru/api/search/secondary';
|
||||
var primary_url = 'https://dev.akarpov.ru/api/search/primary';
|
||||
|
||||
export const SearchPage: react.FC = () => {
|
||||
|
||||
const [searchType, setSearchType] = react.useState('perv');
|
||||
const [shortLong, setShortLong] = react.useState('short');
|
||||
const [minMaxPrice, setMinMaxPrice] = react.useState([0, 0]);
|
||||
const [underOver, setUnderOver] = react.useState('overpriced')
|
||||
|
||||
const [pervData, setPervData] = react.useState([]);
|
||||
const [secData, setSecData] = react.useState([]);
|
||||
|
||||
var maxPrices = {
|
||||
'perv': {
|
||||
'min': 4.1,
|
||||
'max': 17.3
|
||||
},
|
||||
'vtor': {
|
||||
'min': 1,
|
||||
'max': 10
|
||||
}
|
||||
}
|
||||
return <div className='filters__centered'>
|
||||
<div className="filters">
|
||||
<Typography.Title level={4}>Фильтры</Typography.Title>
|
||||
<div className="perv-sec__container">
|
||||
<Typography.Text style={{textAlign: 'center'}}>Первичка</Typography.Text>
|
||||
<Switch onChange={(e) => {
|
||||
if (e) {
|
||||
setSearchType('vtor')
|
||||
} else {
|
||||
setSearchType('perv')
|
||||
}
|
||||
}}></Switch>
|
||||
<Typography.Text>Вторичка</Typography.Text>
|
||||
</div>
|
||||
{
|
||||
searchType == 'perv' ? <div className="perv-sec__container">
|
||||
<Typography.Text>Краткосрочные инвестиции</Typography.Text>
|
||||
<Switch onChange={(e) => {
|
||||
if (e) setShortLong('long')
|
||||
else setShortLong('short')
|
||||
}}></Switch>
|
||||
<Typography.Text>Долгосрочные инвестиции</Typography.Text>
|
||||
</div> : <></>
|
||||
}
|
||||
{
|
||||
searchType == 'vtor' ? <div className="perv-sec__container">
|
||||
<Typography.Text>Недооцененные квартиры</Typography.Text>
|
||||
<Switch onChange={(e) => {
|
||||
if (e) setUnderOver('overpriced')
|
||||
else setUnderOver('underpriced')
|
||||
}}></Switch>
|
||||
<Typography.Text>Переоцененные квартиры</Typography.Text>
|
||||
</div> : <></>
|
||||
}
|
||||
<div>
|
||||
<Typography.Text>Фильтр цены (млн. руб)</Typography.Text>
|
||||
<Slider
|
||||
range
|
||||
min={((maxPrices as any)[searchType] as any)['min']}
|
||||
max={((maxPrices as any)[searchType] as any)['max']}
|
||||
step={0.1}
|
||||
onChange={(e) => {
|
||||
setMinMaxPrice(e)
|
||||
}}
|
||||
></Slider>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type='primary'
|
||||
onClick={async () => {
|
||||
var origin = secondary_url
|
||||
if (searchType == 'perv') {
|
||||
origin = primary_url;
|
||||
origin += `?status=${shortLong}&price_max=${minMaxPrice[1] * 1000000}&price_min=${minMaxPrice[0] * 1000000}`
|
||||
const answer = await axios.get(origin);
|
||||
console.log(answer)
|
||||
setPervData(answer.data.reverse());
|
||||
setSecData([]);
|
||||
|
||||
} else {
|
||||
origin += `?price_max=${minMaxPrice[1] * 1000000}&price_min=${minMaxPrice[0] * 1000000}&marker=${underOver}`
|
||||
const answer = await axios.get(origin);
|
||||
setSecData(answer.data);
|
||||
setPervData([]);
|
||||
}
|
||||
|
||||
}}
|
||||
>Найти</Button>
|
||||
</div>
|
||||
<Divider></Divider>
|
||||
<div className="content">
|
||||
{pervData.map((e) => {
|
||||
return <PrimaryCard {...e as any}/>
|
||||
})}
|
||||
{
|
||||
secData.map((e) => {
|
||||
return <SecondaryCard {...e as any}/>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
27
src/pages/SearchPage/style.css
Normal file
27
src/pages/SearchPage/style.css
Normal file
|
@ -0,0 +1,27 @@
|
|||
.perv-sec__container{
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
.filters{
|
||||
width: 500px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 20px;
|
||||
|
||||
}
|
||||
|
||||
.filters__centered{
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.content{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: 30px;
|
||||
padding: 20px;
|
||||
justify-content: space-between;
|
||||
}
|
16
src/router.tsx
Normal file
16
src/router.tsx
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { createBrowserRouter } from "react-router-dom";
|
||||
import { MapPage } from "./pages/MapPage";
|
||||
import { SearchPage } from "./pages/SearchPage";
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
'path': '/search',
|
||||
'element': <SearchPage />
|
||||
},
|
||||
{
|
||||
'path': '/map',
|
||||
'element': <MapPage />
|
||||
}
|
||||
])
|
||||
|
||||
export default router;
|
Loading…
Reference in New Issue
Block a user