Просмотр исходного кода

Partly finished feature 678

feature/678
Djordje Mitrovic 3 лет назад
Родитель
Сommit
a4bb2a5e39
84 измененных файлов: 1650 добавлений и 509 удалений
  1. 1
    1
      .env
  2. 1
    1
      public/index.html
  3. 0
    2
      src/components/Admin/Sidebar/Sidebar.js
  4. 3
    0
      src/components/Admin/Sidebar/Sidebar.styled.js
  5. 3
    1
      src/components/Cards/CategoryCard/CategoryCard.js
  6. 3
    0
      src/components/Cards/CategoryCard/CategoryCard.styled.js
  7. 2
    4
      src/components/Cards/LabeledCard/LabeledCard.js
  8. 36
    0
      src/components/Cards/LabeledCard/User/UserLabeledCard.js
  9. 59
    0
      src/components/Cards/LabeledCard/User/UserLabeledCard.styled.js
  10. 3
    2
      src/components/Cards/OfferCard/DeleteOffer/CancelButton/CancelButton.js
  11. 10
    4
      src/components/Cards/OfferCard/DeleteOffer/DeleteOffer.js
  12. 4
    2
      src/components/Cards/OfferCard/DeleteOffer/DeleteOffer.styled.js
  13. 45
    0
      src/components/Cards/OfferCard/DeleteOffer/DeleteOfferLabeledCard/DeleteOfferLabeledCard.js
  14. 58
    0
      src/components/Cards/OfferCard/DeleteOffer/DeleteOfferLabeledCard/DeleteOfferLabeledCard.styled.js
  15. 4
    3
      src/components/Cards/OfferCard/DeleteOffer/SaveButton/SaveButton.js
  16. 17
    1
      src/components/Cards/OfferCard/OfferCard.js
  17. 39
    9
      src/components/Cards/OfferCard/OfferCard.styled.js
  18. 56
    12
      src/components/Cards/ProfileCard/BigProfileCard/BigProfileCard.js
  19. 57
    205
      src/components/Cards/ProfileCard/BigProfileCard/BigProfileCard.styled.js
  20. 85
    17
      src/components/Cards/ProfileCard/ProfileCard.js
  21. 104
    7
      src/components/Cards/ProfileCard/ProfileCard.styled.js
  22. 4
    0
      src/components/Cards/ProfileCard/ProfileContact/ProfileContact.styled.js
  23. 16
    4
      src/components/Cards/ProfileCard/ProfileMainInfo/ProfileMainInfo.js
  24. 16
    4
      src/components/Cards/ProfileCard/ProfileMainInfo/ProfileMainInfo.styled.js
  25. 2
    2
      src/components/Cards/ProfileCard/ProfileStats/ProfileStats.js
  26. 5
    4
      src/components/Cards/ProfileCard/ProfileStats/ProfileStats.styled.js
  27. 17
    22
      src/components/Cards/UserReviewsCard/UserReviewsCard.js
  28. 0
    14
      src/components/Cards/UserReviewsCard/UserReviewsCard.styled.js
  29. 18
    0
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/RemoveButton/RemoveButton.js
  30. 21
    0
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/RemoveButton/RemoveButton.styled.js
  31. 0
    0
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewDetails/ReviewDetails.js
  32. 1
    1
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewDetails/ReviewDetails.styled.js
  33. 1
    1
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewOffer/ReviewOffer.js
  34. 1
    1
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewOffer/ReviewOffer.styled.js
  35. 2
    2
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewQuote/ReviewQuote.js
  36. 16
    3
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewQuote/ReviewQuote.styled.js
  37. 5
    5
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewerProfile/ReviewerProfile.js
  38. 1
    1
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewerProfile/ReviewerProfile.styled.js
  39. 44
    0
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/UserReviewsSingleCard.js
  40. 21
    0
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/UserReviewsSingleCard.styled.js
  41. 4
    1
      src/components/CreateReview/SecondStep/NextButton/NextButton.js
  42. 10
    3
      src/components/CreateReview/SecondStep/SecondStepCreateReview.js
  43. 11
    9
      src/components/CreateReview/SecondStep/SecondStepCreateReview.styled.js
  44. 20
    0
      src/components/Header/Drawer/AdminInfo/AdminInfo.js
  45. 24
    0
      src/components/Header/Drawer/AdminInfo/AdminInfo.styled.js
  46. 47
    0
      src/components/Header/Drawer/Buttons/AdminButtons/AdminButton/AdminButton.js
  47. 42
    0
      src/components/Header/Drawer/Buttons/AdminButtons/AdminButton/AdminButton.styled.js
  48. 55
    0
      src/components/Header/Drawer/Buttons/AdminButtons/AdminButtons.js
  49. 9
    0
      src/components/Header/Drawer/Buttons/AdminButtons/AdminButtons.styled.js
  50. 33
    17
      src/components/Header/Drawer/Drawer.js
  51. 10
    4
      src/components/Header/Drawer/Drawer.styled.js
  52. 2
    2
      src/components/Header/DrawerContainer/DrawerContainer.js
  53. 29
    13
      src/components/Modals/DeleteCategory/DeleteCategory.js
  54. 42
    3
      src/components/Modals/DeleteCategory/DeleteCategory.styled.js
  55. 40
    0
      src/components/Modals/DeleteReview/DeleteReview.js
  56. 62
    0
      src/components/Modals/DeleteReview/DeleteReview.styled.js
  57. 36
    26
      src/components/Modals/EditCategory/EditCategory.js
  58. 48
    1
      src/components/Modals/EditCategory/EditCategory.styled.js
  59. 5
    2
      src/components/Profile/Header/Header.js
  60. 2
    1
      src/components/Profile/Header/Header.styled.js
  61. 8
    6
      src/components/Profile/Profile.js
  62. 7
    4
      src/components/Profile/ProfileOffers/ProfileOffers.js
  63. 3
    1
      src/components/Profile/ProfileOffers/ProfileOffers.styled.js
  64. 5
    1
      src/components/ProfileMini/ProfileMini.js
  65. 35
    19
      src/components/UserReviews/ReviewsSorting/ReviewsSorting.js
  66. 12
    4
      src/components/UserReviews/UserReviews.js
  67. 3
    9
      src/components/UserReviews/UserReviews.styled.js
  68. 1
    0
      src/constants/pages.js
  69. 14
    0
      src/enums/sortEnum.js
  70. 27
    1
      src/i18n/resources/rs.js
  71. 30
    0
      src/layouts/AdminLayout/AdminLayout.js
  72. 24
    0
      src/layouts/AdminLayout/AdminLayout.styled.js
  73. 9
    8
      src/pages/AdminHomePage/AdminCategoriesPage/AdminCategoriesPage.styled.js
  74. 14
    3
      src/pages/AdminHomePage/AdminHomePage.js
  75. 2
    2
      src/pages/AdminHomePage/AdminHomePage.styled.js
  76. 8
    7
      src/pages/AdminHomePage/AdminLocationsPage/AdminLocationsPage.styled.js
  77. 5
    4
      src/pages/AdminHomePage/AdminSubcategoriesPage/AdminSubcategoriesPage.js
  78. 1
    1
      src/pages/AdminHomePage/AdminSubcategoriesPage/AdminSubcategoriesPage.styled.js
  79. 25
    0
      src/pages/AdminHomePage/AdminUsersPage/AdminSingleUserPage/AdminSingleUserPage.js
  80. 26
    0
      src/pages/AdminHomePage/AdminUsersPage/AdminSingleUserPage/AdminSingleUserPage.styled.js
  81. 36
    9
      src/pages/AdminHomePage/AdminUsersPage/AdminUsersPage.js
  82. 39
    6
      src/pages/AdminHomePage/AdminUsersPage/AdminUsersPage.styled.js
  83. 1
    0
      src/util/helpers/imageUrlGetter.js
  84. 3
    7
      src/util/helpers/routeHelpers.js

+ 1
- 1
.env Просмотреть файл

@@ -1 +1 @@
REACT_APP_BASE_API_URL=https://trampa-api-test.dilig.net/
REACT_APP_BASE_API_URL=http://localhost:3001/

+ 1
- 1
public/index.html Просмотреть файл

@@ -21,7 +21,7 @@
<link
rel="stylesheet"
type="text/css"
href="https://fonts.googleapis.com/css?family=DM+Sans"
href="https://fonts.googleapis.com/css?family=DM+Sans:300,400,500,600,700,800"
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />

+ 0
- 2
src/components/Admin/Sidebar/Sidebar.js Просмотреть файл

