Merge pull request #4 from task-17-lct/adaptive

Adaptive
This commit is contained in:
Firesieht 2023-06-08 15:58:43 +03:00 committed by GitHub
commit 49636402bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 632 additions and 323 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"liveServer.settings.port": 5501
}

View File

@ -48,16 +48,8 @@
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
"browserslist": [
"defaults",
"not ie 11"
]
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 63 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -25,10 +25,10 @@
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>
<title>Russpass MAGNUM OPUS</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<noscript>Включите JavaScript чтобы насладится нашим шикарном приложением</noscript>
<div id="root"></div>
<!--
This HTML file is a template.

View File

@ -1,8 +1,8 @@
<svg width="108" height="49" viewBox="0 0 108 49" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg width="111" height="49" viewBox="0 0 111 49" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_0_55)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.96 16.25C24.7049 16.25 22.8767 18.0782 22.8767 20.3333C22.8767 22.5885 24.7049 24.4167 26.96 24.4167C29.2152 24.4167 31.0433 22.5885 31.0433 20.3333C31.0433 18.0782 29.2152 16.25 26.96 16.25ZM24.46 26.25C22.2049 26.25 20.3767 28.0782 20.3767 30.3333C20.3767 31.668 21.4587 32.75 22.7934 32.75H31.1267C32.4614 32.75 33.5433 31.668 33.5433 30.3333C33.5433 28.0782 31.7152 26.25 29.46 26.25H24.46Z" fill="#1D1D1D"/>
</g>
<path d="M46.4298 18.9H50.0618C52.8938 18.9 54.8778 19.54 54.8778 22.404C54.8778 25.284 52.8938 25.908 50.0618 25.908H48.0618V30.5H46.4298V18.9ZM50.1898 20.276H48.0618V24.484H50.1898C51.9018 24.484 53.2138 24.308 53.2138 22.404C53.2138 20.516 51.9018 20.276 50.1898 20.276ZM60.5094 21.86V23.412C60.2054 23.364 59.9334 23.348 59.6934 23.348C58.3494 23.348 57.6774 24.084 57.6774 25.988V30.5H56.2214V21.892H57.6454V23.396C58.0774 22.42 58.9414 21.892 60.0774 21.844C60.2214 21.844 60.3334 21.844 60.5094 21.86ZM62.7446 26.228C62.7446 28.532 63.9926 29.428 65.3206 29.428C66.6486 29.428 67.8966 28.436 67.8966 26.228C67.8966 23.924 66.6486 23.028 65.3206 23.028C63.9926 23.028 62.7446 23.876 62.7446 26.228ZM65.3206 21.748C67.3206 21.748 69.4486 23.108 69.4486 26.228C69.4486 29.348 67.3206 30.708 65.3206 30.708C63.3206 30.708 61.1926 29.348 61.1926 26.228C61.1926 23.108 63.3206 21.748 65.3206 21.748ZM71.6363 21.892V21.268C71.6363 19.476 71.9883 18.9 73.9563 18.9H74.7083V20.116H73.9883C73.2203 20.116 73.0923 20.292 73.0923 21.188V21.892H74.7083V23.06H73.0923V30.5H71.6363V23.06H70.4363V21.892H71.6363ZM76.2839 21.892H77.7399V30.5H76.2839V21.892ZM76.2839 18.9H77.7399V20.66H76.2839V18.9ZM81.5055 18.9V30.5H80.0495V18.9H81.5055ZM91.4151 26.676H84.7911C84.8391 28.532 86.1831 29.428 87.4471 29.428C88.7271 29.428 89.4311 28.852 89.7991 28.004H91.3031C90.9191 29.476 89.5431 30.708 87.4471 30.708C84.7271 30.708 83.2231 28.756 83.2231 26.212C83.2231 23.476 85.0471 21.748 87.3991 21.748C90.0391 21.748 91.5911 23.94 91.4151 26.676ZM87.3991 22.996C86.1191 22.996 84.9351 23.7 84.8071 25.428H89.8791C89.8311 24.212 88.9511 22.996 87.3991 22.996Z" fill="#1D1D1D"/>
<path d="M47.0097 30.5V18.8636H51.0779C51.8885 18.8636 52.5571 19.0038 53.0836 19.2841C53.6101 19.5606 54.0022 19.9337 54.2597 20.4034C54.5173 20.8693 54.6461 21.3864 54.6461 21.9545C54.6461 22.4545 54.5571 22.8674 54.3791 23.1932C54.2048 23.5189 53.9738 23.7765 53.6859 23.9659C53.4018 24.1553 53.0931 24.2955 52.7597 24.3864V24.5C53.1158 24.5227 53.4738 24.6477 53.8336 24.875C54.1935 25.1023 54.4946 25.428 54.737 25.8523C54.9794 26.2765 55.1006 26.7955 55.1006 27.4091C55.1006 27.9924 54.9681 28.517 54.7029 28.983C54.4378 29.4489 54.0192 29.8182 53.4472 30.0909C52.8753 30.3636 52.131 30.5 51.2143 30.5H47.0097ZM48.4188 29.25H51.2143C52.1347 29.25 52.7881 29.072 53.1745 28.7159C53.5647 28.3561 53.7597 27.9205 53.7597 27.4091C53.7597 27.0152 53.6594 26.6515 53.4586 26.3182C53.2578 25.9811 52.9719 25.7121 52.6006 25.5114C52.2294 25.3068 51.79 25.2045 51.2825 25.2045H48.4188V29.25ZM48.4188 23.9773H51.0325C51.4567 23.9773 51.8393 23.8939 52.1802 23.7273C52.5249 23.5606 52.7976 23.3258 52.9984 23.0227C53.2029 22.7197 53.3052 22.3636 53.3052 21.9545C53.3052 21.4432 53.1272 21.0095 52.7711 20.6534C52.415 20.2936 51.8506 20.1136 51.0779 20.1136H48.4188V23.9773ZM58.3933 24.9318H60.8933C61.916 24.9318 62.6982 25.1913 63.2399 25.7102C63.7815 26.2292 64.0524 26.8864 64.0524 27.6818C64.0524 28.2045 63.9311 28.6799 63.6887 29.108C63.4463 29.5322 63.0902 29.8712 62.6205 30.125C62.1508 30.375 61.5751 30.5 60.8933 30.5H57.2342V21.7727H58.5751V29.25H60.8933C61.4236 29.25 61.8592 29.1098 62.2001 28.8295C62.541 28.5492 62.7114 28.1894 62.7114 27.75C62.7114 27.2879 62.541 26.911 62.2001 26.6193C61.8592 26.3277 61.4236 26.1818 60.8933 26.1818H58.3933V24.9318ZM65.4387 30.5V21.7727H66.7796V30.5H65.4387ZM70.5751 28.5227L74.7796 21.7727H76.3251V30.5H74.9842V23.75L70.8024 30.5H69.2342V21.7727H70.5751V28.5227ZM73.8933 18.8636H75.1433C75.1433 19.4773 74.9311 19.9792 74.5069 20.3693C74.0827 20.7595 73.5069 20.9545 72.7796 20.9545C72.0637 20.9545 71.4936 20.7595 71.0694 20.3693C70.6489 19.9792 70.4387 19.4773 70.4387 18.8636H71.6887C71.6887 19.1591 71.7702 19.4186 71.933 19.642C72.0997 19.8655 72.3819 19.9773 72.7796 19.9773C73.1774 19.9773 73.4614 19.8655 73.6319 19.642C73.8061 19.4186 73.8933 19.1591 73.8933 18.8636ZM77.5935 23.0227V21.7727H84.6845V23.0227H81.8208V30.5H80.4799V23.0227H77.5935ZM87.9813 28.5227L92.1859 21.7727H93.7313V30.5H92.3904V23.75L88.2086 30.5H86.6404V21.7727H87.9813V28.5227Z" fill="#1D1D1D"/>
<defs>
<clipPath id="clip0_0_55">
<rect width="20" height="20" fill="white" transform="translate(16.96 14.5)"/>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1 +1 @@
export const origin = 'https://dev2.akarpov.ru/'
export const origin = 'https://0e06-92-100-146-65.ngrok-free.app/'

