瀏覽代碼

Merged with master

feature/684
Djordje Mitrovic 3 年之前
父節點
當前提交
345469694d
共有 100 個文件被更改,包括 1813 次插入538 次删除
  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. 4
    1
      src/components/Cards/CategoryCard/CategoryCard.js
  6. 3
    0
      src/components/Cards/CategoryCard/CategoryCard.styled.js
  7. 1
    1
      src/components/Cards/CategoryCard/CategoryRemoveButton/CategoryRemoveButton.styled.js
  8. 5
    2
      src/components/Cards/FilterCard/Choser/LocationChoser/LocationChoser.js
  9. 2
    4
      src/components/Cards/LabeledCard/LabeledCard.js
  10. 36
    0
      src/components/Cards/LabeledCard/User/UserLabeledCard.js
  11. 59
    0
      src/components/Cards/LabeledCard/User/UserLabeledCard.styled.js
  12. 3
    2
      src/components/Cards/OfferCard/DeleteOffer/CancelButton/CancelButton.js
  13. 1
    1
      src/components/Cards/OfferCard/DeleteOffer/CancelButton/CancelButton.styled.js
  14. 12
    5
      src/components/Cards/OfferCard/DeleteOffer/DeleteOffer.js
  15. 24
    4
      src/components/Cards/OfferCard/DeleteOffer/DeleteOffer.styled.js
  16. 45
    0
      src/components/Cards/OfferCard/DeleteOffer/DeleteOfferLabeledCard/DeleteOfferLabeledCard.js
  17. 58
    0
      src/components/Cards/OfferCard/DeleteOffer/DeleteOfferLabeledCard/DeleteOfferLabeledCard.styled.js
  18. 15
    3
      src/components/Cards/OfferCard/DeleteOffer/OfferDescription/OfferDescription.styled.js
  19. 4
    3
      src/components/Cards/OfferCard/DeleteOffer/SaveButton/SaveButton.js
  20. 1
    1
      src/components/Cards/OfferCard/DeleteOffer/SaveButton/SaveButton.styled.js
  21. 17
    1
      src/components/Cards/OfferCard/OfferCard.js
  22. 39
    9
      src/components/Cards/OfferCard/OfferCard.styled.js
  23. 56
    12
      src/components/Cards/ProfileCard/BigProfileCard/BigProfileCard.js
  24. 61
    206
      src/components/Cards/ProfileCard/BigProfileCard/BigProfileCard.styled.js
  25. 86
    18
      src/components/Cards/ProfileCard/ProfileCard.js
  26. 104
    7
      src/components/Cards/ProfileCard/ProfileCard.styled.js
  27. 5
    1
      src/components/Cards/ProfileCard/ProfileContact/ProfileContact.styled.js
  28. 16
    4
      src/components/Cards/ProfileCard/ProfileMainInfo/ProfileMainInfo.js
  29. 16
    4
      src/components/Cards/ProfileCard/ProfileMainInfo/ProfileMainInfo.styled.js
  30. 2
    2
      src/components/Cards/ProfileCard/ProfileStats/ProfileStats.js
  31. 5
    4
      src/components/Cards/ProfileCard/ProfileStats/ProfileStats.styled.js
  32. 21
    21
      src/components/Cards/UserReviewsCard/UserReviewsCard.js
  33. 0
    14
      src/components/Cards/UserReviewsCard/UserReviewsCard.styled.js
  34. 18
    0
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/RemoveButton/RemoveButton.js
  35. 21
    0
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/RemoveButton/RemoveButton.styled.js
  36. 0
    0
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewDetails/ReviewDetails.js
  37. 1
    1
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewDetails/ReviewDetails.styled.js
  38. 4
    2
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewOffer/ReviewOffer.js
  39. 14
    1
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewOffer/ReviewOffer.styled.js
  40. 2
    2
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewQuote/ReviewQuote.js
  41. 16
    3
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewQuote/ReviewQuote.styled.js
  42. 5
    5
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewerProfile/ReviewerProfile.js
  43. 1
    1
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewerProfile/ReviewerProfile.styled.js
  44. 46
    0
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/UserReviewsSingleCard.js
  45. 21
    0
      src/components/Cards/UserReviewsCard/UserReviewsSingleCard/UserReviewsSingleCard.styled.js
  46. 4
    1
      src/components/CreateReview/SecondStep/NextButton/NextButton.js
  47. 10
    3
      src/components/CreateReview/SecondStep/SecondStepCreateReview.js
  48. 11
    9
      src/components/CreateReview/SecondStep/SecondStepCreateReview.styled.js
  49. 20
    0
      src/components/Header/Drawer/AdminInfo/AdminInfo.js
  50. 24
    0
      src/components/Header/Drawer/AdminInfo/AdminInfo.styled.js
  51. 47
    0
      src/components/Header/Drawer/Buttons/AdminButtons/AdminButton/AdminButton.js
  52. 42
    0
      src/components/Header/Drawer/Buttons/AdminButtons/AdminButton/AdminButton.styled.js
  53. 55
    0
      src/components/Header/Drawer/Buttons/AdminButtons/AdminButtons.js
  54. 9
    0
      src/components/Header/Drawer/Buttons/AdminButtons/AdminButtons.styled.js
  55. 33
    17
      src/components/Header/Drawer/Drawer.js
  56. 10
    4
      src/components/Header/Drawer/Drawer.styled.js
  57. 2
    2
      src/components/Header/DrawerContainer/DrawerContainer.js
  58. 1
    1
      src/components/ItemDetails/ItemDetails.styled.js
  59. 1
    1
      src/components/ItemDetails/ItemDetailsHeaderCard/ItemDetailsHeaderCard.styled.js
  60. 29
    13
      src/components/Modals/DeleteCategory/DeleteCategory.js
  61. 42
    3
      src/components/Modals/DeleteCategory/DeleteCategory.styled.js
  62. 27
    0
      src/components/Modals/DeleteReview/DeleteButton/DeleteButton.js
  63. 20
    0
      src/components/Modals/DeleteReview/DeleteButton/DeleteButton.styled.js
  64. 42
    0
      src/components/Modals/DeleteReview/DeleteReview.js
  65. 62
    0
      src/components/Modals/DeleteReview/DeleteReview.styled.js
  66. 40
    27
      src/components/Modals/EditCategory/EditCategory.js
  67. 49
    1
      src/components/Modals/EditCategory/EditCategory.styled.js
  68. 6
    2
      src/components/Profile/Header/Header.js
  69. 3
    2
      src/components/Profile/Header/Header.styled.js
  70. 8
    6
      src/components/Profile/Profile.js
  71. 8
    5
      src/components/Profile/ProfileOffers/ProfileOffers.js
  72. 4
    1
      src/components/Profile/ProfileOffers/ProfileOffers.styled.js
  73. 5
    1
      src/components/ProfileMini/ProfileMini.js
  74. 3
    2
      src/components/ProfileMini/ProfileMini.styled.js
  75. 2
    0
      src/components/StepProgress/StepProgress.styled.js
  76. 35
    19
      src/components/UserReviews/ReviewsSorting/ReviewsSorting.js
  77. 14
    4
      src/components/UserReviews/UserReviews.js
  78. 3
    9
      src/components/UserReviews/UserReviews.styled.js
  79. 1
    0
      src/constants/pages.js
  80. 14
    0
      src/enums/sortEnum.js
  81. 7
    3
      src/hooks/useOffers/useCompanyFilter.js
  82. 31
    1
      src/i18n/resources/rs.js
  83. 30
    0
      src/layouts/AdminLayout/AdminLayout.js
  84. 24
    0
      src/layouts/AdminLayout/AdminLayout.styled.js
  85. 9
    9
      src/layouts/ItemDetailsLayout/ItemDetailsLayout.styled.js
  86. 1
    0
      src/pages/AdminHomePage/AdminCategoriesPage/AdminCategoriesPage.js
  87. 9
    8
      src/pages/AdminHomePage/AdminCategoriesPage/AdminCategoriesPage.styled.js
  88. 14
    3
      src/pages/AdminHomePage/AdminHomePage.js
  89. 2
    2
      src/pages/AdminHomePage/AdminHomePage.styled.js
  90. 1
    0
      src/pages/AdminHomePage/AdminLocationsPage/AdminLocationsPage.js
  91. 8
    7
      src/pages/AdminHomePage/AdminLocationsPage/AdminLocationsPage.styled.js
  92. 6
    4
      src/pages/AdminHomePage/AdminSubcategoriesPage/AdminSubcategoriesPage.js
  93. 1
    1
      src/pages/AdminHomePage/AdminSubcategoriesPage/AdminSubcategoriesPage.styled.js
  94. 25
    0
      src/pages/AdminHomePage/AdminUsersPage/AdminSingleUserPage/AdminSingleUserPage.js
  95. 26
    0
      src/pages/AdminHomePage/AdminUsersPage/AdminSingleUserPage/AdminSingleUserPage.styled.js
  96. 36
    9
      src/pages/AdminHomePage/AdminUsersPage/AdminUsersPage.js
  97. 39
    6
      src/pages/AdminHomePage/AdminUsersPage/AdminUsersPage.styled.js
  98. 1
    1
      src/store/saga/locationsSaga.js
  99. 2
    2
      src/util/helpers/dateHelpers.js
  100. 0
    0
      src/util/helpers/imageUrlGetter.js

+ 1
- 1
.env 查看文件

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

+ 1
- 1
public/index.html 查看文件

<link <link
rel="stylesheet" rel="stylesheet"
type="text/css" 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="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />

+ 0
- 2
src/components/Admin/Sidebar/Sidebar.js 查看文件

const dispatch = useDispatch(); const dispatch = useDispatch();
const { isMobile } = useIsMobile(); const { isMobile } = useIsMobile();
const { t } = useTranslation(); const { t } = useTranslation();
console.log(profile);
const routeToItem = (route) => { const routeToItem = (route) => {
console.log(route);
history.push(route); history.push(route);
}; };
const logoutHandler = () => { const logoutHandler = () => {

+ 3
- 0
src/components/Admin/Sidebar/Sidebar.styled.js 查看文件

min-width: 281px; min-width: 281px;
overflow-y: auto; overflow-y: auto;
height: 100vh; height: 100vh;
@media (max-width: 1536px) {
width: 25%;
}
@media (max-width: 600px) { @media (max-width: 600px) {
display: none; display: none;
} }

+ 4
- 1
src/components/Cards/CategoryCard/CategoryCard.js 查看文件

); );
} }
}; };
console.log(props);
return ( return (
<> <>
<CategoryCardContainer className={props.className}> <CategoryCardContainer className={props.className}>
)} )}
{openedEditModal && ( {openedEditModal && (
<EditCategory <EditCategory
hideImagePicker
hideImagePicker={props.type !== "categories"}
setOpenedEditModal={setOpenedEditModal} setOpenedEditModal={setOpenedEditModal}
category={props.category} category={props.category}
subcategory={props.subcategory} subcategory={props.subcategory}
type={props.type} type={props.type}
method="edit" method="edit"
firstOutlined={false}
// showSecondButton
/> />
)} )}
</> </>

+ 3
- 0
src/components/Cards/CategoryCard/CategoryCard.styled.js 查看文件

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

+ 1
- 1
src/components/Cards/CategoryCard/CategoryRemoveButton/CategoryRemoveButton.styled.js 查看文件

height: 16px; height: 16px;
position: relative; position: relative;
top: -3px; top: -3px;
left: -1.5px;
left: -2.5px;
} }
} }
`; `;

+ 5
- 2
src/components/Cards/FilterCard/Choser/LocationChoser/LocationChoser.js 查看文件

import React, { forwardRef, useEffect, useImperativeHandle, useState } from "react";
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useState } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import FilterCheckboxDropdown from "../../FilterDropdown/Checkbox/FilterCheckboxDropdown"; import FilterCheckboxDropdown from "../../FilterDropdown/Checkbox/FilterCheckboxDropdown";
import { LocationIcon } from "./LocationChoser.styled"; import { LocationIcon } from "./LocationChoser.styled";
const [isOpened, setIsOpened] = useState(false); const [isOpened, setIsOpened] = useState(false);
const filters = props.filters; const filters = props.filters;