@@ -34,9 +34,7 @@ const Sidebar = () => {
const dispatch = useDispatch();
const { isMobile } = useIsMobile();
const { t } = useTranslation();
console.log(profile);
const routeToItem = (route) => {
console.log(route);
history.push(route);
};
const logoutHandler = () => {

+ 3
- 0
src/components/Admin/Sidebar/Sidebar.styled.js Просмотреть файл

@@ -11,6 +11,9 @@ export const SidebarContainer = styled(Box)`
min-width: 281px;
overflow-y: auto;
height: 100vh;
@media (max-width: 1536px) {
width: 25%;
}
@media (max-width: 600px) {
display: none;
}

+ 3
- 1
src/components/Cards/CategoryCard/CategoryCard.js Просмотреть файл

@@ -32,6 +32,7 @@ const CategoryCard = (props) => {
);
}
};
console.log(props);
return (
<>
<CategoryCardContainer className={props.className}>
@@ -74,12 +75,13 @@ const CategoryCard = (props) => {
)}
{openedEditModal && (
<EditCategory
hideImagePicker
hideImagePicker={props.type !== "categories"}
setOpenedEditModal={setOpenedEditModal}
category={props.category}
subcategory={props.subcategory}
type={props.type}
method="edit"
showSecondButton
/>
)}
</>

+ 3
- 0
src/components/Cards/CategoryCard/CategoryCard.styled.js Просмотреть файл

@@ -17,6 +17,9 @@ export const CategoryCardContainer = styled(Box)`
position: relative;
@media (max-width: 600px) {
height: 102px;
margin-left: 0;
margin-right: 0;
width: 100%;
}
`;
export const CategoryCardLeftContainer = styled(Box)`

+ 2
- 4
src/components/Cards/LabeledCard/LabeledCard.js Просмотреть файл

@@ -7,10 +7,8 @@ import {

const LabeledCard = (props) => {
return (
<LabeledCardContainer>
<LabeledCardIconContainer width={props.width} height={props.height}>
{props.icon}
</LabeledCardIconContainer>
<LabeledCardContainer width={props.width} height={props.height}>
<LabeledCardIconContainer>{props.icon}</LabeledCardIconContainer>
{props.children}
</LabeledCardContainer>
);

+ 36
- 0
src/components/Cards/LabeledCard/User/UserLabeledCard.js Просмотреть файл

@@ -0,0 +1,36 @@
import React from "react";
import PropTypes from "prop-types";
import {
PIBContainer,
PIBIcon,
PIBText,
UserImage,
UserLabeledCardContainer,
UserLabeledCardDetailsContainer,
UserName,
} from "./UserLabeledCard.styled";
import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter";
import { useTranslation } from "react-i18next";

const UserLabeledCard = (props) => {
const { t } = useTranslation();
return (
<UserLabeledCardContainer>
<UserImage src={getImageUrl(props.user.image, variants.reviewCard)} />
<UserLabeledCardDetailsContainer>
<UserName>{props.user.company.name}</UserName>
<PIBContainer>
<PIBIcon />
<PIBText>{t("itemDetailsCard.PIB") + props.user.company.PIB}</PIBText>
</PIBContainer>
</UserLabeledCardDetailsContainer>
</UserLabeledCardContainer>
);
};

UserLabeledCard.propTypes = {
children: PropTypes.node,
user: PropTypes.object,
};

export default UserLabeledCard;

+ 59
- 0
src/components/Cards/LabeledCard/User/UserLabeledCard.styled.js Просмотреть файл

@@ -0,0 +1,59 @@
import { Box, Typography } from "@mui/material";
import styled from "styled-components";
import { ReactComponent as PIB } from "../../../../assets/images/svg/pib.svg";
import selectedTheme from "../../../../themes";

export const UserLabeledCardContainer = styled(Box)`
display: flex;
flex-direction: row;
gap: 9px;
@media (max-width: 600px) {
max-height: 216px;
}
`;
export const UserLabeledCardDetailsContainer = styled(Box)`
display: flex;
flex-direction: column;
gap: 1px;
`;
export const UserName = styled(Typography)`
font-family: ${selectedTheme.fonts.textFont};
font-style: normal;
font-weight: 700;
font-size: 16px;
line-height: 21px;
color: ${selectedTheme.colors.primaryPurple};
padding-top: 7px;
white-space: nowrap;
@media (max-width: 600px) {
padding-top: 9px;
font-size: 14px;
line-height: 19px;
font-weight: 600;
}
`;
export const PIBContainer = styled(Box)`
display: flex;
flex-direction: row;
gap: 5px;
`;
export const PIBIcon = styled(PIB)`
width: 12px;
height: 12px;
position: relative;
top: 1.5px;
`;
export const PIBText = styled(Typography)`
font-family: ${selectedTheme.fonts.textFont};
font-weight: 400;
font-size: 12px;
line-height: 16px;
letter-spacing: 0.01em;
color: ${selectedTheme.colors.primaryDarkText};
white-space: nowrap;
`;
export const UserImage = styled.img`
width: 54px;
height: 54px;
border-radius: 100%;
`;

+ 3
- 2
src/components/Cards/OfferCard/DeleteOffer/CancelButton/CancelButton.js Просмотреть файл

@@ -8,12 +8,12 @@ const CancelButton = (props) => {
const { t } = useTranslation();
return (
<CancelButtonContainer
variant="contained"
variant={props.pin ? "outlined" : "contained"}
height="48px"
width="180px"
fullWidth
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor="white"
textcolor={props.pin ? selectedTheme.colors.primaryPurple : "white"}
onClick={props.onClick}
>
{t("deleteOffer.cancel")}
@@ -23,6 +23,7 @@ const CancelButton = (props) => {

CancelButton.propTypes = {
onClick: PropTypes.func,
pin: PropTypes.bool,
};

export default CancelButton;

+ 10
- 4
src/components/Cards/OfferCard/DeleteOffer/DeleteOffer.js Просмотреть файл

@@ -17,7 +17,7 @@ import {
fetchProfileOffers,
removeOffer,
} from "../../../../store/actions/offers/offersActions";
import { Trans } from "react-i18next";
import { Trans, useTranslation } from "react-i18next";
import { useHistory } from "react-router-dom";
import useIsMobile from "../../../../hooks/useIsMobile";
import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter";
@@ -28,6 +28,7 @@ import SaveButton from "./SaveButton/SaveButton";

const DeleteOffer = (props) => {
const dispatch = useDispatch();
const { t } = useTranslation();
const queryString = useSelector(selectQueryString);
const history = useHistory();
const userId = props.offer.userId;
@@ -77,11 +78,15 @@ const DeleteOffer = (props) => {
</RemoveIconContainer>
</OfferInfo>
<DeleteQuestion>
<Trans i18nKey="deleteOffer.areYouSure" />
{props.pin ? (
t("admin.pin.reassurancePin")
) : (
<Trans i18nKey="deleteOffer.areYouSure" />
)}
</DeleteQuestion>
<ButtonsContainer>
<CancelButton onClick={closeDeleteModalHandler} />
<SaveButton onClick={removeOfferHandler} />
<CancelButton pin={props.pin} onClick={closeDeleteModalHandler} />
<SaveButton pin={props.pin} onClick={removeOfferHandler} />
</ButtonsContainer>
</DeleteOfferContainer>
</>
@@ -91,6 +96,7 @@ const DeleteOffer = (props) => {
DeleteOffer.propTypes = {
offer: PropTypes.node,
closeModalHandler: PropTypes.func,
pin: PropTypes.bool,
};

export default DeleteOffer;

+ 4
- 2
src/components/Cards/OfferCard/DeleteOffer/DeleteOffer.styled.js Просмотреть файл

@@ -3,7 +3,7 @@ import { Box } from "@mui/system";
import styled from "styled-components";
import { ReactComponent as Remove } from "../../../../assets/images/svg/trash-gold.svg";
import selectedTheme from "../../../../themes";
import { IconButton } from "../../../Buttons/IconButton/IconButton";
import { Icon } from "../../../Icon/Icon";

export const DeleteOfferContainer = styled(Box)`
width: 537px;
@@ -73,7 +73,7 @@ export const DeleteQuestion = styled(Typography)`
}
`;

export const RemoveIconBorder = styled(IconButton)`
export const RemoveIconBorder = styled(Icon)`
width: 40px;
height: 40px;
position: absolute;
@@ -95,6 +95,8 @@ export const RemoveIconContainer = styled(RemoveIconBorder)`

export const RemoveIcon = styled(Remove)`
cursor: default;
position: relative;
top: 7px;
`;

export const ButtonsContainer = styled(Box)`

+ 45
- 0
src/components/Cards/OfferCard/DeleteOffer/DeleteOfferLabeledCard/DeleteOfferLabeledCard.js Просмотреть файл

@@ -0,0 +1,45 @@
import React from "react";
import PropTypes from "prop-types";
import {
OfferImage,
OfferImageContainer,
OfferInfo,
RemoveIcon,
RemoveIconContainer,
} from "./DeleteOfferLabeledCard.styled";
import {
getImageUrl,
variants,
} from "../../../../../util/helpers/imageUrlGetter";
import OfferDescription from "../OfferDescription/OfferDescription";
import useIsMobile from "../../../../../hooks/useIsMobile";

const DeleteOfferLabeledCard = (props) => {
const { isMobile } = useIsMobile();
return (
<OfferInfo>
<OfferImageContainer>
<OfferImage
src={getImageUrl(
props.offer.images[0],
variants.deleteChat,
isMobile
)}
/>
</OfferImageContainer>
<OfferDescription
offerName={props.offer.name}
categoryName={props.offer.category.name}
/>
<RemoveIconContainer>
<RemoveIcon />
</RemoveIconContainer>
</OfferInfo>
);
};

DeleteOfferLabeledCard.propTypes = {
offer: PropTypes.node,
};

export default DeleteOfferLabeledCard;

+ 58
- 0
src/components/Cards/OfferCard/DeleteOffer/DeleteOfferLabeledCard/DeleteOfferLabeledCard.styled.js Просмотреть файл

@@ -0,0 +1,58 @@
import { Box } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../../../themes";
import { ReactComponent as Remove } from "../../../../../assets/images/svg/trash-gold.svg";
import { IconButton } from "../../../../Buttons/IconButton/IconButton";
export const OfferInfo = styled(Box)`
width: 211px;
height: 90px;
border: 1px solid #d4d4d4;
display: flex;
align-items: center;
padding: 18px;
margin-top: 36px;

@media screen and (max-width: 600px) {
margin-left: calc(50% - 105px) !important;
}
`;

export const OfferImageContainer = styled(Box)`
width: 54px;
height: 54px;
border-radius: 2px;

@media screen and (max-width: 600px) {
margin-right: 13px;
}
`;

export const OfferImage = styled.img`
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 2px;
`;
export const RemoveIconBorder = styled(IconButton)`
width: 40px;
height: 40px;
position: absolute;
top: 16px;
right: 143px;
background-color: ${selectedTheme.colors.primaryPurple};
border-radius: 100%;
padding-top: 2px;
text-align: center;

@media screen and (max-width: 600px) {
right: 50px;
}
`;

export const RemoveIconContainer = styled(RemoveIconBorder)`
cursor: default;
`;

export const RemoveIcon = styled(Remove)`
cursor: default;
`;

+ 4
- 3
src/components/Cards/OfferCard/DeleteOffer/SaveButton/SaveButton.js Просмотреть файл

@@ -9,21 +9,22 @@ const SaveButton = (props) => {
return (
<SaveButtonContainer
type="submit"
variant="outlined"
variant={props.pin ? "contained" : "outlined"}
height="48px"
width="180px"
fullWidth
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor={selectedTheme.colors.primaryPurple}
textcolor={props.pin ? "white" : selectedTheme.colors.primaryPurple}
onClick={props.onClick}
>
{t("deleteOffer.delete")}
{props.pin ? t("admin.pin.confirm") : t("deleteOffer.delete")}
</SaveButtonContainer>
);
};

SaveButton.propTypes = {
onClick: PropTypes.func,
pin: PropTypes.bool,
};

export default SaveButton;

+ 17
- 1
src/components/Cards/OfferCard/OfferCard.js Просмотреть файл

@@ -47,6 +47,7 @@ import { formatDateLocale } from "../../../util/helpers/dateHelpers";
const OfferCard = (props) => {
const [deleteOfferModal, setDeleteOfferModal] = useState(false);
const [editOfferModal, setEditOfferModal] = useState(false);
const [pinOfferModal, setPinOfferModal] = useState(false);
const history = useHistory();
const userId = useSelector(selectUserId);
const { isMobile } = useIsMobile();
@@ -54,6 +55,7 @@ const OfferCard = (props) => {

const pinOffer = (event) => {
event.stopPropagation();
setPinOfferModal(true);
};
const routeToItem = (itemId) => {
if (!props.disabledCheckButton) {
@@ -82,6 +84,9 @@ const OfferCard = (props) => {
const closeModalHandler = () => {
setDeleteOfferModal(false);
};
const closePinOfferModal = () => {
setPinOfferModal(false);
};

const closeCreateOfferModal = () => {
setEditOfferModal(false);
@@ -223,7 +228,11 @@ const OfferCard = (props) => {
</MessageIcon>
)}
{props.isAdmin && !props.pinned && (
<PinIconContainer showMessageIcon onClick={pinOffer}>
<PinIconContainer
showMessageIcon
onClick={pinOffer}
vertical={props.vertical}
>
<PinOutlinedIcon />
</PinIconContainer>
)}
@@ -236,6 +245,13 @@ const OfferCard = (props) => {
closeModalHandler={closeModalHandler}
/>
)}
{pinOfferModal && (
<DeleteOffer
pin
offer={props.offer}
closeModalHandler={closePinOfferModal}
/>
)}
{editOfferModal && (
<CreateOffer
editOffer

+ 39
- 9
src/components/Cards/OfferCard/OfferCard.styled.js Просмотреть файл

@@ -38,7 +38,7 @@ export const OfferCardContainer = styled(Container)`
${(props) =>
props.vertical &&
`
height: 373px;
height: 400px;
width: 180px;
margin: 0 18px;
`}
@@ -111,13 +111,14 @@ export const OfferTitle = styled(Typography)`
props.vertical &&
`
display: flex;
flex: none;
flex-basis: 44px;
height: 44px;
max-height: 44px;
position: relative;
line-height: 22px;
margin-top: 5px;
font-size: 18px;
margin-bottom: 0px;
margin-bottom: 0px !important;

`}
}
@@ -204,6 +205,13 @@ export const OfferDate = styled(Box)`
line-height: 16px;
font-size: 12px;
margin-top: 1px;
@media (max-width: 600px) {
${(props) =>
props.vertical &&
`
margin-top: -18px;
`}
}
`;

export const Line = styled(Box)`
@@ -314,9 +322,14 @@ export const RemoveIconContainer = styled(MessageIcon)`

@media screen and (max-width: 600px) {
display: block;
position: ${(props) => props.vertical && "absolute"};
top: ${(props) => props.vertical && "325px"};
left: ${(props) => props.vertical && "59px"};
${(props) =>
props.vertical &&
`
position: absolute;
top: initial;
bottom: 18px;
left: 59px;
`}
}
`;
export const RemoveIcon = styled(Remove)``;
@@ -328,9 +341,13 @@ export const EditIconContainer = styled(MessageIcon)`
@media screen and (max-width: 600px) {
position: absolute;
display: block;
right: ${(props) => !props.vertical && "64px"};
top: ${(props) => props.vertical && "325px"};
left: ${(props) => props.vertical && "18px"};
${(props) =>
props.vertical &&
`
top: initial;
bottom: 18px;
left: 18px;
`}
}
`;
export const EditIcon = styled(Edit)``;
@@ -349,6 +366,19 @@ export const LikeIconContainer = styled(MessageIcon)`
export const PinIconContainer = styled(MessageIcon)`
right: 134px;
top: 18px;
@media (max-width: 600px) {
${props => props.vertical && `
display: block;
top: initial;
right: initial;
bottom: 18px;
left: 100px;
& button svg {
width: 19px;
height: 19px;
}
`}
}
`;
export const LikeIcon = styled(Like)`
& path {

+ 56
- 12
src/components/Cards/ProfileCard/BigProfileCard/BigProfileCard.js Просмотреть файл

@@ -3,6 +3,8 @@ import PropTypes from "prop-types";
import {
BlockIcon,
BlockIconContainer,
BlockLabelIcon,
ButtonsContainer,
CheckButton,
EditButton,
EditIcon,
@@ -17,28 +19,58 @@ import ProfileContact from "../ProfileContact/ProfileContact";
import EditProfile from "../EditProfile/EditProfile";
import selectedTheme from "../../../../themes";
import { useTranslation } from "react-i18next";
import history from "../../../../store/utils/history";
import { replaceInRoute } from "../../../../util/helpers/routeHelpers";
import { ADMIN_SINGLE_USER_PAGE } from "../../../../constants/pages";
import DeleteCategory from "../../../Modals/DeleteCategory/DeleteCategory";
import UserLabeledCard from "../../LabeledCard/User/UserLabeledCard";

const BigProfileCard = (props) => {
const { t } = useTranslation();
const [editProfileModal, setEditProfileModal] = useState(false);
const [deleteOrEditModal, setDeleteOrEditModal] = useState({
show: false,
type: "",
});
const closeModalHandler = () => {
setEditProfileModal(false);
if (editProfileModal) setEditProfileModal(false);
else setDeleteOrEditModal({ show: false, type: "" });
};
const removeUser = () => {
setDeleteOrEditModal({
show: true,
type: "deleteUser",
});
};
console.log(props.profile);
const blockUser = () => {
setDeleteOrEditModal({
show: true,
type: "blockUser",
});
};
const goToUser = () => {
history.push(
replaceInRoute(ADMIN_SINGLE_USER_PAGE, {
idProfile: props.profile?._id,
})
);
};
const removeUser = () => {};
const blockUser = () => {};
return (
<>
<ProfileCardContainer halfwidth={props.halfwidth}>
<ProfileCardWrapper variant="outlined">
<EditButton onClick={() => setEditProfileModal(true)}>
<EditIcon />
</EditButton>
<RemoveIconContainer onClick={removeUser}>
<RemoveIcon />
</RemoveIconContainer>
<BlockIconContainer onClick={blockUser}>
<BlockIcon />
</BlockIconContainer>
<ButtonsContainer>
<EditButton onClick={() => setEditProfileModal(true)}>
<EditIcon />
</EditButton>
<RemoveIconContainer onClick={removeUser}>
<RemoveIcon />
</RemoveIconContainer>
<BlockIconContainer onClick={blockUser}>
<BlockIcon />
</BlockIconContainer>
</ButtonsContainer>
<ProfileInfoContainer>
{/* Profile Main Info */}
<ProfileMainInfo profile={props.profile} isAdmin />
@@ -51,6 +83,7 @@ const BigProfileCard = (props) => {
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor={selectedTheme.colors.primaryPurple}
style={{ fontWeight: "600" }}
onClick={goToUser}
>
{t("admin.users.checkProfile")}
</CheckButton>
@@ -65,6 +98,17 @@ const BigProfileCard = (props) => {
userId={props.profile._id}
/>
)}
{deleteOrEditModal.show && (
<DeleteCategory
setOpenedDeleteModal={closeModalHandler}
type={deleteOrEditModal.type}
customLabeledCard={<UserLabeledCard user={props.profile} />}
customLabeledCardHeight="90px"
customLabeledCardIcon={
deleteOrEditModal.type === "blockUser" && <BlockLabelIcon />
}
/>
)}
</>
);
};

+ 57
- 205
src/components/Cards/ProfileCard/BigProfileCard/BigProfileCard.styled.js Просмотреть файл

@@ -14,12 +14,10 @@ import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton";
export const ProfileCardContainer = styled(Box)`
width: ${(props) => (props.halfwidth ? `49%` : `100%`)};
box-sizing: border-box;
max-height: 184px;
max-height: min-content;
margin-top: 34px;
overflow: hidden;
border: 1px solid ${selectedTheme.colors.borderNormal};
border-radius: 0 0 4px 4px;

border-radius: 4px 4px;
&:nth-child(1) {
margin-top: 20px;
}
@@ -29,7 +27,32 @@ export const ProfileCardContainer = styled(Box)`
@media (max-width: 1200px) {
padding: 0;
}
@media (max-width: 600px) {
max-height: fit-content;
margin-top: 18px;
&:nth-child(1) {
margin-top: 0;
}
}
`;

export const ProfileCardWrapper = styled(Card)`
background: ${(props) =>
props.isMyProfile ? selectedTheme.colors.primaryPurple : "white"};
width: 100%;
min-width: fit-content;
padding: 1rem;
border-radius: 0 0 4px 4px;
position: relative;
`;

export const ProfileCardHeader = styled(Grid)`
display: flex;
justify-content: start;
align-items: center;
margin-bottom: 11px;
`;

export const EditIcon = styled(Edit)`
width: 18px;
height: 18px;
@@ -38,19 +61,25 @@ export const EditIcon = styled(Edit)`
}
`;

export const MessageButton = styled(IconButton)`
width: 40px;
height: 40px;
export const ButtonsContainer = styled(Box)`
position: absolute;
top: 18px;
right: 18px;
display: flex;
flex-direction: row;
gap: 12px;
`;

export const MessageButton = styled(IconButton)`
width: 40px;
height: 40px;
background-color: ${selectedTheme.colors.primaryIconBackgroundColor};
border-radius: 100%;
padding-top: 2px;
text-align: center;
@media (max-width: 600px) {
width: 30px;
height: 30px;
width: 32px;
height: 32px;
top: 16px;
right: 16px;
padding: 0;
@@ -63,35 +92,31 @@ export const MessageButton = styled(IconButton)`
width: 16px;
height: 16px;
position: relative;
top: -3px;
left: -3.5px;
top: -2px;
left: -2px;
}
}
`;
export const EditButton = styled(MessageButton)`
right: 76px;
`;
export const ProfileCardWrapper = styled(Card)`
background: ${(props) =>
props.isMyProfile ? selectedTheme.colors.primaryPurple : "white"};
width: 100%;
min-width: fit-content;
padding: 1rem;
border-radius: 0 0 4px 4px;
position: relative;
`;
export const EditButton = styled(MessageButton)``;

export const RemoveIconContainer = styled(MessageButton)`
display: block;
top: 18px;
right: 18px;
`;
export const RemoveIcon = styled(Remove)``;
export const BlockIconContainer = styled(MessageButton)`
display: block;
top: 18px;
right: 134px;
`;
export const BlockIcon = styled(Block)``;
export const BlockLabelIcon = styled(Block)`
width: 18px;
height: 18px;
position: relative;
top: 10px;
left: 11px;
& path {
stroke: ${selectedTheme.colors.iconYellowColor};
}
`;
export const CheckButton = styled(PrimaryButton)`
width: 180px;
height: 48px;
@@ -108,128 +133,6 @@ export const CheckButton = styled(PrimaryButton)`
}
`;

// export const ProfileName = styled(Typography)`
// color: ${(props) =>
// props.isMyProfile
// ? selectedTheme.colors.primaryYellow
// : selectedTheme.colors.primaryPurple};
// font-weight: 700;
// font-size: 24px;
// font-family: ${selectedTheme.fonts.textFont};
// margin-bottom: 5px;
// @media (max-width: 600px) {
// font-size: 18px;
// }
// `;

// export const ProfilePIB = styled(Typography)`
// color: ${(props) =>
// props.isMyProfile ? "white" : selectedTheme.colors.primaryDarkText};
// margin-top: 0.18rem;
// font-family: ${selectedTheme.fonts.textFont};
// font-size: 16px;
// padding-top: 1px;
// @media (max-width: 600px) {
// font-size: 14px;
// }
// `;
// export const ProfilePIBContainer = styled(Grid)`
// display: flex;
// justify-content: center;
// align-items: center;
// position: relative;
// left: 5px;
// `;

// export const ProfileMainInfo = styled(Grid)`
// display: flex;
// justify-content: start;
// align-items: start;
// `;

// export const AvatarImageContainer = styled(Grid)`
// display: flex;
// justify-content: start;
// align-items: center;
// `;

// export const ProfileMainInfoGrid = styled(Grid)`
// display: flex;
// flex-direction: column;
// align-items: start;
// margin-left: 16px;
// `;

// export const ProfileContact = styled(Grid)`
// padding-top: 2rem;
// padding-bottom: 2rem;
// @media (max-width: 600px) {
// padding-bottom: 1rem;
// }
// `;

// export const ContactItem = styled(Typography)`
// margin-right: 2rem;
// margin-left: 0.4rem;
// color: ${(props) =>
// props.isMyProfile ? "white" : selectedTheme.colors.primaryDarkText};
// display: unset;
// font-family: ${selectedTheme.fonts.textFont};
// letter-spacing: 0.02em;
// font-size: 16px;
// position: relative;
// bottom: 1px;
// @media (max-width: 600px) {
// font-size: 14px;
// bottom: 4px;
// }
// `;

// export const StatsItem = styled(Typography)`
// margin-right: 2rem;
// display: unset;
// margin-left: 1rem;
// font-family: ${selectedTheme.fonts.textFont};
// font-size: 16px;
// margin-bottom: 2px;
// @media (max-width: 600px) {
// font-size: 12px;
// }
// `;

// export const ProfileStats = styled(Grid)`
// display: flex;
// justify-content: start;
// align-items: center;
// background: ${selectedTheme.colors.primaryDarkTextSecond};
// width: calc(100% + 2rem);
// padding-top: 1.3rem;
// padding-bottom: 1.3rem;
// margin-bottom: -1rem;
// margin-left: -1rem;
// border-radius: 0 0 4px 4px;
// `;
// export const AvatarImage = styled.img`
// min-height: 144px;
// min-width: 144px;
// width: 144px;
// height: 144px;
// border-radius: 100%;
// @media (max-width: 600px) {
// min-height: 90px;
// min-width: 90px;
// width: 90px;
// height: 90px;
// }
// `;

export const ProfileCardHeader = styled(Grid)`
display: flex;
justify-content: start;
align-items: center;
margin-bottom: 11px;
`;

export const HeaderTitle = styled(Typography)`
font-size: 16px;
font-family: ${selectedTheme.fonts.textFont};
@@ -239,62 +142,6 @@ export const HeaderTitle = styled(Typography)`
font-size: 12px;
}
`;
// export const PocketIcon = styled(Pocket)`
// width: 22px;
// height: 22px;
// position: relative;
// left: -5px;
// top: 2px;
// & path {
// stroke: #b4b4b4;
// }
// @media (max-width: 600px) {
// width: 14px;
// height: 14px;
// }
// `;
// export const MailIcon = styled(Mail)`
// height: 24px;
// width: 24px;
// & path {
// stroke: ${(props) =>
// props.isMyProfile
// ? selectedTheme.colors.iconMineProfileColor
// : selectedTheme.colors.iconProfileColor};
// }
// @media (max-width: 600px) {
// width: 14px;
// height: 14px;
// }
// `;
// export const GlobeIcon = styled(Globe)`
// height: 22px;
// width: 22px;
// & path {
// stroke: ${(props) =>
// props.isMyProfile
// ? selectedTheme.colors.iconMineProfileColor
// : selectedTheme.colors.iconProfileColor};
// }
// @media (max-width: 600px) {
// width: 14px;
// height: 14px;
// }
// `;
// export const LocationIcon = styled(Location)`
// height: 22px;
// width: 22px;
// & path {
// stroke: ${(props) =>
// props.isMyProfile
// ? selectedTheme.colors.iconMineProfileColor
// : selectedTheme.colors.iconProfileColor};
// }
// @media (max-width: 600px) {
// width: 14px;
// height: 14px;
// }
// `;
export const MessageIcon = styled(Mail)`
width: 19.5px;
height: 19.5px;
@@ -317,4 +164,9 @@ export const ProfileInfoContainer = styled(Grid)`
flex-direction: column;
justify-content: center;
align-items: start;
@media (max-width: 600px) {
flex-direction: row;
gap: 18px;
justify-content: space-between;
}
`;

+ 85
- 17
src/components/Cards/ProfileCard/ProfileCard.js Просмотреть файл

@@ -8,6 +8,15 @@ import {
HeaderTitle,
EditIcon,
ProfileInfoContainer,
RemoveButton,
RemoveIcon,
BlockButton,
BlockIcon,
ButtonsContainer,
BlockLabelIcon,
MessageButton,
MessageIcon,
ProfileInfoAndContactContainer,
} from "./ProfileCard.styled";
import PersonOutlineIcon from "@mui/icons-material/PersonOutline";
import { useRouteMatch } from "react-router-dom";
@@ -28,10 +37,15 @@ import { PROFILE_SCOPE } from "../../../store/actions/profile/profileActionConst
import SkeletonProfileCard from "./SkeletonProfileCard/SkeletonProfileCard";
import { useMemo } from "react";
import companyData from "../../../notFoundData/companyData";
import DeleteCategory from "../../Modals/DeleteCategory/DeleteCategory";
import UserLabeledCard from "../LabeledCard/User/UserLabeledCard";

const ProfileCard = () => {
const [isMyProfile, setIsMyProfile] = useState(false);
const ProfileCard = (props) => {
const [editProfileModal, setEditProfileModal] = useState(false);
const [deleteOrEditModal, setDeleteOrEditModal] = useState({
show: false,
type: "",
});
const isLoading = useSelector(selectIsLoadingByActionType(PROFILE_SCOPE));
const routeMatch = useRouteMatch();
const dispatch = useDispatch();
@@ -51,16 +65,17 @@ const ProfileCard = () => {
return companyData;
}, [profileFromRedux]);

const isMyProfile = useMemo(
() => userId === idProfile && !props.isAdmin,
[userId, idProfile]
);

useEffect(() => {
if (idProfile?.length > 0) {
reFetchProfile();
}
}, [idProfile]);

useEffect(() => {
setIsMyProfile(userId === idProfile);
}, [userId, idProfile]);

const reFetchProfile = () => {
dispatch(fetchProfile(idProfile));
dispatch(fetchProfileOffers(idProfile));
@@ -78,7 +93,20 @@ const ProfileCard = () => {
}

const closeModalHandler = () => {
setEditProfileModal(false);
if (editProfileModal) setEditProfileModal(false);
else setDeleteOrEditModal({ show: false, type: "" });
};
const removeUser = () => {
setDeleteOrEditModal({
show: true,
type: "deleteUser",
});
};
const blockUser = () => {
setDeleteOrEditModal({
show: true,
type: "blockUser",
});
};

if (editProfileModal) {
@@ -96,19 +124,47 @@ const ProfileCard = () => {
<ProfileCardContainer>
<ProfileCardHeader>
<PersonOutlineIcon color="action" sx={{ mr: 0.9 }} />
<HeaderTitle>{t("profile.myProfile")}</HeaderTitle>
<HeaderTitle>
{isMyProfile
? t("profile.myProfile")
: t("profile.companyProfile")}
</HeaderTitle>
</ProfileCardHeader>
<ProfileCardWrapper variant="outlined" isMyProfile={isMyProfile}>
{isMyProfile && (
<EditButton onClick={() => setEditProfileModal(true)}>
<EditIcon />
</EditButton>
)}
<ButtonsContainer>
{props.isAdmin && (
<>
<BlockButton onClick={blockUser}>
<BlockIcon />
</BlockButton>
<RemoveButton onClick={removeUser}>
<RemoveIcon />
</RemoveButton>
</>
)}
{isMyProfile || props.isAdmin ? (
<EditButton
onClick={() => setEditProfileModal(true)}
isAdmin={props.isAdmin}
>
<EditIcon />
</EditButton>
) : (
<MessageButton>
<MessageIcon />
</MessageButton>
)}
</ButtonsContainer>
<ProfileInfoContainer>
{/* Profile Main Info */}
<ProfileMainInfo profile={profile} isMyProfile={isMyProfile} />
{/* Profile Contact */}
<ProfileContact profile={profile} isMyProfile={isMyProfile} />
<ProfileInfoAndContactContainer>
{/* Profile Main Info */}
<ProfileMainInfo
profile={profile}
isMyProfile={isMyProfile}
/>
{/* Profile Contact */}
<ProfileContact profile={profile} isMyProfile={isMyProfile} />
</ProfileInfoAndContactContainer>
{/* Profile Stats */}
<ProfileStats
profile={profile}
@@ -126,12 +182,24 @@ const ProfileCard = () => {
reFetchProfile={reFetchProfile}
/>
)}
{deleteOrEditModal.show && (
<DeleteCategory
setOpenedDeleteModal={closeModalHandler}
type={deleteOrEditModal.type}
customLabeledCard={<UserLabeledCard user={profile} />}
customLabeledCardHeight="90px"
customLabeledCardIcon={
deleteOrEditModal.type === "blockUser" && <BlockLabelIcon />
}
/>
)}
</>
);
};

ProfileCard.propTypes = {
children: PropTypes.node,
isAdmin: PropTypes.bool,
};

export default ProfileCard;

+ 104
- 7
src/components/Cards/ProfileCard/ProfileCard.styled.js Просмотреть файл

@@ -2,6 +2,8 @@ import styled from "styled-components";
import { Card, Typography, Grid, Box } from "@mui/material";
import selectedTheme from "../../../themes";
import { ReactComponent as Edit } from "../../../assets/images/svg/edit.svg";
import { ReactComponent as Block } from "../../../assets/images/svg/block.svg";
import { ReactComponent as Remove } from "../../../assets/images/svg/trash.svg";
// import { ReactComponent as Pocket } from "../../assets/images/svg/pocket.svg";
// import { ReactComponent as Globe } from "../../assets/images/svg/globe.svg";
import { ReactComponent as Mail } from "../../../assets/images/svg/mail.svg";
@@ -19,26 +21,99 @@ export const ProfileCardContainer = styled(Box)`
padding: 0 36px 0 0;
}
@media (max-width: 600px) {
padding: 0;
padding: 0 18px;
}
`;
export const EditIcon = styled(Edit)`
position: relative;
top: 3px;
left: 2px;
width: 18px;
height: 18px;
@media (max-width: 600px) {
top: 0;
left: -2px;
}
& path {
stroke: ${selectedTheme.colors.primaryPurple};
}
`;
export const EditButton = styled(Box)`
position: absolute;
right: 1rem;
top: 1rem;
color: ${selectedTheme.colors.primaryPurple};
width: 40px;
height: 40px;
font-weight: 900;
background: ${selectedTheme.colors.primaryIconBackgroundColor};
border-radius: 360px;
padding: 0.45rem 0.45rem 0.27rem 0.57rem;
cursor: pointer;
@media (max-width: 600px) {
width: 32px;
height: 32px;
}
`;
export const RemoveIcon = styled(Remove)`
position: relative;
top: 3px;
left: 2px;
width: 18px;
height: 18px;
@media (max-width: 600px) {
top: 0;
left: -2px;
}
& path {
stroke: ${selectedTheme.colors.primaryPurple};
}
`;
export const RemoveButton = styled(Box)`
width: 40px;
height: 40px;
font-weight: 900;
background: ${selectedTheme.colors.primaryIconBackgroundColor};
border-radius: 360px;
padding: 0.45rem 0.45rem 0.27rem 0.57rem;
cursor: pointer;
@media (max-width: 600px) {
width: 32px;
height: 32px;
}
`;
export const BlockIcon = styled(Block)`
position: relative;
top: 3px;
left: 2px;
width: 18px;
height: 18px;
@media (max-width: 600px) {
top: 0;
left: -2px;
}
& path {
stroke: ${selectedTheme.colors.primaryPurple};
}
`;
export const BlockLabelIcon = styled(Block)`
width: 18px;
height: 18px;
position: relative;
top: 10px;
left: 11px;
& path {
stroke: ${selectedTheme.colors.iconYellowColor};
}
`;
export const BlockButton = styled(Box)`
width: 40px;
height: 40px;
font-weight: 900;
background: #f4f4f4;
background: ${selectedTheme.colors.primaryIconBackgroundColor};
border-radius: 360px;
padding: 0.45rem 0.45rem 0.27rem 0.57rem;
cursor: pointer;
@media (max-width: 600px) {
width: 32px;
height: 32px;
}
`;

export const MessageButton = styled(EditButton)`
@@ -50,6 +125,18 @@ export const MessageButton = styled(EditButton)`
height: 32px;
}
`;
export const ButtonsContainer = styled(Box)`
position: absolute;
top: 18px;
right: 18px;
gap: 16px;
display: flex;
justify-content: flex-end;
flex-direction: row;
@media (max-width: 600px) {
gap: 12px;
}
`;

export const ProfileCardWrapper = styled(Card)`
border: 1px solid ${selectedTheme.colors.borderNormal};
@@ -263,7 +350,7 @@ export const MessageIcon = styled(Mail)`
height: 16px;
left: -1px;
top: 1px;
}
}
`;

export const ProfileInfoContainer = styled(Grid)`
@@ -271,6 +358,16 @@ export const ProfileInfoContainer = styled(Grid)`
flex-direction: column;
justify-content: center;
align-items: start;
@media (max-width: 600px) {
}
`;
export const ProfileInfoAndContactContainer = styled(Box)`
display: flex;
flex-direction: column;
@media (max-width: 600px) {
padding-bottom: 18px;
flex-direction: row;
}
`;

// export const ProfileStatsGrid = styled(Grid)`

+ 4
- 0
src/components/Cards/ProfileCard/ProfileContact/ProfileContact.styled.js Просмотреть файл

@@ -10,6 +10,9 @@ export const ProfileContactContainer = styled(Grid)`
padding-bottom: 2rem;
@media (max-width: 600px) {
padding-bottom: 1rem;
padding-top: 88px;
gap: 5px;
width: calc(100vw - 216px);
}
`;
export const LocationIcon = styled(Location)`
@@ -40,6 +43,7 @@ export const ContactItem = styled(Typography)`
@media (max-width: 600px) {
font-size: 14px;
bottom: 4px;
margin-right: 0;
}
`;
export const MailIcon = styled(Mail)`

+ 16
- 4
src/components/Cards/ProfileCard/ProfileMainInfo/ProfileMainInfo.js Просмотреть файл

@@ -13,17 +13,28 @@ import {
import { useTranslation } from "react-i18next";
import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter";
import useIsMobile from "../../../../hooks/useIsMobile";
import history from "../../../../store/utils/history";
import {
isAdminRoute,
replaceInRoute,
} from "../../../../util/helpers/routeHelpers";
import { ADMIN_SINGLE_USER_PAGE } from "../../../../constants/pages";

const ProfileMainInfo = (props) => {
const { t } = useTranslation();
const { isMobile } = useIsMobile();
const goToUser = () => {
if (isAdminRoute()) {
history.push(
replaceInRoute(ADMIN_SINGLE_USER_PAGE, {
idProfile: props.profile?._id,
})
);
}
};
return (
<ProfileMainInfoContainer>
<AvatarImageContainer>
{/* <AvatarImage
alt={props.profile?.company?.name}
src={props.profile?.image}
/> */}
<AvatarImage
isAdmin={props.isAdmin}
src={getImageUrl(
@@ -38,6 +49,7 @@ const ProfileMainInfo = (props) => {
isAdmin={props.isAdmin}
isMyProfile={props.isMyProfile}
variant="h5"
onClick={goToUser}
>
{props.profile?.company?.name}
</ProfileName>

+ 16
- 4
src/components/Cards/ProfileCard/ProfileMainInfo/ProfileMainInfo.styled.js Просмотреть файл

@@ -7,6 +7,12 @@ export const ProfileMainInfoContainer = styled(Grid)`
display: flex;
justify-content: start;
align-items: start;
flex-direction: row;
@media (max-width: 600px) {
flex-direction: column-reverse;
gap: 18px;
max-width: 108px;
}
`;
export const AvatarImageContainer = styled(Grid)`
display: flex;
@@ -20,10 +26,10 @@ export const AvatarImage = styled.img`
height: ${(props) => (props.isAdmin ? `108px` : `144px`)};
border-radius: 100%;
@media (max-width: 600px) {
min-height: 90px;
min-width: 90px;
width: 90px;
height: 90px;
min-height: ${(props) => (props.isAdmin ? "108px" : "90px")};
min-width: ${(props) => (props.isAdmin ? "108px" : "90px")};
width: ${(props) => (props.isAdmin ? "108px" : "90px")};
height: ${(props) => (props.isAdmin ? "108px" : "90px")};
}
`;
export const ProfileMainInfoGrid = styled(Grid)`
@@ -31,6 +37,9 @@ export const ProfileMainInfoGrid = styled(Grid)`
flex-direction: column;
align-items: start;
margin-left: 16px;
@media (max-width: 600px) {
margin-left: 0;
}
`;
export const ProfileName = styled(Typography)`
color: ${(props) =>
@@ -39,11 +48,13 @@ export const ProfileName = styled(Typography)`
: selectedTheme.colors.primaryPurple};
font-weight: 700;
font-size: 24px;
min-width: 200px;
font-family: ${selectedTheme.fonts.textFont};
margin-bottom: 5px;
cursor: ${(props) => props.isAdmin && `pointer`};
@media (max-width: 600px) {
font-size: 18px;
margin-bottom: 0;
}
`;
export const ProfilePIBContainer = styled(Grid)`
@@ -74,6 +85,7 @@ export const ProfilePIB = styled(Typography)`
font-family: ${selectedTheme.fonts.textFont};
font-size: 16px;
padding-top: 1px;
white-space: nowrap;
@media (max-width: 600px) {
font-size: 14px;
}

+ 2
- 2
src/components/Cards/ProfileCard/ProfileStats/ProfileStats.js Просмотреть файл

@@ -21,8 +21,8 @@ const ProfileStats = (props) => {
<b>{props.percentOfSucceededExchanges}%</b>
{t("profile.successExchange")}
</StatsItem>
</ProfileStatsGrid>
<ProfileStatsGrid>
{/* </ProfileStatsGrid>
<ProfileStatsGrid> */}
<StatsItem variant="subtitle2">
<b>{props.profile?.statistics?.views?.count}</b>
{t("profile.numberOfViews")}

+ 5
- 4
src/components/Cards/ProfileCard/ProfileStats/ProfileStats.styled.js Просмотреть файл

@@ -7,11 +7,11 @@ export const ProfileStatsContainer = styled(Grid)`
justify-content: start;
align-items: center;
background: ${selectedTheme.colors.primaryDarkTextSecond};
width: calc(100% + 2rem);
padding-top: 1.3rem;
padding-bottom: 1.3rem;
width: calc(100% + 36px);
padding-top: 18px;
padding-bottom: 18px;
margin-bottom: -1rem;
margin-left: -1rem;
margin-left: -18px;
/* border-radius: 0 0 4px 4px; */
`;
export const ProfileStatsGrid = styled(Grid)`
@@ -19,6 +19,7 @@ export const ProfileStatsGrid = styled(Grid)`
flex-direction: column;
justify-content: center;
align-items: start;
gap: 3px;
`;
export const StatsItem = styled(Typography)`
margin-right: 2rem;

+ 17
- 22
src/components/Cards/UserReviewsCard/UserReviewsCard.js Просмотреть файл

@@ -1,13 +1,14 @@
import React, { useMemo } from "react";
import React, { useMemo, useState } from "react";
import PropTypes from "prop-types";
import { ReviewContainer } from "./UserReviewsCard.styled";
import ReviewOffer from "./ReviewOffer/ReviewOffer";
import { reviewEnum } from "../../../enums/reviewEnum";
import ReviewerProfile from "./ReviewerProfile/ReviewerProfile";
import ReviewQuote from "./ReviewQuote/ReviewQuote";
import ReviewDetails from "./ReviewDetails/ReviewDetails";
import UserReviewsSingleCard from "./UserReviewsSingleCard/UserReviewsSingleCard";
import DeleteReview from "../../Modals/DeleteReview/DeleteReview";

const UserReviewsCard = (props) => {
const [removeModalOpened, setRemoveModalOpened] = useState();
const handleRemove = () => {
setRemoveModalOpened(true);
};
const review = useMemo(() => {
if (props.givingReview) {
return {
@@ -42,24 +43,18 @@ const UserReviewsCard = (props) => {
offerImage: props.review.offer.image,
};
}, [props.review]);
console.log(review);

return (
<ReviewContainer key={review?.image}>
<ReviewerProfile
profileName={review.name}
profileImage={review.image}
userId={review.userId}
/>
<ReviewQuote
isSuccessfulSwap={review?.isSuccessfulSwap}
quote={review?.quote}
/>
<ReviewDetails
isSuccessfulSwap={review?.isSuccessfulSwap}
isGoodCommunication={review?.isGoodCommunication}
/>
<ReviewOffer name={review.offerName} image={review.offerImage} />
</ReviewContainer>
<>
<UserReviewsSingleCard review={review} handleRemove={handleRemove} />
{removeModalOpened && (
<DeleteReview
review={review}
setOpenedDeleteModal={setRemoveModalOpened}
/>
)}
</>
);
};


+ 0
- 14
src/components/Cards/UserReviewsCard/UserReviewsCard.styled.js Просмотреть файл

@@ -73,17 +73,3 @@ export const NoReviewsAltText = styled(Typography)`
width: 100%;
margin-bottom: 36px;
`;

export const ReviewContainer = styled(Box)`
padding-top: 18px;
&::after {
content: "";
display: block;
border-bottom: 1px solid ${selectedTheme.colors.primaryIconBackgroundColor};
width: calc(100% + 24.4px);
height: 1px;
position: relative;
left: -18px;
margin-top: 18px;
}
`;

+ 18
- 0
src/components/Cards/UserReviewsCard/UserReviewsSingleCard/RemoveButton/RemoveButton.js Просмотреть файл

@@ -0,0 +1,18 @@
import React from "react";
import PropTypes from "prop-types";
import { RemoveButtonContainer, RemoveIcon } from "./RemoveButton.styled";

const RemoveButton = (props) => {
return (
<RemoveButtonContainer onClick={props.onClick}>
<RemoveIcon />
</RemoveButtonContainer>
);
};

RemoveButton.propTypes = {
children: PropTypes.node,
onClick: PropTypes.func,
};

export default RemoveButton;

+ 21
- 0
src/components/Cards/UserReviewsCard/UserReviewsSingleCard/RemoveButton/RemoveButton.styled.js Просмотреть файл

@@ -0,0 +1,21 @@
// import { Box } from "@mui/material";
import styled from "styled-components";
import { ReactComponent as Remove } from "../../../../../assets/images/svg/trash.svg";
import selectedTheme from "../../../../../themes";
import { IconButton } from "../../../../Buttons/IconButton/IconButton";

export const RemoveButtonContainer = styled(IconButton)`
position: absolute;
top: 16px;
right: 16px;
background-color: ${selectedTheme.colors.primaryIconBackgroundColor};
border-radius: 100%;
width: 32px;
height: 32px;
& button {
width: 32px;
height: 32px;
}
`;
export const RemoveIcon = styled(Remove)`
`;

src/components/Cards/UserReviewsCard/ReviewDetails/ReviewDetails.js → src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewDetails/ReviewDetails.js Просмотреть файл


src/components/Cards/UserReviewsCard/ReviewDetails/ReviewDetails.styled.js → src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewDetails/ReviewDetails.styled.js Просмотреть файл

@@ -1,6 +1,6 @@
import { Grid, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../../themes";
import selectedTheme from "../../../../../themes";

export const ReviewDetailsContainer = styled(Grid)`
padding-bottom: 1rem;

src/components/Cards/UserReviewsCard/ReviewOffer/ReviewOffer.js → src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewOffer/ReviewOffer.js Просмотреть файл

@@ -7,7 +7,7 @@ import {
ReviewOfferImage,
ReviewOfferTitle,
} from "./ReviewOffer.styled";
import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter";
import { getImageUrl, variants } from "../../../../../util/helpers/imageUrlGetter";

const ReviewOffer = (props) => {
return (

src/components/Cards/UserReviewsCard/ReviewOffer/ReviewOffer.styled.js → src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewOffer/ReviewOffer.styled.js Просмотреть файл

@@ -1,6 +1,6 @@
import { Box, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../../themes";
import selectedTheme from "../../../../../themes";

export const ReviewOfferContainer = styled(Box)`
display: flex;

src/components/Cards/UserReviewsCard/ReviewQuote/ReviewQuote.js → src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewQuote/ReviewQuote.js Просмотреть файл

@@ -8,13 +8,13 @@ import {
ThumbDown,
ThumbUp,
} from "./ReviewQuote.styled";
import { reviewEnum } from "../../../../enums/reviewEnum";
import { reviewEnum } from "../../../../../enums/reviewEnum";

const ReviewQuote = (props) => {
return (
<ReviewQuoteContainer>
<ThumbContainer item>
{props.isSuccessfulSwap.toLowerCase() ===
{props.isSuccessfulSwap?.toLowerCase() ===
reviewEnum.YES.mainText.toLowerCase() ? (
<ThumbUp color="success" />
) : (

src/components/Cards/UserReviewsCard/ReviewQuote/ReviewQuote.styled.js → src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewQuote/ReviewQuote.styled.js Просмотреть файл

@@ -1,8 +1,8 @@
import { Box, Grid, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../../themes";
import selectedTheme from "../../../../../themes";
import ThumbUpIcon from "@mui/icons-material/ThumbUp";
import ThumbDownIcon from "@mui/icons-material/ThumbDown";
import ThumbDownIcon from "@mui/icons-material/ThumbDown";

export const ReviewQuoteContainer = styled(Box)`
position: relative;
@@ -26,11 +26,24 @@ export const ReviewQuoteText = styled(Typography)`
color: ${selectedTheme.colors.primaryDarkText};
position: relative;
left: 10px;
@media (max-width: 600px) {
font-size: 12px;
}
`;
export const ThumbUp = styled(ThumbUpIcon)`
position: relative;
@media (max-width: 600px) {
width: 18px;
height: 18px;
top: 3px;
}
`;
export const ThumbDown = styled(ThumbDownIcon)`
position: relative;
top: 3px;
position: relative;
@media (max-width: 600px) {
width: 18px;
height: 18px;
top: 3px;
}
`;

src/components/Cards/UserReviewsCard/ReviewerProfile/ReviewerProfile.js → src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewerProfile/ReviewerProfile.js Просмотреть файл

@@ -1,16 +1,16 @@
import React from "react";
import PropTypes from "prop-types";
import useIsMobile from "../../../../hooks/useIsMobile";
import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter";
import useIsMobile from "../../../../../hooks/useIsMobile";
import { getImageUrl, variants } from "../../../../../util/helpers/imageUrlGetter";
import {
ProfileContainer,
ProfileImage,
ProfileImageContainer,
ProfileName,
} from "./ReviewerProfile.styled";
import history from "../../../../store/utils/history";
import { replaceInRoute } from "../../../../util/helpers/routeHelpers";
import { PROFILE_PAGE } from "../../../../constants/pages";
import history from "../../../../../store/utils/history";
import { replaceInRoute } from "../../../../../util/helpers/routeHelpers";
import { PROFILE_PAGE } from "../../../../../constants/pages";

const ReviewerProfile = (props) => {
const { isMobile } = useIsMobile();

src/components/Cards/UserReviewsCard/ReviewerProfile/ReviewerProfile.styled.js → src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewerProfile/ReviewerProfile.styled.js Просмотреть файл

@@ -1,6 +1,6 @@
import { Box, ListItem, Typography } from "@mui/material"
import styled from "styled-components"
import selectedTheme from "../../../../themes"
import selectedTheme from "../../../../../themes"

export const ProfileImage = styled.img`
width: 54px;

+ 44
- 0
src/components/Cards/UserReviewsCard/UserReviewsSingleCard/UserReviewsSingleCard.js Просмотреть файл

@@ -0,0 +1,44 @@
import React from "react";
import PropTypes from "prop-types";
import { ReviewContainer } from "./UserReviewsSingleCard.styled";
import ReviewerProfile from "./ReviewerProfile/ReviewerProfile";
import ReviewQuote from "./ReviewQuote/ReviewQuote";
import ReviewDetails from "./ReviewDetails/ReviewDetails";
import RemoveButton from "./RemoveButton/RemoveButton";
import ReviewOffer from "./ReviewOffer/ReviewOffer";

const UserReviewsSingleCard = (props) => {
const handleRemove = () => {
props.handleRemove();
};
return (
<ReviewContainer>
<ReviewerProfile
profileName={props.review?.name}
profileImage={props.review?.image}
userId={props.review?.userId}
/>
<ReviewQuote
isSuccessfulSwap={props.review?.isSuccessfulSwap}
quote={props.review?.quote}
/>
<ReviewDetails
isSuccessfulSwap={props.review?.isSuccessfulSwap}
isGoodCommunication={props.review?.isGoodCommunication}
/>
{!props.showRemoveIcon && <RemoveButton review={props.review} onClick={handleRemove} />}
<ReviewOffer
name={props.review?.offerName}
image={props.review?.offerImage}
/>
</ReviewContainer>
);
};

UserReviewsSingleCard.propTypes = {
review: PropTypes.any,
handleRemove: PropTypes.func,
showRemoveIcon: PropTypes.bool,
};

export default UserReviewsSingleCard;

+ 21
- 0
src/components/Cards/UserReviewsCard/UserReviewsSingleCard/UserReviewsSingleCard.styled.js Просмотреть файл

@@ -0,0 +1,21 @@
import { Box } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../../themes";

export const ReviewContainer = styled(Box)`
padding-top: 18px;
position: relative;
@media (max-width: 600px) {
height: 258px;
}
&::after {
content: "";
display: block;
border-bottom: 1px solid ${selectedTheme.colors.primaryIconBackgroundColor};
width: calc(100% + 24.4px);
height: 1px;
position: relative;
left: -18px;
margin-top: 18px;
}
`;

+ 4
- 1
src/components/CreateReview/SecondStep/NextButton/NextButton.js Просмотреть файл

@@ -14,13 +14,16 @@ const NextButton = (props) => {
height="48px"
onClick={props.onClick}
>
{t("reviews.leaveComment")}
{props.removingReview
? t("admin.reviews.confirm")
: t("reviews.leaveComment")}
</NextButtonContainer>
);
};

NextButton.propTypes = {
onClick: PropTypes.func,
removingReview: PropTypes.bool,
};

export default NextButton;

+ 10
- 3
src/components/CreateReview/SecondStep/SecondStepCreateReview.js Просмотреть файл

@@ -15,12 +15,17 @@ const SecondStepCreateReview = (props) => {
const mineProfile = useSelector(selectMineProfile);

const goToNextStep = () => {
props.goToNextStep();
if (props.removingReview) props.closeModal();
else props.goToNextStep();
};

return (
<SecondStepCreateReviewContainer>
<CreateReviewTitle>{t("reviews.modalTitle")}</CreateReviewTitle>
<CreateReviewTitle>
{props.removingReview
? t("admin.reviews.title")
: t("reviews.modalTitle")}
</CreateReviewTitle>
<ReviewCard
givingReview
profileReviews={[
@@ -35,7 +40,7 @@ const SecondStepCreateReview = (props) => {
},
]}
/>
<NextButton onClick={goToNextStep} />
<NextButton removingReview={props.removingReview} onClick={goToNextStep} />
</SecondStepCreateReviewContainer>
);
};
@@ -46,6 +51,8 @@ SecondStepCreateReview.propTypes = {
offer: PropTypes.any,
interlocutor: PropTypes.any,
goToNextStep: PropTypes.func,
removingReview: PropTypes.bool,
closeModal: PropTypes.func,
};

export default SecondStepCreateReview;

+ 11
- 9
src/components/CreateReview/SecondStep/SecondStepCreateReview.styled.js Просмотреть файл

@@ -4,19 +4,21 @@ import selectedTheme from "../../../themes";
import UserReviews from "../../UserReviews/UserReviews";

export const SecondStepCreateReviewContainer = styled(Box)`
padding: 36px;
@media (max-width: 600px) {
padding: 18px;
}
`
padding: 36px;
@media (max-width: 600px) {
padding: 18px;
}
`;
export const ReviewCard = styled(UserReviews)`
& > div {
margin-bottom: 36px;
margin-top: 18px;
& ul {
background-color: ${selectedTheme.colors.chatHeaderColor};
padding: 0 14px;
background-color: ${selectedTheme.colors.chatHeaderColor};
padding: 0 14px;
}
& ul li {
margin: 0;
margin: 0;
}
`
}
`;

+ 20
- 0
src/components/Header/Drawer/AdminInfo/AdminInfo.js Просмотреть файл

@@ -0,0 +1,20 @@
import React from "react";
import PropTypes from "prop-types";
import { AdminInfoContainer, AdminName, AdminText } from "./AdminInfo.styled";
import { useTranslation } from "react-i18next";

const AdminInfo = (props) => {
const { t } = useTranslation();
return (
<AdminInfoContainer>
<AdminName>{props.name}</AdminName>
<AdminText>{t("admin.navigation.role")}</AdminText>
</AdminInfoContainer>
);
};

AdminInfo.propTypes = {
name: PropTypes.string,
};

export default AdminInfo;

+ 24
- 0
src/components/Header/Drawer/AdminInfo/AdminInfo.styled.js Просмотреть файл

@@ -0,0 +1,24 @@
import { Box, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../../themes";

export const AdminInfoContainer = styled(Box)`
display: flex;
flex-direction: column;
gap: 4px;
`;
export const AdminName = styled(Typography)`
font-family: ${selectedTheme.fonts.textFont};
font-weight: 700;
font-size: 18px;
line-height: 25px;
color: ${selectedTheme.colors.primaryPurple};
`;
export const AdminText = styled(Typography)`
font-family: ${selectedTheme.fonts.textFont};
font-weight: 400;
font-size: 12px;
line-height: 16px;
letter-spacing: 0.01em;
color: ${selectedTheme.colors.primaryPurple};
`;

+ 47
- 0
src/components/Header/Drawer/Buttons/AdminButtons/AdminButton/AdminButton.js Просмотреть файл

@@ -0,0 +1,47 @@
import React, { useMemo } from "react";
import PropTypes from "prop-types";
import { routeMatches } from "../../../../../../util/helpers/routeHelpers";
import { useLocation } from "react-router-dom";
import {
AdminButtonContainer,
AdminButtonIcon,
AdminButtonText,
} from "./AdminButton.styled";
import {
ADMIN_HOME_PAGE,
ADMIN_USERS_PAGE,
} from "../../../../../../constants/pages";
import history from "../../../../../../store/utils/history";
import { useDispatch } from "react-redux";
import { setManualSearchString } from "../../../../../../store/actions/filters/filtersActions";

const AdminButton = (props) => {
const location = useLocation();
const dispatch = useDispatch();
const isSelected = useMemo(() => {
if (routeMatches(ADMIN_HOME_PAGE) && props.route === ADMIN_USERS_PAGE)
return true;
return routeMatches(props.route);
}, [props.route, location.pathname]);
const goToRoute = () => {
dispatch(setManualSearchString(""));
history.push(props.route);
props.toggleDrawer();
};
return (
<AdminButtonContainer onClick={goToRoute} isSelected={isSelected}>
<AdminButtonIcon isSelected={isSelected}>{props.icon}</AdminButtonIcon>
<AdminButtonText isSelected={isSelected}>{props.title}</AdminButtonText>
</AdminButtonContainer>
);
};

AdminButton.propTypes = {
icon: PropTypes.node,
route: PropTypes.string,
title: PropTypes.string,
onClick: PropTypes.func,
toggleDrawer: PropTypes.func,
};

export default AdminButton;

+ 42
- 0
src/components/Header/Drawer/Buttons/AdminButtons/AdminButton/AdminButton.styled.js Просмотреть файл

@@ -0,0 +1,42 @@
import { Box, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../../../../themes";

export const AdminButtonContainer = styled(Box)`
display: flex;
flex-direction: row;
gap: 18px;
background: ${(props) =>
props.isSelected
? selectedTheme.colors.backgroundSponsoredColor
: "transparent"};
width: 100vw;
height: 61px;
padding: 18px;
border-radius: 4px;
`;
export const AdminButtonText = styled(Typography)`
font-family: ${selectedTheme.fonts.textFont};
font-weight: ${(props) => (props.isSelected ? "600" : "400")};
font-size: 18px;
line-height: 25px;
color: ${selectedTheme.colors.primaryPurple};
`;
export const AdminButtonIcon = styled(Box)`
& svg {
width: 24px;
height: 24px;
}
& svg path {
stroke: ${(props) =>
props.isSelected
? selectedTheme.colors.iconYellowColor
: selectedTheme.colors.iconStrokeDisabledColor};
}
& svg g path {
stroke: ${(props) =>
props.isSelected
? selectedTheme.colors.iconYellowColor
: selectedTheme.colors.iconStrokeDisabledColor};
}
`;

+ 55
- 0
src/components/Header/Drawer/Buttons/AdminButtons/AdminButtons.js Просмотреть файл

@@ -0,0 +1,55 @@
import React from "react";
import PropTypes from "prop-types";
import AdminButton from "./AdminButton/AdminButton";
import {
CategoryIcon,
DollarIcon,
LocationIcon,
UserIcon,
} from "./AdminButtons.styled";
import {
ADMIN_CATEGORIES_PAGE,
ADMIN_LOCATIONS_PAGE,
ADMIN_PAYMENT_PAGE,
ADMIN_USERS_PAGE,
} from "../../../../../constants/pages";
import { useTranslation } from "react-i18next";

const AdminButtons = (props) => {
const { t } = useTranslation();
return (
<>
<AdminButton
toggleDrawer={props.toggleDrawer}
icon={<UserIcon />}
title={t("admin.navigation.users")}
route={ADMIN_USERS_PAGE}
/>
<AdminButton
toggleDrawer={props.toggleDrawer}
icon={<CategoryIcon />}
title={t("admin.navigation.categories")}
route={ADMIN_CATEGORIES_PAGE}
/>
<AdminButton
toggleDrawer={props.toggleDrawer}
icon={<LocationIcon />}
title={t("admin.navigation.locations")}
route={ADMIN_LOCATIONS_PAGE}
/>
<AdminButton
toggleDrawer={props.toggleDrawer}
icon={<DollarIcon />}
title={t("admin.navigation.payment")}
route={ADMIN_PAYMENT_PAGE}
/>
</>
);
};

AdminButtons.propTypes = {
children: PropTypes.node,
toggleDrawer: PropTypes.func,
};

export default AdminButtons;

+ 9
- 0
src/components/Header/Drawer/Buttons/AdminButtons/AdminButtons.styled.js Просмотреть файл

@@ -0,0 +1,9 @@
import { ReactComponent as User } from "../../../../../assets/images/svg/user.svg";
import { ReactComponent as Location } from "../../../../../assets/images/svg/location.svg";
import { ReactComponent as Category } from "../../../../../assets/images/svg/category.svg";
import { ReactComponent as Dollar } from "../../../../../assets/images/svg/dollar-sign.svg";
import styled from "styled-components";
export const LocationIcon = styled(Location)``;
export const UserIcon = styled(User)``;
export const CategoryIcon = styled(Category)``;
export const DollarIcon = styled(Dollar)``;

+ 33
- 17
src/components/Header/Drawer/Drawer.js Просмотреть файл

@@ -1,4 +1,4 @@
import React from "react";
import React, { useMemo } from "react";
import PropTypes from "prop-types";
import {
CloseButton,
@@ -22,10 +22,18 @@ import AboutButton from "./Buttons/AboutButton/AboutButton";
import PrivacyPolicyButton from "./Buttons/PrivacyPolicyButton/PrivacyPolicyButton";
import { useSelector } from "react-redux";
import { selectUserId } from "../../../store/selectors/loginSelectors";
import { isAdminRoute } from "../../../util/helpers/routeHelpers";
import { useLocation } from "react-router-dom";
import AdminButtons from "./Buttons/AdminButtons/AdminButtons";
import AdminInfo from "./AdminInfo/AdminInfo";
import { selectMineProfile } from "../../../store/selectors/profileSelectors";

export const Drawer = (props) => {
const { t } = useTranslation();
const user = useSelector(selectUserId);
const mineProfile = useSelector(selectMineProfile);
const location = useLocation();
const isAdmin = useMemo(() => isAdminRoute(), [location.pathname]);

return (
<DrawerContainer>
@@ -34,18 +42,22 @@ export const Drawer = (props) => {
</CloseButton>
<HeaderTitle>{t("header.navMenu")}</HeaderTitle>
<React.Fragment>
<ToolsContainer mobile>
<ToolsContainer mobile isAdmin={isAdmin}>
{user ? (
<>
<MyPostsButton toggleDrawer={props.toggleDrawer} />
<MyMessagesButton toggleDrawer={props.toggleDrawer} />
<MyProfileButton toggleDrawer={props.toggleDrawer} />
<Separator />
<PricesButton toggleDrawer={props.toggleDrawer} />
<AboutButton toggleDrawer={props.toggleDrawer} />
<PrivacyPolicyButton toggleDrawer={props.toggleDrawer} />
<Separator />
</>
isAdmin ? (
<AdminButtons toggleDrawer={props.toggleDrawer}/>
) : (
<>
<MyPostsButton toggleDrawer={props.toggleDrawer} />
<MyMessagesButton toggleDrawer={props.toggleDrawer} />
<MyProfileButton toggleDrawer={props.toggleDrawer} />
<Separator />
<PricesButton toggleDrawer={props.toggleDrawer} />
<AboutButton toggleDrawer={props.toggleDrawer} />
<PrivacyPolicyButton toggleDrawer={props.toggleDrawer} />
<Separator />
</>
)
) : (
<>
<LoginButton toggleDrawer={props.toggleDrawer} />
@@ -54,11 +66,15 @@ export const Drawer = (props) => {
)}
</ToolsContainer>
{user && (
<FooterButtons>
<AddOfferButton
toggleDrawer={props.toggleDrawer}
addOffer={props.addOffer}
/>
<FooterButtons isAdmin={isAdmin}>
{isAdmin ? (
<AdminInfo name={mineProfile?.company?.name} />
) : (
<AddOfferButton
toggleDrawer={props.toggleDrawer}
addOffer={props.addOffer}
/>
)}
<LogoutButton toggleDrawer={props.toggleDrawer} />
</FooterButtons>
)}

+ 10
- 4
src/components/Header/Drawer/Drawer.styled.js Просмотреть файл

@@ -2,12 +2,14 @@ import { Box, Typography } from "@mui/material";
import styled from "styled-components";
import { ReactComponent as Close } from "../../../assets/images/svg/close-modal.svg";
import selectedTheme from "../../../themes";
import { hexToRGB } from "../../../util/helpers/colorHelper";
import { IconButton } from "../../Buttons/IconButton/IconButton";

export const DrawerContainer = styled(Box)`
width: 100vw;
position: relative;
height: 100%;
overflow: hidden;
`;
export const ToolsContainer = styled(Box)`
display: flex;
@@ -22,8 +24,8 @@ export const ToolsContainer = styled(Box)`
position: absolute;
top: 0px;
bottom: 70px;
left: 36px;
gap: 36px;
left: ${(props) => (props.isAdmin ? "18px" : "36px")};
gap: ${(props) => (props.isAdmin ? "0" : "36px")};
`;

export const AuthButtonsDrawerContainer = styled(Box)`
@@ -59,10 +61,14 @@ export const DrawerButton = styled(Box)`
export const FooterButtons = styled(Box)`
position: absolute;
bottom: 36px;
margin-left: 36px;
margin-right: 36px;
padding-top: 10px;
display: flex;
flex-direction: row;
width: 100vw;
justify-content: space-around;
width: calc(100vw - 72px);
justify-content: space-between;
border-top: 3px solid ${hexToRGB(selectedTheme.colors.borderNormal, 0.12)};
`;

export const HeaderTitle = styled(Typography)`

+ 2
- 2
src/components/Header/DrawerContainer/DrawerContainer.js Просмотреть файл

@@ -12,8 +12,8 @@ const DrawerContainer = forwardRef((props, ref) => {
const { isMobile } = useIsMobile();

useImperativeHandle(ref, () => ({
handleToggleDrawer
}))
handleToggleDrawer,
}));

const handleToggleDrawer = () => {
setOpenDrawer((prevOpenDrawer) => !prevOpenDrawer);

+ 29
- 13
src/components/Modals/DeleteCategory/DeleteCategory.js Просмотреть файл

@@ -3,15 +3,17 @@ import PropTypes from "prop-types";
import BackdropComponent from "../../MUI/BackdropComponent";
import {
ButtonsContainer,
CancelButton,
CategoryName,
DeleteCategoryContainer,
DeleteIcon,
ReassuranceText,
SaveButton,
} from "./DeleteCategory.styled";
import LabeledCard from "../../Cards/LabeledCard/LabeledCard";
import { useTranslation } from "react-i18next";
import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton";
import { useMemo } from "react";
import selectedTheme from "../../../themes";

const DeleteCategory = (props) => {
const { t } = useTranslation();
@@ -21,7 +23,7 @@ const DeleteCategory = (props) => {
};
const reassuranceText = useMemo(() => {
return t(`admin.${props.type}.reassuranceDelete`);
}, [props]);
}, [props, t]);
return (
<>
<BackdropComponent
@@ -29,23 +31,33 @@ const DeleteCategory = (props) => {
handleClose={() => props.setOpenedDeleteModal(false)}
position="fixed"
/>
<DeleteCategoryContainer>
<LabeledCard icon={<DeleteIcon />}>
<CategoryName>{props.category?.name || props.category?.city}</CategoryName>
<DeleteCategoryContainer type={props.type}>
<LabeledCard
icon={props.customLabeledCardIcon || <DeleteIcon />}
width={props.customLabeledCardWidth}
height={props.customLabeledCardHeight}
>
{props.customLabeledCard || (
<CategoryName>
{props.category?.name || props.category?.city}
</CategoryName>
)}
</LabeledCard>
<ReassuranceText>{reassuranceText}</ReassuranceText>
<ButtonsContainer>
<PrimaryButton
<CancelButton
onClick={handleCancel}
variant="contained"
height="49px"
width="180px"
buttoncolor={selectedTheme.colors.primaryPurple}
>
{t("admin.categories.cancel")}
</PrimaryButton>
<PrimaryButton variant="outlined" height="49px" width="180px">
{t("admin.categories.delete")}
</PrimaryButton>
{t(`admin.${props.type}.cancel`)}
</CancelButton>
<SaveButton
variant="outlined"
buttoncolor={selectedTheme.colors.primaryPurple}
>
{t(`admin.${props.type}.delete`)}
</SaveButton>
</ButtonsContainer>
</DeleteCategoryContainer>
</>
@@ -57,6 +69,10 @@ DeleteCategory.propTypes = {
category: PropTypes.object,
subcategory: PropTypes.bool,
type: PropTypes.string,
customLabeledCard: PropTypes.node,
customLabeledCardWidth: PropTypes.string,
customLabeledCardHeight: PropTypes.string,
customLabeledCardIcon: PropTypes.node,
};

export default DeleteCategory;

+ 42
- 3
src/components/Modals/DeleteCategory/DeleteCategory.styled.js Просмотреть файл

@@ -2,14 +2,19 @@ import { Box, Typography } from "@mui/material";
import styled from "styled-components";
import { ReactComponent as Delete } from "../../../assets/images/svg/trash.svg";
import selectedTheme from "../../../themes";
import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton";

export const DeleteCategoryContainer = styled(Box)`
width: 537px;
height: 274px;
height: ${(props) =>
["blockUser", "deleteUser"].includes(props.type) ? "309px" : "274px"};
position: fixed;
z-index: 150;
left: calc(50vw - 268px);
top: calc(50vh - 137px);
top: ${(props) =>
["blockUser", "deleteUser"].includes(props.type)
? `calc(50vh - 153px)`
: `calc(50vh - 137px)`};
padding-top: 36px;
padding-bottom: 18px;
background: white;
@@ -17,6 +22,16 @@ export const DeleteCategoryContainer = styled(Box)`
margin-left: auto;
margin-right: auto;
}
@media (max-width: 600px) {
width: 350px;
left: calc(50vw - 175px);
height: ${(props) =>
["blockUser", "deleteUser"].includes(props.type) ? "281px" : "246px"};
top: ${(props) =>
["blockUser", "deleteUser"].includes(props.type)
? `calc(50vh - 140px)`
: `calc(50vh - 123px)`};
}
`;
export const DeleteIcon = styled(Delete)`
z-index: 155;
@@ -45,6 +60,10 @@ export const ReassuranceText = styled(Typography)`
line-height: 21px;
color: ${selectedTheme.colors.messageText};
margin-top: 36px;
@media (max-width: 600px) {
font-size: 14px;
margin-top: 27px;
}
`;
export const ButtonsContainer = styled(Box)`
display: flex;
@@ -52,4 +71,24 @@ export const ButtonsContainer = styled(Box)`
flex-direction: row;
gap: 18px;
margin: 36px auto;
`
@media (max-width: 600px) {
margin-bottom: 18px;
margin-top: 27px;
}
`;
export const CancelButton = styled(PrimaryButton)`
width: 180px;
height: 49px;
@media (max-width: 600px) {
width: 149px;
height: 45px;
}
`;
export const SaveButton = styled(PrimaryButton)`
width: 180px;
height: 49px;
@media (max-width: 600px) {
width: 149px;
height: 45px;
}
`;

+ 40
- 0
src/components/Modals/DeleteReview/DeleteReview.js Просмотреть файл

@@ -0,0 +1,40 @@
import React from "react";
import PropTypes from "prop-types";
import {
DeleteReviewContainer,
DeleteReviewTitle,
XIcon,
} from "./DeleteReview.styled";
import BackdropComponent from "../../MUI/BackdropComponent";
import UserReviewsSingleCard from "../../Cards/UserReviewsCard/UserReviewsSingleCard/UserReviewsSingleCard";
import { useTranslation } from "react-i18next";

const DeleteReview = (props) => {
const { t } = useTranslation();
return (
<>
<BackdropComponent
isLoading
handleClose={() => props.setOpenedDeleteModal(false)}
position="fixed"
/>
<DeleteReviewContainer>
<DeleteReviewTitle>{t("admin.review.title")}</DeleteReviewTitle>
<UserReviewsSingleCard
showRemoveIcon
deleteModal
review={props.review}
/>
<XIcon />
</DeleteReviewContainer>
</>
);
};

DeleteReview.propTypes = {
review: PropTypes.any,
setOpenedDeleteModal: PropTypes.func,
cardComponent: PropTypes.any,
};

export default DeleteReview;

+ 62
- 0
src/components/Modals/DeleteReview/DeleteReview.styled.js Просмотреть файл

@@ -0,0 +1,62 @@
import { Box, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../themes";
import { ReactComponent as X } from "../../../assets/images/svg/plus.svg";

export const DeleteReviewContainer = styled(Box)`
position: fixed;
width: 100vw;
height: 100vh;
top: 0;
left: 0;
background-color: white;
z-index: 150;
padding: 28px;
& > div {
margin: 0 auto;
background-color: ${selectedTheme.colors.skeletonItemColor};
padding: 18px;
border: 1px solid ${selectedTheme.colors.borderNormal};
border-radius: 2px;
}
& > div::after {
border: 0;
}
@media (max-width: 600px) {
padding: 36px 28px;
}
`;
export const DeleteReviewTitle = styled(Typography)`
font-family: ${selectedTheme.fonts.textFont};
display: block;
font-weight: 700;
font-size: 24px;
line-height: 31px;
text-align: center;
margin-bottom: 36px;
color: ${selectedTheme.colors.primaryPurple};
@media (max-width: 600px) {
font-weight: 700;
font-size: 18px;
line-height: 25px;
}
`;
export const XIcon = styled(X)`
transform: rotate(45deg);
position: absolute;
top: 36px;
right: 36px;
cursor: pointer;
width: 26px;
height: 26px;
& path {
stroke: ${selectedTheme.colors.messageText};
/* stroke-width: 2; */
}
@media (max-width: 600px) {
width: 16px;
height: 16px;
top: 40px;
right: 18px;
}
`;

+ 36
- 26
src/components/Modals/EditCategory/EditCategory.js Просмотреть файл

@@ -8,6 +8,7 @@ import {
EditCategoryImagePicker,
EditCategoryTitle,
FieldLabel,
InputContainer,
SaveButton,
SupportedFormats,
XIcon,
@@ -51,6 +52,7 @@ const EditCategory = (props) => {
},
onSubmit: handleSubmit,
});
console.log(props);
return (
<>
<BackdropComponent
@@ -69,38 +71,39 @@ const EditCategory = (props) => {
</SupportedFormats>
</>
)}
<FieldLabel leftText={fieldLabel} />
<CategoryTitleField
name="title"
placeholder={placeholder}
italicPlaceholder
margin="normal"
value={formik.values.title}
onChange={formik.handleChange}
error={formik.touched.title && formik.errors.title}
helperText={formik.touched.title && formik.errors.title}
autoFocus
fullWidth
/>
<InputContainer hideImagePicker={props.hideImagePicker}>
<FieldLabel leftText={fieldLabel} />
<CategoryTitleField
name="title"
placeholder={placeholder}
italicPlaceholder
margin="normal"
value={formik.values.title}
onChange={formik.handleChange}
error={formik.touched.title && formik.errors.title}
helperText={formik.touched.title && formik.errors.title}
autoFocus
fullWidth
/>
</InputContainer>
<ButtonsContainer>
{props.method === "add" && (
<SaveButton
variant="contained"
width="180px"
height="48px"
onClick={formik.handleSubmit}
>
{firstButtonText}
</SaveButton>
)}
<SaveButton
variant={props.method === "add" ? "outlined" : "contained"}
width={props.method === "add" ? "180px" : "376px"}
showSecondButton={props.showSecondButton}
variant={props.firstOutlined ? "outlined" : "contained"}
height="48px"
onClick={formik.handleSubmit}
>
{secondButtonText}
{firstButtonText}
</SaveButton>
{props.showSecondButton && (
<SaveButton
variant={props.secondOutlined ? "outlined" : "contained"}
showSecondButton={props.showSecondButton}
onClick={formik.handleSubmit}
>
{secondButtonText}
</SaveButton>
)}
</ButtonsContainer>
</EditCategoryContainer>
</>
@@ -112,7 +115,14 @@ EditCategory.propTypes = {
setOpenedEditModal: PropTypes.func,
hideImagePicker: PropTypes.bool,
type: PropTypes.string,
showSecondButton: PropTypes.bool,
method: PropTypes.string,
firstOutlined: PropTypes.bool,
secondOutlined: PropTypes.bool,
};

EditCategory.defaultProps = {
firstOutlined: true,
};

export default EditCategory;

+ 48
- 1
src/components/Modals/EditCategory/EditCategory.styled.js Просмотреть файл

@@ -21,6 +21,13 @@ export const EditCategoryContainer = styled(Box)`
margin-left: auto;
margin-right: auto;
}
@media (max-width: 600px) {
width: 350px;
height: ${(props) => (props.hideImagePicker ? "207px" : "412px")};
left: calc(50vw - 175px);
top: ${(props) =>
props.hideImagePicker ? "calc(50vh - 103px)" : "calc(50vh - 206px)"};
}
`;
export const EditCategoryTitle = styled(Typography)`
display: block;
@@ -32,6 +39,11 @@ export const EditCategoryTitle = styled(Typography)`
margin-top: 36px;
width: 256px;
color: ${selectedTheme.colors.primaryPurple};
@media (max-width: 600px) {
font-size: 18px;
line-height: 24px;
margin-top: 18px;
}
`;
export const EditCategoryImagePicker = styled(ImagePicker)`
background: none;
@@ -43,12 +55,18 @@ export const EditCategoryImagePicker = styled(ImagePicker)`
position: relative;
left: calc(50% - 72px);
margin-bottom: 18px;
@media (max-width: 600px) {
margin-top: 27px;
}
`;
export const SupportedFormats = styled(Typography)`
font-size: 13px;
width: 100%;
text-align: center;
font-family: ${selectedTheme.fonts.textFont};
@media (max-width: 600px) {
font-size: 13px;
}
`;
export const CategoryTitleField = styled(TextField)`
width: 375px;
@@ -61,6 +79,7 @@ export const CategoryTitleField = styled(TextField)`
}
& div {
height: 40px;
width: 314px;
}
}
`;
@@ -68,7 +87,6 @@ export const FieldLabel = styled(Label)`
position: relative;
bottom: -14px;
width: 376px;
margin-top: 22px;
& label {
font-size: 12px;
font-weight: 600;
@@ -83,12 +101,34 @@ export const FieldLabel = styled(Label)`
}
}
`;
export const InputContainer = styled(Box)`
display: block;
width: fit-content;
margin-top: 22px;

@media (max-width: 600px) {
width: 314px;
height: 56px;
margin-top: 27px;
position: relative;
top: -18px;
${(props) =>
!props.hideImagePicker &&
`
margin-top: 25px;
`}
}
`;
export const SaveButton = styled(PrimaryButton)`
max-width: 376px;
height: 48px;
& button {
letter-spacing: 1.5px;
}
@media (max-width: 600px) {
height: 45px;
width: ${(props) => (props.showSecondButton ? "149px" : "314px")};
}
`;
export const XIcon = styled(X)`
transform: rotate(45deg);
@@ -102,6 +142,10 @@ export const XIcon = styled(X)`
stroke: ${selectedTheme.colors.messageText};
stroke-width: 2;
}
@media (max-width: 600px) {
top: 18px;
right: 18px;
}
`;
export const ButtonsContainer = styled(Box)`
display: flex;
@@ -109,4 +153,7 @@ export const ButtonsContainer = styled(Box)`
flex-direction: row;
gap: 18px;
margin: 36px auto;
@media (max-width: 600px) {
margin-top: 18px;
}
`;

+ 5
- 2
src/components/Profile/Header/Header.js Просмотреть файл

@@ -10,8 +10,10 @@ const Header = (props) => {
const history = useHistory();
const { t } = useTranslation();


const handleBackButton = () => {
history.push(HOME_PAGE);
if (props.isAdmin) history.goBack();
else history.push(HOME_PAGE);
};

return (
@@ -22,7 +24,7 @@ const Header = (props) => {
>
<ButtonContainer>
<ArrowButton side={"left"}></ArrowButton>
<HeaderText>{t("profile.backToHome")}</HeaderText>
<HeaderText>{props.isAdmin ? t("admin.users.goBack") : t("profile.backToHome")}</HeaderText>
</ButtonContainer>
</HeaderContainer>
);
@@ -35,6 +37,7 @@ Header.propTypes = {
filters: PropTypes.array,
category: PropTypes.string,
className: PropTypes.string,
isAdmin: PropTypes.bool,
};
Header.defaultProps = {
isGrid: false,

+ 2
- 1
src/components/Profile/Header/Header.styled.js Просмотреть файл

@@ -7,6 +7,7 @@ export const HeaderContainer = styled(Box)`

@media (max-width: 600px) {
margin-top: 40px;
margin-left: 18px;
}
`;
export const ButtonContainer = styled(Link)`
@@ -23,5 +24,5 @@ export const HeaderText = styled(Typography)`
line-height: 22px;
font-size: 16px;
color: ${selectedTheme.colors.primaryPurple};
border: 1px dotted ${selectedTheme.colors.primaryPurple};
border-bottom: 1px dotted ${selectedTheme.colors.primaryPurple};
`;

+ 8
- 6
src/components/Profile/Profile.js Просмотреть файл

@@ -10,11 +10,11 @@ import { fetchProfile } from "../../store/actions/profile/profileActions";
import { fetchProfileOffers } from "../../store/actions/offers/offersActions";
import Header from "./Header/Header";

const Profile = () => {
const Profile = (props) => {
const userId = useSelector(selectUserId);
const dispatch = useDispatch();
const routeMatch = useRouteMatch();
const idProfile = useMemo(() => routeMatch.params.idProfile, [routeMatch]);
const idProfile = useMemo(() => routeMatch.params?.idProfile, [routeMatch]);
useEffect(() => {
if (idProfile?.length > 0) {
dispatch(fetchProfile(idProfile));
@@ -25,16 +25,18 @@ const Profile = () => {
return userId === routeMatch.params.idProfile;
}, [userId, routeMatch]);
return (
<ProfileContainer>
<Header />
<ProfileCard isMyProfile={isMyProfile} />
<ProfileOffers isMyProfile={isMyProfile} />
<ProfileContainer className={props.className}>
<Header isAdmin={props.isAdmin} />
<ProfileCard isAdmin={props.isAdmin} isMyProfile={isMyProfile} />
<ProfileOffers isAdmin={props.isAdmin} isMyProfile={isMyProfile} />
</ProfileContainer>
);
};

Profile.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
isAdmin: PropTypes.bool,
};

export default Profile;

+ 7
- 4
src/components/Profile/ProfileOffers/ProfileOffers.js Просмотреть файл

@@ -78,7 +78,7 @@ const ProfileOffers = (props) => {
offersToShow={offersToShow}
setOffersToShow={setOffersToShow}
/>
<HeaderTitle isMyProfile={props.isMyProfile} />
<HeaderTitle isMyProfile={props.isMyProfile && !props.isAdmin} />
<SearchBar handleSearch={handleSearch} />
</>
)}
@@ -95,7 +95,8 @@ const ProfileOffers = (props) => {
) : offersToShow.length !== 0 ? (
offersToShow.map((item) => (
<OfferCard
isMyOffer={props.isMyProfile}
isAdmin={props.isAdmin}
isMyOffer={props.isMyProfile || props.isAdmin}
offer={item}
key={JSON.stringify(item)}
messageUser={messageUser}
@@ -108,11 +109,12 @@ const ProfileOffers = (props) => {
<OffersScroller hideArrows>
{offersToShow.map((item) => (
<OfferCard
isAdmin={props.isAdmin}
vertical
isMyOffer={props.isMyProfile}
isMyOffer={props.isMyProfile || props.isAdmin}
offer={item}
key={JSON.stringify(item)}
pinned
pinned={item.pinned}
messageUser={messageUser}
/>
))}
@@ -127,6 +129,7 @@ const ProfileOffers = (props) => {
ProfileOffers.propTypes = {
children: PropTypes.node,
isMyProfile: PropTypes.bool,
isAdmin: PropTypes.bool,
};

export default ProfileOffers;

+ 3
- 1
src/components/Profile/ProfileOffers/ProfileOffers.styled.js Просмотреть файл

@@ -13,13 +13,15 @@ export const ProfileOffersContainer = styled(Box)`
}
@media (max-width: 600px) {
padding: 0;
width: calc(100vw - 36px);
margin: 34px 18px;
}
`;
export const OffersContainer = styled(Box)`
margin-top: 30px;
`;
export const OffersScroller = styled(HorizontalScroller)`
height: 373px;
height: 400px;
width: 100%;
margin-left: 0;
& div {

+ 5
- 1
src/components/ProfileMini/ProfileMini.js Просмотреть файл

@@ -35,7 +35,11 @@ const ProfileMini = () => {
<ProfileHeader>
<ProfileHeaderIconContainer>
<ProfileIcon />
<ProfileHeaderText>{t("profile.companyProfile")}</ProfileHeaderText>
<ProfileHeaderText>
{isMyProfile
? t("profile.myProfile")
: t("profile.companyProfile")}
</ProfileHeaderText>
</ProfileHeaderIconContainer>
<ItemDetailsHeaderCard
offer={offer}

+ 35
- 19
src/components/UserReviews/ReviewsSorting/ReviewsSorting.js Просмотреть файл

@@ -1,4 +1,4 @@
import React from "react";
import React, { forwardRef, useImperativeHandle, useMemo } from "react";
import PropTypes from "prop-types";
import {
DownArrowIcon,
@@ -11,50 +11,66 @@ import { selectSelectedReviews } from "../../../store/selectors/reviewSelector";
import { sortReviews } from "../../../util/helpers/reviewsHelper";
import { reviewSortEnum } from "../../../enums/reviewEnum";
import { setReviews } from "../../../store/actions/review/reviewActions";
import { sortAdminEnum } from "../../../enums/sortEnum";

const ReviewsSorting = (props) => {
const ReviewsSorting = forwardRef((props, ref) => {
const reviews = useSelector(selectSelectedReviews);
const dispatch = useDispatch();
const [value, setValue] = useState();
const changeValue = (event) => {
dispatch(
setReviews(
sortReviews(
reviews,
event.target.value.value === reviewSortEnum.POSITIVE.value
if (props.isAdmin) {
console.log("sortiranje: ", event.target.value)
} else {
dispatch(
setReviews(
sortReviews(
reviews,
event.target.value.value === reviewSortEnum.POSITIVE.value
)
)
)
);
props.changeSorting();
);
props.changeSorting();
}
setValue(event.target.value);
};
const sortEnum = useMemo(() => {
if (props.isAdmin) return sortAdminEnum;
return reviewSortEnum;
});
useImperativeHandle(ref, () => ({
sortValue: value,
hasGivenReview: value?.value === sortAdminEnum.GIVEN.value
}))
return (
<HeaderSelect
value={value || reviewSortEnum.INITIAL}
value={value || sortEnum.INITIAL}
IconComponent={DownArrowIcon}
onChange={changeValue}
>
<SelectOption style={{ display: "none" }} value={reviewSortEnum.INITIAL}>
{reviewSortEnum.INITIAL.mainText}
<SelectOption style={{ display: "none" }} value={sortEnum.INITIAL}>
{sortEnum.INITIAL.mainText}
</SelectOption>
{Object.keys(reviewSortEnum).map((property) => {
if (reviewSortEnum[property].value === 0) return;
{Object.keys(sortEnum).map((property) => {
if (sortEnum[property].value === 0) return;
return (
<SelectOption
value={reviewSortEnum[property]}
key={reviewSortEnum[property].value}
value={sortEnum[property]}
key={sortEnum[property].value}
>
{reviewSortEnum[property].mainText}
{sortEnum[property].mainText}
</SelectOption>
);
})}
</HeaderSelect>
);
};
});

ReviewsSorting.displayName = "ReviewsSorting";

ReviewsSorting.propTypes = {
children: PropTypes.node,
changeSorting: PropTypes.func,
isAdmin: PropTypes.bool,
};

export default ReviewsSorting;

+ 12
- 4
src/components/UserReviews/UserReviews.js Просмотреть файл

@@ -6,6 +6,7 @@ import {
ReviewsHeader,
ReviewsHeaderTitle,
ReviewsTitle,
UserReviewsContainer,
} from "./UserReviews.styled";

import StarBorderIcon from "@mui/icons-material/StarBorder";
@@ -34,6 +35,7 @@ const UserReviews = (props) => {
const routeMatch = useRouteMatch();
const dispatch = useDispatch();
const listRef = useRef(null);
const sortRef = useRef(null);

const isLoadingReview = useSelector(
selectIsLoadingByActionType(
@@ -72,15 +74,15 @@ const UserReviews = (props) => {
listRef.current.scrollTo({ top: 0, behaviour: "smooth" });
};

console.log(sortRef.current?.sortValue);
return (
<>
<UserReviewsContainer className={props.className}>
{!props.givingReview &&
(isLoadingReview || isLoadingReview === undefined) ? (
<SkeletonUserReviews />
) : (
<ReviewsBox
profile={props.isProfileReviews}
className={props.className}
numOfReviews={lastThreeReviews?.length}
>
{!props.givingReview && (
@@ -98,7 +100,11 @@ const UserReviews = (props) => {
/>
<ReviewsTitle>{t("reviews.rates")}</ReviewsTitle>
</ReviewsHeaderTitle>
<ReviewsSorting changeSorting={scrollToTop} />
<ReviewsSorting
changeSorting={scrollToTop}
ref={sortRef}
isAdmin={props.isAdmin}
/>
</ReviewsHeader>
)}
<ReviewList ref={listRef} isProfileReviews={props.isProfileReviews}>
@@ -107,6 +113,7 @@ const UserReviews = (props) => {
<UserReviewsCard
review={review}
key={index}
hasGivenReview={sortRef.current?.hasGivenReview}
givingReview={props.givingReview}
/>
))
@@ -116,7 +123,7 @@ const UserReviews = (props) => {
</ReviewList>
</ReviewsBox>
)}
</>
</UserReviewsContainer>
);
};

@@ -128,6 +135,7 @@ UserReviews.propTypes = {
className: PropTypes.string,
givingReview: PropTypes.bool,
offer: PropTypes.any,
isAdmin: PropTypes.bool,
};
UserReviews.defaultProps = {
isProfileReviews: false,

+ 3
- 9
src/components/UserReviews/UserReviews.styled.js Просмотреть файл

@@ -5,18 +5,11 @@ import ThumbDownIcon from "@mui/icons-material/ThumbDown";
import selectedTheme from "../../themes";
import { ReactComponent as DownArrow } from "../../assets/images/svg/up-arrow.svg";

export const UserReviewsContainer = styled(Box)``;

export const ReviewsBox = styled(Box)`
width: 100%;
/* One review is 185px in height and 82 px are header title + padding */
/* height: ${(props) =>
props.numOfReviews > 0
? props.numOfReviews * 185 + 82 + "px"
: `calc(100% - 90px)`}; */
/* max-height: 100vh; */
min-width: 290px;
/* @media (max-width: 1200px) {
padding: 0 50px;
} */
${(props) =>
props.profile &&
`
@@ -35,6 +28,7 @@ export const ReviewsBox = styled(Box)`
? "450px"
: "350px"};
padding: 0;
margin: 0 18px;
margin-top: 60px;
}
`;

+ 1
- 0
src/constants/pages.js Просмотреть файл

@@ -20,6 +20,7 @@ export const PRICES_PAGE = "/prices";
export const POLICY_PRIVACY_PAGE = "/policy";
export const ADMIN_HOME_PAGE = "/admin";
export const ADMIN_USERS_PAGE = "/admin/users";
export const ADMIN_SINGLE_USER_PAGE = "/admin/users/:idProfile";
export const ADMIN_CATEGORIES_PAGE = "/admin/categories";
export const ADMIN_LOCATIONS_PAGE = "/admin/locations";
export const ADMIN_PAYMENT_PAGE = "/admin/payment";

+ 14
- 0
src/enums/sortEnum.js Просмотреть файл

@@ -19,4 +19,18 @@ export const sortEnum = {
mainText: "Najstarije",
queryString: "oldest"
}
}
export const sortAdminEnum = {
INITIAL: {
value: 0,
mainText: "Sortiraj po"
},
GIVEN: {
value: 1,
mainText: "Date"
},
RECIEVED: {
value: 2,
mainText: "Dobijene"
}
}

+ 27
- 1
src/i18n/resources/rs.js Просмотреть файл

@@ -425,9 +425,10 @@ export default {
headerTitle: "Ulogujte se",
},
users: {
headerTitle: "Profili korisnika",
headerTitle: "Profili kompanija",
searchPlaceholder: "Pretražite korisnike....",
checkProfile: "Pogledaj profil",
goBack: "Nazad na sve kompanije",
},
navigation: {
role: "Administrator",
@@ -454,6 +455,7 @@ export default {
fieldTitle: "Naslov",
placeholder: "Naziv kategorije...",
save: "Izmeni",
next: "Sledeća",
},
add: {
title: "Nova Kategorija",
@@ -469,6 +471,8 @@ export default {
subcategoriesHeaderTitle: "Podkategorije",
placeholder: "Pretražite podkategorije...",
addSubcategory: "Dodaj podkategoriju",
cancel: "Otkaži",
delete: "Obriši",
reassuranceDelete:
"Da li ste sigurni da želite da obrišete odabranu podkategoriju?",
edit: {
@@ -476,6 +480,7 @@ export default {
fieldTitle: "Naslov",
placeholder: "Naziv podkategorije...",
save: "Izmeni",
next: "Sledeća"
},
add: {
title: "Nova Podkategorija",
@@ -506,5 +511,26 @@ export default {
next: "Sledeća",
},
},
deleteUser: {
reassuranceDelete:
"Da li ste sigurni da želite da obrišete profil kompanje?",
cancel: "Otkaži",
delete: "Obriši",
},
blockUser: {
reassuranceDelete:
"Da li ste sigurni da želite da blokirate profil kompanje?",
cancel: "Otkaži",
delete: "Blokiraj",
},
pin: {
reassurancePin:
"Da li ste sigurni da želite da zakačite proizvod na vrhu?",
confirm: "Zakači",
},
review: {
title: "Brisanje Komentara",
confirm: "Obriši komentar"
}
},
};

+ 30
- 0
src/layouts/AdminLayout/AdminLayout.js Просмотреть файл

@@ -0,0 +1,30 @@
import React from "react";
import PropTypes from "prop-types";
import { Content, LeftCard, AdminLayoutContainer } from "./AdminLayout.styled";
import { Grid } from "@mui/material";

const AdminLayout = (props) => {
return (
<AdminLayoutContainer className={props.className}>
{props.children}
<Grid container maxHeight="xl">
<LeftCard item xs={0} sm={3} md={3} lg={3} xl={2.4}>
{props.leftCard}
</LeftCard>
<Content item xs={12} sm={9} md={9} lg={9} xl={9.6}>
{props.content}
</Content>
</Grid>
</AdminLayoutContainer>
);
};

AdminLayout.propTypes = {
children: PropTypes.node,
leftCard: PropTypes.node,
content: PropTypes.node,
rightCard: PropTypes.node,
className: PropTypes.string,
};

export default AdminLayout;

+ 24
- 0
src/layouts/AdminLayout/AdminLayout.styled.js Просмотреть файл

@@ -0,0 +1,24 @@
import { Container, Grid } from "@mui/material";
import styled from "styled-components";

export const AdminLayoutContainer = styled(Container)`
padding-left: 0;
padding-right: 0;
margin: 0;
width: 100%;
max-width: none;
display: flex;
flex: 1;
height: 100%;
margin-top: 80px;
@media (max-width: 600px) {
margin-top: 100px;
}
`

export const LeftCard = styled(Grid)`
margin-top: 30px;
border-top-right-radius: 4px;
`
export const Content = styled(Grid)`
`

+ 9
- 8
src/pages/AdminHomePage/AdminCategoriesPage/AdminCategoriesPage.styled.js Просмотреть файл

@@ -13,7 +13,7 @@ export const AdminCategoriesPageContainer = styled(Box)`
@media (max-width: 600px) {
padding: 18px;
min-height: calc(100vh - 72px);
padding-bottom: 54px;
padding-bottom: 100px;
top: 65px;
}
`;
@@ -21,13 +21,14 @@ export const AdminCategoriesHeader = styled(Header)`
/* top: 40px; */
top: 0;
@media (max-width: 600px) {
top: -10px;
margin-top: 18px;
& div {
margin-top: 10px;
top: -5px;
margin-top: 0px;
& > div {
margin-top: -10px;
}
& div div:nth-child(1) {
top: 22px;
& > div > div > div:nth-child(1) {
top: 15px;
left: 0;
}
}
`;
@@ -52,5 +53,5 @@ export const NewCategoryButton = styled(PrimaryButton)`
}
`
export const CategoriesList = styled(Box)`
padding-top: 10px
/* padding-top: 10px */
`

+ 14
- 3
src/pages/AdminHomePage/AdminHomePage.js Просмотреть файл

@@ -3,7 +3,6 @@ import PropTypes from "prop-types";
// import MarketPlace from "../../components/MarketPlace/MarketPlace";
// import useOffers from "../../hooks/useOffers/useOffers";
import Sidebar from "../../components/Admin/Sidebar/Sidebar";
import { MainLayoutAdminHomePage } from "./AdminHomePage.styled";
import { useSelector } from "react-redux";
// import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors";
// import { OFFERS_SCOPE } from "../../store/actions/offers/offersActionConstants";
@@ -14,6 +13,7 @@ import {
ADMIN_CATEGORIES_PAGE,
ADMIN_LOCATIONS_PAGE,
ADMIN_PAYMENT_PAGE,
ADMIN_SINGLE_USER_PAGE,
ADMIN_SUBCATEGORIES_PAGE,
ADMIN_USERS_PAGE,
HOME_PAGE,
@@ -24,6 +24,8 @@ import AdminRoute from "../../components/Router/AdminRoute";
import AdminSubcategoriesPage from "./AdminSubcategoriesPage/AdminSubcategoriesPage";
import AdminLocationsPage from "./AdminLocationsPage/AdminLocationsPage";
import AdminPaymentPage from "./AdminPaymentPage/AdminPaymentPage";
import AdminSingleUserPage from "./AdminUsersPage/AdminSingleUserPage/AdminSingleUserPage";
import { AdminLayoutHomePage } from "./AdminHomePage.styled";

const AdminHomePage = () => {
const profile = useSelector(selectMineProfile);
@@ -37,16 +39,25 @@ const AdminHomePage = () => {
history.push(HOME_PAGE);
}
return (
<MainLayoutAdminHomePage
<AdminLayoutHomePage
leftCard={<Sidebar />}
content={
<Switch>
<AdminRoute path={ADMIN_USERS_PAGE} component={AdminUsersPage} />
<AdminRoute
exact
path={ADMIN_USERS_PAGE}
component={AdminUsersPage}
/>
<AdminRoute
exact
path={ADMIN_CATEGORIES_PAGE}
component={AdminCategoriesPage}
/>
<AdminRoute
exact
path={ADMIN_SINGLE_USER_PAGE}
component={AdminSingleUserPage}
/>
<AdminRoute
path={ADMIN_SUBCATEGORIES_PAGE}
component={AdminSubcategoriesPage}

+ 2
- 2
src/pages/AdminHomePage/AdminHomePage.styled.js Просмотреть файл

@@ -1,6 +1,6 @@
import styled from "styled-components";
import MainLayout from "../../layouts/MainLayout/MainLayout";
import AdminLayout from "../../layouts/AdminLayout/AdminLayout";

export const MainLayoutAdminHomePage = styled(MainLayout)`
export const AdminLayoutHomePage = styled(AdminLayout)`
margin-top: 0;
`;

+ 8
- 7
src/pages/AdminHomePage/AdminLocationsPage/AdminLocationsPage.styled.js Просмотреть файл

@@ -14,20 +14,21 @@ export const AdminLocationsPageContainer = styled(Box)`
@media (max-width: 600px) {
padding: 18px;
min-height: (100vh - 72px);
padding-bottom: 54px;
padding-bottom: 100px;
top: 65px;
}
`;
export const AdminLocationsHeader = styled(Header)`
top: 0;
@media (max-width: 600px) {
top: -10px;
margin-top: 18px;
& div {
margin-top: 10px;
top: -5px;
margin-top: 0px;
& > div {
margin-top: -10px;
}
& div div:nth-child(1) {
top: 22px;
& > div > div > div:nth-child(1) {
top: 15px;
left: 0;
}
}
`;

+ 5
- 4
src/pages/AdminHomePage/AdminSubcategoriesPage/AdminSubcategoriesPage.js Просмотреть файл

@@ -21,8 +21,6 @@ import CategoryCard from "../../../components/Cards/CategoryCard/CategoryCard";
import selectedTheme from "../../../themes";
import { useState } from "react";
import EditCategory from "../../../components/Modals/EditCategory/EditCategory";
import { isInRoute } from "../../../util/helpers/routeHelpers";
import { ADMIN_SUBCATEGORIES_PAGE } from "../../../constants/pages";

const AdminSubcategoriesPage = () => {
const { t } = useTranslation();
@@ -32,15 +30,15 @@ const AdminSubcategoriesPage = () => {
const manualSearchString = useSelector(selectManualSearchString);
const [openedAddModal, setOpenedAddModal] = useState(false);

console.log(isInRoute(ADMIN_SUBCATEGORIES_PAGE));

useEffect(() => {
dispatch(fetchCategories());
}, []);

const handleSearch = (value) => {
console.log(value);
dispatch(setManualSearchString(value));
};

const category = useMemo(() => {
if (routeMatch.params?.categoryId) {
const categoryId = routeMatch.params.categoryId;
@@ -48,6 +46,7 @@ const AdminSubcategoriesPage = () => {
}
return {};
}, [routeMatch, categories]);

const subcategories = useMemo(() => {
if (category) {
if (manualSearchString)
@@ -60,6 +59,8 @@ const AdminSubcategoriesPage = () => {
}
return [];
}, [category, manualSearchString]);
console.log("subc", categories);
return (
<>
<AdminSubcategoriesPageContainer>

+ 1
- 1
src/pages/AdminHomePage/AdminSubcategoriesPage/AdminSubcategoriesPage.styled.js Просмотреть файл

@@ -17,7 +17,7 @@ export const AdminSubcategoriesPageContainer = styled(Box)`
@media (max-width: 600px) {
padding: 18px;
min-height: (100vh - 72px);
padding-bottom: 54px;
padding-bottom: 100px;
top: 65px;
}
`;

+ 25
- 0
src/pages/AdminHomePage/AdminUsersPage/AdminSingleUserPage/AdminSingleUserPage.js Просмотреть файл

@@ -0,0 +1,25 @@
import React, { useEffect } from "react";
import PropTypes from "prop-types";
import {
AdminSingleUserPageContainer,
AdminSingleUserPageProfile,
AdminSingleUserPageReviews,
} from "./AdminSingleUserPage.styled";

const AdminSingleUserPage = () => {
useEffect(() => {
window.scrollTo({ top: 0, behaviour: "smooth" });
}, []);
return (
<AdminSingleUserPageContainer>
<AdminSingleUserPageProfile isAdmin />
<AdminSingleUserPageReviews isProfileReviews isAdmin />
</AdminSingleUserPageContainer>
);
};

AdminSingleUserPage.propTypes = {
children: PropTypes.node,
};

export default AdminSingleUserPage;

+ 26
- 0
src/pages/AdminHomePage/AdminUsersPage/AdminSingleUserPage/AdminSingleUserPage.styled.js Просмотреть файл

@@ -0,0 +1,26 @@
import { Box } from "@mui/material";
import styled from "styled-components";
import Profile from "../../../../components/Profile/Profile";
import UserReviews from "../../../../components/UserReviews/UserReviews";

export const AdminSingleUserPageContainer = styled(Box)`
@media (max-width: 600px) {
margin-top: 90px;
}
`;
export const AdminSingleUserPageProfile = styled(Profile)`
margin-bottom: 5px;
`;
export const AdminSingleUserPageReviews = styled(UserReviews)`
padding: 0 50px;
@media (max-width: 600px) {
padding: 0;
width: calc(100% - 36px);
& > div {
margin-top: 0;
height: 500px;
position: relative;
top: -18px;
}
}
`;

+ 36
- 9
src/pages/AdminHomePage/AdminUsersPage/AdminUsersPage.js Просмотреть файл

@@ -1,26 +1,53 @@
import React, { useEffect } from "react";
import React, { useEffect, useMemo } from "react";
import PropTypes from "prop-types";
import MarketPlace from "../../../components/MarketPlace/MarketPlace";
import { useDispatch, useSelector } from "react-redux";
import { selectAllProfiles } from "../../../store/selectors/profileSelectors";
import { fetchAllProfiles } from "../../../store/actions/profile/profileActions";
import { AdminUsersPageContainer } from "./AdminUsersPage.styled";
import {
AdminUsersHeader,
AdminUsersList,
AdminUsersPageContainer,
AdminUsersSearchField,
} from "./AdminUsersPage.styled";
import BigProfileCard from "../../../components/Cards/ProfileCard/BigProfileCard/BigProfileCard";
import { useTranslation } from "react-i18next";

const AdminUsersPage = () => {
const dispatch = useDispatch();
const { t } = useTranslation();
const allUsers = useSelector(selectAllProfiles);
const allUsersToShow = useMemo(
() => (Array.isArray(allUsers) ? allUsers : []),
[allUsers]
);
useEffect(() => {
dispatch(fetchAllProfiles());
}, []);

const handleSearch = () => {};

return (
<AdminUsersPageContainer>
<MarketPlace
isAdmin
myOffers
users
allUsers={Array.isArray(allUsers) ? allUsers : []}
/>
<>
<AdminUsersSearchField
isAdmin
handleSearch={handleSearch}
placeholder={t("admin.subcategories.placeholder")}
/>
<AdminUsersHeader
myOffers
category
hideGrid
isAdmin
users
hideBackButton
/>
<AdminUsersList>
{allUsersToShow.map((singleUser) => (
<BigProfileCard key={singleUser._id} profile={singleUser} />
))}
</AdminUsersList>
</>
</AdminUsersPageContainer>
);
};

+ 39
- 6
src/pages/AdminHomePage/AdminUsersPage/AdminUsersPage.styled.js Просмотреть файл

@@ -1,13 +1,46 @@
import { Box } from "@mui/material";
import styled from "styled-components";
import Header from "../../../components/MarketPlace/Header/Header";
import SearchField from "../../../components/TextFields/SearchField/SearchField";

export const AdminUsersPageContainer = styled(Box)`
padding: 60px;
/* display: flex; */
position: relative;
padding-top: 38px;
padding-bottom: 100px;
min-height: 100vh;
flex-direction: column;
@media (max-width: 600px) {
padding: 18px;
min-height: (100vh - 72px);
padding-bottom: 54px;
top: 38px;
}
`;
export const AdminUsersHeader = styled(Header)`
top: 4px;
@media (max-width: 600px) {
top: 0px;
/* margin-top: 18px; */
& > div {
margin-left: 60px;
margin-right: 60px;
margin-top: 43px;
margin-top: 0;
}
& > div > div:nth-child(2) {
top: 77px;
& > div > div > div {
left: 0;
top: 25px;
}
`
& > div:nth-child(2) {
white-space: nowrap;
}
}
`;
export const AdminUsersSearchField = styled(SearchField)`
top: -15px;
@media (max-width: 600px) {
display: none;
}
`;
export const AdminUsersList = styled(Box)`
padding-top: 18px;
`;

+ 1
- 0
src/util/helpers/imageUrlGetter.js Просмотреть файл

@@ -15,6 +15,7 @@ export const variants = {
profileCard: "profileCard",
createReviewCard: "createReviewCard",
carousel: "carousel",
adminProfileCard: "reviewCard"
};

const cloudFlareVariants = {

+ 3
- 7
src/util/helpers/routeHelpers.js Просмотреть файл

@@ -4,6 +4,7 @@ import {
ADMIN_LOCATIONS_PAGE,
ADMIN_LOGIN_PAGE,
ADMIN_PAYMENT_PAGE,
ADMIN_SINGLE_USER_PAGE,
ADMIN_SUBCATEGORIES_PAGE,
ADMIN_USERS_PAGE,
FORGOT_PASSWORD_MAIL_SENT,
@@ -55,7 +56,8 @@ export const isAdminRoute = () => {
routeMatches(ADMIN_CATEGORIES_PAGE) ||
dynamicRouteMatches(ADMIN_SUBCATEGORIES_PAGE) ||
routeMatches(ADMIN_LOCATIONS_PAGE) ||
routeMatches(ADMIN_PAYMENT_PAGE)
routeMatches(ADMIN_PAYMENT_PAGE) ||
dynamicRouteMatches(ADMIN_SINGLE_USER_PAGE)
)
return true;
return false;
@@ -69,12 +71,6 @@ export const dynamicRouteMatches = (dynamicRoute) => {
};

export const isInRoute = (routeToCheck) => {
console.log("routeToCheck", routeToCheck);
console.log(
"first Expression",
history.location.pathname.includes(routeToCheck)
);
console.log("second expression", dynamicRouteMatches(routeToCheck));
return (
history.location.pathname.includes(routeToCheck) ||
dynamicRouteMatches(routeToCheck)

Загрузка…
Отмена
Сохранить