View File

@ -1,60 +1,103 @@
import axios from 'axios';
import { origin } from './config';
export const register = async (username: string, password: string) => {
await axios.post(
origin + 'api/auth/register/',
{
'username': username,
'email': username,
'password': password
}
)
}
export const signin = async (username: string, password: string) => {
const response = await axios.post(
origin + 'api/auth/token/',
{
'username': username,
'password': password
}
);
return response.data;
}
export const startTinder = async () => {
const data = await axios.get(
origin + 'api/tinder/start',
{
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token')
}
}
);
return data.data;
}
export const swipe = async (itemId: string, type: string) => {
var url = origin + 'api/tinder/' + itemId + '/proceed/';
console.log(url, itemId)
try{
const data = await axios.post(
url,
{
'action': type,
},
{
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token')
}
}
);
return data.data;
} catch {
return false
}
import axios from 'axios';
import { origin } from './config';
export const register = async (username: string, password: string) => {
await axios.post(
origin + 'api/auth/register/',
{
'username': username,
'email': username,
'password': password
}
)
}
export const signin = async (username: string, password: string) => {
const response = await axios.post(
origin + 'api/auth/token/',
{
'username': username,
'password': password
}
);
return response.data;
}
export const startTinder = async () => {
const data = await axios.get(
origin + 'api/tinder/start',
{
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token')
}
}
);
return data.data;
}
export const swipe = async (itemId: string, type: string) => {
var url = origin + 'api/tinder/' + itemId + '/proceed/';
console.log(url, itemId)
try{
const data = await axios.post(
url,
{
'action': type,
},
{
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token')
}
}
);
return data.data;
} catch {
return false
}
}
export const dailySelectionGenerate = async () => {
var data = await axios.get(
origin + 'api/recommendations/get_daily_selection/',
{
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token')
}
}
);
return data.data;
}
export const dailySelectionBuild = async (buildData: any) => {
var data = await axios.post(
origin + 'api/recommendations/generate_daily_selection/',
{nodes: buildData},
{
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token')
}
}
);
return data.data;
}
export const saveTinderPath = async (tinderData: any) => {
await axios.post(
origin + 'api/route/save', {
"points": [{
date: '2000-01-01',
paths: tinderData
},]
},
{
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token')
}
}
)
}