const allLocations = useMemo(() => filters.locations.allLocations || [], [filters.locations])
console.log("allLocations", allLocations);

useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
closeSection: () => { closeSection: () => {
setIsOpened(false); setIsOpened(false);
return ( return (
<FilterCheckboxDropdown <FilterCheckboxDropdown
searchPlaceholder={t("filters.location.placeholder")} searchPlaceholder={t("filters.location.placeholder")}
data={[...filters.locations.allLocations]}
data={[...allLocations]}
filters={[...filters.locations.selectedLocationsLocally]} filters={[...filters.locations.selectedLocationsLocally]}
open={isOpened} open={isOpened}
handleOpen={() => setIsOpened((prevIsOpened) => !prevIsOpened)} handleOpen={() => setIsOpened((prevIsOpened) => !prevIsOpened)}

+ 2
- 4
src/components/Cards/LabeledCard/LabeledCard.js 查看文件



const LabeledCard = (props) => { const LabeledCard = (props) => {
return ( 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} {props.children}
</LabeledCardContainer> </LabeledCardContainer>
); );

+ 36
- 0
src/components/Cards/LabeledCard/User/UserLabeledCard.js 查看文件

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 查看文件

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 查看文件

const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<CancelButtonContainer <CancelButtonContainer
variant="contained"
variant={props.pin ? "outlined" : "contained"}
height="48px" height="48px"
width="180px" width="180px"
fullWidth fullWidth
buttoncolor={selectedTheme.colors.primaryPurple} buttoncolor={selectedTheme.colors.primaryPurple}
textcolor="white"
textcolor={props.pin ? selectedTheme.colors.primaryPurple : "white"}
onClick={props.onClick} onClick={props.onClick}
> >
{t("deleteOffer.cancel")} {t("deleteOffer.cancel")}


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


export default CancelButton; export default CancelButton;

+ 1
- 1
src/components/Cards/OfferCard/DeleteOffer/CancelButton/CancelButton.styled.js 查看文件



export const CancelButtonContainer = styled(PrimaryButton)` export const CancelButtonContainer = styled(PrimaryButton)`
@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
width: 140px;
width: 147px;
height: 45px; height: 45px;
} }
`; `;

+ 12
- 5
src/components/Cards/OfferCard/DeleteOffer/DeleteOffer.js 查看文件

OfferImage, OfferImage,
RemoveIconContainer, RemoveIconContainer,
RemoveIcon, RemoveIcon,
PinIcon,
} from "./DeleteOffer.styled"; } from "./DeleteOffer.styled";
import BackdropComponent from "../../../MUI/BackdropComponent"; import BackdropComponent from "../../../MUI/BackdropComponent";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
fetchProfileOffers, fetchProfileOffers,
removeOffer, removeOffer,
} from "../../../../store/actions/offers/offersActions"; } from "../../../../store/actions/offers/offersActions";
import { Trans } from "react-i18next";
import { Trans, useTranslation } from "react-i18next";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import useIsMobile from "../../../../hooks/useIsMobile"; import useIsMobile from "../../../../hooks/useIsMobile";
import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter"; import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter";


const DeleteOffer = (props) => { const DeleteOffer = (props) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { t } = useTranslation();
const queryString = useSelector(selectQueryString); const queryString = useSelector(selectQueryString);
const history = useHistory(); const history = useHistory();
const userId = props.offer.userId; const userId = props.offer.userId;
categoryName={props.offer.category.name} categoryName={props.offer.category.name}
/> />
<RemoveIconContainer> <RemoveIconContainer>
<RemoveIcon />
{props.pin ? <PinIcon /> : <RemoveIcon />}
</RemoveIconContainer> </RemoveIconContainer>
</OfferInfo> </OfferInfo>
<DeleteQuestion> <DeleteQuestion>
<Trans i18nKey="deleteOffer.areYouSure" />
{props.pin ? (
t("admin.pin.reassurancePin")
) : (
<Trans i18nKey="deleteOffer.areYouSure" />
)}
</DeleteQuestion> </DeleteQuestion>
<ButtonsContainer> <ButtonsContainer>
<CancelButton onClick={closeDeleteModalHandler} />
<SaveButton onClick={removeOfferHandler} />
<CancelButton pin={props.pin} onClick={closeDeleteModalHandler} />
<SaveButton pin={props.pin} onClick={removeOfferHandler} />
</ButtonsContainer> </ButtonsContainer>
</DeleteOfferContainer> </DeleteOfferContainer>
</> </>
DeleteOffer.propTypes = { DeleteOffer.propTypes = {
offer: PropTypes.node, offer: PropTypes.node,
closeModalHandler: PropTypes.func, closeModalHandler: PropTypes.func,
pin: PropTypes.bool,
}; };


export default DeleteOffer; export default DeleteOffer;

+ 24
- 4
src/components/Cards/OfferCard/DeleteOffer/DeleteOffer.styled.js 查看文件

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


export const DeleteOfferContainer = styled(Box)` export const DeleteOfferContainer = styled(Box)`
width: 537px; width: 537px;
align-items: center; align-items: center;
padding: 18px; padding: 18px;
margin-top: 36px; margin-top: 36px;
gap: 9px !important;
background-color: ${selectedTheme.colors.chatHeaderColor};


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


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


@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {


@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
font-size: 14px; font-size: 14px;
margin: 27px 0;
display: block;
margin: 27px auto;
text-align: center; text-align: center;
width: 100%;
width: 220px;
} }
`; `;


export const RemoveIconBorder = styled(IconButton)`
export const RemoveIconBorder = styled(Icon)`
width: 40px; width: 40px;
height: 40px; height: 40px;
position: absolute; position: absolute;


export const RemoveIconContainer = styled(RemoveIconBorder)` export const RemoveIconContainer = styled(RemoveIconBorder)`
cursor: default; cursor: default;
& span {
position: relative;
top: 4px;
}
`; `;


export const RemoveIcon = styled(Remove)` export const RemoveIcon = styled(Remove)`
cursor: default; cursor: default;
position: relative;
top: 2px;
`;
export const PinIcon = styled(Pin)`
cursor: default;
position: relative;
top: 3px;
& g path {
stroke: ${selectedTheme.colors.iconYellowColor};
}
`; `;


export const ButtonsContainer = styled(Box)` export const ButtonsContainer = styled(Box)`

+ 45
- 0
src/components/Cards/OfferCard/DeleteOffer/DeleteOfferLabeledCard/DeleteOfferLabeledCard.js 查看文件

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 查看文件

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

+ 15
- 3
src/components/Cards/OfferCard/DeleteOffer/OfferDescription/OfferDescription.styled.js 查看文件

display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-left: 9px; margin-left: 9px;
gap: 0 !important;
`; `;


export const OfferDescriptionTitle = styled(Typography)` export const OfferDescriptionTitle = styled(Typography)`
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
color: ${selectedTheme.colors.primaryPurple}; color: ${selectedTheme.colors.primaryPurple};
font-family: ${selectedTheme.fonts.textFont};
overflow: hidden;
line-height: 19px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
max-height: 38px;


@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
font-size: 14px; font-size: 14px;
export const OfferDescriptionCategory = styled(Typography)` export const OfferDescriptionCategory = styled(Typography)`
font-size: 12px; font-size: 12px;
letter-spacing: 2%; letter-spacing: 2%;
font-family: ${selectedTheme.fonts.textFont};
color: ${selectedTheme.colors.primaryDarkText};
`; `;


export const CategoryIconContainer = styled(Icon)` export const CategoryIconContainer = styled(Icon)`
margin-right: 4px; margin-right: 4px;
position: relative;
top: 2px;
& svg { & svg {
width: 14px; width: 14px;
position: relative; position: relative;
top: -1px;
top: -6px;
} }
`; `;
export const CategoryIcon = styled(Category)`
`
export const CategoryIcon = styled(Category)``;

+ 4
- 3
src/components/Cards/OfferCard/DeleteOffer/SaveButton/SaveButton.js 查看文件

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


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


export default SaveButton; export default SaveButton;

+ 1
- 1
src/components/Cards/OfferCard/DeleteOffer/SaveButton/SaveButton.styled.js 查看文件



export const SaveButtonContainer = styled(PrimaryButton)` export const SaveButtonContainer = styled(PrimaryButton)`
@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
width: 140px;
width: 147px;
height: 45px; height: 45px;
} }
`; `;

+ 17
- 1
src/components/Cards/OfferCard/OfferCard.js 查看文件

const OfferCard = (props) => { const OfferCard = (props) => {
const [deleteOfferModal, setDeleteOfferModal] = useState(false); const [deleteOfferModal, setDeleteOfferModal] = useState(false);
const [editOfferModal, setEditOfferModal] = useState(false); const [editOfferModal, setEditOfferModal] = useState(false);
const [pinOfferModal, setPinOfferModal] = useState(false);
const history = useHistory(); const history = useHistory();
const userId = useSelector(selectUserId); const userId = useSelector(selectUserId);
const { isMobile } = useIsMobile(); const { isMobile } = useIsMobile();


const pinOffer = (event) => { const pinOffer = (event) => {
event.stopPropagation(); event.stopPropagation();
setPinOfferModal(true);
}; };
const routeToItem = (itemId) => { const routeToItem = (itemId) => {
if (!props.disabledCheckButton) { if (!props.disabledCheckButton) {
const closeModalHandler = () => { const closeModalHandler = () => {
setDeleteOfferModal(false); setDeleteOfferModal(false);
}; };
const closePinOfferModal = () => {
setPinOfferModal(false);
};


const closeCreateOfferModal = () => { const closeCreateOfferModal = () => {
setEditOfferModal(false); setEditOfferModal(false);
</MessageIcon> </MessageIcon>
)} )}
{props.isAdmin && !props.pinned && ( {props.isAdmin && !props.pinned && (
<PinIconContainer showMessageIcon onClick={pinOffer}>
<PinIconContainer
showMessageIcon
onClick={pinOffer}
vertical={props.vertical}
>
<PinOutlinedIcon /> <PinOutlinedIcon />
</PinIconContainer> </PinIconContainer>
)} )}
closeModalHandler={closeModalHandler} closeModalHandler={closeModalHandler}
/> />
)} )}
{pinOfferModal && (
<DeleteOffer
pin
offer={props.offer}
closeModalHandler={closePinOfferModal}
/>
)}
{editOfferModal && ( {editOfferModal && (
<CreateOffer <CreateOffer
editOffer editOffer

+ 39
- 9
src/components/Cards/OfferCard/OfferCard.styled.js 查看文件

${(props) => ${(props) =>
props.vertical && props.vertical &&
` `
height: 373px;
height: 400px;
width: 180px; width: 180px;
margin: 0 18px; margin: 0 18px;
`} `}
props.vertical && props.vertical &&
` `
display: flex; display: flex;
flex: none;
flex-basis: 44px;
height: 44px;
max-height: 44px; max-height: 44px;
position: relative; position: relative;
line-height: 22px; line-height: 22px;
margin-top: 5px; margin-top: 5px;
font-size: 18px; font-size: 18px;
margin-bottom: 0px;
margin-bottom: 0px !important;


`} `}
} }
line-height: 16px; line-height: 16px;
font-size: 12px; font-size: 12px;
margin-top: 1px; margin-top: 1px;
@media (max-width: 600px) {
${(props) =>
props.vertical &&
`
margin-top: -18px;
`}
}
`; `;


export const Line = styled(Box)` export const Line = styled(Box)`


@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
display: block; 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)``; export const RemoveIcon = styled(Remove)``;
@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
position: absolute; position: absolute;
display: block; 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)``; export const EditIcon = styled(Edit)``;
export const PinIconContainer = styled(MessageIcon)` export const PinIconContainer = styled(MessageIcon)`
right: 134px; right: 134px;
top: 18px; 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)` export const LikeIcon = styled(Like)`
& path { & path {

+ 56
- 12
src/components/Cards/ProfileCard/BigProfileCard/BigProfileCard.js 查看文件

import { import {
BlockIcon, BlockIcon,
BlockIconContainer, BlockIconContainer,
BlockLabelIcon,
ButtonsContainer,
CheckButton, CheckButton,
EditButton, EditButton,
EditIcon, EditIcon,
import EditProfile from "../EditProfile/EditProfile"; import EditProfile from "../EditProfile/EditProfile";
import selectedTheme from "../../../../themes"; import selectedTheme from "../../../../themes";
import { useTranslation } from "react-i18next"; 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 BigProfileCard = (props) => {
const { t } = useTranslation(); const { t } = useTranslation();
const [editProfileModal, setEditProfileModal] = useState(false); const [editProfileModal, setEditProfileModal] = useState(false);
const [deleteOrEditModal, setDeleteOrEditModal] = useState({
show: false,
type: "",
});
const closeModalHandler = () => { 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 ( return (
<> <>
<ProfileCardContainer halfwidth={props.halfwidth}> <ProfileCardContainer halfwidth={props.halfwidth}>
<ProfileCardWrapper variant="outlined"> <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> <ProfileInfoContainer>
{/* Profile Main Info */} {/* Profile Main Info */}
<ProfileMainInfo profile={props.profile} isAdmin /> <ProfileMainInfo profile={props.profile} isAdmin />
buttoncolor={selectedTheme.colors.primaryPurple} buttoncolor={selectedTheme.colors.primaryPurple}
textcolor={selectedTheme.colors.primaryPurple} textcolor={selectedTheme.colors.primaryPurple}
style={{ fontWeight: "600" }} style={{ fontWeight: "600" }}
onClick={goToUser}
> >
{t("admin.users.checkProfile")} {t("admin.users.checkProfile")}
</CheckButton> </CheckButton>
userId={props.profile._id} userId={props.profile._id}
/> />
)} )}
{deleteOrEditModal.show && (
<DeleteCategory
setOpenedDeleteModal={closeModalHandler}
type={deleteOrEditModal.type}
customLabeledCard={<UserLabeledCard user={props.profile} />}
customLabeledCardHeight="90px"
customLabeledCardIcon={
deleteOrEditModal.type === "blockUser" && <BlockLabelIcon />
}
/>
)}
</> </>
); );
}; };

