update page favorites react
This commit is contained in:
parent
7568268621
commit
9b9956dcaa
|
@ -0,0 +1,18 @@
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
export default class ApartamentService {
|
||||||
|
static async getAll(limit, offest) {
|
||||||
|
const response = await axios.get('http://127.0.0.1:8000/api/apartaments/', {
|
||||||
|
params: {
|
||||||
|
limit: limit,
|
||||||
|
...(offest !== 0 ? {offset: offest} : {})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async getById(id) {
|
||||||
|
const response = await axios.get('http://127.0.0.1:8000/api/apartament/' + id)
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,3 +24,59 @@ main{
|
||||||
height: 1px;
|
height: 1px;
|
||||||
background-color: #CCC;
|
background-color: #CCC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*Кнопки выбора страницы*/
|
||||||
|
.btnSection{
|
||||||
|
display: flex;
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Кнопка "Показать весь список*/
|
||||||
|
.allBtn{
|
||||||
|
width: 208px;
|
||||||
|
height: 32px;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Кнопки переключения страниц*/
|
||||||
|
.choiceBtn{
|
||||||
|
display: flex;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Кнопки "предыдущая" и "следующая"*/
|
||||||
|
.btnPrevious, .btnNext {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btnNext{
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pageBtn{
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
margin-left: 10px;
|
||||||
|
background: #D9D9D9;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activePage{
|
||||||
|
border: 2px solid #175FA9;
|
||||||
|
background-color: #fff;
|
||||||
|
color: #175FA9;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
import React from 'react';
|
||||||
|
import './styles/CardSmallApartament.css';
|
||||||
|
|
||||||
|
const CardSmallApartament = function (props) {
|
||||||
|
return (
|
||||||
|
<div className="viewedElem">
|
||||||
|
<img src="/images/apartment.png" alt=""></img>
|
||||||
|
<p>{props.results.perimetrs} м², {props.results.rooms}-х комнатная</p>
|
||||||
|
<h3>{props.results.price}₽ / мес.</h3>
|
||||||
|
<p>{props.results.address}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CardSmallApartament;
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*Квартира*/
|
||||||
|
.viewedElem{
|
||||||
|
width: 24%;
|
||||||
|
padding-bottom: 1%;
|
||||||
|
background: #fff;
|
||||||
|
border: 2px solid #ccc;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewedElem img{
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 3%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewedElem h3, .viewedElem p{
|
||||||
|
margin-left: 5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewedElem h3{
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 24px;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewedElem p{
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #222;
|
||||||
|
}
|
|
@ -1,29 +1,31 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React from 'react';
|
||||||
import CardApartament from '../../components/CardApartament/CardApartament';
|
|
||||||
import axios from 'axios'; /* БЛЯ 10 КБ СУКА */
|
import FavoritesApartamentsList from './FavoritesApartamentsList';
|
||||||
|
import LastView from '../../components/LastView/LastView';
|
||||||
|
|
||||||
import './styles/Favorites.css';
|
import './styles/Favorites.css';
|
||||||
|
|
||||||
const Favorites = function () {
|
const Favorites = function () {
|
||||||
const [apartaments, setApartaments] = useState([])
|
|
||||||
|
|
||||||
async function fetchApartaments() {
|
|
||||||
const response = await axios.get('http://127.0.0.1:8000/api/apartaments/')
|
|
||||||
setApartaments(response.data.results)
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchApartaments()
|
|
||||||
})
|
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<>
|
<>
|
||||||
<h2>Избранное</h2>
|
<h2>Избранное</h2>
|
||||||
{apartaments.map((apartament, index) =>
|
<FavoritesApartamentsList/>
|
||||||
<>
|
<section className="questionBtnSection">
|
||||||
<CardApartament results={apartament}/>
|
<button className="questionBtn orangeBtn">
|
||||||
<div className="separationLine"></div>
|
<h3>Рестик или кафешка?</h3>
|
||||||
</>
|
<p>Какой общепит предпочтительнее для вас возле жилища?</p>
|
||||||
)}
|
</button>
|
||||||
|
<button className="questionBtn greenBtn">
|
||||||
|
<h3>Двушка или однушка?</h3>
|
||||||
|
<p>Как выбрать квартиру под себя, чтобы не переплачивать?</p>
|
||||||
|
</button>
|
||||||
|
<button className="questionBtn blueBtn">
|
||||||
|
<h3>Совмещенный или отдельно?</h3>
|
||||||
|
<p>Какой санузел будет для вас лучшим вариантом?</p>
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
<LastView/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import ApartamentService from '../../API/ApartamentService';
|
||||||
|
import {useFetching} from '../../hooks/useFetching';
|
||||||
|
import {getPageCount} from '../../utils/Pages';
|
||||||
|
|
||||||
|
import CardApartament from '../../components/CardApartament/CardApartament';
|
||||||
|
import Pagination from '../../components/UI/Pagination/Pagination';
|
||||||
|
|
||||||
|
const FavoritesApartamentsList = () => {
|
||||||
|
const [apartaments, setApartaments] = useState([])
|
||||||
|
const [totalPages, setTotalPages] = useState(0);
|
||||||
|
const limit = 1;
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
|
||||||
|
const [fetchApartaments, isApartamentsLoading, apartamentsError] = useFetching(async (limit) => {
|
||||||
|
let offset = (page - 1) * limit;
|
||||||
|
const response = await ApartamentService.getAll(limit, offset);
|
||||||
|
setApartaments(response.data.results)
|
||||||
|
const totalCount = response.data.count
|
||||||
|
setTotalPages(getPageCount(totalCount, limit))
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchApartaments(limit)
|
||||||
|
}, [page])
|
||||||
|
|
||||||
|
const changePage = (page) => {
|
||||||
|
setPage(page)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Переделать, сейчас сделанно для MVP (то есть заглушки)
|
||||||
|
if (!apartaments.length && !isApartamentsLoading && !apartamentsError) {
|
||||||
|
return (
|
||||||
|
<h1 style={{textAlign: 'center'}}>В избранном ничего нет :/</h1>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apartamentsError){
|
||||||
|
return(
|
||||||
|
<h1 style={{textAlign: 'center'}}>Произошла ошибка ({apartamentsError})</h1>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{isApartamentsLoading &&
|
||||||
|
<h1 style={{textAlign: 'center'}}>Идет загрузка...</h1>
|
||||||
|
}
|
||||||
|
{apartaments.map((apartament, index) =>
|
||||||
|
<>
|
||||||
|
<CardApartament results={apartament}/>
|
||||||
|
<div className="separationLine"></div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<Pagination page={page} changePage={changePage} totalPages={totalPages}/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FavoritesApartamentsList;
|
|
@ -14,3 +14,54 @@ h2{
|
||||||
margin-left: 34%;
|
margin-left: 34%;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*Кнопки с вопросами*/
|
||||||
|
.questionBtnSection{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.questionBtn{
|
||||||
|
width: 323px;
|
||||||
|
height: 128px;
|
||||||
|
padding: 2% 5% 2% 3%;
|
||||||
|
border-radius: 12px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.questionBtn h3{
|
||||||
|
font-size: 18px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.questionBtn p{
|
||||||
|
margin-top: 16px;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 19px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orangeBtn{
|
||||||
|
background: linear-gradient(180deg, #F76D09 0%, #FFA800 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.orangeBtn:active{
|
||||||
|
background: linear-gradient(180deg, #FFA800 0%, #F76D09 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.greenBtn{
|
||||||
|
background: linear-gradient(180deg, #107A34 0%, #51A633 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.greenBtn:active{
|
||||||
|
background: linear-gradient(180deg, #51A633 0%, #107A34 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.blueBtn{
|
||||||
|
background: linear-gradient(180deg, #2E50A7 0%, #0993F7 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.blueBtn:active{
|
||||||
|
background: linear-gradient(180deg, #0993F7 0%, #2E50A7 100%);
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import CardSmallApartament from '../../components/CardSmallApartament/CardSmallApartament';
|
||||||
|
import axios from 'axios';
|
||||||
|
import './styles/LastView.css';
|
||||||
|
|
||||||
|
const LastView = function () {
|
||||||
|
const [apartamentsLastView, setApartamentsLastView] = useState([])
|
||||||
|
|
||||||
|
async function fetchLastApartamentsView() {
|
||||||
|
const response = await axios.get('http://127.0.0.1:8000/api/apartaments/')
|
||||||
|
setApartamentsLastView(response.data.results)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchLastApartamentsView()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return(
|
||||||
|
<>
|
||||||
|
<section className="viewedSection">
|
||||||
|
<div className="viewedTittle">
|
||||||
|
<h2>Недавно просмотренные <span>15</span></h2>
|
||||||
|
<div className="viewedBtnSection">
|
||||||
|
<button className="btnViewed">Посмотреть все Недавние</button>
|
||||||
|
<div className="viewedBtn">
|
||||||
|
<button className="btnPrevious">
|
||||||
|
<svg width="9" height="16" viewBox="0 0 9 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0.238707 8.62179L6.83881 15.7424C7.15713 16.0859 7.6732 16.0859 7.99148 15.7424L8.76127 14.9119C9.07904 14.5691 9.07965 14.0134 8.76263 13.6698L3.53193 7.99998L8.76263 2.33019C9.07965 1.98655 9.07904 1.43091 8.76127 1.08808L7.99148 0.257567C7.67316 -0.0858556 7.15709 -0.0858556 6.83881 0.257567L0.238741 7.37821C-0.0795746 7.72159 -0.0795746 8.27837 0.238707 8.62179Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button className="btnNext">
|
||||||
|
<svg width="9" height="16" viewBox="0 0 9 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.76129 8.62179L2.16119 15.7424C1.84287 16.0859 1.3268 16.0859 1.00852 15.7424L0.238729 14.9119C-0.0790435 14.5691 -0.0796547 14.0134 0.237371 13.6698L5.46807 7.99998L0.237371 2.33019C-0.0796547 1.98655 -0.0790435 1.43091 0.238729 1.08808L1.00852 0.257567C1.32684 -0.0858556 1.84291 -0.0858556 2.16119 0.257567L8.76126 7.37821C9.07957 7.72159 9.07957 8.27837 8.76129 8.62179Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="viewedBlock">
|
||||||
|
{apartamentsLastView.map((apartament, index) =>
|
||||||
|
<>
|
||||||
|
<CardSmallApartament key={index} results={apartament}/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LastView;
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*Недавно просмотренные*/
|
||||||
|
.viewedSection{
|
||||||
|
margin-top: 46px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewedTittle{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewedTittle h2{
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 20px;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewedTittle span{
|
||||||
|
margin-left: 30px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #A9A9A9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Кнопки*/
|
||||||
|
.viewedBtnSection{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Кнопка "посмотреть все недавние"*/
|
||||||
|
.btnViewed{
|
||||||
|
width: 208px;
|
||||||
|
height: 32px;
|
||||||
|
margin-top: 15px;
|
||||||
|
margin-right: 22px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #CCCCCC;
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Кнопки "предыдущие" и "следующие"*/
|
||||||
|
.viewedBtn{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Недавно просмотренные квартиры*/
|
||||||
|
.viewedBlock{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 27px;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
import React from 'react';
|
||||||
|
import {getPagesArray} from "../../../utils/Pages";
|
||||||
|
|
||||||
|
const Pagination = ({totalPages, page, changePage}) => {
|
||||||
|
let pagesArray = getPagesArray(totalPages);
|
||||||
|
let previousPage = page !== 1 ? page - 1 : page
|
||||||
|
let nextPage = page < pagesArray.length ? page + 1 : page
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="btnSection">
|
||||||
|
<button className="allBtn">Показать весь список</button>
|
||||||
|
<div className="choiceBtn">
|
||||||
|
<button onClick={() => changePage(previousPage)} className="btnPrevious">
|
||||||
|
<svg width="9" height="16" viewBox="0 0 9 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0.238707 8.62179L6.83881 15.7424C7.15713 16.0859 7.6732 16.0859 7.99148 15.7424L8.76127 14.9119C9.07904 14.5691 9.07965 14.0134 8.76263 13.6698L3.53193 7.99998L8.76263 2.33019C9.07965 1.98655 9.07904 1.43091 8.76127 1.08808L7.99148 0.257567C7.67316 -0.0858556 7.15709 -0.0858556 6.83881 0.257567L0.238741 7.37821C-0.0795746 7.72159 -0.0795746 8.27837 0.238707 8.62179Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
{pagesArray.map(p =>
|
||||||
|
<button onClick={() => changePage(p)} key={p} className={page === p ? "pageBtn activePage" : "pageBtn"}>{p}</button>
|
||||||
|
)}
|
||||||
|
<button onClick={() => changePage(nextPage)} className="btnNext">
|
||||||
|
<svg width="9" height="16" viewBox="0 0 9 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.76129 8.62179L2.16119 15.7424C1.84287 16.0859 1.3268 16.0859 1.00852 15.7424L0.238729 14.9119C-0.0790435 14.5691 -0.0796547 14.0134 0.237371 13.6698L5.46807 7.99998L0.237371 2.33019C-0.0796547 1.98655 -0.0790435 1.43091 0.238729 1.08808L1.00852 0.257567C1.32684 -0.0858556 1.84291 -0.0858556 2.16119 0.257567L8.76126 7.37821C9.07957 7.72159 9.07957 8.27837 8.76129 8.62179Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Pagination;
|
|
@ -0,0 +1,19 @@
|
||||||
|
import {useState} from "react";
|
||||||
|
|
||||||
|
export const useFetching = (callback) => {
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [error, setError] = useState('');
|
||||||
|
|
||||||
|
const fetching = async (...args) => {
|
||||||
|
try {
|
||||||
|
setIsLoading(true)
|
||||||
|
await callback(...args)
|
||||||
|
} catch (e) {
|
||||||
|
setError(e.message);
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [fetching, isLoading, error]
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
export const getPageCount = (totalCount, limit) => {
|
||||||
|
return Math.ceil(totalCount / limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getPagesArray = (totalPages) => {
|
||||||
|
let result = [];
|
||||||
|
for (let i = 0; i < totalPages; i++) {
|
||||||
|
result.push(i + 1)
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
Loading…
Reference in New Issue