View File

@ -7,9 +7,18 @@ import axios from "axios";
// });
export const backend = axios.create({
export let backend = axios.create({
baseURL: 'https://0e06-92-100-146-65.ngrok-free.app/api/',
timeout: 100000,
headers: {'Authorization': 'Bearer ' + localStorage.getItem('token')}
}
)
)
export const updateBackend = () =>{
backend = axios.create({
baseURL: 'https://0e06-92-100-146-65.ngrok-free.app/api/',
timeout: 100000,
headers: {'Authorization': 'Bearer ' + localStorage.getItem('token')}
}
)
}

View File

@ -20,7 +20,7 @@ interface ITinderCard{
export const TinderCardContent: react.FC<ITinderCard> = (props) => {
return <Card className='tinder-card__card'>
<img src='/sample.jpg' width={200} height={200}></img>
<img src='/generateTour.png' width={300} height={300}></img>
<div className="tinder__content">
<span><strong>Название:</strong> {props.title}</span>

View File

@ -1,36 +1,37 @@
.card__container{
background-color: white;
border-radius: 15px;
}
.tinder-card__card{
border-radius: 0px!important;
display: flex;
flex-direction: column;
border: none!important;
gap: 10px;
}
.tinder__content{
display: flex;
flex-direction: column;
border: none!important;
gap: 5px;
padding: 10px;
max-width: 180px;
}
.tin{
display: flex;
flex-direction: column;
gap: 20px;
}
.tin-dir{
display: flex;
width: 700px;
gap: 10px;
}
.main-btn{
background-color: #FFCF08;
.card__container{
background-color: white;
border-radius: 15px;
}
.tinder-card__card{
border-radius: 0px!important;
display: flex;
flex-direction: column;
border: none!important;
gap: 10px;
}
.tinder__content{
display: flex;
flex-direction: column;
border: none!important;
gap: 5px;
padding: 10px;
max-width: 280px;
height: 210px;
}
.tin{
display: flex;
flex-direction: column;
gap: 20px;
}
.tin-dir{
display: flex;
width: 700px;
gap: 10px;
}
.main-btn{
background-color: #FFCF08;
}

View File

@ -41,4 +41,17 @@
align-items: center;
justify-content: center;
gap:10px
}
@media screen and (max-device-width: 500px) {
.choiceIconWrapper{
gap:15px
}
.choiceBtn{
width: 20px;
padding: 10px;
}
.choiceBtnActive{
width: 20px;
padding: 10px;
}
}

View File

@ -9,13 +9,12 @@ export const RusPassHeader:React.FC = () =>{
<div className="headerWrapper">
<div className="iconWrapper">
<img className="headerIcon" src='/logo.svg' onClick={()=>navigate('/')}></img>
<img className="headerIcon" src='/menu.svg' onClick={()=>navigate('/')}></img>
<img className="headerIcon" src='/bonus.svg' onClick={()=>navigate('/event-match')}></img>
<img className="headerIcon" src='/search.svg' onClick={()=>navigate('/')}></img>
<img className="headerIcon delete600" src='/menu.svg' onClick={()=>navigate('/')}></img>
<img className="headerIcon delete600" src='/bonus.svg' onClick={()=>navigate('/event-match')}></img>
<img className="headerIcon delete600" src='/search.svg' onClick={()=>navigate('/')}></img>
</div>
<div className="iconWrapper">
<img className="headerIcon" src='/language.svg'></img>
<img className="headerIcon" src='/support.svg'></img>
<img className="headerIcon delete600" src='/language.svg'></img>
<img className="headerIcon" src='/favorites.svg' onClick={()=>navigate('/favorites')}></img>
<img className="headerIcon" src='/profile.svg'onClick={()=>navigate('/login')} ></img>
</div>

View File

@ -24,4 +24,24 @@
.headerIcon:hover{
transform: scale(1.05);
}
@media screen and (max-device-width: 1000px) {
.headerWrapper{
flex-wrap: wrap;
}
}
@media screen and (max-device-width: 600px) {
.delete600{
display: none;
}
}
@media screen and (max-device-width: 400px) {
.padding{
padding-left: 15px;
padding-right: 15px;
width: calc(100% - 30px);
}
}

View File

@ -58,11 +58,12 @@ export const HotelCard:React.FC<HotelCardIE> = (props) =>{
</div>
</div>
<div>
{props.rooms.map((room)=><div>
{props.rooms != null? props.rooms.map((room)=><div>
<h5>{room.name}</h5>
<div>{room.description}</div>
</div>
)}
) : null
}
</div>
<Button className="" onClick={()=>setOpened(!opened)}>Закрыть</Button>
</div>

View File

@ -12,17 +12,9 @@ import { AttractionCard, AttractionCardIE } from "../AttractionCard";
import { useNavigate } from "react-router-dom";
export const Prefernces = () =>{
const [activeTab, setActiveTab] = useState(1)
const [cities, setCities] = useState([])
const [regions, setRegions] = useState([])
const [hotels, setHotels] = useState([])
const [events, setEvents] = useState([])
useEffect(()=>{
if (cities.length == 0){
backend.get('/data/cities').then((response)=>setCities(response.data))
backend.get('/data/regions').then((response)=>setRegions(response.data))
}
})
const transportOptions = {
@ -255,7 +247,7 @@ export const Prefernces = () =>{
label: `Проживание`,
children: <div>
<div>
<h2>Где вы предпочитаете остановится</h2>
<h2>Где вы предпочитаете остановиться</h2>
<ChoiceIcon {...hotelOptions}></ChoiceIcon>
</div>
<div>
@ -263,7 +255,7 @@ export const Prefernces = () =>{
<ChoiceIcon {...ratingOptions}></ChoiceIcon>
</div>
<div>
<h2>Выберите понравившеися вам отели</h2>
<h2>Выберите понравившиеся вам отели</h2>
<div className='hotelsCardWrapper'>
{
hotels.length == 0? <Spin></Spin>:

View File

@ -3,12 +3,13 @@
position: fixed;
top:0px;
right:0px;
height: 100vh;
height: calc(100vh - 50px);
display: flex;
flex-direction: column;
justify-content: flex-start;
padding: 25px;
background-color: white;
overflow-y: scroll;
}
.prefsHeadWrapper{
@ -20,7 +21,7 @@
}
.prefsbg{
position: absolute;
position: fixed;
right: 0;
top:0;
width: 100%;
@ -39,4 +40,19 @@
align-items: center;
overflow-y: scroll;
margin-bottom: 15px;
}
@media screen and (max-device-width: 700px) {
.prefs{
width: calc(100% - 50px);
}
}
@media screen and (max-device-width: 600px) {
h2{
font-size: 16px;
}
}
@media screen and (max-device-width: 500px) {
}

View File

@ -157,4 +157,29 @@
.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;
}
}

View File

@ -1,14 +1,13 @@
import { AutoComplete, DatePicker, Input, Checkbox, Select, Radio, Space } from 'antd';
import react, { useEffect, useState } from 'react'
import { DatePicker, Checkbox, Select, Radio, Space } from 'antd';
import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom';
import { backend } from '../../consts';
import { backend, updateBackend } from '../../consts';
import { Button } from '../../elements/Button';
import './style.css'
import dayjs from 'dayjs';
import type { RangePickerProps } from 'antd/es/date-picker';
import type { Dayjs } from 'dayjs';
import { propTypes } from 'react-tinder-card';
type RangeValue = [Dayjs | null, Dayjs | null] | null;
@ -19,7 +18,9 @@ export const Search:React.FC<{onSearch?:()=>void}> = (props) =>{
useEffect(()=>{
if (cities.length == 0){
if (cities.length == 0 && localStorage.getItem('token') != null){
updateBackend()
console.log(localStorage.getItem('token'))
backend.get('/data/cities').then((response)=>setCities(response.data))
}
})
@ -79,12 +80,10 @@ export const Search:React.FC<{onSearch?:()=>void}> = (props) =>{
}
let searchParams = {}
if (datesValue.length == 2){
searchParams = {
date_from: new Date((datesValue as any)[0]).toISOString().split('T')[0],
date_to: new Date((datesValue as any)[1]).toISOString().split('T')[0],
let searchParams = {
date_from: datesValue.length == 2? new Date((datesValue as any)[0]).toISOString().split('T')[0]:null,
date_to: datesValue.length == 2? new Date((datesValue as any)[1]).toISOString().split('T')[0]:null,
city: city,
stars:stars,
what_to_see:whatToSee,
@ -94,7 +93,7 @@ export const Search:React.FC<{onSearch?:()=>void}> = (props) =>{
with_animals: withAnimals,
movement: transport
}
}
const disabledDate: RangePickerProps['disabledDate'] = (current:any) => {
if (!dates) {
@ -106,6 +105,8 @@ export const Search:React.FC<{onSearch?:()=>void}> = (props) =>{
return current && current < dayjs().endOf('day') || !!tooEarly || !!tooLate;;
};
const onOpenChange = (open: boolean) => {
if (open) {
setDates([null, null]);
@ -129,7 +130,7 @@ export const Search:React.FC<{onSearch?:()=>void}> = (props) =>{
<img src='/filter.svg'></img>
<div>Фильтры</div>
</div>
<img src='/react.svg'></img>
<img className='rectIMG' src='/react.svg'></img>
<Select
className='antdBorder'
showSearch
@ -148,7 +149,7 @@ export const Search:React.FC<{onSearch?:()=>void}> = (props) =>{
)}
/>
<img src='/react.svg'></img>
<img className='rectIMG' src='/react.svg'></img>
<RangePicker
disabledDate={disabledDate}
onCalendarChange={(val) => {
@ -158,7 +159,7 @@ export const Search:React.FC<{onSearch?:()=>void}> = (props) =>{
changeOnBlur
onChange={(e)=>setDatesValue(e as any)}
></RangePicker>
<img src='/react.svg'></img>
<img className='rectIMG' src='/react.svg'></img>
<Button className='btn-y' onClick={()=>onNavigate()}>Сгенерировать</Button>
</div>
{

View File

@ -1,93 +1,113 @@
import react, { useRef } from 'react'
import TinderCard from 'react-tinder-card'
import './style.css'
import { Block } from '../../elements/Block'
import { Card, TinderCardContent } from '../../elements/Card'
import { Button } from '../../elements/Button'
import { startTinder, swipe, } from '../../client'
import {useNavigate} from 'react-router-dom';
interface IEventData{
title: string;
description: string;
id: string;
}
export const EventMatch: react.FC = () => {
const ref = useRef(null);
const navigate = useNavigate();
const started = useRef(false);
const swiping = useRef(false);
const [cardData, setCardData] = react.useState({title: "", description: "", id: ''} as IEventData);
const data = react.useRef({title: "", description: "", id: ''} as IEventData)
if (!started.current) {
started.current = true;
startTinder().then((e) => {
data.current = {
title: e.title,
description: e.description.split(' ').slice(0, 10).join(' '),
id: e.oid
};
setCardData({
title: e.title,
description: e.description.split(' ').slice(0, 10).join(' '),
id: e.oid
});
})
}
return <div className='centered tin'>
<Block className='tinder-block'>
<TinderCard ref={ref} onSwipe={(type) => {
console.log("swipe");
if (swiping.current) return;
swiping.current = true;
swipe(data.current.id, type).then((e) => {
if (!e) {
navigate('/');
return;
}
data.current = {
title: e.event.title,
description: e.event.description.split(' ').slice(0, 10).join(' '),
id: e.event.oid
};
setCardData(
{
title: e.event.title,
description: e.event.description.split(' ').slice(0, 10).join(' '),
id: e.event.oid
}
);
setTimeout(() => {
(ref.current as any).restoreCard();
swiping.current = false;
}, 2000);
})
}}>
<Card className=''>
<TinderCardContent
title={data.current.title}
description={data.current.description}
></TinderCardContent>
</Card>
</TinderCard>
</Block>
<Block className='tin-dir'>
<Button className='' onClick={() => {
(ref.current as any).swipe('left')
}}>Не нравится</Button>
<Button className='main-btn'>На главную</Button>
<Button className='' onClick={() => {
(ref.current as any).swipe('right')
}}>Нравится</Button>
</Block>
</div>
import react, { useRef, useState } from 'react'
import TinderCard from 'react-tinder-card'
import './style.css'
import { Block } from '../../elements/Block'
import { Card, TinderCardContent } from '../../elements/Card'
import { Button } from '../../elements/Button'
import { dailySelectionBuild, dailySelectionGenerate, saveTinderPath, startTinder, swipe, } from '../../client'
import {useNavigate} from 'react-router-dom';
import { MyMap } from '../../elements/map'
import { RusPassHeader } from '../../elements/Header'
interface IEventData{
title: string;
description: string;
id: string;
}
export const EventMatch: react.FC = () => {
const ref = useRef(null);
const navigate = useNavigate();
const started = useRef(false);
const [dailyData, setDailyData] = useState([]);
const [resData, setResData] = useState<any[]>([]);
const queried = useRef(false);
const [answerData, setAnswerData] = useState([]);
if (!started.current) {
started.current = true;
dailySelectionGenerate().then((e) => {
console.log(e)
setDailyData(e.events);
})
}
return <div className='centered tin'>
<RusPassHeader></RusPassHeader>
<Block className='tinder-block'>
{
dailyData.map((e) => {
return <TinderCard
ref={ref}
className='card'
onSwipe={(type) => {
console.log(dailyData.indexOf(e))
if (dailyData.indexOf(e) == 0) {
if (!resData.length) return;
if (!queried.current) {
dailySelectionBuild(resData).then((e) => {
setAnswerData(e.path);
});
queried.current = true;
}
}
if (type == 'right') {
setResData(resData.concat([
{
'action': 'right',
'oid': (e as any).oid
} as any
]))
}
}}
>
<Card className=''>
<TinderCardContent
title={dailyData.length ? (e as any).title : ""}
description={dailyData.length ? (e as any).description.slice(0, 70) : ""}
></TinderCardContent>
</Card>
</TinderCard>
})
}
<div className='cont-span'>
{
dailyData.length && !answerData.length ?
(!queried.current ?
<div className='span-cont'><span className='span-er'>Вы не выбрали ни одного события, Мы не можем сгенерировать вам маршрут. Возвращяйтесь к нам завтра. <a
href="" onClick={() => {
navigate('/');
}}
>Вернуться на главную</a></span></div> : <span>Подождите немного, мы генерируем для вас ежедневный маршрут</span>) : answerData.length ? <MyMap points={
answerData.filter((e: any) => e.type == 'point').map((e: any) => {return {
cords: [e.point.lat, e.point.lon],
title: e.point.title,
description: ""
}})
}></MyMap> : <></>
}
{
answerData.length ? <div className='btns'>
<Button onClick={() => {
saveTinderPath(answerData);
navigate('/');
}} className=''>
Сохранить
</Button>
<Button onClick={() => {
navigate('/');
}} className=''>
На главную
</Button>
</div> : <></>
}
</div>
</Block>
</div>
}

View File

@ -1,9 +1,59 @@
.tinder-block{
width: 700px;
display: flex;
justify-content: center;
}
.main-btn{
background-color: #FFCF08;
.tinder-block{
width: 700px;
display: flex;
justify-content: center;
}
.main-btn{
background-color: #FFCF08;
}
.tinder-block{
height: 600px;
}
.card{
position: absolute;
}
.span-er{
width: 250px;
text-align: center;
}
a{
color: black;
}
a:visited{
color: black;
}
.btns{
display: flex;
flex-direction: column;
gap: 10px;
margin-top: 20px;
}
.cont-span{
display: flex;
justify-content: center;
flex-direction: column;
width: 500px;
}
.span-cont{
display: flex;
justify-content: center;
}
@media screen and (max-device-width: 800px) {
.tinder-block{
width: auto;
padding: 10px;
}
.cont-span{
width: auto;
padding: 50px;
align-items: center ;
}
}

View File

@ -25,6 +25,7 @@ export const Login: react.FC = () => {
<Input placeholder='Пароль' className='reg-input' onChange={setPassword}/>
<Button className='' onClick={() => {
signin(username, password).then((e) => {
console.log(e)
localStorage.setItem('token', e.access);
localStorage.setItem('firstAuth', 'true');
@ -36,9 +37,9 @@ export const Login: react.FC = () => {
<span>или</span>
<div className="sep-item"></div>
</div>
<YandexLogin clientID={clientID} onSuccess={() => {}}>
<button className="btn-y">Yandex login</button>
</YandexLogin>
<Button className='login-btn-y' onClick={()=>navigate('/register')}>Зарегистрироваться</Button>
</Block>
</div>
}

View File

@ -20,8 +20,7 @@
width: 400px;
}
.btn-y{
width: 440px!important;
.login-btn-y{
background-color: #FFCF08;
border-radius: 10px;
padding: 15px 50px;

View File

@ -1,7 +1,7 @@
import { AutoComplete, DatePicker, Input, Checkbox, Select, Radio, Space, Spin } from 'antd';
import react, { useEffect, useState } from 'react'
import react, { useEffect, useRef, useState } from 'react'
import { useNavigate } from 'react-router-dom';
import { backend } from '../../consts';
import { backend, updateBackend } from '../../consts';
import { Button } from '../../elements/Button';
import { FavoriteCard, FavoriteCardIE } from '../../elements/FavoriteCard';
import { GenerateCard } from '../../elements/GenerateCard';
@ -21,31 +21,42 @@ export const Main: react.FC = () => {
let navigate = useNavigate()
let token = localStorage.getItem('token')
let firstAuth = localStorage.getItem('firstAuth')
console.log(token)
const queried = useRef(false);
useEffect(()=>{
updateBackend()
const dataLoad = async () =>{
const favorites = await backend.get('user/favorite')
const events = await backend.get('recommendations/recommendations/')
return {
favorites, events
}
}
if (!queried.current && localStorage.getItem('token') != null && localStorage.getItem('firstAuth') != 'true') {
queried.current = true;
dataLoad().then((data) => {
setFavorites(data.favorites.data as any);
setEvents(data.events.data as any);
})
}
if (null == localStorage.getItem('token')){
navigate('/login')
}
if (favorites.length == 0){
backend.get('user/favorite').then((e)=>setFavorites(e.data))
}
if (events.length == 0){
backend.get('recommendations/recommendations/').then((e)=>setEvents(e.data as any));
}
// if (favorites.length == 0){
// backend.get('user/favorite').then((e)=>setFavorites(e.data))
// }
// if (events.length == 0){
// backend.get('recommendations/recommendations/').then((e)=>setEvents(e.data as any));
// }
})
const favoriteCardProps = {
imageURL:'restourant.png',
title:'Кафе Сказка',
location:'Казань'
} as FavoriteCardIE
return (
<div className='mainWrapper'>
{
@ -53,7 +64,10 @@ export const Main: react.FC = () => {
}
<RusPassHeader></RusPassHeader>
<div className='headMainWrapper'>
<img className='backgroundIMG' src='background.png'></img>
<div className='backgroundMainIMG'>
<div className='imgHeader'>Сгенерируйте ваш идеальный тур</div>
<div className='imgDescr'>Туры, достопримечательности, отели - все в одном cервисе</div>
</div>
<Search onSearch={()=>null}></Search>
</div>
<div className='mainCard'>
@ -102,7 +116,7 @@ export const Main: react.FC = () => {
</div>
</div>
<a href='/'>Документация</a>
<a href='https://1drv.ms/w/s!AuaFmGWFNV5Np0OhMmVtxPXlG2Ob?e=f7NDCp'>Документация</a>
<div className='mainIconWrapper'>
<img className='mainIcon' src='icons/yt.svg'></img>

View File

@ -1,6 +1,6 @@
.mainCard{
background-color: #FFFBF3;
width: сalc(100%-100px);
width: calc(100%-100px);
margin: 0px 50px;
display: flex;
flex-direction: column;
@ -9,9 +9,9 @@
padding: 50px;
width: calc(100% - 200px);
}
.mainCard>h2{
display: inline-block;
width: 400px;
}
.cardWrapper{
@ -24,9 +24,10 @@
.fav-wrapper{
display: flex;
justify-content: space-between;
justify-content: center;
gap: 25px;
flex-wrap: wrap;
align-items: center;
}
.grey{
@ -80,8 +81,18 @@
}
.backgroundIMG{
width: calc(100% - 100px);
.backgroundMainIMG{
width: calc(100% - 260px);
height: 25vh;
background-image: url('../../../public/background.png');
background-size: cover;
border-radius: 48px;
display: flex;
padding: 80px;
flex-direction: column;
align-items: center;
justify-content: flex-end;
gap:20px
}
.rowWrapper{
@ -121,3 +132,51 @@
.ant-select-selector, .ant-picker{
border: 0px !important;
}
.imgHeader{
font-style: normal;
font-weight: 600;
font-size: 44px;
line-height: 46px;
color: #FFFFFF;
text-align: center;
}
.imgDescr{
font-style: normal;
font-weight: 500;
font-size: 20px;
line-height: 24px;
display: flex;
align-items: flex-end;
text-align: center;
color: #FFFFFF;
}
@media screen and (max-device-width: 700px) {
.imgHeader{
font-size: 24px;
line-height: 28px;
}
.imgDescr{
font-size: 18px;
line-height: 22px;
}
.mainCard{
padding: 25px !important;
margin: 0px 25px !important;
border-radius: 20px !important;
}
}
@media screen and (max-device-width: 500px) {
.backgroundMainIMG{
width: calc(100% - 90px) !important;
padding: 20px !important;
padding-bottom: 60px !important;
}
}

View File

@ -38,9 +38,8 @@ export const Register: react.FC = () => {
<span>или</span>
<div className="sep-item"></div>
</div>
<YandexLogin clientID={clientID} onSuccess={() => {}}>
<button className="btn-y">Yandex login</button>
</YandexLogin>
<Button className='login-btn-y' onClick={()=>navigate('/login')}>Войти</Button>
</Block>
</div>
}

View File

@ -20,12 +20,23 @@
width: 400px;
}
.btn-y{
width: 440px!important;
.login-btn-y{
background-color: #FFCF08;
border-radius: 10px;
padding: 15px 50px;
outline: none;
border: none;
cursor: pointer;
}
@media screen and (max-device-width: 600px) {
.reg-input{
width: 280px !important;
}
}
@media screen and (max-device-width: 600px) {
.reg-input{
width: 200px !important;
}
}

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import { useParams } from "react-router-dom";
import { backend } from "../../consts";
import { RouteCard, RouteCardIE } from "../../elements/RouteCard";
@ -11,18 +11,28 @@ import { EventCard } from "../../elements/EventCard";
export const SearchPage:React.FC = () =>{
let { prefs } = useParams();
const [cities, setCities] = useState([])
const [data, setData] = useState([])
const [events, setEvents] = useState([])
useEffect(()=>{
if (cities.length == 0){
backend.get('/data/cities').then((response)=>setCities(response.data))
backend.post('/route/build',JSON.parse(prefs as string)).then((r)=>setData(r.data as any))
backend.post('/recommendations/build_events/',JSON.parse(prefs as string)).then((r)=>setEvents(r.data as any))
}
})
const queried = useRef(false);
useEffect(()=>{
const dataLoad = async (prefs: string) => {
const routes = await backend.post('/route/build',JSON.parse(prefs as string))
const events = await backend.post('/recommendations/build_events/',JSON.parse(prefs as string))
return {
routes, events
}
}
if (!queried.current) {
queried.current = true;
dataLoad(prefs as string).then((data) => {
setData(data.routes.data as any);
setEvents(data.events.data as any);
})
}
}, [prefs])
console.log(events)
let newData;
@ -62,21 +72,12 @@ export const SearchPage:React.FC = () =>{
const onSearch = () =>{
setData([])
}
const contentStyle: React.CSSProperties = {
height: '160px',
color: '#fff',
lineHeight: '160px',
textAlign: 'center',
background: '#364d79',
};
return(
<div className="mainWrapper">
<RusPassHeader></RusPassHeader>
<h1>Посмотрите, что мы нашли по вашему запросу</h1>
<Search onSearch={()=>onSearch()}></Search>
{
@ -112,7 +113,7 @@ export const SearchPage:React.FC = () =>{
}
<a href='/'>Документация</a>
<a href='https://1drv.ms/w/s!AuaFmGWFNV5Np0OhMmVtxPXlG2Ob?e=f7NDCp'>Документация</a>
<div className='mainIconWrapper'>
<img className='mainIcon' src='/icons/yt.svg'></img>

View File

@ -1,6 +1,5 @@
.mainCard{
background-color: #FFFBF3;
width: сalc(100%-100px);
margin: 0px 50px;
display: flex;
flex-direction: column;
@ -21,7 +20,7 @@
.fav-wrapper{
display: flex;
justify-content: space-between;
justify-content: center;
gap: 25px;
flex-wrap: wrap;
}
@ -53,6 +52,7 @@
justify-content: center;
align-items: center;
padding-bottom: 100px;
width: 100%;
}
@ -118,3 +118,42 @@
.ant-select-selector, .ant-picker{
border: 0px !important;
}
@media screen and (max-device-width: 1000px) {
.toolsMainWrapper{
flex-wrap: wrap;
align-items: center;
justify-content: center;
padding: 10px 15px;
}
.rectIMG{
display: none;
}
.mainCard{
padding: 25px !important;
margin: 0px 25px !important;
border-radius: 20px !important;
}
}
@media screen and (max-device-width: 700px) {
h1{
font-size: 24px;
text-align: center;
}
}
@media screen and (max-device-width: 500px) {
.mainCard{
margin: 0px 15px !important;
padding: 10px;
width: calc(100% - 100px);
}
h1{
width: 100%;
font-size: 16px;
text-align: center;
margin-top: -50px;
}
}

View File

@ -1,5 +1,5 @@
import {
createBrowserRouter
createBrowserRouter, createHashRouter
} from 'react-router-dom'
import App from './App'
import { Register } from './pages/Register';
@ -7,8 +7,8 @@ import { Login } from './pages/Login';
import { Main } from './pages/Main';
import { EventMatch } from './pages/EventMatch';
import { GenerateTour } from './pages/GenerateTour';
import { Prefernces } from './elements/Prefernces';
import { SearchPage } from './pages/SearchPage';
import { Prefernces } from './elements/Prefernces';
const routes = [
@ -47,4 +47,4 @@ const routes = [
]
export const router = createBrowserRouter(routes);
export const router = createHashRouter(routes);