+ 61
- 206
src/components/Cards/ProfileCard/BigProfileCard/BigProfileCard.styled.js 查看文件

export const ProfileCardContainer = styled(Box)` export const ProfileCardContainer = styled(Box)`
width: ${(props) => (props.halfwidth ? `49%` : `100%`)}; width: ${(props) => (props.halfwidth ? `49%` : `100%`)};
box-sizing: border-box; box-sizing: border-box;
max-height: 184px;
max-height: min-content;
margin-top: 34px; margin-top: 34px;
overflow: hidden; overflow: hidden;
border: 1px solid ${selectedTheme.colors.borderNormal};
border-radius: 0 0 4px 4px;

border-radius: 4px 4px;
&:nth-child(1) { &:nth-child(1) {
margin-top: 20px; margin-top: 20px;
} }
@media (max-width: 1200px) { @media (max-width: 1200px) {
padding: 0; 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)` export const EditIcon = styled(Edit)`
width: 18px; width: 18px;
height: 18px; height: 18px;
} }
`; `;


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

export const MessageButton = styled(IconButton)`
width: 40px;
height: 40px;
background-color: ${selectedTheme.colors.primaryIconBackgroundColor}; background-color: ${selectedTheme.colors.primaryIconBackgroundColor};
border-radius: 100%; border-radius: 100%;
padding-top: 2px; padding-top: 2px;
text-align: center; text-align: center;
@media (max-width: 600px) { @media (max-width: 600px) {
width: 30px;
height: 30px;
width: 32px;
height: 32px;
top: 16px; top: 16px;
right: 16px; right: 16px;
padding: 0; padding: 0;
width: 16px; width: 16px;
height: 16px; height: 16px;
position: relative; 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)` export const RemoveIconContainer = styled(MessageButton)`
display: block; display: block;
top: 18px;
right: 18px;
`; `;
export const RemoveIcon = styled(Remove)``; export const RemoveIcon = styled(Remove)``;
export const BlockIconContainer = styled(MessageButton)` export const BlockIconContainer = styled(MessageButton)`
display: block; display: block;
top: 18px;
right: 134px;
`; `;
export const BlockIcon = styled(Block)``; 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)` export const CheckButton = styled(PrimaryButton)`
width: 180px; width: 180px;
height: 48px; height: 48px;
position: absolute; position: absolute;
bottom: 25px;
bottom: 11px;
right: 9px; right: 9px;
display: ${(props) => (props.halfwidth ? `none` : `block`)}; display: ${(props) => (props.halfwidth ? `none` : `block`)};
& button:hover { & button:hover {
} }
`; `;


// 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)` export const HeaderTitle = styled(Typography)`
font-size: 16px; font-size: 16px;
font-family: ${selectedTheme.fonts.textFont}; font-family: ${selectedTheme.fonts.textFont};
font-size: 12px; 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)` export const MessageIcon = styled(Mail)`
width: 19.5px; width: 19.5px;
height: 19.5px; height: 19.5px;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: start; align-items: start;
@media (max-width: 600px) {
flex-direction: row;
gap: 18px;
justify-content: space-between;
}
`; `;

+ 86
- 18
src/components/Cards/ProfileCard/ProfileCard.js 查看文件

HeaderTitle, HeaderTitle,
EditIcon, EditIcon,
ProfileInfoContainer, ProfileInfoContainer,
RemoveButton,
RemoveIcon,
BlockButton,
BlockIcon,
ButtonsContainer,
BlockLabelIcon,
MessageButton,
MessageIcon,
ProfileInfoAndContactContainer,
} from "./ProfileCard.styled"; } from "./ProfileCard.styled";
import PersonOutlineIcon from "@mui/icons-material/PersonOutline"; import PersonOutlineIcon from "@mui/icons-material/PersonOutline";
import { useRouteMatch } from "react-router-dom"; import { useRouteMatch } from "react-router-dom";
import SkeletonProfileCard from "./SkeletonProfileCard/SkeletonProfileCard"; import SkeletonProfileCard from "./SkeletonProfileCard/SkeletonProfileCard";
import { useMemo } from "react"; import { useMemo } from "react";
import companyData from "../../../notFoundData/companyData"; 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 [editProfileModal, setEditProfileModal] = useState(false);
const [deleteOrEditModal, setDeleteOrEditModal] = useState({
show: false,
type: "",
});
const isLoading = useSelector(selectIsLoadingByActionType(PROFILE_SCOPE)); const isLoading = useSelector(selectIsLoadingByActionType(PROFILE_SCOPE));
const routeMatch = useRouteMatch(); const routeMatch = useRouteMatch();
const dispatch = useDispatch(); const dispatch = useDispatch();
return companyData; return companyData;
}, [profileFromRedux]); }, [profileFromRedux]);


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

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


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

const reFetchProfile = () => { const reFetchProfile = () => {
dispatch(fetchProfile(idProfile)); dispatch(fetchProfile(idProfile));
dispatch(fetchProfileOffers(idProfile)); dispatch(fetchProfileOffers(idProfile));
} }


const closeModalHandler = () => { 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) { if (editProfileModal) {
<SkeletonProfileCard /> <SkeletonProfileCard />
) : ( ) : (
<> <>
<ProfileCardContainer>
<ProfileCardContainer isAdmin={props.isAdmin}>
<ProfileCardHeader> <ProfileCardHeader>
<PersonOutlineIcon color="action" sx={{ mr: 0.9 }} /> <PersonOutlineIcon color="action" sx={{ mr: 0.9 }} />
<HeaderTitle>{t("profile.myProfile")}</HeaderTitle>
<HeaderTitle>
{isMyProfile
? t("profile.myProfile")
: t("profile.companyProfile")}
</HeaderTitle>
</ProfileCardHeader> </ProfileCardHeader>
<ProfileCardWrapper variant="outlined" isMyProfile={isMyProfile}> <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> <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 */} {/* Profile Stats */}
<ProfileStats <ProfileStats
profile={profile} profile={profile}
reFetchProfile={reFetchProfile} reFetchProfile={reFetchProfile}
/> />
)} )}
{deleteOrEditModal.show && (
<DeleteCategory
setOpenedDeleteModal={closeModalHandler}
type={deleteOrEditModal.type}
customLabeledCard={<UserLabeledCard user={profile} />}
customLabeledCardHeight="90px"
customLabeledCardIcon={
deleteOrEditModal.type === "blockUser" && <BlockLabelIcon />
}
/>
)}
</> </>
); );
}; };


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


export default ProfileCard; export default ProfileCard;

+ 104
- 7
src/components/Cards/ProfileCard/ProfileCard.styled.js 查看文件

import { Card, Typography, Grid, Box } from "@mui/material"; import { Card, Typography, Grid, Box } from "@mui/material";
import selectedTheme from "../../../themes"; import selectedTheme from "../../../themes";
import { ReactComponent as Edit } from "../../../assets/images/svg/edit.svg"; 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 Pocket } from "../../assets/images/svg/pocket.svg";
// import { ReactComponent as Globe } from "../../assets/images/svg/globe.svg"; // import { ReactComponent as Globe } from "../../assets/images/svg/globe.svg";
import { ReactComponent as Mail } from "../../../assets/images/svg/mail.svg"; import { ReactComponent as Mail } from "../../../assets/images/svg/mail.svg";
padding: 0 36px 0 0; padding: 0 36px 0 0;
} }
@media (max-width: 600px) { @media (max-width: 600px) {
padding: 0;
padding: 0 ${props => props.isAdmin ? "18px" : "0"};
} }
`; `;
export const EditIcon = styled(Edit)` export const EditIcon = styled(Edit)`
position: relative;
top: 3px;
left: 2px;
width: 18px; width: 18px;
height: 18px; height: 18px;
@media (max-width: 600px) {
top: 0;
left: -2px;
}
& path { & path {
stroke: ${selectedTheme.colors.primaryPurple}; stroke: ${selectedTheme.colors.primaryPurple};
} }
`; `;
export const EditButton = styled(Box)` 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; font-weight: 900;
background: #f4f4f4;
background: ${selectedTheme.colors.primaryIconBackgroundColor};
border-radius: 360px; border-radius: 360px;
padding: 0.45rem 0.45rem 0.27rem 0.57rem; padding: 0.45rem 0.45rem 0.27rem 0.57rem;
cursor: pointer; cursor: pointer;
@media (max-width: 600px) {
width: 32px;
height: 32px;
}
`; `;


export const MessageButton = styled(EditButton)` export const MessageButton = styled(EditButton)`
height: 32px; 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)` export const ProfileCardWrapper = styled(Card)`
border: 1px solid ${selectedTheme.colors.borderNormal}; border: 1px solid ${selectedTheme.colors.borderNormal};
height: 16px; height: 16px;
left: -1px; left: -1px;
top: 1px; top: 1px;
}
}
`; `;


export const ProfileInfoContainer = styled(Grid)` export const ProfileInfoContainer = styled(Grid)`
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: start; 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)` // export const ProfileStatsGrid = styled(Grid)`

+ 5
- 1
src/components/Cards/ProfileCard/ProfileContact/ProfileContact.styled.js 查看文件



export const ProfileContactContainer = styled(Grid)` export const ProfileContactContainer = styled(Grid)`
padding-top: ${(props) => (props.isAdmin ? `20px` : `2rem`)}; padding-top: ${(props) => (props.isAdmin ? `20px` : `2rem`)};
padding-bottom: 2rem;
padding-bottom: ${(props) => (props.isAdmin ? "0" : "2rem")};
@media (max-width: 600px) { @media (max-width: 600px) {
padding-bottom: 1rem; padding-bottom: 1rem;
padding-top: 88px;
gap: 5px;
width: calc(100vw - 216px);
} }
`; `;
export const LocationIcon = styled(Location)` export const LocationIcon = styled(Location)`
@media (max-width: 600px) { @media (max-width: 600px) {
font-size: 14px; font-size: 14px;
bottom: 4px; bottom: 4px;
margin-right: 0;
} }
`; `;
export const MailIcon = styled(Mail)` export const MailIcon = styled(Mail)`

