add weather page

This commit is contained in:
= 2023-06-08 23:53:27 +03:00
parent 8a24801641
commit 3b9e028c0b
7 changed files with 436 additions and 2 deletions

BIN
public/redpin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

View File

@ -0,0 +1,102 @@
import React, { useState } from "react";
import { Button } from '../Button'
import { Block } from '../Block'
import './style.css'
import { MyMap } from "../map";
import Sidebar from "react-sidebar";
import { PlaceCard } from "../TourCard";
import { Collapse, Tabs, TabsProps } from "antd";
import { backend } from "../../consts";
export interface RouteCardIE{
rawProps:any,
city:string,
options: {
date:string,
paths:({
type:string
distance:number,
point_type:string,
point:{
lat:number,
lon:number,
title: string,
description:string,
oid:string
}
})[]
}[]
}
const { Panel } = Collapse;
export const RouteChangeCard:React.FC<RouteCardIE> = (props) =>{
const [selectedDay, setSelectedDay] = useState('0')
let cntPlaces = 0
props.options.forEach((route)=>{
cntPlaces += route.paths.length
})
let points = props.options[Number(selectedDay)].paths.map((path)=>{
return {
description:path.point.description,
title: path.point.title,
cords:[path.point.lon, path.point.lat]
}
})
let remappedPoints = props.options[Number(selectedDay)].paths.map((path)=>{
if (path.point_type == 'remapped_point'){
return {
description:path.point.description,
title: path.point.title,
cords:[path.point.lon, path.point.lat]
}
}
})
for (let i = 0; i < remappedPoints.length; i++) {
if (remappedPoints[i] == undefined) {
remappedPoints.splice(i, 1);
i--;
}
}
console.log(remappedPoints)
const colapseItems: TabsProps['items'] = props.options.map((day, index)=>{
return {
key:index.toString(),
label: (index+1).toString() + 'день',
children: <Collapse
bordered={false}
>
{
day.paths.map((value, index2) =>
<Panel header={value.point.title} key={'collapse'+index.toString()+index2.toString()}>
<img style={{width:'200px'}} src='/icons/not_found.jpeg'></img>
<p>{value.point.description}</p>
</Panel>
)
}
</Collapse>
}
})
return(
<div className='sidebarChangeContent' key={props.city + props.options[0].paths[0].point.oid}>
<div className="titleText">{props.city}</div>
<MyMap remapedPoints={remappedPoints as any} points={points}></MyMap>
<Tabs className="tabs" defaultActiveKey="0" items={colapseItems} onChange={(e:string)=>setSelectedDay(e)} />
</div>
);
}

View File

