Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ShelterPetsPage #242

Merged
merged 11 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/components/PetCard/PetCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import maleIcon from '../../images/icons/ic_male.svg';
import femaleIcon from '../../images/icons/ic_female.svg';

const PetCard = ({
id, shelterId, name, age, sex, gallery,
name, age, sex, gallery, link
}) => {
return (
<Link
className='pet-card'
to={`/shelters/${shelterId}/pets/${id}`}
to={link}
>
<img className='pet-card__photo' src={gallery[0].image} alt={name} />
<div className='pet-card__cover' />
Expand Down
3 changes: 3 additions & 0 deletions src/images/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/modules/PetModule/styles/pet-module.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.pet-module {
display: flex;
width: 1440px;
width: 100%;

&__pet-part {
display: flex;
Expand Down
5 changes: 5 additions & 0 deletions src/modules/ShelterOwnerStatistics/ShelterOwnerStatistics.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import ShelterMetricsOverview from '../../components/ShelterMetricsOverview/Shel

const ShelterOwnerStatistics = ({ shelter }) => {
const metrics = [
{ title: 'Количество питомцев: ',
valueKey: shelter.count_pets,
actionText: 'Посмотреть всех питомцев',
path: `/profile/my-shelter/${shelter.id}/all-pets` },
{ title: 'Количество вакансий: ', valueKey: shelter.count_pets, actionText: 'Посмотреть все вакансии', path: '/' },
{ title: 'Количество питомцев: ', valueKey: shelter.count_pets, actionText: 'Посмотреть всех питомцев', path: '/' },
karlbelousov marked this conversation as resolved.
Show resolved Hide resolved
{ title: 'Количество вакансий: ', valueKey: shelter.count_vacancies, actionText: 'Посмотреть все вакансии', path: `/shelters/${shelter.id}/vacancies` },
karlbelousov marked this conversation as resolved.
Show resolved Hide resolved
{ title: 'Количество тегов: ', valueKey: shelter.count_pets, actionText: 'Посмотреть все теги', path: '/' },
Expand Down
160 changes: 160 additions & 0 deletions src/modules/ShelterPetsType/ShelterPetsType.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import React, { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import shelterPetsApi from './api';
import './ShelterPetsType.scss';
import PetCard from '../../components/PetCard/PetCard';
import { Button } from '../../ui';
import DeleteIcon from '../../images/DeleteIcon/DeleteIcon';

const ShelterPetsType = ({ type }) => {
const { id } = useParams();
const [pets, setPets] = useState([]);
const [isChecked, setIsChecked] = useState(false);
const [isSelected, setIsSelected] = useState(false);
const [checkedId, setCheckedId] = useState([]);

useEffect(() => {
shelterPetsApi
.getPetsByShelterId(id, type, 24, 0)
.then((res) => {
setPets(res.results);
})
.catch((err) => {
throw new Error(err);
});
}, []);

let petType;
switch (type.toLowerCase()) {
case 'cat':
petType = 'Кошки';
break;
case 'dog':
petType = 'Собаки';
break;
case 'parrot':
petType = 'Попугаи';
break;
case 'hamster':
petType = 'Хомяки';
break;
default:
petType = '';
}
const handleButtonSelectedClick = () => {
setIsSelected(true);
};
const handleButtonCancelSelectedClick = () => {
setIsSelected(false);
setCheckedId([]);
};
const handleButtonSelectedAllClick = () => {
setIsSelected(true);
setIsChecked(true);
setCheckedId((items) => {
return [...items, ...pets];
});
};
const handleButtonCancelSelectedAllClick = () => {
setIsSelected(false);
setIsChecked(false);
setCheckedId([]);
};
const handleChangePet = (pet) => {
if (!checkedId.includes(pet)) {
setCheckedId((items) => {
return [...items, pet];
});
} else {
setCheckedId (
checkedId.filter((petsId) => {
return !(petsId === pet);
})
);
}
};

return (
<div className='shelter-pets-type'>
<div className='shelter-pets-type__header'>
<h2 className='shelter-pets-type__title'>{petType}</h2>
<div className='shelter-pets-type__controls'>
{checkedId.length !== 0 ? (
<Button theme='tertiary' className='shelter-pets-type__btn-deleted'>
<DeleteIcon />
Удалить
</Button>
) : null}
{pets.length !== 0 ? (
<>
{!isSelected && !isChecked && <Button
theme='tertiary'
className='shelter-pets-type__btn-selected'
onClick={handleButtonSelectedClick}
>
Выбрать
</Button>}
{isSelected && !isChecked && <Button
theme='tertiary'
className='shelter-pets-type__btn-cancel-selected'
onClick={handleButtonCancelSelectedClick}
>
Отменить выбор
</Button>}
{!isChecked && <Button
theme='tertiary'
className='shelter-pets-type__btn-selected'
onClick={handleButtonSelectedAllClick}
>
Выбрать все
</Button>}
{isChecked && <Button
theme='tertiary'
className='shelter-pets-type__btn-cancel-selected'
onClick={handleButtonCancelSelectedAllClick}
>
Отменить выбор
</Button>}
</>
) : (
<Button
theme='tertiary'
>
Удалить
</Button>
)
}
</div>
</div>
{pets.length !== 0 ? (
<ul className='shelter-pets-type__list'>
{pets.map((pet) => {
const isCheckedPet = checkedId.includes(pet);
const className = `${isSelected ? 'shelter-pets-type__input_selected' : ''} ${isCheckedPet ? 'shelter-pets-type__input_checked' : ''}`;
return (
<li className='shelter-pets-type__list-item' key={pet.id}>
<input
className={`shelter-pets-type__input ${className}`}
type='checkbox'
onChange={() => {
handleChangePet(pet);
}}
/>
<PetCard
link={!isSelected ? `../${id}/pets/${pet.id}` : ''}
id={pet.id}
name={pet.name}
age={pet.age}
sex={pet.sex}
gallery={pet.gallery}
/>
</li>
);
})}
</ul>
) : null}
</div>
);
};

export default ShelterPetsType;
111 changes: 111 additions & 0 deletions src/modules/ShelterPetsType/ShelterPetsType.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
.shelter-pets-type {
width: 100%;
margin-bottom: 40px;
}

.shelter-pets-type__header {
display: flex;
justify-content: space-between;
align-items: center;
}

.shelter-pets-type__controls {
width: 646px;
display: flex;
justify-content: flex-end;
align-items: center;
gap: 0 24px;
}

.shelter-pets-type__btn-deleted {
margin-right: auto;
display: flex;
align-items: center;
gap: 0 8px;
color: var(--color-verify-invalid);

svg {
height: 28px;
}
}

.shelter-pets-type__btn-cancel-selected {
position: relative;

&::before {
position: absolute;
content: '';
left: -20px;
top: 4px;
width: 12px;
height: 12px;
border-radius: 50%;
background-color: var(--color-accent-base);
}
}

.shelter-pets-type__title {
font-size: 40px;
line-height: 49px;
font-weight: 600;
margin: 0;
}

.shelter-pets-type__list {
display: flex;
flex-wrap: wrap;
gap: 24px;
margin: 0;
margin-top: 36px;
padding: 0;
list-style-type: none;
}

.shelter-pets-type__list-item {
position: relative;
}

.shelter-pets-type__input {
display: none;
position: absolute;
top: 16px;
right: 16px;
width: 20px;
height: 20px;

&::before {
position: absolute;
content: '';
width: 20px;
height: 20px;
background-color: var(--color-background-additional);
opacity: 0;
z-index: 10;
}

&::after {
position: absolute;
content: '';
width: 20px;
height: 20px;
background-color: var(--color-accent-base);
background-image: url('../../images/check.svg');
background-position: center;
opacity: 0;
z-index: 15;
}
}

.shelter-pets-type__input_selected {
display: block;

&::before {
opacity: 1;
}
}

.shelter-pets-type__input_checked {
&::after {
opacity: 1;
}
}
25 changes: 25 additions & 0 deletions src/modules/ShelterPetsType/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import BaseApi from '../../utils/BaseApi';
import { baseUrl, apiHeaders } from '../../utils/constants';

class ShelterPetsApi extends BaseApi {
constructor({ _baseUrl, _headers }) {
super({ _baseUrl });
this._headers = _headers;
}

getPetsByShelterId(shelterId, animalType, limit, offset) { // offset - начиная с какого питомца по счёту
return fetch(`${this._baseUrl}/v1/shelters/${shelterId}/pets/?animal_type=${animalType}&limit=${limit}&offset=${offset}`, {
headers: this._headers,
})
.then((res) => {
return super._processTheResponse(res);
});
}
}

const shelterPetsApi = new ShelterPetsApi({
_baseUrl: baseUrl,
_headers: apiHeaders,
});

export default shelterPetsApi;
2 changes: 1 addition & 1 deletion src/modules/ShelterSamePets/ShelterSamePets.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const ShelterSamePets = () => {
{pets.map((card) => {
return (
<li className='shelter-same-pets__pets-item' key={card.id}>
<PetCard id={card.id} shelterId={card.shelter} name={card.name} age={card.age} sex={card.sex} gallery={card.gallery} />
<PetCard link={`/shelters/${card.shelter}/pets/${card.id}`} name={card.name} age={card.age} sex={card.sex} gallery={card.gallery} />
</li>
);
})}
Expand Down
4 changes: 3 additions & 1 deletion src/pages/App/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import MyShelterPage from '../MyShelterPage/MyShelterPage';
import MyShelterEdit from '../../modules/MySheelterEdit/MyShelterEdit';
import AddNewsPage from '../AddNewsPage/AddNewsPage';
import ConfirmPopup from '../../components/ConfirmPopup/ConfirmPopup';

import ShelterPetsPage from '../ShelterPetsPage/ShelterPetsPage';

const App = () => {
const navigate = useNavigate();
Expand Down Expand Up @@ -223,6 +223,8 @@ const App = () => {
<Route path='/profile/my-shelter' element={<ProtectedRoute condition={loggedIn} component={MyShelterPage} />}>
<Route index element={<ProtectedRoute condition={loggedIn} component={shelterModules.AboutShelter} />} />
<Route path='edit' element={<ProtectedRoute condition={loggedIn} component={MyShelterEdit} />} />
<Route path=':id/all-pets' element={<ProtectedRoute condition={loggedIn} component={ShelterPetsPage} />} />
<Route path=':id/pets/:petId' element={<ProtectedRoute condition={loggedIn} component={shelterModules.PetModule} />} />
</Route>
<Route path='/profile/edit' element={<ProtectedRoute condition={loggedIn} component={EditProfilePage} onUpdateCurrentUser={setCurrentUser} />} />
<Route path='/profile/sign-out' element={<ProtectedRoute condition={loggedIn} component={SignOutPage} onSignOut={handleSignOut} />} />
Expand Down
13 changes: 9 additions & 4 deletions src/pages/MyShelterPage/MyShelterPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,26 @@ import CurrentUserContext from '../../contexts/CurrentUserContext';
const MyShelterPage = () => {
const curentUser = useContext(CurrentUserContext);
const mySheltersId = curentUser.own_shelter.id;
const [shelter, setShelter] = useState({});
const [shelter, setShelter] = useState({});
const isOwner = true;
const [isLoading, setIsLoading] = useState(true);

const location = useLocation();
const contentText = {
GO_TO_BACK: 'Вернуться назад',
BACK_TO_PROFILE: 'Вернуться в Личный Кабинет',
GO_TO_SHELTER: 'Вернуться к приюту'
};
let linkTo;

let linkTo;
let linkText;
if (location.pathname.includes('edit')) {
if (location.pathname.includes('edit') || location.pathname.includes('pets')) {
linkTo = -1;
linkText = contentText.GO_TO_BACK;
}
else if(location.pathname.includes('all-pets')) {
linkTo = -1;
linkText = contentText.GO_TO_SHELTER;
} else {
linkTo = '/profile';
linkText = contentText.BACK_TO_PROFILE;
Expand Down
Loading