+ 16
- 4
src/components/Cards/ProfileCard/ProfileMainInfo/ProfileMainInfo.js 查看文件

import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter"; import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter";
import useIsMobile from "../../../../hooks/useIsMobile"; 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 ProfileMainInfo = (props) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { isMobile } = useIsMobile(); const { isMobile } = useIsMobile();
const goToUser = () => {
if (isAdminRoute()) {
history.push(
replaceInRoute(ADMIN_SINGLE_USER_PAGE, {
idProfile: props.profile?._id,
})
);
}
};
return ( return (
<ProfileMainInfoContainer> <ProfileMainInfoContainer>
<AvatarImageContainer> <AvatarImageContainer>
{/* <AvatarImage
alt={props.profile?.company?.name}
src={props.profile?.image}
/> */}
<AvatarImage <AvatarImage
isAdmin={props.isAdmin} isAdmin={props.isAdmin}
src={getImageUrl( src={getImageUrl(
isAdmin={props.isAdmin} isAdmin={props.isAdmin}
isMyProfile={props.isMyProfile} isMyProfile={props.isMyProfile}
variant="h5" variant="h5"
onClick={goToUser}
> >
{props.profile?.company?.name} {props.profile?.company?.name}
</ProfileName> </ProfileName>

+ 16
- 4
src/components/Cards/ProfileCard/ProfileMainInfo/ProfileMainInfo.styled.js 查看文件

display: flex; display: flex;
justify-content: start; justify-content: start;
align-items: 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)` export const AvatarImageContainer = styled(Grid)`
display: flex; display: flex;
height: ${(props) => (props.isAdmin ? `108px` : `144px`)}; height: ${(props) => (props.isAdmin ? `108px` : `144px`)};
border-radius: 100%; border-radius: 100%;
@media (max-width: 600px) { @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)` export const ProfileMainInfoGrid = styled(Grid)`
flex-direction: column; flex-direction: column;
align-items: start; align-items: start;
margin-left: 16px; margin-left: 16px;
@media (max-width: 600px) {
margin-left: 0;
}
`; `;
export const ProfileName = styled(Typography)` export const ProfileName = styled(Typography)`
color: ${(props) => color: ${(props) =>
: selectedTheme.colors.primaryPurple}; : selectedTheme.colors.primaryPurple};
font-weight: 700; font-weight: 700;
font-size: 24px; font-size: 24px;
min-width: 200px;
font-family: ${selectedTheme.fonts.textFont}; font-family: ${selectedTheme.fonts.textFont};
margin-bottom: 5px; margin-bottom: 5px;
cursor: ${(props) => props.isAdmin && `pointer`}; cursor: ${(props) => props.isAdmin && `pointer`};
@media (max-width: 600px) { @media (max-width: 600px) {
font-size: 18px; font-size: 18px;
margin-bottom: 0;
} }
`; `;
export const ProfilePIBContainer = styled(Grid)` export const ProfilePIBContainer = styled(Grid)`
font-family: ${selectedTheme.fonts.textFont}; font-family: ${selectedTheme.fonts.textFont};
font-size: 16px; font-size: 16px;
padding-top: 1px; padding-top: 1px;
white-space: nowrap;
@media (max-width: 600px) { @media (max-width: 600px) {
font-size: 14px; font-size: 14px;
} }

+ 2
- 2
src/components/Cards/ProfileCard/ProfileStats/ProfileStats.js 查看文件

<b>{props.percentOfSucceededExchanges}%</b> <b>{props.percentOfSucceededExchanges}%</b>
{t("profile.successExchange")} {t("profile.successExchange")}
</StatsItem> </StatsItem>
</ProfileStatsGrid>
<ProfileStatsGrid>
{/* </ProfileStatsGrid>
<ProfileStatsGrid> */}
<StatsItem variant="subtitle2"> <StatsItem variant="subtitle2">
<b>{props.profile?.statistics?.views?.count}</b> <b>{props.profile?.statistics?.views?.count}</b>
{t("profile.numberOfViews")} {t("profile.numberOfViews")}

+ 5
- 4
src/components/Cards/ProfileCard/ProfileStats/ProfileStats.styled.js 查看文件

justify-content: start; justify-content: start;
align-items: center; align-items: center;
background: ${selectedTheme.colors.primaryDarkTextSecond}; 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-bottom: -1rem;
margin-left: -1rem;
margin-left: -18px;
/* border-radius: 0 0 4px 4px; */ /* border-radius: 0 0 4px 4px; */
`; `;
export const ProfileStatsGrid = styled(Grid)` export const ProfileStatsGrid = styled(Grid)`
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: start; align-items: start;
gap: 3px;
`; `;
export const StatsItem = styled(Typography)` export const StatsItem = styled(Typography)`
margin-right: 2rem; margin-right: 2rem;

+ 21
- 21
src/components/Cards/UserReviewsCard/UserReviewsCard.js 查看文件

import React, { useMemo } from "react";
import React, { useMemo, useState } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { ReviewContainer } from "./UserReviewsCard.styled";
import ReviewOffer from "./ReviewOffer/ReviewOffer";
import { reviewEnum } from "../../../enums/reviewEnum"; 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 UserReviewsCard = (props) => {
const [removeModalOpened, setRemoveModalOpened] = useState();
const handleRemove = () => {
setRemoveModalOpened(true);
};
const review = useMemo(() => { const review = useMemo(() => {
if (props.givingReview) { if (props.givingReview) {
return { return {
offerImage: props.review.offer.image, offerImage: props.review.offer.image,
}; };
}, [props.review]); }, [props.review]);
console.log(review);


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


className: PropTypes.string, className: PropTypes.string,
review: PropTypes.any, review: PropTypes.any,
givingReview: PropTypes.bool, givingReview: PropTypes.bool,
showRemoveIcon: PropTypes.bool,
}; };
UserReviewsCard.defaultProps = { UserReviewsCard.defaultProps = {
isProfileReviews: false, isProfileReviews: false,

+ 0
- 14
src/components/Cards/UserReviewsCard/UserReviewsCard.styled.js 查看文件

width: 100%; width: 100%;
margin-bottom: 36px; 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 查看文件

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 查看文件

// 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 查看文件

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


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

src/components/Cards/UserReviewsCard/ReviewOffer/ReviewOffer.js → src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewOffer/ReviewOffer.js 查看文件

ReviewOfferImage, ReviewOfferImage,
ReviewOfferTitle, ReviewOfferTitle,
} from "./ReviewOffer.styled"; } from "./ReviewOffer.styled";
import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter";
import { getImageUrl, variants } from "../../../../../util/helpers/imageUrlGetter";
import { useTranslation } from "react-i18next";


const ReviewOffer = (props) => { const ReviewOffer = (props) => {
const {t} = useTranslation();
return ( return (
<ReviewOfferContainer> <ReviewOfferContainer>
<ReviewOfferImage src={getImageUrl(props.image, variants.reviewCard)} /> <ReviewOfferImage src={getImageUrl(props.image, variants.reviewCard)} />
<ReviewOfferDetails> <ReviewOfferDetails>
<ReviewOfferDescription>Proizvod: </ReviewOfferDescription>
<ReviewOfferDescription>{t("reviews.offerTitle")}</ReviewOfferDescription>
<ReviewOfferTitle>{props.name}</ReviewOfferTitle> <ReviewOfferTitle>{props.name}</ReviewOfferTitle>
</ReviewOfferDetails> </ReviewOfferDetails>
</ReviewOfferContainer> </ReviewOfferContainer>

src/components/Cards/UserReviewsCard/ReviewOffer/ReviewOffer.styled.js → src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewOffer/ReviewOffer.styled.js 查看文件

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


export const ReviewOfferContainer = styled(Box)` export const ReviewOfferContainer = styled(Box)`
display: flex; display: flex;
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
font-family: ${selectedTheme.fonts.textFont}; font-family: ${selectedTheme.fonts.textFont};
overflow: hidden;
line-height: 19px;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
max-height: 19px;
@media (max-width: 600px) {
font-size: 12px;
line-height: 16px;
max-height: 16px;
}
`; `;

src/components/Cards/UserReviewsCard/ReviewQuote/ReviewQuote.js → src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewQuote/ReviewQuote.js 查看文件

ThumbDown, ThumbDown,
ThumbUp, ThumbUp,
} from "./ReviewQuote.styled"; } from "./ReviewQuote.styled";
import { reviewEnum } from "../../../../enums/reviewEnum";
import { reviewEnum } from "../../../../../enums/reviewEnum";


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

src/components/Cards/UserReviewsCard/ReviewQuote/ReviewQuote.styled.js → src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewQuote/ReviewQuote.styled.js 查看文件

import { Box, Grid, Typography } from "@mui/material"; import { Box, Grid, Typography } from "@mui/material";
import styled from "styled-components"; import styled from "styled-components";
import selectedTheme from "../../../../themes";
import selectedTheme from "../../../../../themes";
import ThumbUpIcon from "@mui/icons-material/ThumbUp"; 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)` export const ReviewQuoteContainer = styled(Box)`
position: relative; position: relative;
color: ${selectedTheme.colors.primaryDarkText}; color: ${selectedTheme.colors.primaryDarkText};
position: relative; position: relative;
left: 10px; left: 10px;
@media (max-width: 600px) {
font-size: 12px;
}
`; `;
export const ThumbUp = styled(ThumbUpIcon)` export const ThumbUp = styled(ThumbUpIcon)`
position: relative; position: relative;
@media (max-width: 600px) {
width: 18px;
height: 18px;
top: 3px;
}
`; `;
export const ThumbDown = styled(ThumbDownIcon)` export const ThumbDown = styled(ThumbDownIcon)`
position: relative;
top: 3px; 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 查看文件

import React from "react"; import React from "react";
import PropTypes from "prop-types"; 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 { import {
ProfileContainer, ProfileContainer,
ProfileImage, ProfileImage,
ProfileImageContainer, ProfileImageContainer,
ProfileName, ProfileName,
} from "./ReviewerProfile.styled"; } 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 ReviewerProfile = (props) => {
const { isMobile } = useIsMobile(); const { isMobile } = useIsMobile();

src/components/Cards/UserReviewsCard/ReviewerProfile/ReviewerProfile.styled.js → src/components/Cards/UserReviewsCard/UserReviewsSingleCard/ReviewerProfile/ReviewerProfile.styled.js 查看文件

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


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

+ 46
- 0
src/components/Cards/UserReviewsCard/UserReviewsSingleCard/UserReviewsSingleCard.js 查看文件

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 查看文件

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 查看文件

height="48px" height="48px"
onClick={props.onClick} onClick={props.onClick}
> >
{t("reviews.leaveComment")}
{props.removingReview
? t("admin.reviews.confirm")
: t("reviews.leaveComment")}
</NextButtonContainer> </NextButtonContainer>
); );
}; };


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


export default NextButton; export default NextButton;

+ 10
- 3
src/components/CreateReview/SecondStep/SecondStepCreateReview.js 查看文件

const mineProfile = useSelector(selectMineProfile); const mineProfile = useSelector(selectMineProfile);


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


return ( return (
<SecondStepCreateReviewContainer> <SecondStepCreateReviewContainer>
<CreateReviewTitle>{t("reviews.modalTitle")}</CreateReviewTitle>
<CreateReviewTitle>
{props.removingReview
? t("admin.reviews.title")
: t("reviews.modalTitle")}
</CreateReviewTitle>
<ReviewCard <ReviewCard
givingReview givingReview
profileReviews={[ profileReviews={[
}, },
]} ]}
/> />
<NextButton onClick={goToNextStep} />
<NextButton removingReview={props.removingReview} onClick={goToNextStep} />
</SecondStepCreateReviewContainer> </SecondStepCreateReviewContainer>
); );
}; };
offer: PropTypes.any, offer: PropTypes.any,
interlocutor: PropTypes.any, interlocutor: PropTypes.any,
goToNextStep: PropTypes.func, goToNextStep: PropTypes.func,
removingReview: PropTypes.bool,
closeModal: PropTypes.func,
}; };