@ -0,0 +1,191 @@
.tourcard-block{
width: 400px;
height: 548px;
display: flex;
flex-direction: column;
gap:25px;
padding: 25px;
border: solid #F5DFB8 1px;
background-color: #fff;
}
.cardDescr{
display: flex;
flex-direction: row;
justify-content: space-between;
}
.cardTitle{
display: flex;
flex-direction: column;
gap:15px;
}
.cardInfo{
display: flex;
gap:15px;
color:rgba(29, 29, 29, 0.5)
}
.cardAvatar{
height: 100px;
transform: rotate(5deg);
}
.titleText{
font-size: 24px;
padding-right: 50px;
}
.placesWrapper{
display: flex;
flex-direction: column;
gap:20px;
margin-top: 30px;
height: 260px;
overflow-y: scroll;
}
.placesWrapper::-webkit-scrollbar {
width: 0;
}
.placeCard{
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.placeImage{
width: 40px;
height: 40px;
border-radius: 5px;
}
.placeDescrWrapper{
display: flex;
flex-direction: column;
gap:7px;
font-size: 16px;
}
.placeType{
color:rgba(29, 29, 29, 0.5);
font-size: 12px;
}
.mainCardContent{
position: relative !important;
}
.tourCardSidebar{
position: fixed !important;
left: 0px;
width: 30%;
top:0px;
border-radius: 0px 20px 20px 0px;
padding: 50px;
}
.sidebarChangeContent{
display: flex;
flex-direction: column;
gap:50px;
align-items: center;
justify-content: space-between;
width: 400px;
height: 100%;
}
.openBtn{
display: flex;
flex-direction: row;
}
.yOpenBtn{
width: 80%;
height:48px;
background: #FFCF08;
padding: 0px 16px;
border-radius: 20px 4px 4px 20px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
transition: 0.3s;
}
.yOpenBtn:hover{
opacity: 0.5;
}
.yOpenBtnTitle{
font-weight: 500;
font-size: 16px;
line-height: 22px;
color: #1D1D1D;
}
.yOpenBtnDescr{
font-weight: 500;
font-size: 14px;
line-height: 18px;
text-align: center;
color: rgba(29, 29, 29, 0.5);
}
.btnWrapper{
display: flex;
flex-direction: row;
width: 100%;
gap:5px;
align-items: center;
justify-content: center;
}
.likeBtn{
height:48px;
padding: 0px 13px 0px 11px;
background: rgba(245, 223, 184, 0.5);
border-radius: 4px 20px 20px 4px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
cursor: pointer;
transition: 0.3s;
}
.likeBtn:hover{
opacity: 0.5;
}
@media screen and (max-device-width: 600px) {
.tourcard-block{
width: 300px;
gap:15px;
padding: 15px;
}
.titleText{
font-size: 18px;
line-height: 22px;
}
.cardInfo{
font-size: 14px;
}
.tourCardSidebar{
width: calc(100% - 150px);
}
}
@media screen and (max-device-width: 400px) {
.tourcard-block{
width: 280px;
}
}
.tabs{
width: 100%;
}

View File

@ -14,6 +14,12 @@ export interface MapIE{
description:string description:string
}[] }[]
remapedPoints?:{
cords:number[],
title:string,
description:string
}[]
} }
export const MyMap: React.FC<MapIE> = (props) =>{ export const MyMap: React.FC<MapIE> = (props) =>{
@ -26,7 +32,6 @@ export const MyMap: React.FC<MapIE> = (props) =>{
const [route, setRoute] = useState() const [route, setRoute] = useState()
console.log(route)
useEffect(()=>{ useEffect(()=>{
@ -91,7 +96,6 @@ export const MyMap: React.FC<MapIE> = (props) =>{
} }
}; };
console.log(props)
return ( return (
<div style={{width:'100%'}}> <div style={{width:'100%'}}>
@ -119,6 +123,13 @@ export const MyMap: React.FC<MapIE> = (props) =>{
</Marker> </Marker>
}) })
} }
{
props.remapedPoints != undefined? props.remapedPoints.map((point, index)=>{
return <Marker longitude={point.cords[0]} latitude={point.cords[1]} anchor="bottom" >
<img src="/redpin.png" />
</Marker>
}) : null
}
</Map> </Map>
</div> </div>

104
src/pages/Weather/index.tsx Normal file
View File

@ -0,0 +1,104 @@
import { Spin } from "antd";
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { backend } from "../../consts";
import { Button } from "../../elements/Button";
import { RusPassHeader } from "../../elements/Header";
import { RouteCard } from "../../elements/RouteCard";
import { RouteChangeCard } from "../../elements/RouteChangeCard";
import './styles.css'
export const Weather:React.FC = () =>{
let {routeChangeId} = useParams()
const [weather, setWeather] = useState<any>()
useEffect(()=>{
if (weather == undefined){
backend.get('weather/' + routeChangeId + '/').then((e)=>setWeather(e.data))
}
})
let prev_route;
let predicted_route;
console.log(weather )
if (weather != undefined){
let newPath = weather.prev_route.points.map((path:any)=>{
let newPaths = path.paths
for (let i = 0; i < newPaths.length; i++) {
if (newPaths[i].type == 'transition') {
newPaths.splice(i, 1);
i--;
}
}
return {
date:path.date,
paths: newPaths
}
})
prev_route = {
city: 'Старый маршрут',
path: newPath
}
let newPredictPath = weather.predicted_route.points.map((path:any)=>{
let newPaths = path.paths
for (let i = 0; i < newPaths.length; i++) {
if (newPaths[i].type == 'transition') {
newPaths.splice(i, 1);
i--;
}
}
return {
date:path.date,
paths: newPaths
}
})
predicted_route = {
city: 'Предлагаемый маршрут',
path: newPredictPath
}
}
return <div className="mainWrapper">
<RusPassHeader></RusPassHeader>
{
prev_route == undefined || predicted_route == undefined?
<Spin />:
<div className='mainCard'>
<h2>Измените маршрут из-за погоды!</h2>
<div className='cardWrapper'>
<RouteChangeCard city={predicted_route.city} rawProps={weather.predicted_route} options={predicted_route.path}></RouteChangeCard>
<RouteChangeCard city={prev_route.city} rawProps={weather.prev_route} options={prev_route.path}></RouteChangeCard>
</div>
<div className="changeBtnWrapper">
<Button className="changeYBtn">Согласится</Button>
<Button className="changeBtn">Отказаться</Button>
</div>
</div>
}
<a href='https://1drv.ms/w/s!AuaFmGWFNV5Np0OhMmVtxPXlG2Ob?e=f7NDCp'>Документация</a>
<div className='mainIconWrapper'>
<img className='mainIcon' src='/icons/yt.svg'></img>
<img className='mainIcon' src='/icons/vk.svg'></img>
<img className='mainIcon' src='/icons/dz.svg'></img>
<img className='mainIcon' src='/icons/tg.svg'></img>
<img className='mainIcon' src='/icons/ok.svg'></img>
</div>
<div className='grey'>© 2023 A project of the Government of Moscow</div>
</div>
}

View File

@ -0,0 +1,21 @@
.changeBtnWrapper{
display: flex;
flex-direction: row;
gap:25px;
align-items:center ;
justify-content: center;
}
.changeYBtn{
width: 400px;
background: #FFCF08;
}
.changeBtn{
width: 400px;
}
@media screen and (max-device-width: 500px) {
.changeBtnWrapper{
flex-wrap: wrap;
}
}

View File

@ -10,6 +10,7 @@ import { GenerateTour } from './pages/GenerateTour';
import { SearchPage } from './pages/SearchPage'; import { SearchPage } from './pages/SearchPage';
import { Prefernces } from './elements/Prefernces'; import { Prefernces } from './elements/Prefernces';
import { Favorites } from './pages/Favorites'; import { Favorites } from './pages/Favorites';
import { Weather } from './pages/Weather';
const routes = [ const routes = [
@ -48,6 +49,10 @@ const routes = [
{ {
path:'/favorites', path:'/favorites',
element: <Favorites></Favorites> element: <Favorites></Favorites>
},
{
path: '/route/:routeChangeId/change',
element: <Weather></Weather>
} }
] ]