update page favorites react

This commit is contained in:
Александр Манаенков 2023-05-04 22:16:25 +10:00
parent 7568268621
commit 9b9956dcaa
13 changed files with 415 additions and 19 deletions

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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/>
</> </>
); );
} }

View File

@ -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;

View File

@ -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%);
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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]
}

View File

@ -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;
}