export default SecondStepCreateReview; export default SecondStepCreateReview;

+ 11
- 9
src/components/CreateReview/SecondStep/SecondStepCreateReview.styled.js 查看文件

import UserReviews from "../../UserReviews/UserReviews"; import UserReviews from "../../UserReviews/UserReviews";


export const SecondStepCreateReviewContainer = styled(Box)` 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)` export const ReviewCard = styled(UserReviews)`
& > div {
margin-bottom: 36px; margin-bottom: 36px;
margin-top: 18px; margin-top: 18px;
& ul { & ul {
background-color: ${selectedTheme.colors.chatHeaderColor};
padding: 0 14px;
background-color: ${selectedTheme.colors.chatHeaderColor};
padding: 0 14px;
} }
& ul li { & ul li {
margin: 0;
margin: 0;
} }
`
}
`;

+ 20
- 0
src/components/Header/Drawer/AdminInfo/AdminInfo.js 查看文件

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 查看文件

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 查看文件

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 查看文件

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 查看文件

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 查看文件

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 查看文件

import React from "react";
import React, { useMemo } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { import {
CloseButton, CloseButton,
import PrivacyPolicyButton from "./Buttons/PrivacyPolicyButton/PrivacyPolicyButton"; import PrivacyPolicyButton from "./Buttons/PrivacyPolicyButton/PrivacyPolicyButton";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { selectUserId } from "../../../store/selectors/loginSelectors"; 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) => { export const Drawer = (props) => {
const { t } = useTranslation(); const { t } = useTranslation();
const user = useSelector(selectUserId); const user = useSelector(selectUserId);
const mineProfile = useSelector(selectMineProfile);
const location = useLocation();
const isAdmin = useMemo(() => isAdminRoute(), [location.pathname]);


return ( return (
<DrawerContainer> <DrawerContainer>
</CloseButton> </CloseButton>
<HeaderTitle>{t("header.navMenu")}</HeaderTitle> <HeaderTitle>{t("header.navMenu")}</HeaderTitle>
<React.Fragment> <React.Fragment>
<ToolsContainer mobile>
<ToolsContainer mobile isAdmin={isAdmin}>
{user ? ( {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} /> <LoginButton toggleDrawer={props.toggleDrawer} />
)} )}
</ToolsContainer> </ToolsContainer>
{user && ( {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} /> <LogoutButton toggleDrawer={props.toggleDrawer} />
</FooterButtons> </FooterButtons>
)} )}

+ 10
- 4
src/components/Header/Drawer/Drawer.styled.js 查看文件

import styled from "styled-components"; import styled from "styled-components";
import { ReactComponent as Close } from "../../../assets/images/svg/close-modal.svg"; import { ReactComponent as Close } from "../../../assets/images/svg/close-modal.svg";
import selectedTheme from "../../../themes"; import selectedTheme from "../../../themes";
import { hexToRGB } from "../../../util/helpers/colorHelper";
import { IconButton } from "../../Buttons/IconButton/IconButton"; import { IconButton } from "../../Buttons/IconButton/IconButton";


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


export const AuthButtonsDrawerContainer = styled(Box)` export const AuthButtonsDrawerContainer = styled(Box)`
export const FooterButtons = styled(Box)` export const FooterButtons = styled(Box)`
position: absolute; position: absolute;
bottom: 36px; bottom: 36px;
margin-left: 36px;
margin-right: 36px;
padding-top: 10px;
display: flex; display: flex;
flex-direction: row; 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)` export const HeaderTitle = styled(Typography)`

+ 2
- 2
src/components/Header/DrawerContainer/DrawerContainer.js 查看文件

const { isMobile } = useIsMobile(); const { isMobile } = useIsMobile();


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


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

+ 1
- 1
src/components/ItemDetails/ItemDetails.styled.js 查看文件



@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
margin-left: 0; margin-left: 0;
margin-top: 310px;
margin-top: 345px;


svg { svg {
width: 14px; width: 14px;

+ 1
- 1
src/components/ItemDetails/ItemDetailsHeaderCard/ItemDetailsHeaderCard.styled.js 查看文件

position: relative; position: relative;


@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
width: 92%;
width: calc(100vw - 36px);
} }
`; `;
export const HeaderTop = styled(Box)` export const HeaderTop = styled(Box)`

+ 29
- 13
src/components/Modals/DeleteCategory/DeleteCategory.js 查看文件

import BackdropComponent from "../../MUI/BackdropComponent"; import BackdropComponent from "../../MUI/BackdropComponent";
import { import {
ButtonsContainer, ButtonsContainer,
CancelButton,
CategoryName, CategoryName,
DeleteCategoryContainer, DeleteCategoryContainer,
DeleteIcon, DeleteIcon,
ReassuranceText, ReassuranceText,
SaveButton,
} from "./DeleteCategory.styled"; } from "./DeleteCategory.styled";
import LabeledCard from "../../Cards/LabeledCard/LabeledCard"; import LabeledCard from "../../Cards/LabeledCard/LabeledCard";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton";
import { useMemo } from "react"; import { useMemo } from "react";
import selectedTheme from "../../../themes";


const DeleteCategory = (props) => { const DeleteCategory = (props) => {
const { t } = useTranslation(); const { t } = useTranslation();
}; };
const reassuranceText = useMemo(() => { const reassuranceText = useMemo(() => {
return t(`admin.${props.type}.reassuranceDelete`); return t(`admin.${props.type}.reassuranceDelete`);
}, [props]);
}, [props, t]);
return ( return (
<> <>
<BackdropComponent <BackdropComponent
handleClose={() => props.setOpenedDeleteModal(false)} handleClose={() => props.setOpenedDeleteModal(false)}
position="fixed" 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> </LabeledCard>
<ReassuranceText>{reassuranceText}</ReassuranceText> <ReassuranceText>{reassuranceText}</ReassuranceText>
<ButtonsContainer> <ButtonsContainer>
<PrimaryButton
<CancelButton
onClick={handleCancel} onClick={handleCancel}
variant="contained" 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> </ButtonsContainer>
</DeleteCategoryContainer> </DeleteCategoryContainer>
</> </>
category: PropTypes.object, category: PropTypes.object,
subcategory: PropTypes.bool, subcategory: PropTypes.bool,
type: PropTypes.string, type: PropTypes.string,
customLabeledCard: PropTypes.node,
customLabeledCardWidth: PropTypes.string,
customLabeledCardHeight: PropTypes.string,
customLabeledCardIcon: PropTypes.node,
}; };


export default DeleteCategory; export default DeleteCategory;

+ 42
- 3
src/components/Modals/DeleteCategory/DeleteCategory.styled.js 查看文件

import styled from "styled-components"; import styled from "styled-components";
import { ReactComponent as Delete } from "../../../assets/images/svg/trash.svg"; import { ReactComponent as Delete } from "../../../assets/images/svg/trash.svg";
import selectedTheme from "../../../themes"; import selectedTheme from "../../../themes";
import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton";


export const DeleteCategoryContainer = styled(Box)` export const DeleteCategoryContainer = styled(Box)`
width: 537px; width: 537px;
height: 274px;
height: ${(props) =>
["blockUser", "deleteUser"].includes(props.type) ? "309px" : "274px"};
position: fixed; position: fixed;
z-index: 150; z-index: 150;
left: calc(50vw - 268px); 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-top: 36px;
padding-bottom: 18px; padding-bottom: 18px;
background: white; background: white;
margin-left: auto; margin-left: auto;
margin-right: 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)` export const DeleteIcon = styled(Delete)`
z-index: 155; z-index: 155;
line-height: 21px; line-height: 21px;
color: ${selectedTheme.colors.messageText}; color: ${selectedTheme.colors.messageText};
margin-top: 36px; margin-top: 36px;
@media (max-width: 600px) {
font-size: 14px;
margin-top: 27px;
}
`; `;
export const ButtonsContainer = styled(Box)` export const ButtonsContainer = styled(Box)`
display: flex; display: flex;
flex-direction: row; flex-direction: row;
gap: 18px; gap: 18px;
margin: 36px auto; 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;
}
`;

+ 27
- 0
src/components/Modals/DeleteReview/DeleteButton/DeleteButton.js 查看文件

import React from "react";
import PropTypes from "prop-types";
import { ButtonContainer, DeleteButtonContainer } from "./DeleteButton.styled";
import selectedTheme from "../../../../themes";
import { useTranslation } from "react-i18next";

const DeleteButton = (props) => {
const {t} = useTranslation();
return (
<DeleteButtonContainer>
<ButtonContainer
variant="contained"
buttoncolor={selectedTheme.colors.primaryPurple}
onClick={props.onClick}
textcolor={selectedTheme.colors.primaryTextDisabled}
>
{t("admin.review.confirm")}
</ButtonContainer>
</DeleteButtonContainer>
);
};

DeleteButton.propTypes = {
onClick: PropTypes.func,
};

export default DeleteButton;

+ 20
- 0
src/components/Modals/DeleteReview/DeleteButton/DeleteButton.styled.js 查看文件

import { Box } from "@mui/material";
import styled from "styled-components";
import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton";

export const DeleteButtonContainer = styled(Box)`
position: absolute;
bottom: 36px;
left: 18px;
background-color: white !important;
border: 0 !important;
padding: 0 !important;
`;
export const ButtonContainer = styled(PrimaryButton)`
height: 44px;
width: calc(100vw - 36px);
background-color: white !important;
& > button {
background-color: ${(props) => props.buttoncolor} !important;
}
`;

+ 42
- 0
src/components/Modals/DeleteReview/DeleteReview.js 查看文件

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";
import DeleteButton from "./DeleteButton/DeleteButton";

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 onClick={() => props.setOpenedDeleteModal(false)} />
<DeleteButton />
</DeleteReviewContainer>
</>
);
};

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

export default DeleteReview;

+ 62
- 0
src/components/Modals/DeleteReview/DeleteReview.styled.js 查看文件

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

+ 40
- 27
src/components/Modals/EditCategory/EditCategory.js 查看文件

EditCategoryImagePicker, EditCategoryImagePicker,
EditCategoryTitle, EditCategoryTitle,
FieldLabel, FieldLabel,
InputContainer,
SaveButton, SaveButton,
SupportedFormats, SupportedFormats,
XIcon, XIcon,
const title = useMemo(() => { const title = useMemo(() => {
return t(`admin.${props.type}.${props.method}.title`); return t(`admin.${props.type}.${props.method}.title`);
}, [props.type, props.method]); }, [props.type, props.method]);

const placeholder = useMemo(() => { const placeholder = useMemo(() => {
return t(`admin.${props.type}.${props.method}.placeholder`); return t(`admin.${props.type}.${props.method}.placeholder`);
}, [props.type, props.method]); }, [props.type, props.method]);

const fieldLabel = useMemo(() => { const fieldLabel = useMemo(() => {
return t(`admin.${props.type}.${props.method}.fieldTitle`); return t(`admin.${props.type}.${props.method}.fieldTitle`);
}, [props.type, props.method]); }, [props.type, props.method]);

