mirror of
https://github.com/task-17-lct/frontend.git
synced 2024-11-22 07:16:34 +03:00
Merge pull request #5 from task-17-lct/adaptive
Adaptive and add some pages
This commit is contained in:
commit
0161231b64
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 9.3 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 6.7 KiB |
BIN
public/redpin.png
Normal file
BIN
public/redpin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 662 B |
|
@ -14,7 +14,7 @@ export const RusPassHeader:React.FC = () =>{
|
||||||
<img className="headerIcon delete600" src='/search.svg' onClick={()=>navigate('/')}></img>
|
<img className="headerIcon delete600" src='/search.svg' onClick={()=>navigate('/')}></img>
|
||||||
</div>
|
</div>
|
||||||
<div className="iconWrapper">
|
<div className="iconWrapper">
|
||||||
<img className="headerIcon delete600" src='/language.svg'></img>
|
<img className="headerIcon delete600" onClick={()=>navigate('/buyed')} src='/language.svg'></img>
|
||||||
<img className="headerIcon" src='/favorites.svg' onClick={()=>navigate('/favorites')}></img>
|
<img className="headerIcon" src='/favorites.svg' onClick={()=>navigate('/favorites')}></img>
|
||||||
<img className="headerIcon" src='/profile.svg'onClick={()=>navigate('/login')} ></img>
|
<img className="headerIcon" src='/profile.svg'onClick={()=>navigate('/login')} ></img>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,6 +7,7 @@ import Sidebar from "react-sidebar";
|
||||||
import { PlaceCard } from "../TourCard";
|
import { PlaceCard } from "../TourCard";
|
||||||
import { Collapse, Tabs, TabsProps } from "antd";
|
import { Collapse, Tabs, TabsProps } from "antd";
|
||||||
import { backend } from "../../consts";
|
import { backend } from "../../consts";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
export interface RouteCardIE{
|
export interface RouteCardIE{
|
||||||
rawProps:any,
|
rawProps:any,
|
||||||
|
@ -36,7 +37,7 @@ export const RouteCard:React.FC<RouteCardIE> = (props) =>{
|
||||||
const [showMap, setShowMap] = useState(false)
|
const [showMap, setShowMap] = useState(false)
|
||||||
const [selectedDay, setSelectedDay] = useState('0')
|
const [selectedDay, setSelectedDay] = useState('0')
|
||||||
const [liked, setLiked] = useState(false)
|
const [liked, setLiked] = useState(false)
|
||||||
|
let navigate = useNavigate()
|
||||||
let cntPlaces = 0
|
let cntPlaces = 0
|
||||||
props.options.forEach((route)=>{
|
props.options.forEach((route)=>{
|
||||||
cntPlaces += route.paths.length
|
cntPlaces += route.paths.length
|
||||||
|
@ -92,9 +93,17 @@ export const RouteCard:React.FC<RouteCardIE> = (props) =>{
|
||||||
// backend.get('route/list').then((e)=>console.log(e.data))
|
// backend.get('route/list').then((e)=>console.log(e.data))
|
||||||
backend.post('route/save', {
|
backend.post('route/save', {
|
||||||
points: props.rawProps.path
|
points: props.rawProps.path
|
||||||
})
|
}).then((e)=>console.log(e.data))
|
||||||
setLiked(!liked)
|
setLiked(!liked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onBuy = () =>{
|
||||||
|
backend.post('route/save', {
|
||||||
|
points: props.rawProps.path
|
||||||
|
}).then((e)=>backend.get('buy/' + e.data.id + '/add_to_buy/'))
|
||||||
|
|
||||||
|
navigate('/buyed')
|
||||||
|
}
|
||||||
return(
|
return(
|
||||||
<div key={props.city + props.options[0].paths[0].point.oid}>
|
<div key={props.city + props.options[0].paths[0].point.oid}>
|
||||||
<Sidebar
|
<Sidebar
|
||||||
|
@ -102,6 +111,7 @@ export const RouteCard:React.FC<RouteCardIE> = (props) =>{
|
||||||
<div className='sidebarContent'>
|
<div className='sidebarContent'>
|
||||||
<MyMap points={points}></MyMap>
|
<MyMap points={points}></MyMap>
|
||||||
<Tabs defaultActiveKey="0" items={colapseItems} onChange={(e:string)=>setSelectedDay(e)} />
|
<Tabs defaultActiveKey="0" items={colapseItems} onChange={(e:string)=>setSelectedDay(e)} />
|
||||||
|
<Button className='' onClick={()=>onBuy()}>КУПИТЬ</Button>
|
||||||
<Button className='btn-y' onClick={()=>setShowMap(!showMap)}>Закрыть</Button>
|
<Button className='btn-y' onClick={()=>setShowMap(!showMap)}>Закрыть</Button>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
102
src/elements/RouteChangeCard/index.tsx
Normal file
102
src/elements/RouteChangeCard/index.tsx
Normal 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>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
191
src/elements/RouteChangeCard/style.css
Normal file
191
src/elements/RouteChangeCard/style.css
Normal 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%;
|
||||||
|
}
|
|
@ -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,13 +32,12 @@ export const MyMap: React.FC<MapIE> = (props) =>{
|
||||||
|
|
||||||
const [route, setRoute] = useState()
|
const [route, setRoute] = useState()
|
||||||
|
|
||||||
console.log(route)
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
setTimeout(()=> axios.get('https://api.mapbox.com/directions/v5/mapbox/walking/'+pathString+'?alternatives=true&continue_straight=true&geometries=geojson&language=en&overview=simplified&steps=true&access_token=pk.eyJ1IjoiZmlyZXNpZWh0IiwiYSI6ImNrdW9kemYzbTB4ZGkycHAxbXN2YnIzaGMifQ.G0fl-qVbecucfOvn8OtU4Q').then(
|
setTimeout(()=> axios.get('https://api.mapbox.com/directions/v5/mapbox/walking/'+pathString+'?alternatives=true&continue_straight=true&geometries=geojson&language=en&overview=simplified&steps=true&access_token=pk.eyJ1IjoiZmlyZXNpZWh0IiwiYSI6ImNrdW9kemYzbTB4ZGkycHAxbXN2YnIzaGMifQ.G0fl-qVbecucfOvn8OtU4Q').then(
|
||||||
(data:any) => setRoute(data.data.routes[0].geometry)
|
(data:any) => setRoute(data.data.routes[0].geometry)
|
||||||
), 1000)
|
).catch((err)=>console.log('ERRRRRRRR')), 1000)
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
|
88
src/pages/Buyed/index.tsx
Normal file
88
src/pages/Buyed/index.tsx
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
import { Spin } from "antd";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { backend } from "../../consts";
|
||||||
|
import { RusPassHeader } from "../../elements/Header";
|
||||||
|
import { RouteCard } from "../../elements/RouteCard";
|
||||||
|
|
||||||
|
export const Buyed:React.FC = () =>{
|
||||||
|
const [data, setData] = useState([])
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
backend.get('/buy/').then((e)=>setData(e.data))
|
||||||
|
})
|
||||||
|
let newData;
|
||||||
|
|
||||||
|
if (data.length != 0){
|
||||||
|
newData = data.map((tour:any, index)=>{
|
||||||
|
|
||||||
|
let newPath = tour.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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
city: 'Тур №' + (index+1),
|
||||||
|
path: newPath
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div className="mainWrapper">
|
||||||
|
<RusPassHeader></RusPassHeader>
|
||||||
|
|
||||||
|
<h1>Ваши купленные туры</h1>
|
||||||
|
|
||||||
|
{
|
||||||
|
data.length == 0 || newData == undefined?
|
||||||
|
|
||||||
|
<Spin />:
|
||||||
|
<div className='mainCard'>
|
||||||
|
<h2>Рекомендованные Туры</h2>
|
||||||
|
|
||||||
|
<div className='cardWrapper'>
|
||||||
|
{
|
||||||
|
newData.map((tour:any, index:number)=>
|
||||||
|
<RouteCard city={tour.city} rawProps={data[index]} options={tour.path}></RouteCard>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
</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>
|
||||||
|
);
|
||||||
|
}
|
77
src/pages/Favorites/index.tsx
Normal file
77
src/pages/Favorites/index.tsx
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import react, { useEffect, useRef, useState } from 'react'
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { backend, updateBackend } from '../../consts';
|
||||||
|
|
||||||
|
import { RusPassHeader } from '../../elements/Header';
|
||||||
|
// import './style.css'
|
||||||
|
|
||||||
|
import { EventCard } from '../../elements/EventCard';
|
||||||
|
import { Spin } from 'antd';
|
||||||
|
|
||||||
|
export const Favorites: react.FC = () => {
|
||||||
|
const [favorites, setFavorites] = useState([])
|
||||||
|
let navigate = useNavigate()
|
||||||
|
|
||||||
|
|
||||||
|
const queried = useRef(false);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
updateBackend()
|
||||||
|
|
||||||
|
const dataLoad = async () =>{
|
||||||
|
const favorites = await backend.get('user/favorite')
|
||||||
|
return {
|
||||||
|
favorites
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!queried.current && localStorage.getItem('token') != null && localStorage.getItem('firstAuth') != 'true') {
|
||||||
|
queried.current = true;
|
||||||
|
dataLoad().then((data) => {
|
||||||
|
setFavorites(data.favorites.data as any);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null == localStorage.getItem('token')){
|
||||||
|
navigate('/login')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='mainWrapper'>
|
||||||
|
<RusPassHeader></RusPassHeader>
|
||||||
|
|
||||||
|
<div className='mainCard'>
|
||||||
|
<h2>Избранное</h2>
|
||||||
|
<div className='fav-wrapper'>
|
||||||
|
{
|
||||||
|
favorites.length == 0? <Spin/>
|
||||||
|
:
|
||||||
|
favorites.map((favorite:any, index)=>{
|
||||||
|
return <EventCard category='attraction'
|
||||||
|
description={favorite.description}
|
||||||
|
lat={1}
|
||||||
|
lon={2}
|
||||||
|
oid={favorite.oid}
|
||||||
|
title={favorite.title} ></EventCard>
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</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>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
|
@ -112,7 +112,7 @@ export const Main: react.FC = () => {
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button className=''>Посмотреть все</Button>
|
<Button onClick={()=>navigate('/favorites')} className=''>Посмотреть все</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
104
src/pages/Weather/index.tsx
Normal file
104
src/pages/Weather/index.tsx
Normal 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>
|
||||||
|
}
|
21
src/pages/Weather/styles.css
Normal file
21
src/pages/Weather/styles.css
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,9 @@ import { EventMatch } from './pages/EventMatch';
|
||||||
import { GenerateTour } from './pages/GenerateTour';
|
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 { Weather } from './pages/Weather';
|
||||||
|
import { Buyed } from './pages/Buyed';
|
||||||
|
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
|
@ -43,6 +46,18 @@ const routes = [
|
||||||
{
|
{
|
||||||
path: '/prefs',
|
path: '/prefs',
|
||||||
element: <Prefernces></Prefernces>
|
element: <Prefernces></Prefernces>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/favorites',
|
||||||
|
element: <Favorites></Favorites>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/route/:routeChangeId/change',
|
||||||
|
element: <Weather></Weather>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/buyed',
|
||||||
|
element: <Buyed></Buyed>
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user