const firstButtonText = useMemo(() => { const firstButtonText = useMemo(() => {
return t(`admin.${props.type}.${props.method}.next`); return t(`admin.${props.type}.${props.method}.next`);
}, [props.type, props.method]); }, [props.type, props.method]);
const formik = useFormik({ const formik = useFormik({
initialValues: { initialValues: {
image: "", image: "",
title: props?.category?.name || "",
title: props?.category?.name || props?.category?.city || "",
}, },
onSubmit: handleSubmit, onSubmit: handleSubmit,
}); });
console.log(props);
return ( return (
<> <>
<BackdropComponent <BackdropComponent
</SupportedFormats> </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> <ButtonsContainer>
{props.method === "add" && (
<SaveButton
variant="contained"
width="180px"
height="48px"
onClick={formik.handleSubmit}
>
{firstButtonText}
</SaveButton>
)}
<SaveButton <SaveButton
variant={props.method === "add" ? "outlined" : "contained"}
width={props.method === "add" ? "180px" : "376px"}
showSecondButton={props.showSecondButton}
variant={props.firstOutlined ? "outlined" : "contained"}
height="48px" height="48px"
onClick={formik.handleSubmit} onClick={formik.handleSubmit}
> >
{secondButtonText}
{firstButtonText}
</SaveButton> </SaveButton>
{props.showSecondButton && (
<SaveButton
variant={props.secondOutlined ? "outlined" : "contained"}
showSecondButton={props.showSecondButton}
onClick={formik.handleSubmit}
>
{secondButtonText}
</SaveButton>
)}
</ButtonsContainer> </ButtonsContainer>
</EditCategoryContainer> </EditCategoryContainer>
</> </>
setOpenedEditModal: PropTypes.func, setOpenedEditModal: PropTypes.func,
hideImagePicker: PropTypes.bool, hideImagePicker: PropTypes.bool,
type: PropTypes.string, type: PropTypes.string,
showSecondButton: PropTypes.bool,
method: PropTypes.string, method: PropTypes.string,
firstOutlined: PropTypes.bool,
secondOutlined: PropTypes.bool,
};

EditCategory.defaultProps = {
firstOutlined: true,
}; };


export default EditCategory; export default EditCategory;

+ 49
- 1
src/components/Modals/EditCategory/EditCategory.styled.js 查看文件

margin-left: auto; margin-left: auto;
margin-right: 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)` export const EditCategoryTitle = styled(Typography)`
display: block; display: block;
margin-top: 36px; margin-top: 36px;
width: 256px; width: 256px;
color: ${selectedTheme.colors.primaryPurple}; color: ${selectedTheme.colors.primaryPurple};
@media (max-width: 600px) {
font-size: 18px;
line-height: 24px;
margin-top: 18px;
}
`; `;
export const EditCategoryImagePicker = styled(ImagePicker)` export const EditCategoryImagePicker = styled(ImagePicker)`
background: none; background: none;
position: relative; position: relative;
left: calc(50% - 72px); left: calc(50% - 72px);
margin-bottom: 18px; margin-bottom: 18px;
@media (max-width: 600px) {
margin-top: 27px;
}
`; `;
export const SupportedFormats = styled(Typography)` export const SupportedFormats = styled(Typography)`
font-size: 13px; font-size: 13px;
width: 100%; width: 100%;
text-align: center; text-align: center;
font-family: ${selectedTheme.fonts.textFont}; font-family: ${selectedTheme.fonts.textFont};
@media (max-width: 600px) {
font-size: 13px;
}
`; `;
export const CategoryTitleField = styled(TextField)` export const CategoryTitleField = styled(TextField)`
width: 375px; width: 375px;
} }
& div { & div {
height: 40px; height: 40px;
width: 314px;
} }
} }
`; `;
position: relative; position: relative;
bottom: -14px; bottom: -14px;
width: 376px; width: 376px;
margin-top: 22px;
& label { & label {
font-size: 12px; font-size: 12px;
font-weight: 600; font-weight: 600;
} }
} }
`; `;
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)` export const SaveButton = styled(PrimaryButton)`
max-width: 376px; max-width: 376px;
width: ${(props) => (props.showSecondButton ? "180px" : "376px")};
height: 48px; height: 48px;
& button { & button {
letter-spacing: 1.5px; letter-spacing: 1.5px;
} }
@media (max-width: 600px) {
height: 45px;
width: ${(props) => (props.showSecondButton ? "149px" : "314px")};
}
`; `;
export const XIcon = styled(X)` export const XIcon = styled(X)`
transform: rotate(45deg); transform: rotate(45deg);
stroke: ${selectedTheme.colors.messageText}; stroke: ${selectedTheme.colors.messageText};
stroke-width: 2; stroke-width: 2;
} }
@media (max-width: 600px) {
top: 18px;
right: 18px;
}
`; `;
export const ButtonsContainer = styled(Box)` export const ButtonsContainer = styled(Box)`
display: flex; display: flex;
flex-direction: row; flex-direction: row;
gap: 18px; gap: 18px;
margin: 36px auto; margin: 36px auto;
@media (max-width: 600px) {
margin-top: 18px;
}
`; `;

+ 6
- 2
src/components/Profile/Header/Header.js 查看文件

const history = useHistory(); const history = useHistory();
const { t } = useTranslation(); const { t } = useTranslation();



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


return ( return (
onClick={handleBackButton} onClick={handleBackButton}
component="header" component="header"
className={props.className} className={props.className}
isAdmin={props.isAdmin}
> >
<ButtonContainer> <ButtonContainer>
<ArrowButton side={"left"}></ArrowButton> <ArrowButton side={"left"}></ArrowButton>
<HeaderText>{t("profile.backToHome")}</HeaderText>
<HeaderText>{props.isAdmin ? t("admin.users.goBack") : t("profile.backToHome")}</HeaderText>
</ButtonContainer> </ButtonContainer>
</HeaderContainer> </HeaderContainer>
); );
filters: PropTypes.array, filters: PropTypes.array,
category: PropTypes.string, category: PropTypes.string,
className: PropTypes.string, className: PropTypes.string,
isAdmin: PropTypes.bool,
}; };
Header.defaultProps = { Header.defaultProps = {
isGrid: false, isGrid: false,

+ 3
- 2
src/components/Profile/Header/Header.styled.js 查看文件

margin-top: 20px; margin-top: 20px;


@media (max-width: 600px) { @media (max-width: 600px) {
margin-top: 40px;
margin-top: 49px;
margin-left: ${props => props.isAdmin ? "18px" : "0"};
} }
`; `;
export const ButtonContainer = styled(Link)` export const ButtonContainer = styled(Link)`
line-height: 22px; line-height: 22px;
font-size: 16px; font-size: 16px;
color: ${selectedTheme.colors.primaryPurple}; color: ${selectedTheme.colors.primaryPurple};
border: 1px dotted ${selectedTheme.colors.primaryPurple};
border-bottom: 1px dotted ${selectedTheme.colors.primaryPurple};
`; `;

+ 8
- 6
src/components/Profile/Profile.js 查看文件

import { fetchProfileOffers } from "../../store/actions/offers/offersActions"; import { fetchProfileOffers } from "../../store/actions/offers/offersActions";
import Header from "./Header/Header"; import Header from "./Header/Header";


const Profile = () => {
const Profile = (props) => {
const userId = useSelector(selectUserId); const userId = useSelector(selectUserId);
const dispatch = useDispatch(); const dispatch = useDispatch();
const routeMatch = useRouteMatch(); const routeMatch = useRouteMatch();
const idProfile = useMemo(() => routeMatch.params.idProfile, [routeMatch]);
const idProfile = useMemo(() => routeMatch.params?.idProfile, [routeMatch]);
useEffect(() => { useEffect(() => {
if (idProfile?.length > 0) { if (idProfile?.length > 0) {
dispatch(fetchProfile(idProfile)); dispatch(fetchProfile(idProfile));
return userId === routeMatch.params.idProfile; return userId === routeMatch.params.idProfile;
}, [userId, routeMatch]); }, [userId, routeMatch]);
return ( 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> </ProfileContainer>
); );
}; };


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


export default Profile; export default Profile;

+ 8
- 5
src/components/Profile/ProfileOffers/ProfileOffers.js 查看文件

}; };


return ( return (
<ProfileOffersContainer>
<ProfileOffersContainer isAdmin={props.isAdmin}>
{isLoadingMineOffers || isLoadingMineOffers === undefined ? ( {isLoadingMineOffers || isLoadingMineOffers === undefined ? (
<ProfileOffersHeaderSkeleton /> <ProfileOffersHeaderSkeleton />
) : ( ) : (
offersToShow={offersToShow} offersToShow={offersToShow}
setOffersToShow={setOffersToShow} setOffersToShow={setOffersToShow}
/> />
<HeaderTitle isMyProfile={props.isMyProfile} />
<HeaderTitle isMyProfile={props.isMyProfile && !props.isAdmin} />
<SearchBar handleSearch={handleSearch} /> <SearchBar handleSearch={handleSearch} />
</> </>
)} )}
) : offersToShow.length !== 0 ? ( ) : offersToShow.length !== 0 ? (
offersToShow.map((item) => ( offersToShow.map((item) => (
<OfferCard <OfferCard
isMyOffer={props.isMyProfile}
isAdmin={props.isAdmin}
isMyOffer={props.isMyProfile || props.isAdmin}
offer={item} offer={item}
key={JSON.stringify(item)} key={JSON.stringify(item)}
messageUser={messageUser} messageUser={messageUser}
<OffersScroller hideArrows> <OffersScroller hideArrows>
{offersToShow.map((item) => ( {offersToShow.map((item) => (
<OfferCard <OfferCard
isAdmin={props.isAdmin}
vertical vertical
isMyOffer={props.isMyProfile}
isMyOffer={props.isMyProfile || props.isAdmin}
offer={item} offer={item}
key={JSON.stringify(item)} key={JSON.stringify(item)}
pinned
pinned={item.pinned}
messageUser={messageUser} messageUser={messageUser}
/> />
))} ))}
ProfileOffers.propTypes = { ProfileOffers.propTypes = {
children: PropTypes.node, children: PropTypes.node,
isMyProfile: PropTypes.bool, isMyProfile: PropTypes.bool,
isAdmin: PropTypes.bool,
}; };


export default ProfileOffers; export default ProfileOffers;

+ 4
- 1
src/components/Profile/ProfileOffers/ProfileOffers.styled.js 查看文件

} }
@media (max-width: 600px) { @media (max-width: 600px) {
padding: 0; padding: 0;
width: calc(100vw - 36px);
margin: 34px ${props => props.isAdmin ? "18px" : "0"};
margin-bottom: ${props => !props.isAdmin && '0'}
} }
`; `;
export const OffersContainer = styled(Box)` export const OffersContainer = styled(Box)`
margin-top: 30px; margin-top: 30px;
`; `;
export const OffersScroller = styled(HorizontalScroller)` export const OffersScroller = styled(HorizontalScroller)`
height: 373px;
height: 400px;
width: 100%; width: 100%;
margin-left: 0; margin-left: 0;
& div { & div {

+ 5
- 1
src/components/ProfileMini/ProfileMini.js 查看文件

<ProfileHeader> <ProfileHeader>
<ProfileHeaderIconContainer> <ProfileHeaderIconContainer>
<ProfileIcon /> <ProfileIcon />
<ProfileHeaderText>{t("profile.companyProfile")}</ProfileHeaderText>
<ProfileHeaderText>
{isMyProfile
? t("profile.myProfile")
: t("profile.companyProfile")}
</ProfileHeaderText>
</ProfileHeaderIconContainer> </ProfileHeaderIconContainer>
<ItemDetailsHeaderCard <ItemDetailsHeaderCard
offer={offer} offer={offer}

+ 3
- 2
src/components/ProfileMini/ProfileMini.styled.js 查看文件

margin-top: 60px; margin-top: 60px;


@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
width: 100%;
width: calc(100vw - 36px);
position: absolute; position: absolute;
top: 25px; top: 25px;
left: 18px;
} }
`; `;
export const ProfileHeaderIconContainer = styled(Box)` export const ProfileHeaderIconContainer = styled(Box)`
border: 1px solid ${selectedTheme.colors.primaryPurple}; border: 1px solid ${selectedTheme.colors.primaryPurple};


@media (max-width: 600px) { @media (max-width: 600px) {
width: 92%;
width: calc(100vw - 36px);
} }
`; `;

+ 2
- 0
src/components/StepProgress/StepProgress.styled.js 查看文件

position: relative; position: relative;
left: 2px; left: 2px;
width: 332px; width: 332px;
gap: 0 !important;
${(props) => props.current === 3 && `margin-bottom: 30px;`} ${(props) => props.current === 3 && `margin-bottom: 30px;`}


@media screen and (min-width: 468px) and (max-width: 600px) { @media screen and (min-width: 468px) and (max-width: 600px) {
width: 80%; width: 80%;
gap: 0 !important;
} }


@media (max-width: 600px) { @media (max-width: 600px) {

+ 35
- 19
src/components/UserReviews/ReviewsSorting/ReviewsSorting.js 查看文件

import React from "react";
import React, { forwardRef, useImperativeHandle, useMemo } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { import {
DownArrowIcon, DownArrowIcon,
import { sortReviews } from "../../../util/helpers/reviewsHelper"; import { sortReviews } from "../../../util/helpers/reviewsHelper";
import { reviewSortEnum } from "../../../enums/reviewEnum"; import { reviewSortEnum } from "../../../enums/reviewEnum";
import { setReviews } from "../../../store/actions/review/reviewActions"; 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 reviews = useSelector(selectSelectedReviews);
const dispatch = useDispatch(); const dispatch = useDispatch();
const [value, setValue] = useState(); const [value, setValue] = useState();
const changeValue = (event) => { 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); 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 ( return (
<HeaderSelect <HeaderSelect
value={value || reviewSortEnum.INITIAL}
value={value || sortEnum.INITIAL}
IconComponent={DownArrowIcon} IconComponent={DownArrowIcon}
onChange={changeValue} onChange={changeValue}
> >
<SelectOption style={{ display: "none" }} value={reviewSortEnum.INITIAL}>
{reviewSortEnum.INITIAL.mainText}
<SelectOption style={{ display: "none" }} value={sortEnum.INITIAL}>
{sortEnum.INITIAL.mainText}
</SelectOption> </SelectOption>
{Object.keys(reviewSortEnum).map((property) => {
if (reviewSortEnum[property].value === 0) return;
{Object.keys(sortEnum).map((property) => {
if (sortEnum[property].value === 0) return;
return ( return (
<SelectOption <SelectOption
value={reviewSortEnum[property]}
key={reviewSortEnum[property].value}
value={sortEnum[property]}
key={sortEnum[property].value}
> >
{reviewSortEnum[property].mainText}
{sortEnum[property].mainText}
</SelectOption> </SelectOption>
); );
})} })}
</HeaderSelect> </HeaderSelect>
); );
};
});

ReviewsSorting.displayName = "ReviewsSorting";


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


export default ReviewsSorting; export default ReviewsSorting;

+ 14
- 4
src/components/UserReviews/UserReviews.js 查看文件

ReviewsHeader, ReviewsHeader,
ReviewsHeaderTitle, ReviewsHeaderTitle,
ReviewsTitle, ReviewsTitle,
UserReviewsContainer,
} from "./UserReviews.styled"; } from "./UserReviews.styled";


import StarBorderIcon from "@mui/icons-material/StarBorder"; import StarBorderIcon from "@mui/icons-material/StarBorder";
const routeMatch = useRouteMatch(); const routeMatch = useRouteMatch();
const dispatch = useDispatch(); const dispatch = useDispatch();
const listRef = useRef(null); const listRef = useRef(null);
const sortRef = useRef(null);


const isLoadingReview = useSelector( const isLoadingReview = useSelector(
selectIsLoadingByActionType( selectIsLoadingByActionType(
listRef.current.scrollTo({ top: 0, behaviour: "smooth" }); listRef.current.scrollTo({ top: 0, behaviour: "smooth" });
}; };


console.log(sortRef.current?.sortValue);
return ( return (
<>
<UserReviewsContainer className={props.className}>
{!props.givingReview && {!props.givingReview &&
(isLoadingReview || isLoadingReview === undefined) ? ( (isLoadingReview || isLoadingReview === undefined) ? (
<SkeletonUserReviews /> <SkeletonUserReviews />
) : ( ) : (
<ReviewsBox <ReviewsBox
isAdmin={props.isAdmin}
profile={props.isProfileReviews} profile={props.isProfileReviews}
className={props.className}
numOfReviews={lastThreeReviews?.length} numOfReviews={lastThreeReviews?.length}
> >
{!props.givingReview && ( {!props.givingReview && (
/> />
<ReviewsTitle>{t("reviews.rates")}</ReviewsTitle> <ReviewsTitle>{t("reviews.rates")}</ReviewsTitle>
</ReviewsHeaderTitle> </ReviewsHeaderTitle>
<ReviewsSorting changeSorting={scrollToTop} />
<ReviewsSorting
changeSorting={scrollToTop}
ref={sortRef}
isAdmin={props.isAdmin}
/>
</ReviewsHeader> </ReviewsHeader>
)} )}
<ReviewList ref={listRef} isProfileReviews={props.isProfileReviews}> <ReviewList ref={listRef} isProfileReviews={props.isProfileReviews}>
{lastThreeReviews?.length > 0 ? ( {lastThreeReviews?.length > 0 ? (
lastThreeReviews?.map((review, index) => ( lastThreeReviews?.map((review, index) => (
<UserReviewsCard <UserReviewsCard
showRemoveIcon={props.isAdmin}
review={review} review={review}
key={index} key={index}
hasGivenReview={sortRef.current?.hasGivenReview}
givingReview={props.givingReview} givingReview={props.givingReview}
/> />
)) ))
</ReviewList> </ReviewList>
</ReviewsBox> </ReviewsBox>
)} )}
</>
</UserReviewsContainer>
); );
}; };


className: PropTypes.string, className: PropTypes.string,
givingReview: PropTypes.bool, givingReview: PropTypes.bool,
offer: PropTypes.any, offer: PropTypes.any,
isAdmin: PropTypes.bool,
}; };
UserReviews.defaultProps = { UserReviews.defaultProps = {
isProfileReviews: false, isProfileReviews: false,

+ 3
- 9
src/components/UserReviews/UserReviews.styled.js 查看文件

import selectedTheme from "../../themes"; import selectedTheme from "../../themes";
import { ReactComponent as DownArrow } from "../../assets/images/svg/up-arrow.svg"; import { ReactComponent as DownArrow } from "../../assets/images/svg/up-arrow.svg";


export const UserReviewsContainer = styled(Box)``;

export const ReviewsBox = styled(Box)` export const ReviewsBox = styled(Box)`
width: 100%; 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; min-width: 290px;
/* @media (max-width: 1200px) {
padding: 0 50px;
} */
${(props) => ${(props) =>
props.profile && props.profile &&
` `
? "450px" ? "450px"
: "350px"}; : "350px"};
padding: 0; padding: 0;
margin: 0 ${props => props.isAdmin ? "18px" : "0"};
margin-top: 60px; margin-top: 60px;
} }
`; `;

+ 1
- 0
src/constants/pages.js 查看文件

export const POLICY_PRIVACY_PAGE = "/policy"; export const POLICY_PRIVACY_PAGE = "/policy";
export const ADMIN_HOME_PAGE = "/admin"; export const ADMIN_HOME_PAGE = "/admin";
export const ADMIN_USERS_PAGE = "/admin/users"; 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_CATEGORIES_PAGE = "/admin/categories";
export const ADMIN_LOCATIONS_PAGE = "/admin/locations"; export const ADMIN_LOCATIONS_PAGE = "/admin/locations";
export const ADMIN_PAYMENT_PAGE = "/admin/payment"; export const ADMIN_PAYMENT_PAGE = "/admin/payment";

+ 14
- 0
src/enums/sortEnum.js 查看文件

mainText: "Najstarije", mainText: "Najstarije",
queryString: "oldest" queryString: "oldest"
} }
}
export const sortAdminEnum = {
INITIAL: {
value: 0,
mainText: "Sortiraj po"
},
GIVEN: {
value: 1,
mainText: "Date"
},
RECIEVED: {
value: 2,
mainText: "Dobijene"
}
} }

+ 7
- 3
src/hooks/useOffers/useCompanyFilter.js 查看文件

import { useEffect, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { setFilteredCompany } from "../../store/actions/filters/filtersActions"; import { setFilteredCompany } from "../../store/actions/filters/filtersActions";
import { fetchAllProfiles } from "../../store/actions/profile/profileActions"; import { fetchAllProfiles } from "../../store/actions/profile/profileActions";
import { selectAllProfiles } from "../../store/selectors/profileSelectors"; import { selectAllProfiles } from "../../store/selectors/profileSelectors";


const useCompaniesFilter = () => { const useCompaniesFilter = () => {
const selectedCompanies = useSelector(selectSelectedCompany);
const selectedCompaniesRedux = useSelector(selectSelectedCompany);
const dispatch = useDispatch(); const dispatch = useDispatch();
const allCompanies = useSelector(selectAllProfiles);
const allCompaniesRedux = useSelector(selectAllProfiles);
const [selectedCompaniesLocally, setSelectedCompaniesLocally] = useState([]); const [selectedCompaniesLocally, setSelectedCompaniesLocally] = useState([]);
useEffect(() => { useEffect(() => {
dispatch(fetchAllProfiles()); dispatch(fetchAllProfiles());
}, []); }, []);


const selectedCompanies = useMemo(() => Array.isArray(selectedCompaniesRedux) ? selectedCompaniesRedux : [])
const allCompanies = useMemo(() => Array.isArray(allCompaniesRedux) ? selectedCompaniesRedux : [])

useEffect(() => { useEffect(() => {
setSelectedCompaniesLocally(selectedCompanies); setSelectedCompaniesLocally(selectedCompanies);
}, [selectedCompanies]); }, [selectedCompanies]);

+ 31
- 1
src/i18n/resources/rs.js 查看文件

finishedReviewTitle: "Hvala vam", finishedReviewTitle: "Hvala vam",
finishedReviewAltTitle: "na izdvojenom vremenu i datoj oceni!", finishedReviewAltTitle: "na izdvojenom vremenu i datoj oceni!",
sortBy: "Sortiraj po", sortBy: "Sortiraj po",
offerTitle: "Proizvod:"
}, },
messages: { messages: {
headerTitle: "Moje Ćaskanje", headerTitle: "Moje Ćaskanje",
headerTitle: "Ulogujte se", headerTitle: "Ulogujte se",
}, },
users: { users: {
headerTitle: "Profili korisnika",
headerTitle: "Profili kompanija",
searchPlaceholder: "Pretražite korisnike....", searchPlaceholder: "Pretražite korisnike....",
checkProfile: "Pogledaj profil", checkProfile: "Pogledaj profil",
goBack: "Nazad na sve kompanije",
}, },
navigation: { navigation: {
role: "Administrator", role: "Administrator",
fieldTitle: "Naslov", fieldTitle: "Naslov",
placeholder: "Naziv kategorije...", placeholder: "Naziv kategorije...",
save: "Izmeni", save: "Izmeni",
next: "Izmeni",
}, },
add: { add: {
title: "Nova Kategorija", title: "Nova Kategorija",
subcategoriesHeaderTitle: "Podkategorije", subcategoriesHeaderTitle: "Podkategorije",
placeholder: "Pretražite podkategorije...", placeholder: "Pretražite podkategorije...",
addSubcategory: "Dodaj podkategoriju", addSubcategory: "Dodaj podkategoriju",
cancel: "Otkaži",
delete: "Obriši",
reassuranceDelete: reassuranceDelete:
"Da li ste sigurni da želite da obrišete odabranu podkategoriju?", "Da li ste sigurni da želite da obrišete odabranu podkategoriju?",
edit: { edit: {
fieldTitle: "Naslov", fieldTitle: "Naslov",
placeholder: "Naziv podkategorije...", placeholder: "Naziv podkategorije...",
save: "Izmeni", save: "Izmeni",
next: "Sledeća",
}, },
add: { add: {
title: "Nova Podkategorija", title: "Nova Podkategorija",
noOfCompanies: "Broj firmi u gradu: ", noOfCompanies: "Broj firmi u gradu: ",
placeholder: "Pretražite lokacije...", placeholder: "Pretražite lokacije...",
addLocation: "Dodaj lokaciju", addLocation: "Dodaj lokaciju",
cancel: "Otkaži",
delete: "Obriši",
reassuranceDelete: reassuranceDelete:
"Da li ste sigurni da želite da obrišete odabranu lokaciju?", "Da li ste sigurni da želite da obrišete odabranu lokaciju?",
edit: { edit: {
fieldTitle: "Naslov", fieldTitle: "Naslov",
placeholder: "Naziv lokacije...", placeholder: "Naziv lokacije...",
save: "Izmeni", save: "Izmeni",
next: "Izmeni",
}, },
add: { add: {
title: "Nova Lokacija", title: "Nova Lokacija",
next: "Sledeća", 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 查看文件

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 查看文件

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
- 9
src/layouts/ItemDetailsLayout/ItemDetailsLayout.styled.js 查看文件

import styled from "styled-components"; import styled from "styled-components";


export const ItemDetailsLayoutContainer = styled(Container)` export const ItemDetailsLayoutContainer = styled(Container)`
padding-left: 36px;
padding-right: ${(props) => (props.singleOffer ? "76px" : 0)};
/* padding-left: 36px; */
/* padding-right: ${(props) => (props.singleOffer ? "76px" : 0)}; */
margin: 0; margin: 0;
width: 100%;
max-width: none;
width: 100vw;
max-width: 100vw;
/* display: flex; */ /* display: flex; */
position: relative; position: relative;
/* flex: 1; */ /* flex: 1; */
height: 100%; height: 100%;
@media (max-width: 1200px) { @media (max-width: 1200px) {
padding-right: ${(props) => (props.profile ? 0 : "36px")};
/* padding-right: ${(props) => (props.profile ? 0 : "36px")}; */
} }
@media (max-width: 600px) { @media (max-width: 600px) {
padding-left: 18px;
padding-right: 18px;
/* padding-left: 18px; */
/* padding-right: 18px; */
} }
`; `;




@media screen and (min-width: 600px) { @media screen and (min-width: 600px) {
margin-top: 34px; margin-top: 34px;
margin-left: ${(props) => (props.profile ? "0" : "36px")};
padding-left: ${(props) => (props.singleOffer ? "36px" : 0)};
/* margin-left: ${(props) => (props.profile ? "0" : "36px")}; */
/* padding-left: ${(props) => (props.singleOffer ? "36px" : 0)}; */
border-top-right-radius: 4px; border-top-right-radius: 4px;
${(props) => props.singleOffer && `width: 100%`} ${(props) => props.singleOffer && `width: 100%`}
} }

+ 1
- 0
src/pages/AdminHomePage/AdminCategoriesPage/AdminCategoriesPage.js 查看文件

setOpenedEditModal={setOpenedAddModal} setOpenedEditModal={setOpenedAddModal}
type={"categories"} type={"categories"}
method="add" method="add"
showSecondButton
/> />
)} )}
</> </>

+ 9
- 8
src/pages/AdminHomePage/AdminCategoriesPage/AdminCategoriesPage.styled.js 查看文件

@media (max-width: 600px) { @media (max-width: 600px) {
padding: 18px; padding: 18px;
min-height: calc(100vh - 72px); min-height: calc(100vh - 72px);
padding-bottom: 54px;
padding-bottom: 100px;
top: 65px; top: 65px;
} }
`; `;
/* top: 40px; */ /* top: 40px; */
top: 0; top: 0;
@media (max-width: 600px) { @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;
} }
} }
`; `;
} }
` `
export const CategoriesList = styled(Box)` export const CategoriesList = styled(Box)`
padding-top: 10px
/* padding-top: 10px */
` `

+ 14
- 3
src/pages/AdminHomePage/AdminHomePage.js 查看文件

// import MarketPlace from "../../components/MarketPlace/MarketPlace"; // import MarketPlace from "../../components/MarketPlace/MarketPlace";
// import useOffers from "../../hooks/useOffers/useOffers"; // import useOffers from "../../hooks/useOffers/useOffers";
import Sidebar from "../../components/Admin/Sidebar/Sidebar"; import Sidebar from "../../components/Admin/Sidebar/Sidebar";
import { MainLayoutAdminHomePage } from "./AdminHomePage.styled";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
// import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors"; // import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors";
// import { OFFERS_SCOPE } from "../../store/actions/offers/offersActionConstants"; // import { OFFERS_SCOPE } from "../../store/actions/offers/offersActionConstants";
ADMIN_CATEGORIES_PAGE, ADMIN_CATEGORIES_PAGE,
ADMIN_LOCATIONS_PAGE, ADMIN_LOCATIONS_PAGE,
ADMIN_PAYMENT_PAGE, ADMIN_PAYMENT_PAGE,
ADMIN_SINGLE_USER_PAGE,
ADMIN_SUBCATEGORIES_PAGE, ADMIN_SUBCATEGORIES_PAGE,
ADMIN_USERS_PAGE, ADMIN_USERS_PAGE,
HOME_PAGE, HOME_PAGE,
import AdminSubcategoriesPage from "./AdminSubcategoriesPage/AdminSubcategoriesPage"; import AdminSubcategoriesPage from "./AdminSubcategoriesPage/AdminSubcategoriesPage";
import AdminLocationsPage from "./AdminLocationsPage/AdminLocationsPage"; import AdminLocationsPage from "./AdminLocationsPage/AdminLocationsPage";
import AdminPaymentPage from "./AdminPaymentPage/AdminPaymentPage"; import AdminPaymentPage from "./AdminPaymentPage/AdminPaymentPage";
import AdminSingleUserPage from "./AdminUsersPage/AdminSingleUserPage/AdminSingleUserPage";
import { AdminLayoutHomePage } from "./AdminHomePage.styled";


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

+ 2
- 2
src/pages/AdminHomePage/AdminHomePage.styled.js 查看文件

import styled from "styled-components"; 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; margin-top: 0;
`; `;

+ 1
- 0
src/pages/AdminHomePage/AdminLocationsPage/AdminLocationsPage.js 查看文件

setOpenedEditModal={setOpenedAddModal} setOpenedEditModal={setOpenedAddModal}
type={"locations"} type={"locations"}
method="add" method="add"
showSecondButton
/> />
)} )}
</> </>

+ 8
- 7
src/pages/AdminHomePage/AdminLocationsPage/AdminLocationsPage.styled.js 查看文件

@media (max-width: 600px) { @media (max-width: 600px) {
padding: 18px; padding: 18px;
min-height: (100vh - 72px); min-height: (100vh - 72px);
padding-bottom: 54px;
padding-bottom: 100px;
top: 65px; top: 65px;
} }
`; `;
export const AdminLocationsHeader = styled(Header)` export const AdminLocationsHeader = styled(Header)`
top: 0; top: 0;
@media (max-width: 600px) { @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;
} }
} }
`; `;

+ 6
- 4
src/pages/AdminHomePage/AdminSubcategoriesPage/AdminSubcategoriesPage.js 查看文件

import selectedTheme from "../../../themes"; import selectedTheme from "../../../themes";
import { useState } from "react"; import { useState } from "react";
import EditCategory from "../../../components/Modals/EditCategory/EditCategory"; import EditCategory from "../../../components/Modals/EditCategory/EditCategory";
import { isInRoute } from "../../../util/helpers/routeHelpers";
import { ADMIN_SUBCATEGORIES_PAGE } from "../../../constants/pages";


const AdminSubcategoriesPage = () => { const AdminSubcategoriesPage = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const manualSearchString = useSelector(selectManualSearchString); const manualSearchString = useSelector(selectManualSearchString);
const [openedAddModal, setOpenedAddModal] = useState(false); const [openedAddModal, setOpenedAddModal] = useState(false);


console.log(isInRoute(ADMIN_SUBCATEGORIES_PAGE));

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

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

const category = useMemo(() => { const category = useMemo(() => {
if (routeMatch.params?.categoryId) { if (routeMatch.params?.categoryId) {
const categoryId = routeMatch.params.categoryId; const categoryId = routeMatch.params.categoryId;
} }
return {}; return {};
}, [routeMatch, categories]); }, [routeMatch, categories]);

const subcategories = useMemo(() => { const subcategories = useMemo(() => {
if (category) { if (category) {
if (manualSearchString) if (manualSearchString)
} }
return []; return [];
}, [category, manualSearchString]); }, [category, manualSearchString]);
console.log("subc", categories);
return ( return (
<> <>
<AdminSubcategoriesPageContainer> <AdminSubcategoriesPageContainer>
setOpenedEditModal={setOpenedAddModal} setOpenedEditModal={setOpenedAddModal}
type="subcategories" type="subcategories"
method="add" method="add"
showSecondButton
/> />
)} )}
</> </>

+ 1
- 1
src/pages/AdminHomePage/AdminSubcategoriesPage/AdminSubcategoriesPage.styled.js 查看文件

@media (max-width: 600px) { @media (max-width: 600px) {
padding: 18px; padding: 18px;
min-height: (100vh - 72px); min-height: (100vh - 72px);
padding-bottom: 54px;
padding-bottom: 100px;
top: 65px; top: 65px;
} }
`; `;

+ 25
- 0
src/pages/AdminHomePage/AdminUsersPage/AdminSingleUserPage/AdminSingleUserPage.js 查看文件

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 查看文件

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 查看文件

import React, { useEffect } from "react";
import React, { useEffect, useMemo } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import MarketPlace from "../../../components/MarketPlace/MarketPlace";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { selectAllProfiles } from "../../../store/selectors/profileSelectors"; import { selectAllProfiles } from "../../../store/selectors/profileSelectors";
import { fetchAllProfiles } from "../../../store/actions/profile/profileActions"; 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 AdminUsersPage = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { t } = useTranslation();
const allUsers = useSelector(selectAllProfiles); const allUsers = useSelector(selectAllProfiles);
const allUsersToShow = useMemo(
() => (Array.isArray(allUsers) ? allUsers : []),
[allUsers]
);
useEffect(() => { useEffect(() => {
dispatch(fetchAllProfiles()); dispatch(fetchAllProfiles());
}, []); }, []);


const handleSearch = () => {};

return ( return (
<AdminUsersPageContainer> <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> </AdminUsersPageContainer>
); );
}; };

+ 39
- 6
src/pages/AdminHomePage/AdminUsersPage/AdminUsersPage.styled.js 查看文件

import { Box } from "@mui/material"; import { Box } from "@mui/material";
import styled from "styled-components"; import styled from "styled-components";
import Header from "../../../components/MarketPlace/Header/Header";
import SearchField from "../../../components/TextFields/SearchField/SearchField";


export const AdminUsersPageContainer = styled(Box)` 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 { & > 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
- 1
src/store/saga/locationsSaga.js 查看文件

function* fetchLocations() { function* fetchLocations() {
try { try {
const { data } = yield call(attemptFetchLocations); const { data } = yield call(attemptFetchLocations);
yield put(setLocations(data));
yield put(setLocations(data.value));
yield put(fetchLocationsSuccess()); yield put(fetchLocationsSuccess());
} catch (e) { } catch (e) {
yield put(fetchLocationsError()); yield put(fetchLocationsError());

+ 2
- 2
src/util/helpers/dateHelpers.js 查看文件

const dayCreated = const dayCreated =
date.getDate() < 10 ? "0" + date.getDate() : date.getDate(); date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
const monthCreated = const monthCreated =
date.getMonth() < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
date.getMonth() < 9 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
const yearCreated = date.getFullYear(); const yearCreated = date.getFullYear();
const hourCreated = const hourCreated =
date.getHours() < 10 ? "0" + date.getHours() : date.getHours(); date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
const dayCreated = const dayCreated =
date.getDate() < 10 ? "0" + date.getDate() : date.getDate(); date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
const monthCreated = const monthCreated =
date.getMonth() < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
date.getMonth() < 9 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
const yearCreated = date.getFullYear(); const yearCreated = date.getFullYear();
return `${dayCreated}.${monthCreated}.${yearCreated}.`; return `${dayCreated}.${monthCreated}.${yearCreated}.`;
} }

+ 0
- 0
src/util/helpers/imageUrlGetter.js 查看文件


部分文件因文件數量過多而無法顯示

Loading…
取消
儲存