| @@ -1 +1 @@ | |||
| REACT_APP_BASE_API_URL=https://trampa-api-test.dilig.net/ | |||
| REACT_APP_BASE_API_URL=http://localhost:3001/ | |||
| @@ -21,7 +21,7 @@ | |||
| <link | |||
| rel="stylesheet" | |||
| type="text/css" | |||
| href="https://fonts.googleapis.com/css?family=DM+Sans" | |||
| href="https://fonts.googleapis.com/css?family=DM+Sans:300,400,500,600,700,800" | |||
| /> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |||
| <meta name="theme-color" content="#000000" /> | |||
| @@ -34,9 +34,7 @@ const Sidebar = () => { | |||
| const dispatch = useDispatch(); | |||
| const { isMobile } = useIsMobile(); | |||
| const { t } = useTranslation(); | |||
| console.log(profile); | |||
| const routeToItem = (route) => { | |||
| console.log(route); | |||
| history.push(route); | |||
| }; | |||
| const logoutHandler = () => { | |||
| @@ -11,6 +11,9 @@ export const SidebarContainer = styled(Box)` | |||
| min-width: 281px; | |||
| overflow-y: auto; | |||
| height: 100vh; | |||
| @media (max-width: 1536px) { | |||
| width: 25%; | |||
| } | |||
| @media (max-width: 600px) { | |||
| display: none; | |||
| } | |||
| @@ -32,6 +32,7 @@ const CategoryCard = (props) => { | |||
| ); | |||
| } | |||
| }; | |||
| console.log(props); | |||
| return ( | |||
| <> | |||
| <CategoryCardContainer className={props.className}> | |||
| @@ -74,12 +75,13 @@ const CategoryCard = (props) => { | |||
| )} | |||
| {openedEditModal && ( | |||
| <EditCategory | |||
| hideImagePicker | |||
| hideImagePicker={props.type !== "categories"} | |||
| setOpenedEditModal={setOpenedEditModal} | |||
| category={props.category} | |||
| subcategory={props.subcategory} | |||
| type={props.type} | |||
| method="edit" | |||
| showSecondButton | |||
| /> | |||
| )} | |||
| </> | |||
| @@ -17,6 +17,9 @@ export const CategoryCardContainer = styled(Box)` | |||
| position: relative; | |||
| @media (max-width: 600px) { | |||
| height: 102px; | |||
| margin-left: 0; | |||
| margin-right: 0; | |||
| width: 100%; | |||
| } | |||
| `; | |||
| export const CategoryCardLeftContainer = styled(Box)` | |||
| @@ -7,10 +7,8 @@ import { | |||
| const LabeledCard = (props) => { | |||
| return ( | |||
| <LabeledCardContainer> | |||
| <LabeledCardIconContainer width={props.width} height={props.height}> | |||
| {props.icon} | |||
| </LabeledCardIconContainer> | |||
| <LabeledCardContainer width={props.width} height={props.height}> | |||
| <LabeledCardIconContainer>{props.icon}</LabeledCardIconContainer> | |||
| {props.children} | |||
| </LabeledCardContainer> | |||
| ); | |||
| @@ -0,0 +1,36 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| PIBContainer, | |||
| PIBIcon, | |||
| PIBText, | |||
| UserImage, | |||
| UserLabeledCardContainer, | |||
| UserLabeledCardDetailsContainer, | |||
| UserName, | |||
| } from "./UserLabeledCard.styled"; | |||
| import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter"; | |||
| import { useTranslation } from "react-i18next"; | |||
| const UserLabeledCard = (props) => { | |||
| const { t } = useTranslation(); | |||
| return ( | |||
| <UserLabeledCardContainer> | |||
| <UserImage src={getImageUrl(props.user.image, variants.reviewCard)} /> | |||
| <UserLabeledCardDetailsContainer> | |||
| <UserName>{props.user.company.name}</UserName> | |||
| <PIBContainer> | |||
| <PIBIcon /> | |||
| <PIBText>{t("itemDetailsCard.PIB") + props.user.company.PIB}</PIBText> | |||
| </PIBContainer> | |||
| </UserLabeledCardDetailsContainer> | |||
| </UserLabeledCardContainer> | |||
| ); | |||
| }; | |||
| UserLabeledCard.propTypes = { | |||
| children: PropTypes.node, | |||
| user: PropTypes.object, | |||
| }; | |||
| export default UserLabeledCard; | |||
| @@ -0,0 +1,59 @@ | |||
| import { Box, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import { ReactComponent as PIB } from "../../../../assets/images/svg/pib.svg"; | |||
| import selectedTheme from "../../../../themes"; | |||
| export const UserLabeledCardContainer = styled(Box)` | |||
| display: flex; | |||
| flex-direction: row; | |||
| gap: 9px; | |||
| @media (max-width: 600px) { | |||
| max-height: 216px; | |||
| } | |||
| `; | |||
| export const UserLabeledCardDetailsContainer = styled(Box)` | |||
| display: flex; | |||
| flex-direction: column; | |||
| gap: 1px; | |||
| `; | |||
| export const UserName = styled(Typography)` | |||
| font-family: ${selectedTheme.fonts.textFont}; | |||
| font-style: normal; | |||
| font-weight: 700; | |||
| font-size: 16px; | |||
| line-height: 21px; | |||
| color: ${selectedTheme.colors.primaryPurple}; | |||
| padding-top: 7px; | |||
| white-space: nowrap; | |||
| @media (max-width: 600px) { | |||
| padding-top: 9px; | |||
| font-size: 14px; | |||
| line-height: 19px; | |||
| font-weight: 600; | |||
| } | |||
| `; | |||
| export const PIBContainer = styled(Box)` | |||
| display: flex; | |||
| flex-direction: row; | |||
| gap: 5px; | |||
| `; | |||
| export const PIBIcon = styled(PIB)` | |||
| width: 12px; | |||
| height: 12px; | |||
| position: relative; | |||
| top: 1.5px; | |||
| `; | |||
| export const PIBText = styled(Typography)` | |||
| font-family: ${selectedTheme.fonts.textFont}; | |||
| font-weight: 400; | |||
| font-size: 12px; | |||
| line-height: 16px; | |||
| letter-spacing: 0.01em; | |||
| color: ${selectedTheme.colors.primaryDarkText}; | |||
| white-space: nowrap; | |||
| `; | |||
| export const UserImage = styled.img` | |||
| width: 54px; | |||
| height: 54px; | |||
| border-radius: 100%; | |||
| `; | |||
| @@ -8,12 +8,12 @@ const CancelButton = (props) => { | |||
| const { t } = useTranslation(); | |||
| return ( | |||
| <CancelButtonContainer | |||
| variant="contained" | |||
| variant={props.pin ? "outlined" : "contained"} | |||
| height="48px" | |||
| width="180px" | |||
| fullWidth | |||
| buttoncolor={selectedTheme.colors.primaryPurple} | |||
| textcolor="white" | |||
| textcolor={props.pin ? selectedTheme.colors.primaryPurple : "white"} | |||
| onClick={props.onClick} | |||
| > | |||
| {t("deleteOffer.cancel")} | |||
| @@ -23,6 +23,7 @@ const CancelButton = (props) => { | |||
| CancelButton.propTypes = { | |||
| onClick: PropTypes.func, | |||
| pin: PropTypes.bool, | |||
| }; | |||
| export default CancelButton; | |||
| @@ -17,7 +17,7 @@ import { | |||
| fetchProfileOffers, | |||
| removeOffer, | |||
| } from "../../../../store/actions/offers/offersActions"; | |||
| import { Trans } from "react-i18next"; | |||
| import { Trans, useTranslation } from "react-i18next"; | |||
| import { useHistory } from "react-router-dom"; | |||
| import useIsMobile from "../../../../hooks/useIsMobile"; | |||
| import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter"; | |||
| @@ -28,6 +28,7 @@ import SaveButton from "./SaveButton/SaveButton"; | |||
| const DeleteOffer = (props) => { | |||
| const dispatch = useDispatch(); | |||
| const { t } = useTranslation(); | |||
| const queryString = useSelector(selectQueryString); | |||
| const history = useHistory(); | |||
| const userId = props.offer.userId; | |||
| @@ -77,11 +78,15 @@ const DeleteOffer = (props) => { | |||
| </RemoveIconContainer> | |||
| </OfferInfo> | |||
| <DeleteQuestion> | |||
| <Trans i18nKey="deleteOffer.areYouSure" /> | |||
| {props.pin ? ( | |||
| t("admin.pin.reassurancePin") | |||
| ) : ( | |||
| <Trans i18nKey="deleteOffer.areYouSure" /> | |||
| )} | |||
| </DeleteQuestion> | |||
| <ButtonsContainer> | |||
| <CancelButton onClick={closeDeleteModalHandler} /> | |||
| <SaveButton onClick={removeOfferHandler} /> | |||
| <CancelButton pin={props.pin} onClick={closeDeleteModalHandler} /> | |||
| <SaveButton pin={props.pin} onClick={removeOfferHandler} /> | |||
| </ButtonsContainer> | |||
| </DeleteOfferContainer> | |||
| </> | |||
| @@ -91,6 +96,7 @@ const DeleteOffer = (props) => { | |||
| DeleteOffer.propTypes = { | |||
| offer: PropTypes.node, | |||
| closeModalHandler: PropTypes.func, | |||
| pin: PropTypes.bool, | |||
| }; | |||
| export default DeleteOffer; | |||
| @@ -3,7 +3,7 @@ import { Box } from "@mui/system"; | |||
| import styled from "styled-components"; | |||
| import { ReactComponent as Remove } from "../../../../assets/images/svg/trash-gold.svg"; | |||
| import selectedTheme from "../../../../themes"; | |||
| import { IconButton } from "../../../Buttons/IconButton/IconButton"; | |||
| import { Icon } from "../../../Icon/Icon"; | |||
| export const DeleteOfferContainer = styled(Box)` | |||
| width: 537px; | |||
| @@ -73,7 +73,7 @@ export const DeleteQuestion = styled(Typography)` | |||
| } | |||
| `; | |||
| export const RemoveIconBorder = styled(IconButton)` | |||
| export const RemoveIconBorder = styled(Icon)` | |||
| width: 40px; | |||
| height: 40px; | |||
| position: absolute; | |||
| @@ -95,6 +95,8 @@ export const RemoveIconContainer = styled(RemoveIconBorder)` | |||
| export const RemoveIcon = styled(Remove)` | |||
| cursor: default; | |||
| position: relative; | |||
| top: 7px; | |||
| `; | |||
| export const ButtonsContainer = styled(Box)` | |||
| @@ -0,0 +1,45 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| OfferImage, | |||
| OfferImageContainer, | |||
| OfferInfo, | |||
| RemoveIcon, | |||
| RemoveIconContainer, | |||
| } from "./DeleteOfferLabeledCard.styled"; | |||
| import { | |||
| getImageUrl, | |||
| variants, | |||
| } from "../../../../../util/helpers/imageUrlGetter"; | |||
| import OfferDescription from "../OfferDescription/OfferDescription"; | |||
| import useIsMobile from "../../../../../hooks/useIsMobile"; | |||
| const DeleteOfferLabeledCard = (props) => { | |||
| const { isMobile } = useIsMobile(); | |||
| return ( | |||
| <OfferInfo> | |||
| <OfferImageContainer> | |||
| <OfferImage | |||
| src={getImageUrl( | |||
| props.offer.images[0], | |||
| variants.deleteChat, | |||
| isMobile | |||
| )} | |||
| /> | |||
| </OfferImageContainer> | |||
| <OfferDescription | |||
| offerName={props.offer.name} | |||
| categoryName={props.offer.category.name} | |||
| /> | |||
| <RemoveIconContainer> | |||
| <RemoveIcon /> | |||
| </RemoveIconContainer> | |||
| </OfferInfo> | |||
| ); | |||
| }; | |||
| DeleteOfferLabeledCard.propTypes = { | |||
| offer: PropTypes.node, | |||
| }; | |||
| export default DeleteOfferLabeledCard; | |||
| @@ -0,0 +1,58 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../../../themes"; | |||
| import { ReactComponent as Remove } from "../../../../../assets/images/svg/trash-gold.svg"; | |||
| import { IconButton } from "../../../../Buttons/IconButton/IconButton"; | |||
| export const OfferInfo = styled(Box)` | |||
| width: 211px; | |||
| height: 90px; | |||
| border: 1px solid #d4d4d4; | |||
| display: flex; | |||
| align-items: center; | |||
| padding: 18px; | |||
| margin-top: 36px; | |||
| @media screen and (max-width: 600px) { | |||
| margin-left: calc(50% - 105px) !important; | |||
| } | |||
| `; | |||
| export const OfferImageContainer = styled(Box)` | |||
| width: 54px; | |||
| height: 54px; | |||
| border-radius: 2px; | |||
| @media screen and (max-width: 600px) { | |||
| margin-right: 13px; | |||
| } | |||
| `; | |||
| export const OfferImage = styled.img` | |||
| width: 100%; | |||
| height: 100%; | |||
| object-fit: cover; | |||
| border-radius: 2px; | |||
| `; | |||
| export const RemoveIconBorder = styled(IconButton)` | |||
| width: 40px; | |||
| height: 40px; | |||
| position: absolute; | |||
| top: 16px; | |||
| right: 143px; | |||
| background-color: ${selectedTheme.colors.primaryPurple}; | |||
| border-radius: 100%; | |||
| padding-top: 2px; | |||
| text-align: center; | |||
| @media screen and (max-width: 600px) { | |||
| right: 50px; | |||
| } | |||
| `; | |||
| export const RemoveIconContainer = styled(RemoveIconBorder)` | |||
| cursor: default; | |||
| `; | |||
| export const RemoveIcon = styled(Remove)` | |||
| cursor: default; | |||
| `; | |||
| @@ -9,21 +9,22 @@ const SaveButton = (props) => { | |||
| return ( | |||
| <SaveButtonContainer | |||
| type="submit" | |||
| variant="outlined" | |||
| variant={props.pin ? "contained" : "outlined"} | |||
| height="48px" | |||
| width="180px" | |||
| fullWidth | |||
| buttoncolor={selectedTheme.colors.primaryPurple} | |||
| textcolor={selectedTheme.colors.primaryPurple} | |||
| textcolor={props.pin ? "white" : selectedTheme.colors.primaryPurple} | |||
| onClick={props.onClick} | |||
| > | |||
| {t("deleteOffer.delete")} | |||
| {props.pin ? t("admin.pin.confirm") : t("deleteOffer.delete")} | |||
| </SaveButtonContainer> | |||
| ); | |||
| }; | |||
| SaveButton.propTypes = { | |||
| onClick: PropTypes.func, | |||
| pin: PropTypes.bool, | |||
| }; | |||
| export default SaveButton; | |||
| @@ -47,6 +47,7 @@ import { formatDateLocale } from "../../../util/helpers/dateHelpers"; | |||
| const OfferCard = (props) => { | |||
| const [deleteOfferModal, setDeleteOfferModal] = useState(false); | |||
| const [editOfferModal, setEditOfferModal] = useState(false); | |||
| const [pinOfferModal, setPinOfferModal] = useState(false); | |||
| const history = useHistory(); | |||
| const userId = useSelector(selectUserId); | |||
| const { isMobile } = useIsMobile(); | |||
| @@ -54,6 +55,7 @@ const OfferCard = (props) => { | |||
| const pinOffer = (event) => { | |||
| event.stopPropagation(); | |||
| setPinOfferModal(true); | |||
| }; | |||
| const routeToItem = (itemId) => { | |||
| if (!props.disabledCheckButton) { | |||
| @@ -82,6 +84,9 @@ const OfferCard = (props) => { | |||
| const closeModalHandler = () => { | |||
| setDeleteOfferModal(false); | |||
| }; | |||
| const closePinOfferModal = () => { | |||
| setPinOfferModal(false); | |||
| }; | |||
| const closeCreateOfferModal = () => { | |||
| setEditOfferModal(false); | |||
| @@ -223,7 +228,11 @@ const OfferCard = (props) => { | |||
| </MessageIcon> | |||
| )} | |||
| {props.isAdmin && !props.pinned && ( | |||
| <PinIconContainer showMessageIcon onClick={pinOffer}> | |||
| <PinIconContainer | |||
| showMessageIcon | |||
| onClick={pinOffer} | |||
| vertical={props.vertical} | |||
| > | |||
| <PinOutlinedIcon /> | |||
| </PinIconContainer> | |||
| )} | |||
| @@ -236,6 +245,13 @@ const OfferCard = (props) => { | |||
| closeModalHandler={closeModalHandler} | |||
| /> | |||
| )} | |||
| {pinOfferModal && ( | |||
| <DeleteOffer | |||
| pin | |||
| offer={props.offer} | |||
| closeModalHandler={closePinOfferModal} | |||
| /> | |||
| )} | |||
| {editOfferModal && ( | |||
| <CreateOffer | |||
| editOffer | |||
| @@ -38,7 +38,7 @@ export const OfferCardContainer = styled(Container)` | |||
| ${(props) => | |||
| props.vertical && | |||
| ` | |||
| height: 373px; | |||
| height: 400px; | |||
| width: 180px; | |||
| margin: 0 18px; | |||
| `} | |||
| @@ -111,13 +111,14 @@ export const OfferTitle = styled(Typography)` | |||
| props.vertical && | |||
| ` | |||
| display: flex; | |||
| flex: none; | |||
| flex-basis: 44px; | |||
| height: 44px; | |||
| max-height: 44px; | |||
| position: relative; | |||
| line-height: 22px; | |||
| margin-top: 5px; | |||
| font-size: 18px; | |||
| margin-bottom: 0px; | |||
| margin-bottom: 0px !important; | |||
| `} | |||
| } | |||
| @@ -204,6 +205,13 @@ export const OfferDate = styled(Box)` | |||
| line-height: 16px; | |||
| font-size: 12px; | |||
| margin-top: 1px; | |||
| @media (max-width: 600px) { | |||
| ${(props) => | |||
| props.vertical && | |||
| ` | |||
| margin-top: -18px; | |||
| `} | |||
| } | |||
| `; | |||
| export const Line = styled(Box)` | |||
| @@ -314,9 +322,14 @@ export const RemoveIconContainer = styled(MessageIcon)` | |||
| @media screen and (max-width: 600px) { | |||
| display: block; | |||
| position: ${(props) => props.vertical && "absolute"}; | |||
| top: ${(props) => props.vertical && "325px"}; | |||
| left: ${(props) => props.vertical && "59px"}; | |||
| ${(props) => | |||
| props.vertical && | |||
| ` | |||
| position: absolute; | |||
| top: initial; | |||
| bottom: 18px; | |||
| left: 59px; | |||
| `} | |||
| } | |||
| `; | |||
| export const RemoveIcon = styled(Remove)``; | |||
| @@ -328,9 +341,13 @@ export const EditIconContainer = styled(MessageIcon)` | |||
| @media screen and (max-width: 600px) { | |||
| position: absolute; | |||
| display: block; | |||
| right: ${(props) => !props.vertical && "64px"}; | |||
| top: ${(props) => props.vertical && "325px"}; | |||
| left: ${(props) => props.vertical && "18px"}; | |||
| ${(props) => | |||
| props.vertical && | |||
| ` | |||
| top: initial; | |||
| bottom: 18px; | |||
| left: 18px; | |||
| `} | |||
| } | |||
| `; | |||
| export const EditIcon = styled(Edit)``; | |||
| @@ -349,6 +366,19 @@ export const LikeIconContainer = styled(MessageIcon)` | |||
| export const PinIconContainer = styled(MessageIcon)` | |||
| right: 134px; | |||
| top: 18px; | |||
| @media (max-width: 600px) { | |||
| ${props => props.vertical && ` | |||
| display: block; | |||
| top: initial; | |||
| right: initial; | |||
| bottom: 18px; | |||
| left: 100px; | |||
| & button svg { | |||
| width: 19px; | |||
| height: 19px; | |||
| } | |||
| `} | |||
| } | |||
| `; | |||
| export const LikeIcon = styled(Like)` | |||
| & path { | |||
| @@ -3,6 +3,8 @@ import PropTypes from "prop-types"; | |||
| import { | |||
| BlockIcon, | |||
| BlockIconContainer, | |||
| BlockLabelIcon, | |||
| ButtonsContainer, | |||
| CheckButton, | |||
| EditButton, | |||
| EditIcon, | |||
| @@ -17,28 +19,58 @@ import ProfileContact from "../ProfileContact/ProfileContact"; | |||
| import EditProfile from "../EditProfile/EditProfile"; | |||
| import selectedTheme from "../../../../themes"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import history from "../../../../store/utils/history"; | |||
| import { replaceInRoute } from "../../../../util/helpers/routeHelpers"; | |||
| import { ADMIN_SINGLE_USER_PAGE } from "../../../../constants/pages"; | |||
| import DeleteCategory from "../../../Modals/DeleteCategory/DeleteCategory"; | |||
| import UserLabeledCard from "../../LabeledCard/User/UserLabeledCard"; | |||
| const BigProfileCard = (props) => { | |||
| const { t } = useTranslation(); | |||
| const [editProfileModal, setEditProfileModal] = useState(false); | |||
| const [deleteOrEditModal, setDeleteOrEditModal] = useState({ | |||
| show: false, | |||
| type: "", | |||
| }); | |||
| const closeModalHandler = () => { | |||
| setEditProfileModal(false); | |||
| if (editProfileModal) setEditProfileModal(false); | |||
| else setDeleteOrEditModal({ show: false, type: "" }); | |||
| }; | |||
| const removeUser = () => { | |||
| setDeleteOrEditModal({ | |||
| show: true, | |||
| type: "deleteUser", | |||
| }); | |||
| }; | |||
| console.log(props.profile); | |||
| const blockUser = () => { | |||
| setDeleteOrEditModal({ | |||
| show: true, | |||
| type: "blockUser", | |||
| }); | |||
| }; | |||
| const goToUser = () => { | |||
| history.push( | |||
| replaceInRoute(ADMIN_SINGLE_USER_PAGE, { | |||
| idProfile: props.profile?._id, | |||
| }) | |||
| ); | |||
| }; | |||
| const removeUser = () => {}; | |||
| const blockUser = () => {}; | |||
| return ( | |||
| <> | |||
| <ProfileCardContainer halfwidth={props.halfwidth}> | |||
| <ProfileCardWrapper variant="outlined"> | |||
| <EditButton onClick={() => setEditProfileModal(true)}> | |||
| <EditIcon /> | |||
| </EditButton> | |||
| <RemoveIconContainer onClick={removeUser}> | |||
| <RemoveIcon /> | |||
| </RemoveIconContainer> | |||
| <BlockIconContainer onClick={blockUser}> | |||
| <BlockIcon /> | |||
| </BlockIconContainer> | |||
| <ButtonsContainer> | |||
| <EditButton onClick={() => setEditProfileModal(true)}> | |||
| <EditIcon /> | |||
| </EditButton> | |||
| <RemoveIconContainer onClick={removeUser}> | |||
| <RemoveIcon /> | |||
| </RemoveIconContainer> | |||
| <BlockIconContainer onClick={blockUser}> | |||
| <BlockIcon /> | |||
| </BlockIconContainer> | |||
| </ButtonsContainer> | |||
| <ProfileInfoContainer> | |||
| {/* Profile Main Info */} | |||
| <ProfileMainInfo profile={props.profile} isAdmin /> | |||
| @@ -51,6 +83,7 @@ const BigProfileCard = (props) => { | |||
| buttoncolor={selectedTheme.colors.primaryPurple} | |||
| textcolor={selectedTheme.colors.primaryPurple} | |||
| style={{ fontWeight: "600" }} | |||
| onClick={goToUser} | |||
| > | |||
| {t("admin.users.checkProfile")} | |||
| </CheckButton> | |||
| @@ -65,6 +98,17 @@ const BigProfileCard = (props) => { | |||
| userId={props.profile._id} | |||
| /> | |||
| )} | |||
| {deleteOrEditModal.show && ( | |||
| <DeleteCategory | |||
| setOpenedDeleteModal={closeModalHandler} | |||
| type={deleteOrEditModal.type} | |||
| customLabeledCard={<UserLabeledCard user={props.profile} />} | |||
| customLabeledCardHeight="90px" | |||
| customLabeledCardIcon={ | |||
| deleteOrEditModal.type === "blockUser" && <BlockLabelIcon /> | |||
| } | |||
| /> | |||
| )} | |||
| </> | |||
| ); | |||
| }; | |||
| @@ -14,12 +14,10 @@ import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton"; | |||
| export const ProfileCardContainer = styled(Box)` | |||
| width: ${(props) => (props.halfwidth ? `49%` : `100%`)}; | |||
| box-sizing: border-box; | |||
| max-height: 184px; | |||
| max-height: min-content; | |||
| margin-top: 34px; | |||
| overflow: hidden; | |||
| border: 1px solid ${selectedTheme.colors.borderNormal}; | |||
| border-radius: 0 0 4px 4px; | |||
| border-radius: 4px 4px; | |||
| &:nth-child(1) { | |||
| margin-top: 20px; | |||
| } | |||
| @@ -29,7 +27,32 @@ export const ProfileCardContainer = styled(Box)` | |||
| @media (max-width: 1200px) { | |||
| padding: 0; | |||
| } | |||
| @media (max-width: 600px) { | |||
| max-height: fit-content; | |||
| margin-top: 18px; | |||
| &:nth-child(1) { | |||
| margin-top: 0; | |||
| } | |||
| } | |||
| `; | |||
| export const ProfileCardWrapper = styled(Card)` | |||
| background: ${(props) => | |||
| props.isMyProfile ? selectedTheme.colors.primaryPurple : "white"}; | |||
| width: 100%; | |||
| min-width: fit-content; | |||
| padding: 1rem; | |||
| border-radius: 0 0 4px 4px; | |||
| position: relative; | |||
| `; | |||
| export const ProfileCardHeader = styled(Grid)` | |||
| display: flex; | |||
| justify-content: start; | |||
| align-items: center; | |||
| margin-bottom: 11px; | |||
| `; | |||
| export const EditIcon = styled(Edit)` | |||
| width: 18px; | |||
| height: 18px; | |||
| @@ -38,19 +61,25 @@ export const EditIcon = styled(Edit)` | |||
| } | |||
| `; | |||
| export const MessageButton = styled(IconButton)` | |||
| width: 40px; | |||
| height: 40px; | |||
| export const ButtonsContainer = styled(Box)` | |||
| position: absolute; | |||
| top: 18px; | |||
| right: 18px; | |||
| display: flex; | |||
| flex-direction: row; | |||
| gap: 12px; | |||
| `; | |||
| export const MessageButton = styled(IconButton)` | |||
| width: 40px; | |||
| height: 40px; | |||
| background-color: ${selectedTheme.colors.primaryIconBackgroundColor}; | |||
| border-radius: 100%; | |||
| padding-top: 2px; | |||
| text-align: center; | |||
| @media (max-width: 600px) { | |||
| width: 30px; | |||
| height: 30px; | |||
| width: 32px; | |||
| height: 32px; | |||
| top: 16px; | |||
| right: 16px; | |||
| padding: 0; | |||
| @@ -63,35 +92,31 @@ export const MessageButton = styled(IconButton)` | |||
| width: 16px; | |||
| height: 16px; | |||
| position: relative; | |||
| top: -3px; | |||
| left: -3.5px; | |||
| top: -2px; | |||
| left: -2px; | |||
| } | |||
| } | |||
| `; | |||
| export const EditButton = styled(MessageButton)` | |||
| right: 76px; | |||
| `; | |||
| export const ProfileCardWrapper = styled(Card)` | |||
| background: ${(props) => | |||
| props.isMyProfile ? selectedTheme.colors.primaryPurple : "white"}; | |||
| width: 100%; | |||
| min-width: fit-content; | |||
| padding: 1rem; | |||
| border-radius: 0 0 4px 4px; | |||
| position: relative; | |||
| `; | |||
| export const EditButton = styled(MessageButton)``; | |||
| export const RemoveIconContainer = styled(MessageButton)` | |||
| display: block; | |||
| top: 18px; | |||
| right: 18px; | |||
| `; | |||
| export const RemoveIcon = styled(Remove)``; | |||
| export const BlockIconContainer = styled(MessageButton)` | |||
| display: block; | |||
| top: 18px; | |||
| right: 134px; | |||
| `; | |||
| export const BlockIcon = styled(Block)``; | |||
| export const BlockLabelIcon = styled(Block)` | |||
| width: 18px; | |||
| height: 18px; | |||
| position: relative; | |||
| top: 10px; | |||
| left: 11px; | |||
| & path { | |||
| stroke: ${selectedTheme.colors.iconYellowColor}; | |||
| } | |||
| `; | |||
| export const CheckButton = styled(PrimaryButton)` | |||
| width: 180px; | |||
| height: 48px; | |||
| @@ -108,128 +133,6 @@ export const CheckButton = styled(PrimaryButton)` | |||
| } | |||
| `; | |||
| // export const ProfileName = styled(Typography)` | |||
| // color: ${(props) => | |||
| // props.isMyProfile | |||
| // ? selectedTheme.colors.primaryYellow | |||
| // : selectedTheme.colors.primaryPurple}; | |||
| // font-weight: 700; | |||
| // font-size: 24px; | |||
| // font-family: ${selectedTheme.fonts.textFont}; | |||
| // margin-bottom: 5px; | |||
| // @media (max-width: 600px) { | |||
| // font-size: 18px; | |||
| // } | |||
| // `; | |||
| // export const ProfilePIB = styled(Typography)` | |||
| // color: ${(props) => | |||
| // props.isMyProfile ? "white" : selectedTheme.colors.primaryDarkText}; | |||
| // margin-top: 0.18rem; | |||
| // font-family: ${selectedTheme.fonts.textFont}; | |||
| // font-size: 16px; | |||
| // padding-top: 1px; | |||
| // @media (max-width: 600px) { | |||
| // font-size: 14px; | |||
| // } | |||
| // `; | |||
| // export const ProfilePIBContainer = styled(Grid)` | |||
| // display: flex; | |||
| // justify-content: center; | |||
| // align-items: center; | |||
| // position: relative; | |||
| // left: 5px; | |||
| // `; | |||
| // export const ProfileMainInfo = styled(Grid)` | |||
| // display: flex; | |||
| // justify-content: start; | |||
| // align-items: start; | |||
| // `; | |||
| // export const AvatarImageContainer = styled(Grid)` | |||
| // display: flex; | |||
| // justify-content: start; | |||
| // align-items: center; | |||
| // `; | |||
| // export const ProfileMainInfoGrid = styled(Grid)` | |||
| // display: flex; | |||
| // flex-direction: column; | |||
| // align-items: start; | |||
| // margin-left: 16px; | |||
| // `; | |||
| // export const ProfileContact = styled(Grid)` | |||
| // padding-top: 2rem; | |||
| // padding-bottom: 2rem; | |||
| // @media (max-width: 600px) { | |||
| // padding-bottom: 1rem; | |||
| // } | |||
| // `; | |||
| // export const ContactItem = styled(Typography)` | |||
| // margin-right: 2rem; | |||
| // margin-left: 0.4rem; | |||
| // color: ${(props) => | |||
| // props.isMyProfile ? "white" : selectedTheme.colors.primaryDarkText}; | |||
| // display: unset; | |||
| // font-family: ${selectedTheme.fonts.textFont}; | |||
| // letter-spacing: 0.02em; | |||
| // font-size: 16px; | |||
| // position: relative; | |||
| // bottom: 1px; | |||
| // @media (max-width: 600px) { | |||
| // font-size: 14px; | |||
| // bottom: 4px; | |||
| // } | |||
| // `; | |||
| // export const StatsItem = styled(Typography)` | |||
| // margin-right: 2rem; | |||
| // display: unset; | |||
| // margin-left: 1rem; | |||
| // font-family: ${selectedTheme.fonts.textFont}; | |||
| // font-size: 16px; | |||
| // margin-bottom: 2px; | |||
| // @media (max-width: 600px) { | |||
| // font-size: 12px; | |||
| // } | |||
| // `; | |||
| // export const ProfileStats = styled(Grid)` | |||
| // display: flex; | |||
| // justify-content: start; | |||
| // align-items: center; | |||
| // background: ${selectedTheme.colors.primaryDarkTextSecond}; | |||
| // width: calc(100% + 2rem); | |||
| // padding-top: 1.3rem; | |||
| // padding-bottom: 1.3rem; | |||
| // margin-bottom: -1rem; | |||
| // margin-left: -1rem; | |||
| // border-radius: 0 0 4px 4px; | |||
| // `; | |||
| // export const AvatarImage = styled.img` | |||
| // min-height: 144px; | |||
| // min-width: 144px; | |||
| // width: 144px; | |||
| // height: 144px; | |||
| // border-radius: 100%; | |||
| // @media (max-width: 600px) { | |||
| // min-height: 90px; | |||
| // min-width: 90px; | |||
| // width: 90px; | |||
| // height: 90px; | |||
| // } | |||
| // `; | |||
| export const ProfileCardHeader = styled(Grid)` | |||
| display: flex; | |||
| justify-content: start; | |||
| align-items: center; | |||
| margin-bottom: 11px; | |||
| `; | |||
| export const HeaderTitle = styled(Typography)` | |||
| font-size: 16px; | |||
| font-family: ${selectedTheme.fonts.textFont}; | |||
| @@ -239,62 +142,6 @@ export const HeaderTitle = styled(Typography)` | |||
| font-size: 12px; | |||
| } | |||
| `; | |||
| // export const PocketIcon = styled(Pocket)` | |||
| // width: 22px; | |||
| // height: 22px; | |||
| // position: relative; | |||
| // left: -5px; | |||
| // top: 2px; | |||
| // & path { | |||
| // stroke: #b4b4b4; | |||
| // } | |||
| // @media (max-width: 600px) { | |||
| // width: 14px; | |||
| // height: 14px; | |||
| // } | |||
| // `; | |||
| // export const MailIcon = styled(Mail)` | |||
| // height: 24px; | |||
| // width: 24px; | |||
| // & path { | |||
| // stroke: ${(props) => | |||
| // props.isMyProfile | |||
| // ? selectedTheme.colors.iconMineProfileColor | |||
| // : selectedTheme.colors.iconProfileColor}; | |||
| // } | |||
| // @media (max-width: 600px) { | |||
| // width: 14px; | |||
| // height: 14px; | |||
| // } | |||
| // `; | |||
| // export const GlobeIcon = styled(Globe)` | |||
| // height: 22px; | |||
| // width: 22px; | |||
| // & path { | |||
| // stroke: ${(props) => | |||
| // props.isMyProfile | |||
| // ? selectedTheme.colors.iconMineProfileColor | |||
| // : selectedTheme.colors.iconProfileColor}; | |||
| // } | |||
| // @media (max-width: 600px) { | |||
| // width: 14px; | |||
| // height: 14px; | |||
| // } | |||
| // `; | |||
| // export const LocationIcon = styled(Location)` | |||
| // height: 22px; | |||
| // width: 22px; | |||
| // & path { | |||
| // stroke: ${(props) => | |||
| // props.isMyProfile | |||
| // ? selectedTheme.colors.iconMineProfileColor | |||
| // : selectedTheme.colors.iconProfileColor}; | |||
| // } | |||
| // @media (max-width: 600px) { | |||
| // width: 14px; | |||
| // height: 14px; | |||
| // } | |||
| // `; | |||
| export const MessageIcon = styled(Mail)` | |||
| width: 19.5px; | |||
| height: 19.5px; | |||
| @@ -317,4 +164,9 @@ export const ProfileInfoContainer = styled(Grid)` | |||
| flex-direction: column; | |||
| justify-content: center; | |||
| align-items: start; | |||
| @media (max-width: 600px) { | |||
| flex-direction: row; | |||
| gap: 18px; | |||
| justify-content: space-between; | |||
| } | |||
| `; | |||
| @@ -8,6 +8,15 @@ import { | |||
| HeaderTitle, | |||
| EditIcon, | |||
| ProfileInfoContainer, | |||
| RemoveButton, | |||
| RemoveIcon, | |||
| BlockButton, | |||
| BlockIcon, | |||
| ButtonsContainer, | |||
| BlockLabelIcon, | |||
| MessageButton, | |||
| MessageIcon, | |||
| ProfileInfoAndContactContainer, | |||
| } from "./ProfileCard.styled"; | |||
| import PersonOutlineIcon from "@mui/icons-material/PersonOutline"; | |||
| import { useRouteMatch } from "react-router-dom"; | |||
| @@ -28,10 +37,15 @@ import { PROFILE_SCOPE } from "../../../store/actions/profile/profileActionConst | |||
| import SkeletonProfileCard from "./SkeletonProfileCard/SkeletonProfileCard"; | |||
| import { useMemo } from "react"; | |||
| import companyData from "../../../notFoundData/companyData"; | |||
| import DeleteCategory from "../../Modals/DeleteCategory/DeleteCategory"; | |||
| import UserLabeledCard from "../LabeledCard/User/UserLabeledCard"; | |||
| const ProfileCard = () => { | |||
| const [isMyProfile, setIsMyProfile] = useState(false); | |||
| const ProfileCard = (props) => { | |||
| const [editProfileModal, setEditProfileModal] = useState(false); | |||
| const [deleteOrEditModal, setDeleteOrEditModal] = useState({ | |||
| show: false, | |||
| type: "", | |||
| }); | |||
| const isLoading = useSelector(selectIsLoadingByActionType(PROFILE_SCOPE)); | |||
| const routeMatch = useRouteMatch(); | |||
| const dispatch = useDispatch(); | |||
| @@ -51,16 +65,17 @@ const ProfileCard = () => { | |||
| return companyData; | |||
| }, [profileFromRedux]); | |||
| const isMyProfile = useMemo( | |||
| () => userId === idProfile && !props.isAdmin, | |||
| [userId, idProfile] | |||
| ); | |||
| useEffect(() => { | |||
| if (idProfile?.length > 0) { | |||
| reFetchProfile(); | |||
| } | |||
| }, [idProfile]); | |||
| useEffect(() => { | |||
| setIsMyProfile(userId === idProfile); | |||
| }, [userId, idProfile]); | |||
| const reFetchProfile = () => { | |||
| dispatch(fetchProfile(idProfile)); | |||
| dispatch(fetchProfileOffers(idProfile)); | |||
| @@ -78,7 +93,20 @@ const ProfileCard = () => { | |||
| } | |||
| const closeModalHandler = () => { | |||
| setEditProfileModal(false); | |||
| if (editProfileModal) setEditProfileModal(false); | |||
| else setDeleteOrEditModal({ show: false, type: "" }); | |||
| }; | |||
| const removeUser = () => { | |||
| setDeleteOrEditModal({ | |||
| show: true, | |||
| type: "deleteUser", | |||
| }); | |||
| }; | |||
| const blockUser = () => { | |||
| setDeleteOrEditModal({ | |||
| show: true, | |||
| type: "blockUser", | |||
| }); | |||
| }; | |||
| if (editProfileModal) { | |||
| @@ -96,19 +124,47 @@ const ProfileCard = () => { | |||
| <ProfileCardContainer> | |||
| <ProfileCardHeader> | |||
| <PersonOutlineIcon color="action" sx={{ mr: 0.9 }} /> | |||
| <HeaderTitle>{t("profile.myProfile")}</HeaderTitle> | |||
| <HeaderTitle> | |||
| {isMyProfile | |||
| ? t("profile.myProfile") | |||
| : t("profile.companyProfile")} | |||
| </HeaderTitle> | |||
| </ProfileCardHeader> | |||
| <ProfileCardWrapper variant="outlined" isMyProfile={isMyProfile}> | |||
| {isMyProfile && ( | |||
| <EditButton onClick={() => setEditProfileModal(true)}> | |||
| <EditIcon /> | |||
| </EditButton> | |||
| )} | |||
| <ButtonsContainer> | |||
| {props.isAdmin && ( | |||
| <> | |||
| <BlockButton onClick={blockUser}> | |||
| <BlockIcon /> | |||
| </BlockButton> | |||
| <RemoveButton onClick={removeUser}> | |||
| <RemoveIcon /> | |||
| </RemoveButton> | |||
| </> | |||
| )} | |||
| {isMyProfile || props.isAdmin ? ( | |||
| <EditButton | |||
| onClick={() => setEditProfileModal(true)} | |||
| isAdmin={props.isAdmin} | |||
| > | |||
| <EditIcon /> | |||
| </EditButton> | |||
| ) : ( | |||
| <MessageButton> | |||
| <MessageIcon /> | |||
| </MessageButton> | |||
| )} | |||
| </ButtonsContainer> | |||
| <ProfileInfoContainer> | |||
| {/* Profile Main Info */} | |||
| <ProfileMainInfo profile={profile} isMyProfile={isMyProfile} /> | |||
| {/* Profile Contact */} | |||
| <ProfileContact profile={profile} isMyProfile={isMyProfile} /> | |||
| <ProfileInfoAndContactContainer> | |||
| {/* Profile Main Info */} | |||
| <ProfileMainInfo | |||
| profile={profile} | |||
| isMyProfile={isMyProfile} | |||
| /> | |||
| {/* Profile Contact */} | |||
| <ProfileContact profile={profile} isMyProfile={isMyProfile} /> | |||
| </ProfileInfoAndContactContainer> | |||
| {/* Profile Stats */} | |||
| <ProfileStats | |||
| profile={profile} | |||
| @@ -126,12 +182,24 @@ const ProfileCard = () => { | |||
| reFetchProfile={reFetchProfile} | |||
| /> | |||
| )} | |||
| {deleteOrEditModal.show && ( | |||
| <DeleteCategory | |||
| setOpenedDeleteModal={closeModalHandler} | |||
| type={deleteOrEditModal.type} | |||
| customLabeledCard={<UserLabeledCard user={profile} />} | |||
| customLabeledCardHeight="90px" | |||
| customLabeledCardIcon={ | |||
| deleteOrEditModal.type === "blockUser" && <BlockLabelIcon /> | |||
| } | |||
| /> | |||
| )} | |||
| </> | |||
| ); | |||
| }; | |||
| ProfileCard.propTypes = { | |||
| children: PropTypes.node, | |||
| isAdmin: PropTypes.bool, | |||
| }; | |||
| export default ProfileCard; | |||
| @@ -2,6 +2,8 @@ import styled from "styled-components"; | |||
| import { Card, Typography, Grid, Box } from "@mui/material"; | |||
| import selectedTheme from "../../../themes"; | |||
| import { ReactComponent as Edit } from "../../../assets/images/svg/edit.svg"; | |||
| import { ReactComponent as Block } from "../../../assets/images/svg/block.svg"; | |||
| import { ReactComponent as Remove } from "../../../assets/images/svg/trash.svg"; | |||
| // import { ReactComponent as Pocket } from "../../assets/images/svg/pocket.svg"; | |||
| // import { ReactComponent as Globe } from "../../assets/images/svg/globe.svg"; | |||
| import { ReactComponent as Mail } from "../../../assets/images/svg/mail.svg"; | |||
| @@ -19,26 +21,99 @@ export const ProfileCardContainer = styled(Box)` | |||
| padding: 0 36px 0 0; | |||
| } | |||
| @media (max-width: 600px) { | |||
| padding: 0; | |||
| padding: 0 18px; | |||
| } | |||
| `; | |||
| export const EditIcon = styled(Edit)` | |||
| position: relative; | |||
| top: 3px; | |||
| left: 2px; | |||
| width: 18px; | |||
| height: 18px; | |||
| @media (max-width: 600px) { | |||
| top: 0; | |||
| left: -2px; | |||
| } | |||
| & path { | |||
| stroke: ${selectedTheme.colors.primaryPurple}; | |||
| } | |||
| `; | |||
| export const EditButton = styled(Box)` | |||
| position: absolute; | |||
| right: 1rem; | |||
| top: 1rem; | |||
| color: ${selectedTheme.colors.primaryPurple}; | |||
| width: 40px; | |||
| height: 40px; | |||
| font-weight: 900; | |||
| background: ${selectedTheme.colors.primaryIconBackgroundColor}; | |||
| border-radius: 360px; | |||
| padding: 0.45rem 0.45rem 0.27rem 0.57rem; | |||
| cursor: pointer; | |||
| @media (max-width: 600px) { | |||
| width: 32px; | |||
| height: 32px; | |||
| } | |||
| `; | |||
| export const RemoveIcon = styled(Remove)` | |||
| position: relative; | |||
| top: 3px; | |||
| left: 2px; | |||
| width: 18px; | |||
| height: 18px; | |||
| @media (max-width: 600px) { | |||
| top: 0; | |||
| left: -2px; | |||
| } | |||
| & path { | |||
| stroke: ${selectedTheme.colors.primaryPurple}; | |||
| } | |||
| `; | |||
| export const RemoveButton = styled(Box)` | |||
| width: 40px; | |||
| height: 40px; | |||
| font-weight: 900; | |||
| background: ${selectedTheme.colors.primaryIconBackgroundColor}; | |||
| border-radius: 360px; | |||
| padding: 0.45rem 0.45rem 0.27rem 0.57rem; | |||
| cursor: pointer; | |||
| @media (max-width: 600px) { | |||
| width: 32px; | |||
| height: 32px; | |||
| } | |||
| `; | |||
| export const BlockIcon = styled(Block)` | |||
| position: relative; | |||
| top: 3px; | |||
| left: 2px; | |||
| width: 18px; | |||
| height: 18px; | |||
| @media (max-width: 600px) { | |||
| top: 0; | |||
| left: -2px; | |||
| } | |||
| & path { | |||
| stroke: ${selectedTheme.colors.primaryPurple}; | |||
| } | |||
| `; | |||
| export const BlockLabelIcon = styled(Block)` | |||
| width: 18px; | |||
| height: 18px; | |||
| position: relative; | |||
| top: 10px; | |||
| left: 11px; | |||
| & path { | |||
| stroke: ${selectedTheme.colors.iconYellowColor}; | |||
| } | |||
| `; | |||
| export const BlockButton = styled(Box)` | |||
| width: 40px; | |||
| height: 40px; | |||
| font-weight: 900; | |||
| background: #f4f4f4; | |||
| background: ${selectedTheme.colors.primaryIconBackgroundColor}; | |||
| border-radius: 360px; | |||
| padding: 0.45rem 0.45rem 0.27rem 0.57rem; | |||
| cursor: pointer; | |||
| @media (max-width: 600px) { | |||
| width: 32px; | |||
| height: 32px; | |||
| } | |||
| `; | |||
| export const MessageButton = styled(EditButton)` | |||
| @@ -50,6 +125,18 @@ export const MessageButton = styled(EditButton)` | |||
| height: 32px; | |||
| } | |||
| `; | |||
| export const ButtonsContainer = styled(Box)` | |||
| position: absolute; | |||
| top: 18px; | |||
| right: 18px; | |||
| gap: 16px; | |||
| display: flex; | |||
| justify-content: flex-end; | |||
| flex-direction: row; | |||
| @media (max-width: 600px) { | |||
| gap: 12px; | |||
| } | |||
| `; | |||
| export const ProfileCardWrapper = styled(Card)` | |||
| border: 1px solid ${selectedTheme.colors.borderNormal}; | |||
| @@ -263,7 +350,7 @@ export const MessageIcon = styled(Mail)` | |||
| height: 16px; | |||
| left: -1px; | |||
| top: 1px; | |||
| } | |||
| } | |||
| `; | |||
| export const ProfileInfoContainer = styled(Grid)` | |||
| @@ -271,6 +358,16 @@ export const ProfileInfoContainer = styled(Grid)` | |||
| flex-direction: column; | |||
| justify-content: center; | |||
| align-items: start; | |||
| @media (max-width: 600px) { | |||
| } | |||
| `; | |||
| export const ProfileInfoAndContactContainer = styled(Box)` | |||
| display: flex; | |||
| flex-direction: column; | |||
| @media (max-width: 600px) { | |||
| padding-bottom: 18px; | |||
| flex-direction: row; | |||
| } | |||
| `; | |||
| // export const ProfileStatsGrid = styled(Grid)` | |||
| @@ -10,6 +10,9 @@ export const ProfileContactContainer = styled(Grid)` | |||
| padding-bottom: 2rem; | |||
| @media (max-width: 600px) { | |||
| padding-bottom: 1rem; | |||
| padding-top: 88px; | |||
| gap: 5px; | |||
| width: calc(100vw - 216px); | |||
| } | |||
| `; | |||
| export const LocationIcon = styled(Location)` | |||
| @@ -40,6 +43,7 @@ export const ContactItem = styled(Typography)` | |||
| @media (max-width: 600px) { | |||
| font-size: 14px; | |||
| bottom: 4px; | |||
| margin-right: 0; | |||
| } | |||
| `; | |||
| export const MailIcon = styled(Mail)` | |||
| @@ -13,17 +13,28 @@ import { | |||
| import { useTranslation } from "react-i18next"; | |||
| import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter"; | |||
| import useIsMobile from "../../../../hooks/useIsMobile"; | |||
| import history from "../../../../store/utils/history"; | |||
| import { | |||
| isAdminRoute, | |||
| replaceInRoute, | |||
| } from "../../../../util/helpers/routeHelpers"; | |||
| import { ADMIN_SINGLE_USER_PAGE } from "../../../../constants/pages"; | |||
| const ProfileMainInfo = (props) => { | |||
| const { t } = useTranslation(); | |||
| const { isMobile } = useIsMobile(); | |||
| const goToUser = () => { | |||
| if (isAdminRoute()) { | |||
| history.push( | |||
| replaceInRoute(ADMIN_SINGLE_USER_PAGE, { | |||
| idProfile: props.profile?._id, | |||
| }) | |||
| ); | |||
| } | |||
| }; | |||
| return ( | |||
| <ProfileMainInfoContainer> | |||
| <AvatarImageContainer> | |||
| {/* <AvatarImage | |||
| alt={props.profile?.company?.name} | |||
| src={props.profile?.image} | |||
| /> */} | |||
| <AvatarImage | |||
| isAdmin={props.isAdmin} | |||
| src={getImageUrl( | |||
| @@ -38,6 +49,7 @@ const ProfileMainInfo = (props) => { | |||
| isAdmin={props.isAdmin} | |||
| isMyProfile={props.isMyProfile} | |||
| variant="h5" | |||
| onClick={goToUser} | |||
| > | |||
| {props.profile?.company?.name} | |||
| </ProfileName> | |||
| @@ -7,6 +7,12 @@ export const ProfileMainInfoContainer = styled(Grid)` | |||
| display: flex; | |||
| justify-content: start; | |||
| align-items: start; | |||
| flex-direction: row; | |||
| @media (max-width: 600px) { | |||
| flex-direction: column-reverse; | |||
| gap: 18px; | |||
| max-width: 108px; | |||
| } | |||
| `; | |||
| export const AvatarImageContainer = styled(Grid)` | |||
| display: flex; | |||
| @@ -20,10 +26,10 @@ export const AvatarImage = styled.img` | |||
| height: ${(props) => (props.isAdmin ? `108px` : `144px`)}; | |||
| border-radius: 100%; | |||
| @media (max-width: 600px) { | |||
| min-height: 90px; | |||
| min-width: 90px; | |||
| width: 90px; | |||
| height: 90px; | |||
| min-height: ${(props) => (props.isAdmin ? "108px" : "90px")}; | |||
| min-width: ${(props) => (props.isAdmin ? "108px" : "90px")}; | |||
| width: ${(props) => (props.isAdmin ? "108px" : "90px")}; | |||
| height: ${(props) => (props.isAdmin ? "108px" : "90px")}; | |||
| } | |||
| `; | |||
| export const ProfileMainInfoGrid = styled(Grid)` | |||
| @@ -31,6 +37,9 @@ export const ProfileMainInfoGrid = styled(Grid)` | |||
| flex-direction: column; | |||
| align-items: start; | |||
| margin-left: 16px; | |||
| @media (max-width: 600px) { | |||
| margin-left: 0; | |||
| } | |||
| `; | |||
| export const ProfileName = styled(Typography)` | |||
| color: ${(props) => | |||
| @@ -39,11 +48,13 @@ export const ProfileName = styled(Typography)` | |||
| : selectedTheme.colors.primaryPurple}; | |||
| font-weight: 700; | |||
| font-size: 24px; | |||
| min-width: 200px; | |||
| font-family: ${selectedTheme.fonts.textFont}; | |||
| margin-bottom: 5px; | |||
| cursor: ${(props) => props.isAdmin && `pointer`}; | |||
| @media (max-width: 600px) { | |||
| font-size: 18px; | |||
| margin-bottom: 0; | |||
| } | |||
| `; | |||
| export const ProfilePIBContainer = styled(Grid)` | |||
| @@ -74,6 +85,7 @@ export const ProfilePIB = styled(Typography)` | |||
| font-family: ${selectedTheme.fonts.textFont}; | |||
| font-size: 16px; | |||
| padding-top: 1px; | |||
| white-space: nowrap; | |||
| @media (max-width: 600px) { | |||
| font-size: 14px; | |||
| } | |||
| @@ -21,8 +21,8 @@ const ProfileStats = (props) => { | |||
| <b>{props.percentOfSucceededExchanges}%</b> | |||
| {t("profile.successExchange")} | |||
| </StatsItem> | |||
| </ProfileStatsGrid> | |||
| <ProfileStatsGrid> | |||
| {/* </ProfileStatsGrid> | |||
| <ProfileStatsGrid> */} | |||
| <StatsItem variant="subtitle2"> | |||
| <b>{props.profile?.statistics?.views?.count}</b> | |||
| {t("profile.numberOfViews")} | |||
| @@ -7,11 +7,11 @@ export const ProfileStatsContainer = styled(Grid)` | |||
| justify-content: start; | |||
| align-items: center; | |||
| background: ${selectedTheme.colors.primaryDarkTextSecond}; | |||
| width: calc(100% + 2rem); | |||
| padding-top: 1.3rem; | |||
| padding-bottom: 1.3rem; | |||
| width: calc(100% + 36px); | |||
| padding-top: 18px; | |||
| padding-bottom: 18px; | |||
| margin-bottom: -1rem; | |||
| margin-left: -1rem; | |||
| margin-left: -18px; | |||
| /* border-radius: 0 0 4px 4px; */ | |||
| `; | |||
| export const ProfileStatsGrid = styled(Grid)` | |||
| @@ -19,6 +19,7 @@ export const ProfileStatsGrid = styled(Grid)` | |||
| flex-direction: column; | |||
| justify-content: center; | |||
| align-items: start; | |||
| gap: 3px; | |||
| `; | |||
| export const StatsItem = styled(Typography)` | |||
| margin-right: 2rem; | |||
| @@ -1,13 +1,14 @@ | |||
| import React, { useMemo } from "react"; | |||
| import React, { useMemo, useState } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { ReviewContainer } from "./UserReviewsCard.styled"; | |||
| import ReviewOffer from "./ReviewOffer/ReviewOffer"; | |||
| import { reviewEnum } from "../../../enums/reviewEnum"; | |||
| import ReviewerProfile from "./ReviewerProfile/ReviewerProfile"; | |||
| import ReviewQuote from "./ReviewQuote/ReviewQuote"; | |||
| import ReviewDetails from "./ReviewDetails/ReviewDetails"; | |||
| import UserReviewsSingleCard from "./UserReviewsSingleCard/UserReviewsSingleCard"; | |||
| import DeleteReview from "../../Modals/DeleteReview/DeleteReview"; | |||
| const UserReviewsCard = (props) => { | |||
| const [removeModalOpened, setRemoveModalOpened] = useState(); | |||
| const handleRemove = () => { | |||
| setRemoveModalOpened(true); | |||
| }; | |||
| const review = useMemo(() => { | |||
| if (props.givingReview) { | |||
| return { | |||
| @@ -42,24 +43,18 @@ const UserReviewsCard = (props) => { | |||
| offerImage: props.review.offer.image, | |||
| }; | |||
| }, [props.review]); | |||
| console.log(review); | |||
| return ( | |||
| <ReviewContainer key={review?.image}> | |||
| <ReviewerProfile | |||
| profileName={review.name} | |||
| profileImage={review.image} | |||
| userId={review.userId} | |||
| /> | |||
| <ReviewQuote | |||
| isSuccessfulSwap={review?.isSuccessfulSwap} | |||
| quote={review?.quote} | |||
| /> | |||
| <ReviewDetails | |||
| isSuccessfulSwap={review?.isSuccessfulSwap} | |||
| isGoodCommunication={review?.isGoodCommunication} | |||
| /> | |||
| <ReviewOffer name={review.offerName} image={review.offerImage} /> | |||
| </ReviewContainer> | |||
| <> | |||
| <UserReviewsSingleCard review={review} handleRemove={handleRemove} /> | |||
| {removeModalOpened && ( | |||
| <DeleteReview | |||
| review={review} | |||
| setOpenedDeleteModal={setRemoveModalOpened} | |||
| /> | |||
| )} | |||
| </> | |||
| ); | |||
| }; | |||
| @@ -73,17 +73,3 @@ export const NoReviewsAltText = styled(Typography)` | |||
| width: 100%; | |||
| margin-bottom: 36px; | |||
| `; | |||
| export const ReviewContainer = styled(Box)` | |||
| padding-top: 18px; | |||
| &::after { | |||
| content: ""; | |||
| display: block; | |||
| border-bottom: 1px solid ${selectedTheme.colors.primaryIconBackgroundColor}; | |||
| width: calc(100% + 24.4px); | |||
| height: 1px; | |||
| position: relative; | |||
| left: -18px; | |||
| margin-top: 18px; | |||
| } | |||
| `; | |||
| @@ -0,0 +1,18 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { RemoveButtonContainer, RemoveIcon } from "./RemoveButton.styled"; | |||
| const RemoveButton = (props) => { | |||
| return ( | |||
| <RemoveButtonContainer onClick={props.onClick}> | |||
| <RemoveIcon /> | |||
| </RemoveButtonContainer> | |||
| ); | |||
| }; | |||
| RemoveButton.propTypes = { | |||
| children: PropTypes.node, | |||
| onClick: PropTypes.func, | |||
| }; | |||
| export default RemoveButton; | |||
| @@ -0,0 +1,21 @@ | |||
| // import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import { ReactComponent as Remove } from "../../../../../assets/images/svg/trash.svg"; | |||
| import selectedTheme from "../../../../../themes"; | |||
| import { IconButton } from "../../../../Buttons/IconButton/IconButton"; | |||
| export const RemoveButtonContainer = styled(IconButton)` | |||
| position: absolute; | |||
| top: 16px; | |||
| right: 16px; | |||
| background-color: ${selectedTheme.colors.primaryIconBackgroundColor}; | |||
| border-radius: 100%; | |||
| width: 32px; | |||
| height: 32px; | |||
| & button { | |||
| width: 32px; | |||
| height: 32px; | |||
| } | |||
| `; | |||
| export const RemoveIcon = styled(Remove)` | |||
| `; | |||
| @@ -1,6 +1,6 @@ | |||
| import { Grid, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../../themes"; | |||
| import selectedTheme from "../../../../../themes"; | |||
| export const ReviewDetailsContainer = styled(Grid)` | |||
| padding-bottom: 1rem; | |||
| @@ -7,7 +7,7 @@ import { | |||
| ReviewOfferImage, | |||
| ReviewOfferTitle, | |||
| } from "./ReviewOffer.styled"; | |||
| import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter"; | |||
| import { getImageUrl, variants } from "../../../../../util/helpers/imageUrlGetter"; | |||
| const ReviewOffer = (props) => { | |||
| return ( | |||
| @@ -1,6 +1,6 @@ | |||
| import { Box, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../../themes"; | |||
| import selectedTheme from "../../../../../themes"; | |||
| export const ReviewOfferContainer = styled(Box)` | |||
| display: flex; | |||
| @@ -8,13 +8,13 @@ import { | |||
| ThumbDown, | |||
| ThumbUp, | |||
| } from "./ReviewQuote.styled"; | |||
| import { reviewEnum } from "../../../../enums/reviewEnum"; | |||
| import { reviewEnum } from "../../../../../enums/reviewEnum"; | |||
| const ReviewQuote = (props) => { | |||
| return ( | |||
| <ReviewQuoteContainer> | |||
| <ThumbContainer item> | |||
| {props.isSuccessfulSwap.toLowerCase() === | |||
| {props.isSuccessfulSwap?.toLowerCase() === | |||
| reviewEnum.YES.mainText.toLowerCase() ? ( | |||
| <ThumbUp color="success" /> | |||
| ) : ( | |||
| @@ -1,8 +1,8 @@ | |||
| import { Box, Grid, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../../themes"; | |||
| import selectedTheme from "../../../../../themes"; | |||
| import ThumbUpIcon from "@mui/icons-material/ThumbUp"; | |||
| import ThumbDownIcon from "@mui/icons-material/ThumbDown"; | |||
| import ThumbDownIcon from "@mui/icons-material/ThumbDown"; | |||
| export const ReviewQuoteContainer = styled(Box)` | |||
| position: relative; | |||
| @@ -26,11 +26,24 @@ export const ReviewQuoteText = styled(Typography)` | |||
| color: ${selectedTheme.colors.primaryDarkText}; | |||
| position: relative; | |||
| left: 10px; | |||
| @media (max-width: 600px) { | |||
| font-size: 12px; | |||
| } | |||
| `; | |||
| export const ThumbUp = styled(ThumbUpIcon)` | |||
| position: relative; | |||
| @media (max-width: 600px) { | |||
| width: 18px; | |||
| height: 18px; | |||
| top: 3px; | |||
| } | |||
| `; | |||
| export const ThumbDown = styled(ThumbDownIcon)` | |||
| position: relative; | |||
| top: 3px; | |||
| position: relative; | |||
| @media (max-width: 600px) { | |||
| width: 18px; | |||
| height: 18px; | |||
| top: 3px; | |||
| } | |||
| `; | |||
| @@ -1,16 +1,16 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import useIsMobile from "../../../../hooks/useIsMobile"; | |||
| import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter"; | |||
| import useIsMobile from "../../../../../hooks/useIsMobile"; | |||
| import { getImageUrl, variants } from "../../../../../util/helpers/imageUrlGetter"; | |||
| import { | |||
| ProfileContainer, | |||
| ProfileImage, | |||
| ProfileImageContainer, | |||
| ProfileName, | |||
| } from "./ReviewerProfile.styled"; | |||
| import history from "../../../../store/utils/history"; | |||
| import { replaceInRoute } from "../../../../util/helpers/routeHelpers"; | |||
| import { PROFILE_PAGE } from "../../../../constants/pages"; | |||
| import history from "../../../../../store/utils/history"; | |||
| import { replaceInRoute } from "../../../../../util/helpers/routeHelpers"; | |||
| import { PROFILE_PAGE } from "../../../../../constants/pages"; | |||
| const ReviewerProfile = (props) => { | |||
| const { isMobile } = useIsMobile(); | |||
| @@ -1,6 +1,6 @@ | |||
| import { Box, ListItem, Typography } from "@mui/material" | |||
| import styled from "styled-components" | |||
| import selectedTheme from "../../../../themes" | |||
| import selectedTheme from "../../../../../themes" | |||
| export const ProfileImage = styled.img` | |||
| width: 54px; | |||
| @@ -0,0 +1,44 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { ReviewContainer } from "./UserReviewsSingleCard.styled"; | |||
| import ReviewerProfile from "./ReviewerProfile/ReviewerProfile"; | |||
| import ReviewQuote from "./ReviewQuote/ReviewQuote"; | |||
| import ReviewDetails from "./ReviewDetails/ReviewDetails"; | |||
| import RemoveButton from "./RemoveButton/RemoveButton"; | |||
| import ReviewOffer from "./ReviewOffer/ReviewOffer"; | |||
| const UserReviewsSingleCard = (props) => { | |||
| const handleRemove = () => { | |||
| props.handleRemove(); | |||
| }; | |||
| return ( | |||
| <ReviewContainer> | |||
| <ReviewerProfile | |||
| profileName={props.review?.name} | |||
| profileImage={props.review?.image} | |||
| userId={props.review?.userId} | |||
| /> | |||
| <ReviewQuote | |||
| isSuccessfulSwap={props.review?.isSuccessfulSwap} | |||
| quote={props.review?.quote} | |||
| /> | |||
| <ReviewDetails | |||
| isSuccessfulSwap={props.review?.isSuccessfulSwap} | |||
| isGoodCommunication={props.review?.isGoodCommunication} | |||
| /> | |||
| {!props.showRemoveIcon && <RemoveButton review={props.review} onClick={handleRemove} />} | |||
| <ReviewOffer | |||
| name={props.review?.offerName} | |||
| image={props.review?.offerImage} | |||
| /> | |||
| </ReviewContainer> | |||
| ); | |||
| }; | |||
| UserReviewsSingleCard.propTypes = { | |||
| review: PropTypes.any, | |||
| handleRemove: PropTypes.func, | |||
| showRemoveIcon: PropTypes.bool, | |||
| }; | |||
| export default UserReviewsSingleCard; | |||
| @@ -0,0 +1,21 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../../themes"; | |||
| export const ReviewContainer = styled(Box)` | |||
| padding-top: 18px; | |||
| position: relative; | |||
| @media (max-width: 600px) { | |||
| height: 258px; | |||
| } | |||
| &::after { | |||
| content: ""; | |||
| display: block; | |||
| border-bottom: 1px solid ${selectedTheme.colors.primaryIconBackgroundColor}; | |||
| width: calc(100% + 24.4px); | |||
| height: 1px; | |||
| position: relative; | |||
| left: -18px; | |||
| margin-top: 18px; | |||
| } | |||
| `; | |||
| @@ -14,13 +14,16 @@ const NextButton = (props) => { | |||
| height="48px" | |||
| onClick={props.onClick} | |||
| > | |||
| {t("reviews.leaveComment")} | |||
| {props.removingReview | |||
| ? t("admin.reviews.confirm") | |||
| : t("reviews.leaveComment")} | |||
| </NextButtonContainer> | |||
| ); | |||
| }; | |||
| NextButton.propTypes = { | |||
| onClick: PropTypes.func, | |||
| removingReview: PropTypes.bool, | |||
| }; | |||
| export default NextButton; | |||
| @@ -15,12 +15,17 @@ const SecondStepCreateReview = (props) => { | |||
| const mineProfile = useSelector(selectMineProfile); | |||
| const goToNextStep = () => { | |||
| props.goToNextStep(); | |||
| if (props.removingReview) props.closeModal(); | |||
| else props.goToNextStep(); | |||
| }; | |||
| return ( | |||
| <SecondStepCreateReviewContainer> | |||
| <CreateReviewTitle>{t("reviews.modalTitle")}</CreateReviewTitle> | |||
| <CreateReviewTitle> | |||
| {props.removingReview | |||
| ? t("admin.reviews.title") | |||
| : t("reviews.modalTitle")} | |||
| </CreateReviewTitle> | |||
| <ReviewCard | |||
| givingReview | |||
| profileReviews={[ | |||
| @@ -35,7 +40,7 @@ const SecondStepCreateReview = (props) => { | |||
| }, | |||
| ]} | |||
| /> | |||
| <NextButton onClick={goToNextStep} /> | |||
| <NextButton removingReview={props.removingReview} onClick={goToNextStep} /> | |||
| </SecondStepCreateReviewContainer> | |||
| ); | |||
| }; | |||
| @@ -46,6 +51,8 @@ SecondStepCreateReview.propTypes = { | |||
| offer: PropTypes.any, | |||
| interlocutor: PropTypes.any, | |||
| goToNextStep: PropTypes.func, | |||
| removingReview: PropTypes.bool, | |||
| closeModal: PropTypes.func, | |||
| }; | |||
| export default SecondStepCreateReview; | |||
| @@ -4,19 +4,21 @@ import selectedTheme from "../../../themes"; | |||
| import UserReviews from "../../UserReviews/UserReviews"; | |||
| export const SecondStepCreateReviewContainer = styled(Box)` | |||
| padding: 36px; | |||
| @media (max-width: 600px) { | |||
| padding: 18px; | |||
| } | |||
| ` | |||
| padding: 36px; | |||
| @media (max-width: 600px) { | |||
| padding: 18px; | |||
| } | |||
| `; | |||
| export const ReviewCard = styled(UserReviews)` | |||
| & > div { | |||
| margin-bottom: 36px; | |||
| margin-top: 18px; | |||
| & ul { | |||
| background-color: ${selectedTheme.colors.chatHeaderColor}; | |||
| padding: 0 14px; | |||
| background-color: ${selectedTheme.colors.chatHeaderColor}; | |||
| padding: 0 14px; | |||
| } | |||
| & ul li { | |||
| margin: 0; | |||
| margin: 0; | |||
| } | |||
| ` | |||
| } | |||
| `; | |||
| @@ -0,0 +1,20 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { AdminInfoContainer, AdminName, AdminText } from "./AdminInfo.styled"; | |||
| import { useTranslation } from "react-i18next"; | |||
| const AdminInfo = (props) => { | |||
| const { t } = useTranslation(); | |||
| return ( | |||
| <AdminInfoContainer> | |||
| <AdminName>{props.name}</AdminName> | |||
| <AdminText>{t("admin.navigation.role")}</AdminText> | |||
| </AdminInfoContainer> | |||
| ); | |||
| }; | |||
| AdminInfo.propTypes = { | |||
| name: PropTypes.string, | |||
| }; | |||
| export default AdminInfo; | |||
| @@ -0,0 +1,24 @@ | |||
| import { Box, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../../themes"; | |||
| export const AdminInfoContainer = styled(Box)` | |||
| display: flex; | |||
| flex-direction: column; | |||
| gap: 4px; | |||
| `; | |||
| export const AdminName = styled(Typography)` | |||
| font-family: ${selectedTheme.fonts.textFont}; | |||
| font-weight: 700; | |||
| font-size: 18px; | |||
| line-height: 25px; | |||
| color: ${selectedTheme.colors.primaryPurple}; | |||
| `; | |||
| export const AdminText = styled(Typography)` | |||
| font-family: ${selectedTheme.fonts.textFont}; | |||
| font-weight: 400; | |||
| font-size: 12px; | |||
| line-height: 16px; | |||
| letter-spacing: 0.01em; | |||
| color: ${selectedTheme.colors.primaryPurple}; | |||
| `; | |||
| @@ -0,0 +1,47 @@ | |||
| import React, { useMemo } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { routeMatches } from "../../../../../../util/helpers/routeHelpers"; | |||
| import { useLocation } from "react-router-dom"; | |||
| import { | |||
| AdminButtonContainer, | |||
| AdminButtonIcon, | |||
| AdminButtonText, | |||
| } from "./AdminButton.styled"; | |||
| import { | |||
| ADMIN_HOME_PAGE, | |||
| ADMIN_USERS_PAGE, | |||
| } from "../../../../../../constants/pages"; | |||
| import history from "../../../../../../store/utils/history"; | |||
| import { useDispatch } from "react-redux"; | |||
| import { setManualSearchString } from "../../../../../../store/actions/filters/filtersActions"; | |||
| const AdminButton = (props) => { | |||
| const location = useLocation(); | |||
| const dispatch = useDispatch(); | |||
| const isSelected = useMemo(() => { | |||
| if (routeMatches(ADMIN_HOME_PAGE) && props.route === ADMIN_USERS_PAGE) | |||
| return true; | |||
| return routeMatches(props.route); | |||
| }, [props.route, location.pathname]); | |||
| const goToRoute = () => { | |||
| dispatch(setManualSearchString("")); | |||
| history.push(props.route); | |||
| props.toggleDrawer(); | |||
| }; | |||
| return ( | |||
| <AdminButtonContainer onClick={goToRoute} isSelected={isSelected}> | |||
| <AdminButtonIcon isSelected={isSelected}>{props.icon}</AdminButtonIcon> | |||
| <AdminButtonText isSelected={isSelected}>{props.title}</AdminButtonText> | |||
| </AdminButtonContainer> | |||
| ); | |||
| }; | |||
| AdminButton.propTypes = { | |||
| icon: PropTypes.node, | |||
| route: PropTypes.string, | |||
| title: PropTypes.string, | |||
| onClick: PropTypes.func, | |||
| toggleDrawer: PropTypes.func, | |||
| }; | |||
| export default AdminButton; | |||
| @@ -0,0 +1,42 @@ | |||
| import { Box, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../../../../themes"; | |||
| export const AdminButtonContainer = styled(Box)` | |||
| display: flex; | |||
| flex-direction: row; | |||
| gap: 18px; | |||
| background: ${(props) => | |||
| props.isSelected | |||
| ? selectedTheme.colors.backgroundSponsoredColor | |||
| : "transparent"}; | |||
| width: 100vw; | |||
| height: 61px; | |||
| padding: 18px; | |||
| border-radius: 4px; | |||
| `; | |||
| export const AdminButtonText = styled(Typography)` | |||
| font-family: ${selectedTheme.fonts.textFont}; | |||
| font-weight: ${(props) => (props.isSelected ? "600" : "400")}; | |||
| font-size: 18px; | |||
| line-height: 25px; | |||
| color: ${selectedTheme.colors.primaryPurple}; | |||
| `; | |||
| export const AdminButtonIcon = styled(Box)` | |||
| & svg { | |||
| width: 24px; | |||
| height: 24px; | |||
| } | |||
| & svg path { | |||
| stroke: ${(props) => | |||
| props.isSelected | |||
| ? selectedTheme.colors.iconYellowColor | |||
| : selectedTheme.colors.iconStrokeDisabledColor}; | |||
| } | |||
| & svg g path { | |||
| stroke: ${(props) => | |||
| props.isSelected | |||
| ? selectedTheme.colors.iconYellowColor | |||
| : selectedTheme.colors.iconStrokeDisabledColor}; | |||
| } | |||
| `; | |||
| @@ -0,0 +1,55 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import AdminButton from "./AdminButton/AdminButton"; | |||
| import { | |||
| CategoryIcon, | |||
| DollarIcon, | |||
| LocationIcon, | |||
| UserIcon, | |||
| } from "./AdminButtons.styled"; | |||
| import { | |||
| ADMIN_CATEGORIES_PAGE, | |||
| ADMIN_LOCATIONS_PAGE, | |||
| ADMIN_PAYMENT_PAGE, | |||
| ADMIN_USERS_PAGE, | |||
| } from "../../../../../constants/pages"; | |||
| import { useTranslation } from "react-i18next"; | |||
| const AdminButtons = (props) => { | |||
| const { t } = useTranslation(); | |||
| return ( | |||
| <> | |||
| <AdminButton | |||
| toggleDrawer={props.toggleDrawer} | |||
| icon={<UserIcon />} | |||
| title={t("admin.navigation.users")} | |||
| route={ADMIN_USERS_PAGE} | |||
| /> | |||
| <AdminButton | |||
| toggleDrawer={props.toggleDrawer} | |||
| icon={<CategoryIcon />} | |||
| title={t("admin.navigation.categories")} | |||
| route={ADMIN_CATEGORIES_PAGE} | |||
| /> | |||
| <AdminButton | |||
| toggleDrawer={props.toggleDrawer} | |||
| icon={<LocationIcon />} | |||
| title={t("admin.navigation.locations")} | |||
| route={ADMIN_LOCATIONS_PAGE} | |||
| /> | |||
| <AdminButton | |||
| toggleDrawer={props.toggleDrawer} | |||
| icon={<DollarIcon />} | |||
| title={t("admin.navigation.payment")} | |||
| route={ADMIN_PAYMENT_PAGE} | |||
| /> | |||
| </> | |||
| ); | |||
| }; | |||
| AdminButtons.propTypes = { | |||
| children: PropTypes.node, | |||
| toggleDrawer: PropTypes.func, | |||
| }; | |||
| export default AdminButtons; | |||
| @@ -0,0 +1,9 @@ | |||
| import { ReactComponent as User } from "../../../../../assets/images/svg/user.svg"; | |||
| import { ReactComponent as Location } from "../../../../../assets/images/svg/location.svg"; | |||
| import { ReactComponent as Category } from "../../../../../assets/images/svg/category.svg"; | |||
| import { ReactComponent as Dollar } from "../../../../../assets/images/svg/dollar-sign.svg"; | |||
| import styled from "styled-components"; | |||
| export const LocationIcon = styled(Location)``; | |||
| export const UserIcon = styled(User)``; | |||
| export const CategoryIcon = styled(Category)``; | |||
| export const DollarIcon = styled(Dollar)``; | |||
| @@ -1,4 +1,4 @@ | |||
| import React from "react"; | |||
| import React, { useMemo } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| CloseButton, | |||
| @@ -22,10 +22,18 @@ import AboutButton from "./Buttons/AboutButton/AboutButton"; | |||
| import PrivacyPolicyButton from "./Buttons/PrivacyPolicyButton/PrivacyPolicyButton"; | |||
| import { useSelector } from "react-redux"; | |||
| import { selectUserId } from "../../../store/selectors/loginSelectors"; | |||
| import { isAdminRoute } from "../../../util/helpers/routeHelpers"; | |||
| import { useLocation } from "react-router-dom"; | |||
| import AdminButtons from "./Buttons/AdminButtons/AdminButtons"; | |||
| import AdminInfo from "./AdminInfo/AdminInfo"; | |||
| import { selectMineProfile } from "../../../store/selectors/profileSelectors"; | |||
| export const Drawer = (props) => { | |||
| const { t } = useTranslation(); | |||
| const user = useSelector(selectUserId); | |||
| const mineProfile = useSelector(selectMineProfile); | |||
| const location = useLocation(); | |||
| const isAdmin = useMemo(() => isAdminRoute(), [location.pathname]); | |||
| return ( | |||
| <DrawerContainer> | |||
| @@ -34,18 +42,22 @@ export const Drawer = (props) => { | |||
| </CloseButton> | |||
| <HeaderTitle>{t("header.navMenu")}</HeaderTitle> | |||
| <React.Fragment> | |||
| <ToolsContainer mobile> | |||
| <ToolsContainer mobile isAdmin={isAdmin}> | |||
| {user ? ( | |||
| <> | |||
| <MyPostsButton toggleDrawer={props.toggleDrawer} /> | |||
| <MyMessagesButton toggleDrawer={props.toggleDrawer} /> | |||
| <MyProfileButton toggleDrawer={props.toggleDrawer} /> | |||
| <Separator /> | |||
| <PricesButton toggleDrawer={props.toggleDrawer} /> | |||
| <AboutButton toggleDrawer={props.toggleDrawer} /> | |||
| <PrivacyPolicyButton toggleDrawer={props.toggleDrawer} /> | |||
| <Separator /> | |||
| </> | |||
| isAdmin ? ( | |||
| <AdminButtons toggleDrawer={props.toggleDrawer}/> | |||
| ) : ( | |||
| <> | |||
| <MyPostsButton toggleDrawer={props.toggleDrawer} /> | |||
| <MyMessagesButton toggleDrawer={props.toggleDrawer} /> | |||
| <MyProfileButton toggleDrawer={props.toggleDrawer} /> | |||
| <Separator /> | |||
| <PricesButton toggleDrawer={props.toggleDrawer} /> | |||
| <AboutButton toggleDrawer={props.toggleDrawer} /> | |||
| <PrivacyPolicyButton toggleDrawer={props.toggleDrawer} /> | |||
| <Separator /> | |||
| </> | |||
| ) | |||
| ) : ( | |||
| <> | |||
| <LoginButton toggleDrawer={props.toggleDrawer} /> | |||
| @@ -54,11 +66,15 @@ export const Drawer = (props) => { | |||
| )} | |||
| </ToolsContainer> | |||
| {user && ( | |||
| <FooterButtons> | |||
| <AddOfferButton | |||
| toggleDrawer={props.toggleDrawer} | |||
| addOffer={props.addOffer} | |||
| /> | |||
| <FooterButtons isAdmin={isAdmin}> | |||
| {isAdmin ? ( | |||
| <AdminInfo name={mineProfile?.company?.name} /> | |||
| ) : ( | |||
| <AddOfferButton | |||
| toggleDrawer={props.toggleDrawer} | |||
| addOffer={props.addOffer} | |||
| /> | |||
| )} | |||
| <LogoutButton toggleDrawer={props.toggleDrawer} /> | |||
| </FooterButtons> | |||
| )} | |||
| @@ -2,12 +2,14 @@ import { Box, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import { ReactComponent as Close } from "../../../assets/images/svg/close-modal.svg"; | |||
| import selectedTheme from "../../../themes"; | |||
| import { hexToRGB } from "../../../util/helpers/colorHelper"; | |||
| import { IconButton } from "../../Buttons/IconButton/IconButton"; | |||
| export const DrawerContainer = styled(Box)` | |||
| width: 100vw; | |||
| position: relative; | |||
| height: 100%; | |||
| overflow: hidden; | |||
| `; | |||
| export const ToolsContainer = styled(Box)` | |||
| display: flex; | |||
| @@ -22,8 +24,8 @@ export const ToolsContainer = styled(Box)` | |||
| position: absolute; | |||
| top: 0px; | |||
| bottom: 70px; | |||
| left: 36px; | |||
| gap: 36px; | |||
| left: ${(props) => (props.isAdmin ? "18px" : "36px")}; | |||
| gap: ${(props) => (props.isAdmin ? "0" : "36px")}; | |||
| `; | |||
| export const AuthButtonsDrawerContainer = styled(Box)` | |||
| @@ -59,10 +61,14 @@ export const DrawerButton = styled(Box)` | |||
| export const FooterButtons = styled(Box)` | |||
| position: absolute; | |||
| bottom: 36px; | |||
| margin-left: 36px; | |||
| margin-right: 36px; | |||
| padding-top: 10px; | |||
| display: flex; | |||
| flex-direction: row; | |||
| width: 100vw; | |||
| justify-content: space-around; | |||
| width: calc(100vw - 72px); | |||
| justify-content: space-between; | |||
| border-top: 3px solid ${hexToRGB(selectedTheme.colors.borderNormal, 0.12)}; | |||
| `; | |||
| export const HeaderTitle = styled(Typography)` | |||
| @@ -12,8 +12,8 @@ const DrawerContainer = forwardRef((props, ref) => { | |||
| const { isMobile } = useIsMobile(); | |||
| useImperativeHandle(ref, () => ({ | |||
| handleToggleDrawer | |||
| })) | |||
| handleToggleDrawer, | |||
| })); | |||
| const handleToggleDrawer = () => { | |||
| setOpenDrawer((prevOpenDrawer) => !prevOpenDrawer); | |||
| @@ -3,15 +3,17 @@ import PropTypes from "prop-types"; | |||
| import BackdropComponent from "../../MUI/BackdropComponent"; | |||
| import { | |||
| ButtonsContainer, | |||
| CancelButton, | |||
| CategoryName, | |||
| DeleteCategoryContainer, | |||
| DeleteIcon, | |||
| ReassuranceText, | |||
| SaveButton, | |||
| } from "./DeleteCategory.styled"; | |||
| import LabeledCard from "../../Cards/LabeledCard/LabeledCard"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton"; | |||
| import { useMemo } from "react"; | |||
| import selectedTheme from "../../../themes"; | |||
| const DeleteCategory = (props) => { | |||
| const { t } = useTranslation(); | |||
| @@ -21,7 +23,7 @@ const DeleteCategory = (props) => { | |||
| }; | |||
| const reassuranceText = useMemo(() => { | |||
| return t(`admin.${props.type}.reassuranceDelete`); | |||
| }, [props]); | |||
| }, [props, t]); | |||
| return ( | |||
| <> | |||
| <BackdropComponent | |||
| @@ -29,23 +31,33 @@ const DeleteCategory = (props) => { | |||
| handleClose={() => props.setOpenedDeleteModal(false)} | |||
| position="fixed" | |||
| /> | |||
| <DeleteCategoryContainer> | |||
| <LabeledCard icon={<DeleteIcon />}> | |||
| <CategoryName>{props.category?.name || props.category?.city}</CategoryName> | |||
| <DeleteCategoryContainer type={props.type}> | |||
| <LabeledCard | |||
| icon={props.customLabeledCardIcon || <DeleteIcon />} | |||
| width={props.customLabeledCardWidth} | |||
| height={props.customLabeledCardHeight} | |||
| > | |||
| {props.customLabeledCard || ( | |||
| <CategoryName> | |||
| {props.category?.name || props.category?.city} | |||
| </CategoryName> | |||
| )} | |||
| </LabeledCard> | |||
| <ReassuranceText>{reassuranceText}</ReassuranceText> | |||
| <ButtonsContainer> | |||
| <PrimaryButton | |||
| <CancelButton | |||
| onClick={handleCancel} | |||
| variant="contained" | |||
| height="49px" | |||
| width="180px" | |||
| buttoncolor={selectedTheme.colors.primaryPurple} | |||
| > | |||
| {t("admin.categories.cancel")} | |||
| </PrimaryButton> | |||
| <PrimaryButton variant="outlined" height="49px" width="180px"> | |||
| {t("admin.categories.delete")} | |||
| </PrimaryButton> | |||
| {t(`admin.${props.type}.cancel`)} | |||
| </CancelButton> | |||
| <SaveButton | |||
| variant="outlined" | |||
| buttoncolor={selectedTheme.colors.primaryPurple} | |||
| > | |||
| {t(`admin.${props.type}.delete`)} | |||
| </SaveButton> | |||
| </ButtonsContainer> | |||
| </DeleteCategoryContainer> | |||
| </> | |||
| @@ -57,6 +69,10 @@ DeleteCategory.propTypes = { | |||
| category: PropTypes.object, | |||
| subcategory: PropTypes.bool, | |||
| type: PropTypes.string, | |||
| customLabeledCard: PropTypes.node, | |||
| customLabeledCardWidth: PropTypes.string, | |||
| customLabeledCardHeight: PropTypes.string, | |||
| customLabeledCardIcon: PropTypes.node, | |||
| }; | |||
| export default DeleteCategory; | |||
| @@ -2,14 +2,19 @@ import { Box, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import { ReactComponent as Delete } from "../../../assets/images/svg/trash.svg"; | |||
| import selectedTheme from "../../../themes"; | |||
| import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton"; | |||
| export const DeleteCategoryContainer = styled(Box)` | |||
| width: 537px; | |||
| height: 274px; | |||
| height: ${(props) => | |||
| ["blockUser", "deleteUser"].includes(props.type) ? "309px" : "274px"}; | |||
| position: fixed; | |||
| z-index: 150; | |||
| left: calc(50vw - 268px); | |||
| top: calc(50vh - 137px); | |||
| top: ${(props) => | |||
| ["blockUser", "deleteUser"].includes(props.type) | |||
| ? `calc(50vh - 153px)` | |||
| : `calc(50vh - 137px)`}; | |||
| padding-top: 36px; | |||
| padding-bottom: 18px; | |||
| background: white; | |||
| @@ -17,6 +22,16 @@ export const DeleteCategoryContainer = styled(Box)` | |||
| margin-left: auto; | |||
| margin-right: auto; | |||
| } | |||
| @media (max-width: 600px) { | |||
| width: 350px; | |||
| left: calc(50vw - 175px); | |||
| height: ${(props) => | |||
| ["blockUser", "deleteUser"].includes(props.type) ? "281px" : "246px"}; | |||
| top: ${(props) => | |||
| ["blockUser", "deleteUser"].includes(props.type) | |||
| ? `calc(50vh - 140px)` | |||
| : `calc(50vh - 123px)`}; | |||
| } | |||
| `; | |||
| export const DeleteIcon = styled(Delete)` | |||
| z-index: 155; | |||
| @@ -45,6 +60,10 @@ export const ReassuranceText = styled(Typography)` | |||
| line-height: 21px; | |||
| color: ${selectedTheme.colors.messageText}; | |||
| margin-top: 36px; | |||
| @media (max-width: 600px) { | |||
| font-size: 14px; | |||
| margin-top: 27px; | |||
| } | |||
| `; | |||
| export const ButtonsContainer = styled(Box)` | |||
| display: flex; | |||
| @@ -52,4 +71,24 @@ export const ButtonsContainer = styled(Box)` | |||
| flex-direction: row; | |||
| gap: 18px; | |||
| margin: 36px auto; | |||
| ` | |||
| @media (max-width: 600px) { | |||
| margin-bottom: 18px; | |||
| margin-top: 27px; | |||
| } | |||
| `; | |||
| export const CancelButton = styled(PrimaryButton)` | |||
| width: 180px; | |||
| height: 49px; | |||
| @media (max-width: 600px) { | |||
| width: 149px; | |||
| height: 45px; | |||
| } | |||
| `; | |||
| export const SaveButton = styled(PrimaryButton)` | |||
| width: 180px; | |||
| height: 49px; | |||
| @media (max-width: 600px) { | |||
| width: 149px; | |||
| height: 45px; | |||
| } | |||
| `; | |||
| @@ -0,0 +1,40 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| DeleteReviewContainer, | |||
| DeleteReviewTitle, | |||
| XIcon, | |||
| } from "./DeleteReview.styled"; | |||
| import BackdropComponent from "../../MUI/BackdropComponent"; | |||
| import UserReviewsSingleCard from "../../Cards/UserReviewsCard/UserReviewsSingleCard/UserReviewsSingleCard"; | |||
| import { useTranslation } from "react-i18next"; | |||
| const DeleteReview = (props) => { | |||
| const { t } = useTranslation(); | |||
| return ( | |||
| <> | |||
| <BackdropComponent | |||
| isLoading | |||
| handleClose={() => props.setOpenedDeleteModal(false)} | |||
| position="fixed" | |||
| /> | |||
| <DeleteReviewContainer> | |||
| <DeleteReviewTitle>{t("admin.review.title")}</DeleteReviewTitle> | |||
| <UserReviewsSingleCard | |||
| showRemoveIcon | |||
| deleteModal | |||
| review={props.review} | |||
| /> | |||
| <XIcon /> | |||
| </DeleteReviewContainer> | |||
| </> | |||
| ); | |||
| }; | |||
| DeleteReview.propTypes = { | |||
| review: PropTypes.any, | |||
| setOpenedDeleteModal: PropTypes.func, | |||
| cardComponent: PropTypes.any, | |||
| }; | |||
| export default DeleteReview; | |||
| @@ -0,0 +1,62 @@ | |||
| import { Box, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../themes"; | |||
| import { ReactComponent as X } from "../../../assets/images/svg/plus.svg"; | |||
| export const DeleteReviewContainer = styled(Box)` | |||
| position: fixed; | |||
| width: 100vw; | |||
| height: 100vh; | |||
| top: 0; | |||
| left: 0; | |||
| background-color: white; | |||
| z-index: 150; | |||
| padding: 28px; | |||
| & > div { | |||
| margin: 0 auto; | |||
| background-color: ${selectedTheme.colors.skeletonItemColor}; | |||
| padding: 18px; | |||
| border: 1px solid ${selectedTheme.colors.borderNormal}; | |||
| border-radius: 2px; | |||
| } | |||
| & > div::after { | |||
| border: 0; | |||
| } | |||
| @media (max-width: 600px) { | |||
| padding: 36px 28px; | |||
| } | |||
| `; | |||
| export const DeleteReviewTitle = styled(Typography)` | |||
| font-family: ${selectedTheme.fonts.textFont}; | |||
| display: block; | |||
| font-weight: 700; | |||
| font-size: 24px; | |||
| line-height: 31px; | |||
| text-align: center; | |||
| margin-bottom: 36px; | |||
| color: ${selectedTheme.colors.primaryPurple}; | |||
| @media (max-width: 600px) { | |||
| font-weight: 700; | |||
| font-size: 18px; | |||
| line-height: 25px; | |||
| } | |||
| `; | |||
| export const XIcon = styled(X)` | |||
| transform: rotate(45deg); | |||
| position: absolute; | |||
| top: 36px; | |||
| right: 36px; | |||
| cursor: pointer; | |||
| width: 26px; | |||
| height: 26px; | |||
| & path { | |||
| stroke: ${selectedTheme.colors.messageText}; | |||
| /* stroke-width: 2; */ | |||
| } | |||
| @media (max-width: 600px) { | |||
| width: 16px; | |||
| height: 16px; | |||
| top: 40px; | |||
| right: 18px; | |||
| } | |||
| `; | |||
| @@ -8,6 +8,7 @@ import { | |||
| EditCategoryImagePicker, | |||
| EditCategoryTitle, | |||
| FieldLabel, | |||
| InputContainer, | |||
| SaveButton, | |||
| SupportedFormats, | |||
| XIcon, | |||
| @@ -51,6 +52,7 @@ const EditCategory = (props) => { | |||
| }, | |||
| onSubmit: handleSubmit, | |||
| }); | |||
| console.log(props); | |||
| return ( | |||
| <> | |||
| <BackdropComponent | |||
| @@ -69,38 +71,39 @@ const EditCategory = (props) => { | |||
| </SupportedFormats> | |||
| </> | |||
| )} | |||
| <FieldLabel leftText={fieldLabel} /> | |||
| <CategoryTitleField | |||
| name="title" | |||
| placeholder={placeholder} | |||
| italicPlaceholder | |||
| margin="normal" | |||
| value={formik.values.title} | |||
| onChange={formik.handleChange} | |||
| error={formik.touched.title && formik.errors.title} | |||
| helperText={formik.touched.title && formik.errors.title} | |||
| autoFocus | |||
| fullWidth | |||
| /> | |||
| <InputContainer hideImagePicker={props.hideImagePicker}> | |||
| <FieldLabel leftText={fieldLabel} /> | |||
| <CategoryTitleField | |||
| name="title" | |||
| placeholder={placeholder} | |||
| italicPlaceholder | |||
| margin="normal" | |||
| value={formik.values.title} | |||
| onChange={formik.handleChange} | |||
| error={formik.touched.title && formik.errors.title} | |||
| helperText={formik.touched.title && formik.errors.title} | |||
| autoFocus | |||
| fullWidth | |||
| /> | |||
| </InputContainer> | |||
| <ButtonsContainer> | |||
| {props.method === "add" && ( | |||
| <SaveButton | |||
| variant="contained" | |||
| width="180px" | |||
| height="48px" | |||
| onClick={formik.handleSubmit} | |||
| > | |||
| {firstButtonText} | |||
| </SaveButton> | |||
| )} | |||
| <SaveButton | |||
| variant={props.method === "add" ? "outlined" : "contained"} | |||
| width={props.method === "add" ? "180px" : "376px"} | |||
| showSecondButton={props.showSecondButton} | |||
| variant={props.firstOutlined ? "outlined" : "contained"} | |||
| height="48px" | |||
| onClick={formik.handleSubmit} | |||
| > | |||
| {secondButtonText} | |||
| {firstButtonText} | |||
| </SaveButton> | |||
| {props.showSecondButton && ( | |||
| <SaveButton | |||
| variant={props.secondOutlined ? "outlined" : "contained"} | |||
| showSecondButton={props.showSecondButton} | |||
| onClick={formik.handleSubmit} | |||
| > | |||
| {secondButtonText} | |||
| </SaveButton> | |||
| )} | |||
| </ButtonsContainer> | |||
| </EditCategoryContainer> | |||
| </> | |||
| @@ -112,7 +115,14 @@ EditCategory.propTypes = { | |||
| setOpenedEditModal: PropTypes.func, | |||
| hideImagePicker: PropTypes.bool, | |||
| type: PropTypes.string, | |||
| showSecondButton: PropTypes.bool, | |||
| method: PropTypes.string, | |||
| firstOutlined: PropTypes.bool, | |||
| secondOutlined: PropTypes.bool, | |||
| }; | |||
| EditCategory.defaultProps = { | |||
| firstOutlined: true, | |||
| }; | |||
| export default EditCategory; | |||
| @@ -21,6 +21,13 @@ export const EditCategoryContainer = styled(Box)` | |||
| margin-left: auto; | |||
| margin-right: auto; | |||
| } | |||
| @media (max-width: 600px) { | |||
| width: 350px; | |||
| height: ${(props) => (props.hideImagePicker ? "207px" : "412px")}; | |||
| left: calc(50vw - 175px); | |||
| top: ${(props) => | |||
| props.hideImagePicker ? "calc(50vh - 103px)" : "calc(50vh - 206px)"}; | |||
| } | |||
| `; | |||
| export const EditCategoryTitle = styled(Typography)` | |||
| display: block; | |||
| @@ -32,6 +39,11 @@ export const EditCategoryTitle = styled(Typography)` | |||
| margin-top: 36px; | |||
| width: 256px; | |||
| color: ${selectedTheme.colors.primaryPurple}; | |||
| @media (max-width: 600px) { | |||
| font-size: 18px; | |||
| line-height: 24px; | |||
| margin-top: 18px; | |||
| } | |||
| `; | |||
| export const EditCategoryImagePicker = styled(ImagePicker)` | |||
| background: none; | |||
| @@ -43,12 +55,18 @@ export const EditCategoryImagePicker = styled(ImagePicker)` | |||
| position: relative; | |||
| left: calc(50% - 72px); | |||
| margin-bottom: 18px; | |||
| @media (max-width: 600px) { | |||
| margin-top: 27px; | |||
| } | |||
| `; | |||
| export const SupportedFormats = styled(Typography)` | |||
| font-size: 13px; | |||
| width: 100%; | |||
| text-align: center; | |||
| font-family: ${selectedTheme.fonts.textFont}; | |||
| @media (max-width: 600px) { | |||
| font-size: 13px; | |||
| } | |||
| `; | |||
| export const CategoryTitleField = styled(TextField)` | |||
| width: 375px; | |||
| @@ -61,6 +79,7 @@ export const CategoryTitleField = styled(TextField)` | |||
| } | |||
| & div { | |||
| height: 40px; | |||
| width: 314px; | |||
| } | |||
| } | |||
| `; | |||
| @@ -68,7 +87,6 @@ export const FieldLabel = styled(Label)` | |||
| position: relative; | |||
| bottom: -14px; | |||
| width: 376px; | |||
| margin-top: 22px; | |||
| & label { | |||
| font-size: 12px; | |||
| font-weight: 600; | |||
| @@ -83,12 +101,34 @@ export const FieldLabel = styled(Label)` | |||
| } | |||
| } | |||
| `; | |||
| export const InputContainer = styled(Box)` | |||
| display: block; | |||
| width: fit-content; | |||
| margin-top: 22px; | |||
| @media (max-width: 600px) { | |||
| width: 314px; | |||
| height: 56px; | |||
| margin-top: 27px; | |||
| position: relative; | |||
| top: -18px; | |||
| ${(props) => | |||
| !props.hideImagePicker && | |||
| ` | |||
| margin-top: 25px; | |||
| `} | |||
| } | |||
| `; | |||
| export const SaveButton = styled(PrimaryButton)` | |||
| max-width: 376px; | |||
| height: 48px; | |||
| & button { | |||
| letter-spacing: 1.5px; | |||
| } | |||
| @media (max-width: 600px) { | |||
| height: 45px; | |||
| width: ${(props) => (props.showSecondButton ? "149px" : "314px")}; | |||
| } | |||
| `; | |||
| export const XIcon = styled(X)` | |||
| transform: rotate(45deg); | |||
| @@ -102,6 +142,10 @@ export const XIcon = styled(X)` | |||
| stroke: ${selectedTheme.colors.messageText}; | |||
| stroke-width: 2; | |||
| } | |||
| @media (max-width: 600px) { | |||
| top: 18px; | |||
| right: 18px; | |||
| } | |||
| `; | |||
| export const ButtonsContainer = styled(Box)` | |||
| display: flex; | |||
| @@ -109,4 +153,7 @@ export const ButtonsContainer = styled(Box)` | |||
| flex-direction: row; | |||
| gap: 18px; | |||
| margin: 36px auto; | |||
| @media (max-width: 600px) { | |||
| margin-top: 18px; | |||
| } | |||
| `; | |||
| @@ -10,8 +10,10 @@ const Header = (props) => { | |||
| const history = useHistory(); | |||
| const { t } = useTranslation(); | |||
| const handleBackButton = () => { | |||
| history.push(HOME_PAGE); | |||
| if (props.isAdmin) history.goBack(); | |||
| else history.push(HOME_PAGE); | |||
| }; | |||
| return ( | |||
| @@ -22,7 +24,7 @@ const Header = (props) => { | |||
| > | |||
| <ButtonContainer> | |||
| <ArrowButton side={"left"}></ArrowButton> | |||
| <HeaderText>{t("profile.backToHome")}</HeaderText> | |||
| <HeaderText>{props.isAdmin ? t("admin.users.goBack") : t("profile.backToHome")}</HeaderText> | |||
| </ButtonContainer> | |||
| </HeaderContainer> | |||
| ); | |||
| @@ -35,6 +37,7 @@ Header.propTypes = { | |||
| filters: PropTypes.array, | |||
| category: PropTypes.string, | |||
| className: PropTypes.string, | |||
| isAdmin: PropTypes.bool, | |||
| }; | |||
| Header.defaultProps = { | |||
| isGrid: false, | |||
| @@ -7,6 +7,7 @@ export const HeaderContainer = styled(Box)` | |||
| @media (max-width: 600px) { | |||
| margin-top: 40px; | |||
| margin-left: 18px; | |||
| } | |||
| `; | |||
| export const ButtonContainer = styled(Link)` | |||
| @@ -23,5 +24,5 @@ export const HeaderText = styled(Typography)` | |||
| line-height: 22px; | |||
| font-size: 16px; | |||
| color: ${selectedTheme.colors.primaryPurple}; | |||
| border: 1px dotted ${selectedTheme.colors.primaryPurple}; | |||
| border-bottom: 1px dotted ${selectedTheme.colors.primaryPurple}; | |||
| `; | |||
| @@ -10,11 +10,11 @@ import { fetchProfile } from "../../store/actions/profile/profileActions"; | |||
| import { fetchProfileOffers } from "../../store/actions/offers/offersActions"; | |||
| import Header from "./Header/Header"; | |||
| const Profile = () => { | |||
| const Profile = (props) => { | |||
| const userId = useSelector(selectUserId); | |||
| const dispatch = useDispatch(); | |||
| const routeMatch = useRouteMatch(); | |||
| const idProfile = useMemo(() => routeMatch.params.idProfile, [routeMatch]); | |||
| const idProfile = useMemo(() => routeMatch.params?.idProfile, [routeMatch]); | |||
| useEffect(() => { | |||
| if (idProfile?.length > 0) { | |||
| dispatch(fetchProfile(idProfile)); | |||
| @@ -25,16 +25,18 @@ const Profile = () => { | |||
| return userId === routeMatch.params.idProfile; | |||
| }, [userId, routeMatch]); | |||
| return ( | |||
| <ProfileContainer> | |||
| <Header /> | |||
| <ProfileCard isMyProfile={isMyProfile} /> | |||
| <ProfileOffers isMyProfile={isMyProfile} /> | |||
| <ProfileContainer className={props.className}> | |||
| <Header isAdmin={props.isAdmin} /> | |||
| <ProfileCard isAdmin={props.isAdmin} isMyProfile={isMyProfile} /> | |||
| <ProfileOffers isAdmin={props.isAdmin} isMyProfile={isMyProfile} /> | |||
| </ProfileContainer> | |||
| ); | |||
| }; | |||
| Profile.propTypes = { | |||
| children: PropTypes.node, | |||
| className: PropTypes.string, | |||
| isAdmin: PropTypes.bool, | |||
| }; | |||
| export default Profile; | |||
| @@ -78,7 +78,7 @@ const ProfileOffers = (props) => { | |||
| offersToShow={offersToShow} | |||
| setOffersToShow={setOffersToShow} | |||
| /> | |||
| <HeaderTitle isMyProfile={props.isMyProfile} /> | |||
| <HeaderTitle isMyProfile={props.isMyProfile && !props.isAdmin} /> | |||
| <SearchBar handleSearch={handleSearch} /> | |||
| </> | |||
| )} | |||
| @@ -95,7 +95,8 @@ const ProfileOffers = (props) => { | |||
| ) : offersToShow.length !== 0 ? ( | |||
| offersToShow.map((item) => ( | |||
| <OfferCard | |||
| isMyOffer={props.isMyProfile} | |||
| isAdmin={props.isAdmin} | |||
| isMyOffer={props.isMyProfile || props.isAdmin} | |||
| offer={item} | |||
| key={JSON.stringify(item)} | |||
| messageUser={messageUser} | |||
| @@ -108,11 +109,12 @@ const ProfileOffers = (props) => { | |||
| <OffersScroller hideArrows> | |||
| {offersToShow.map((item) => ( | |||
| <OfferCard | |||
| isAdmin={props.isAdmin} | |||
| vertical | |||
| isMyOffer={props.isMyProfile} | |||
| isMyOffer={props.isMyProfile || props.isAdmin} | |||
| offer={item} | |||
| key={JSON.stringify(item)} | |||
| pinned | |||
| pinned={item.pinned} | |||
| messageUser={messageUser} | |||
| /> | |||
| ))} | |||
| @@ -127,6 +129,7 @@ const ProfileOffers = (props) => { | |||
| ProfileOffers.propTypes = { | |||
| children: PropTypes.node, | |||
| isMyProfile: PropTypes.bool, | |||
| isAdmin: PropTypes.bool, | |||
| }; | |||
| export default ProfileOffers; | |||
| @@ -13,13 +13,15 @@ export const ProfileOffersContainer = styled(Box)` | |||
| } | |||
| @media (max-width: 600px) { | |||
| padding: 0; | |||
| width: calc(100vw - 36px); | |||
| margin: 34px 18px; | |||
| } | |||
| `; | |||
| export const OffersContainer = styled(Box)` | |||
| margin-top: 30px; | |||
| `; | |||
| export const OffersScroller = styled(HorizontalScroller)` | |||
| height: 373px; | |||
| height: 400px; | |||
| width: 100%; | |||
| margin-left: 0; | |||
| & div { | |||
| @@ -35,7 +35,11 @@ const ProfileMini = () => { | |||
| <ProfileHeader> | |||
| <ProfileHeaderIconContainer> | |||
| <ProfileIcon /> | |||
| <ProfileHeaderText>{t("profile.companyProfile")}</ProfileHeaderText> | |||
| <ProfileHeaderText> | |||
| {isMyProfile | |||
| ? t("profile.myProfile") | |||
| : t("profile.companyProfile")} | |||
| </ProfileHeaderText> | |||
| </ProfileHeaderIconContainer> | |||
| <ItemDetailsHeaderCard | |||
| offer={offer} | |||
| @@ -1,4 +1,4 @@ | |||
| import React from "react"; | |||
| import React, { forwardRef, useImperativeHandle, useMemo } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| DownArrowIcon, | |||
| @@ -11,50 +11,66 @@ import { selectSelectedReviews } from "../../../store/selectors/reviewSelector"; | |||
| import { sortReviews } from "../../../util/helpers/reviewsHelper"; | |||
| import { reviewSortEnum } from "../../../enums/reviewEnum"; | |||
| import { setReviews } from "../../../store/actions/review/reviewActions"; | |||
| import { sortAdminEnum } from "../../../enums/sortEnum"; | |||
| const ReviewsSorting = (props) => { | |||
| const ReviewsSorting = forwardRef((props, ref) => { | |||
| const reviews = useSelector(selectSelectedReviews); | |||
| const dispatch = useDispatch(); | |||
| const [value, setValue] = useState(); | |||
| const changeValue = (event) => { | |||
| dispatch( | |||
| setReviews( | |||
| sortReviews( | |||
| reviews, | |||
| event.target.value.value === reviewSortEnum.POSITIVE.value | |||
| if (props.isAdmin) { | |||
| console.log("sortiranje: ", event.target.value) | |||
| } else { | |||
| dispatch( | |||
| setReviews( | |||
| sortReviews( | |||
| reviews, | |||
| event.target.value.value === reviewSortEnum.POSITIVE.value | |||
| ) | |||
| ) | |||
| ) | |||
| ); | |||
| props.changeSorting(); | |||
| ); | |||
| props.changeSorting(); | |||
| } | |||
| setValue(event.target.value); | |||
| }; | |||
| const sortEnum = useMemo(() => { | |||
| if (props.isAdmin) return sortAdminEnum; | |||
| return reviewSortEnum; | |||
| }); | |||
| useImperativeHandle(ref, () => ({ | |||
| sortValue: value, | |||
| hasGivenReview: value?.value === sortAdminEnum.GIVEN.value | |||
| })) | |||
| return ( | |||
| <HeaderSelect | |||
| value={value || reviewSortEnum.INITIAL} | |||
| value={value || sortEnum.INITIAL} | |||
| IconComponent={DownArrowIcon} | |||
| onChange={changeValue} | |||
| > | |||
| <SelectOption style={{ display: "none" }} value={reviewSortEnum.INITIAL}> | |||
| {reviewSortEnum.INITIAL.mainText} | |||
| <SelectOption style={{ display: "none" }} value={sortEnum.INITIAL}> | |||
| {sortEnum.INITIAL.mainText} | |||
| </SelectOption> | |||
| {Object.keys(reviewSortEnum).map((property) => { | |||
| if (reviewSortEnum[property].value === 0) return; | |||
| {Object.keys(sortEnum).map((property) => { | |||
| if (sortEnum[property].value === 0) return; | |||
| return ( | |||
| <SelectOption | |||
| value={reviewSortEnum[property]} | |||
| key={reviewSortEnum[property].value} | |||
| value={sortEnum[property]} | |||
| key={sortEnum[property].value} | |||
| > | |||
| {reviewSortEnum[property].mainText} | |||
| {sortEnum[property].mainText} | |||
| </SelectOption> | |||
| ); | |||
| })} | |||
| </HeaderSelect> | |||
| ); | |||
| }; | |||
| }); | |||
| ReviewsSorting.displayName = "ReviewsSorting"; | |||
| ReviewsSorting.propTypes = { | |||
| children: PropTypes.node, | |||
| changeSorting: PropTypes.func, | |||
| isAdmin: PropTypes.bool, | |||
| }; | |||
| export default ReviewsSorting; | |||
| @@ -6,6 +6,7 @@ import { | |||
| ReviewsHeader, | |||
| ReviewsHeaderTitle, | |||
| ReviewsTitle, | |||
| UserReviewsContainer, | |||
| } from "./UserReviews.styled"; | |||
| import StarBorderIcon from "@mui/icons-material/StarBorder"; | |||
| @@ -34,6 +35,7 @@ const UserReviews = (props) => { | |||
| const routeMatch = useRouteMatch(); | |||
| const dispatch = useDispatch(); | |||
| const listRef = useRef(null); | |||
| const sortRef = useRef(null); | |||
| const isLoadingReview = useSelector( | |||
| selectIsLoadingByActionType( | |||
| @@ -72,15 +74,15 @@ const UserReviews = (props) => { | |||
| listRef.current.scrollTo({ top: 0, behaviour: "smooth" }); | |||
| }; | |||
| console.log(sortRef.current?.sortValue); | |||
| return ( | |||
| <> | |||
| <UserReviewsContainer className={props.className}> | |||
| {!props.givingReview && | |||
| (isLoadingReview || isLoadingReview === undefined) ? ( | |||
| <SkeletonUserReviews /> | |||
| ) : ( | |||
| <ReviewsBox | |||
| profile={props.isProfileReviews} | |||
| className={props.className} | |||
| numOfReviews={lastThreeReviews?.length} | |||
| > | |||
| {!props.givingReview && ( | |||
| @@ -98,7 +100,11 @@ const UserReviews = (props) => { | |||
| /> | |||
| <ReviewsTitle>{t("reviews.rates")}</ReviewsTitle> | |||
| </ReviewsHeaderTitle> | |||
| <ReviewsSorting changeSorting={scrollToTop} /> | |||
| <ReviewsSorting | |||
| changeSorting={scrollToTop} | |||
| ref={sortRef} | |||
| isAdmin={props.isAdmin} | |||
| /> | |||
| </ReviewsHeader> | |||
| )} | |||
| <ReviewList ref={listRef} isProfileReviews={props.isProfileReviews}> | |||
| @@ -107,6 +113,7 @@ const UserReviews = (props) => { | |||
| <UserReviewsCard | |||
| review={review} | |||
| key={index} | |||
| hasGivenReview={sortRef.current?.hasGivenReview} | |||
| givingReview={props.givingReview} | |||
| /> | |||
| )) | |||
| @@ -116,7 +123,7 @@ const UserReviews = (props) => { | |||
| </ReviewList> | |||
| </ReviewsBox> | |||
| )} | |||
| </> | |||
| </UserReviewsContainer> | |||
| ); | |||
| }; | |||
| @@ -128,6 +135,7 @@ UserReviews.propTypes = { | |||
| className: PropTypes.string, | |||
| givingReview: PropTypes.bool, | |||
| offer: PropTypes.any, | |||
| isAdmin: PropTypes.bool, | |||
| }; | |||
| UserReviews.defaultProps = { | |||
| isProfileReviews: false, | |||
| @@ -5,18 +5,11 @@ import ThumbDownIcon from "@mui/icons-material/ThumbDown"; | |||
| import selectedTheme from "../../themes"; | |||
| import { ReactComponent as DownArrow } from "../../assets/images/svg/up-arrow.svg"; | |||
| export const UserReviewsContainer = styled(Box)``; | |||
| export const ReviewsBox = styled(Box)` | |||
| width: 100%; | |||
| /* One review is 185px in height and 82 px are header title + padding */ | |||
| /* height: ${(props) => | |||
| props.numOfReviews > 0 | |||
| ? props.numOfReviews * 185 + 82 + "px" | |||
| : `calc(100% - 90px)`}; */ | |||
| /* max-height: 100vh; */ | |||
| min-width: 290px; | |||
| /* @media (max-width: 1200px) { | |||
| padding: 0 50px; | |||
| } */ | |||
| ${(props) => | |||
| props.profile && | |||
| ` | |||
| @@ -35,6 +28,7 @@ export const ReviewsBox = styled(Box)` | |||
| ? "450px" | |||
| : "350px"}; | |||
| padding: 0; | |||
| margin: 0 18px; | |||
| margin-top: 60px; | |||
| } | |||
| `; | |||
| @@ -20,6 +20,7 @@ export const PRICES_PAGE = "/prices"; | |||
| export const POLICY_PRIVACY_PAGE = "/policy"; | |||
| export const ADMIN_HOME_PAGE = "/admin"; | |||
| export const ADMIN_USERS_PAGE = "/admin/users"; | |||
| export const ADMIN_SINGLE_USER_PAGE = "/admin/users/:idProfile"; | |||
| export const ADMIN_CATEGORIES_PAGE = "/admin/categories"; | |||
| export const ADMIN_LOCATIONS_PAGE = "/admin/locations"; | |||
| export const ADMIN_PAYMENT_PAGE = "/admin/payment"; | |||
| @@ -19,4 +19,18 @@ export const sortEnum = { | |||
| mainText: "Najstarije", | |||
| queryString: "oldest" | |||
| } | |||
| } | |||
| export const sortAdminEnum = { | |||
| INITIAL: { | |||
| value: 0, | |||
| mainText: "Sortiraj po" | |||
| }, | |||
| GIVEN: { | |||
| value: 1, | |||
| mainText: "Date" | |||
| }, | |||
| RECIEVED: { | |||
| value: 2, | |||
| mainText: "Dobijene" | |||
| } | |||
| } | |||
| @@ -425,9 +425,10 @@ export default { | |||
| headerTitle: "Ulogujte se", | |||
| }, | |||
| users: { | |||
| headerTitle: "Profili korisnika", | |||
| headerTitle: "Profili kompanija", | |||
| searchPlaceholder: "Pretražite korisnike....", | |||
| checkProfile: "Pogledaj profil", | |||
| goBack: "Nazad na sve kompanije", | |||
| }, | |||
| navigation: { | |||
| role: "Administrator", | |||
| @@ -454,6 +455,7 @@ export default { | |||
| fieldTitle: "Naslov", | |||
| placeholder: "Naziv kategorije...", | |||
| save: "Izmeni", | |||
| next: "Sledeća", | |||
| }, | |||
| add: { | |||
| title: "Nova Kategorija", | |||
| @@ -469,6 +471,8 @@ export default { | |||
| subcategoriesHeaderTitle: "Podkategorije", | |||
| placeholder: "Pretražite podkategorije...", | |||
| addSubcategory: "Dodaj podkategoriju", | |||
| cancel: "Otkaži", | |||
| delete: "Obriši", | |||
| reassuranceDelete: | |||
| "Da li ste sigurni da želite da obrišete odabranu podkategoriju?", | |||
| edit: { | |||
| @@ -476,6 +480,7 @@ export default { | |||
| fieldTitle: "Naslov", | |||
| placeholder: "Naziv podkategorije...", | |||
| save: "Izmeni", | |||
| next: "Sledeća" | |||
| }, | |||
| add: { | |||
| title: "Nova Podkategorija", | |||
| @@ -506,5 +511,26 @@ export default { | |||
| next: "Sledeća", | |||
| }, | |||
| }, | |||
| deleteUser: { | |||
| reassuranceDelete: | |||
| "Da li ste sigurni da želite da obrišete profil kompanje?", | |||
| cancel: "Otkaži", | |||
| delete: "Obriši", | |||
| }, | |||
| blockUser: { | |||
| reassuranceDelete: | |||
| "Da li ste sigurni da želite da blokirate profil kompanje?", | |||
| cancel: "Otkaži", | |||
| delete: "Blokiraj", | |||
| }, | |||
| pin: { | |||
| reassurancePin: | |||
| "Da li ste sigurni da želite da zakačite proizvod na vrhu?", | |||
| confirm: "Zakači", | |||
| }, | |||
| review: { | |||
| title: "Brisanje Komentara", | |||
| confirm: "Obriši komentar" | |||
| } | |||
| }, | |||
| }; | |||
| @@ -0,0 +1,30 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { Content, LeftCard, AdminLayoutContainer } from "./AdminLayout.styled"; | |||
| import { Grid } from "@mui/material"; | |||
| const AdminLayout = (props) => { | |||
| return ( | |||
| <AdminLayoutContainer className={props.className}> | |||
| {props.children} | |||
| <Grid container maxHeight="xl"> | |||
| <LeftCard item xs={0} sm={3} md={3} lg={3} xl={2.4}> | |||
| {props.leftCard} | |||
| </LeftCard> | |||
| <Content item xs={12} sm={9} md={9} lg={9} xl={9.6}> | |||
| {props.content} | |||
| </Content> | |||
| </Grid> | |||
| </AdminLayoutContainer> | |||
| ); | |||
| }; | |||
| AdminLayout.propTypes = { | |||
| children: PropTypes.node, | |||
| leftCard: PropTypes.node, | |||
| content: PropTypes.node, | |||
| rightCard: PropTypes.node, | |||
| className: PropTypes.string, | |||
| }; | |||
| export default AdminLayout; | |||
| @@ -0,0 +1,24 @@ | |||
| import { Container, Grid } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const AdminLayoutContainer = styled(Container)` | |||
| padding-left: 0; | |||
| padding-right: 0; | |||
| margin: 0; | |||
| width: 100%; | |||
| max-width: none; | |||
| display: flex; | |||
| flex: 1; | |||
| height: 100%; | |||
| margin-top: 80px; | |||
| @media (max-width: 600px) { | |||
| margin-top: 100px; | |||
| } | |||
| ` | |||
| export const LeftCard = styled(Grid)` | |||
| margin-top: 30px; | |||
| border-top-right-radius: 4px; | |||
| ` | |||
| export const Content = styled(Grid)` | |||
| ` | |||
| @@ -13,7 +13,7 @@ export const AdminCategoriesPageContainer = styled(Box)` | |||
| @media (max-width: 600px) { | |||
| padding: 18px; | |||
| min-height: calc(100vh - 72px); | |||
| padding-bottom: 54px; | |||
| padding-bottom: 100px; | |||
| top: 65px; | |||
| } | |||
| `; | |||
| @@ -21,13 +21,14 @@ export const AdminCategoriesHeader = styled(Header)` | |||
| /* top: 40px; */ | |||
| top: 0; | |||
| @media (max-width: 600px) { | |||
| top: -10px; | |||
| margin-top: 18px; | |||
| & div { | |||
| margin-top: 10px; | |||
| top: -5px; | |||
| margin-top: 0px; | |||
| & > div { | |||
| margin-top: -10px; | |||
| } | |||
| & div div:nth-child(1) { | |||
| top: 22px; | |||
| & > div > div > div:nth-child(1) { | |||
| top: 15px; | |||
| left: 0; | |||
| } | |||
| } | |||
| `; | |||
| @@ -52,5 +53,5 @@ export const NewCategoryButton = styled(PrimaryButton)` | |||
| } | |||
| ` | |||
| export const CategoriesList = styled(Box)` | |||
| padding-top: 10px | |||
| /* padding-top: 10px */ | |||
| ` | |||
| @@ -3,7 +3,6 @@ import PropTypes from "prop-types"; | |||
| // import MarketPlace from "../../components/MarketPlace/MarketPlace"; | |||
| // import useOffers from "../../hooks/useOffers/useOffers"; | |||
| import Sidebar from "../../components/Admin/Sidebar/Sidebar"; | |||
| import { MainLayoutAdminHomePage } from "./AdminHomePage.styled"; | |||
| import { useSelector } from "react-redux"; | |||
| // import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors"; | |||
| // import { OFFERS_SCOPE } from "../../store/actions/offers/offersActionConstants"; | |||
| @@ -14,6 +13,7 @@ import { | |||
| ADMIN_CATEGORIES_PAGE, | |||
| ADMIN_LOCATIONS_PAGE, | |||
| ADMIN_PAYMENT_PAGE, | |||
| ADMIN_SINGLE_USER_PAGE, | |||
| ADMIN_SUBCATEGORIES_PAGE, | |||
| ADMIN_USERS_PAGE, | |||
| HOME_PAGE, | |||
| @@ -24,6 +24,8 @@ import AdminRoute from "../../components/Router/AdminRoute"; | |||
| import AdminSubcategoriesPage from "./AdminSubcategoriesPage/AdminSubcategoriesPage"; | |||
| import AdminLocationsPage from "./AdminLocationsPage/AdminLocationsPage"; | |||
| import AdminPaymentPage from "./AdminPaymentPage/AdminPaymentPage"; | |||
| import AdminSingleUserPage from "./AdminUsersPage/AdminSingleUserPage/AdminSingleUserPage"; | |||
| import { AdminLayoutHomePage } from "./AdminHomePage.styled"; | |||
| const AdminHomePage = () => { | |||
| const profile = useSelector(selectMineProfile); | |||
| @@ -37,16 +39,25 @@ const AdminHomePage = () => { | |||
| history.push(HOME_PAGE); | |||
| } | |||
| return ( | |||
| <MainLayoutAdminHomePage | |||
| <AdminLayoutHomePage | |||
| leftCard={<Sidebar />} | |||
| content={ | |||
| <Switch> | |||
| <AdminRoute path={ADMIN_USERS_PAGE} component={AdminUsersPage} /> | |||
| <AdminRoute | |||
| exact | |||
| path={ADMIN_USERS_PAGE} | |||
| component={AdminUsersPage} | |||
| /> | |||
| <AdminRoute | |||
| exact | |||
| path={ADMIN_CATEGORIES_PAGE} | |||
| component={AdminCategoriesPage} | |||
| /> | |||
| <AdminRoute | |||
| exact | |||
| path={ADMIN_SINGLE_USER_PAGE} | |||
| component={AdminSingleUserPage} | |||
| /> | |||
| <AdminRoute | |||
| path={ADMIN_SUBCATEGORIES_PAGE} | |||
| component={AdminSubcategoriesPage} | |||
| @@ -1,6 +1,6 @@ | |||
| import styled from "styled-components"; | |||
| import MainLayout from "../../layouts/MainLayout/MainLayout"; | |||
| import AdminLayout from "../../layouts/AdminLayout/AdminLayout"; | |||
| export const MainLayoutAdminHomePage = styled(MainLayout)` | |||
| export const AdminLayoutHomePage = styled(AdminLayout)` | |||
| margin-top: 0; | |||
| `; | |||
| @@ -14,20 +14,21 @@ export const AdminLocationsPageContainer = styled(Box)` | |||
| @media (max-width: 600px) { | |||
| padding: 18px; | |||
| min-height: (100vh - 72px); | |||
| padding-bottom: 54px; | |||
| padding-bottom: 100px; | |||
| top: 65px; | |||
| } | |||
| `; | |||
| export const AdminLocationsHeader = styled(Header)` | |||
| top: 0; | |||
| @media (max-width: 600px) { | |||
| top: -10px; | |||
| margin-top: 18px; | |||
| & div { | |||
| margin-top: 10px; | |||
| top: -5px; | |||
| margin-top: 0px; | |||
| & > div { | |||
| margin-top: -10px; | |||
| } | |||
| & div div:nth-child(1) { | |||
| top: 22px; | |||
| & > div > div > div:nth-child(1) { | |||
| top: 15px; | |||
| left: 0; | |||
| } | |||
| } | |||
| `; | |||
| @@ -21,8 +21,6 @@ import CategoryCard from "../../../components/Cards/CategoryCard/CategoryCard"; | |||
| import selectedTheme from "../../../themes"; | |||
| import { useState } from "react"; | |||
| import EditCategory from "../../../components/Modals/EditCategory/EditCategory"; | |||
| import { isInRoute } from "../../../util/helpers/routeHelpers"; | |||
| import { ADMIN_SUBCATEGORIES_PAGE } from "../../../constants/pages"; | |||
| const AdminSubcategoriesPage = () => { | |||
| const { t } = useTranslation(); | |||
| @@ -32,15 +30,15 @@ const AdminSubcategoriesPage = () => { | |||
| const manualSearchString = useSelector(selectManualSearchString); | |||
| const [openedAddModal, setOpenedAddModal] = useState(false); | |||
| console.log(isInRoute(ADMIN_SUBCATEGORIES_PAGE)); | |||
| useEffect(() => { | |||
| dispatch(fetchCategories()); | |||
| }, []); | |||
| const handleSearch = (value) => { | |||
| console.log(value); | |||
| dispatch(setManualSearchString(value)); | |||
| }; | |||
| const category = useMemo(() => { | |||
| if (routeMatch.params?.categoryId) { | |||
| const categoryId = routeMatch.params.categoryId; | |||
| @@ -48,6 +46,7 @@ const AdminSubcategoriesPage = () => { | |||
| } | |||
| return {}; | |||
| }, [routeMatch, categories]); | |||
| const subcategories = useMemo(() => { | |||
| if (category) { | |||
| if (manualSearchString) | |||
| @@ -60,6 +59,8 @@ const AdminSubcategoriesPage = () => { | |||
| } | |||
| return []; | |||
| }, [category, manualSearchString]); | |||
| console.log("subc", categories); | |||
| return ( | |||
| <> | |||
| <AdminSubcategoriesPageContainer> | |||
| @@ -17,7 +17,7 @@ export const AdminSubcategoriesPageContainer = styled(Box)` | |||
| @media (max-width: 600px) { | |||
| padding: 18px; | |||
| min-height: (100vh - 72px); | |||
| padding-bottom: 54px; | |||
| padding-bottom: 100px; | |||
| top: 65px; | |||
| } | |||
| `; | |||
| @@ -0,0 +1,25 @@ | |||
| import React, { useEffect } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| AdminSingleUserPageContainer, | |||
| AdminSingleUserPageProfile, | |||
| AdminSingleUserPageReviews, | |||
| } from "./AdminSingleUserPage.styled"; | |||
| const AdminSingleUserPage = () => { | |||
| useEffect(() => { | |||
| window.scrollTo({ top: 0, behaviour: "smooth" }); | |||
| }, []); | |||
| return ( | |||
| <AdminSingleUserPageContainer> | |||
| <AdminSingleUserPageProfile isAdmin /> | |||
| <AdminSingleUserPageReviews isProfileReviews isAdmin /> | |||
| </AdminSingleUserPageContainer> | |||
| ); | |||
| }; | |||
| AdminSingleUserPage.propTypes = { | |||
| children: PropTypes.node, | |||
| }; | |||
| export default AdminSingleUserPage; | |||
| @@ -0,0 +1,26 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import Profile from "../../../../components/Profile/Profile"; | |||
| import UserReviews from "../../../../components/UserReviews/UserReviews"; | |||
| export const AdminSingleUserPageContainer = styled(Box)` | |||
| @media (max-width: 600px) { | |||
| margin-top: 90px; | |||
| } | |||
| `; | |||
| export const AdminSingleUserPageProfile = styled(Profile)` | |||
| margin-bottom: 5px; | |||
| `; | |||
| export const AdminSingleUserPageReviews = styled(UserReviews)` | |||
| padding: 0 50px; | |||
| @media (max-width: 600px) { | |||
| padding: 0; | |||
| width: calc(100% - 36px); | |||
| & > div { | |||
| margin-top: 0; | |||
| height: 500px; | |||
| position: relative; | |||
| top: -18px; | |||
| } | |||
| } | |||
| `; | |||
| @@ -1,26 +1,53 @@ | |||
| import React, { useEffect } from "react"; | |||
| import React, { useEffect, useMemo } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import MarketPlace from "../../../components/MarketPlace/MarketPlace"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| import { selectAllProfiles } from "../../../store/selectors/profileSelectors"; | |||
| import { fetchAllProfiles } from "../../../store/actions/profile/profileActions"; | |||
| import { AdminUsersPageContainer } from "./AdminUsersPage.styled"; | |||
| import { | |||
| AdminUsersHeader, | |||
| AdminUsersList, | |||
| AdminUsersPageContainer, | |||
| AdminUsersSearchField, | |||
| } from "./AdminUsersPage.styled"; | |||
| import BigProfileCard from "../../../components/Cards/ProfileCard/BigProfileCard/BigProfileCard"; | |||
| import { useTranslation } from "react-i18next"; | |||
| const AdminUsersPage = () => { | |||
| const dispatch = useDispatch(); | |||
| const { t } = useTranslation(); | |||
| const allUsers = useSelector(selectAllProfiles); | |||
| const allUsersToShow = useMemo( | |||
| () => (Array.isArray(allUsers) ? allUsers : []), | |||
| [allUsers] | |||
| ); | |||
| useEffect(() => { | |||
| dispatch(fetchAllProfiles()); | |||
| }, []); | |||
| const handleSearch = () => {}; | |||
| return ( | |||
| <AdminUsersPageContainer> | |||
| <MarketPlace | |||
| isAdmin | |||
| myOffers | |||
| users | |||
| allUsers={Array.isArray(allUsers) ? allUsers : []} | |||
| /> | |||
| <> | |||
| <AdminUsersSearchField | |||
| isAdmin | |||
| handleSearch={handleSearch} | |||
| placeholder={t("admin.subcategories.placeholder")} | |||
| /> | |||
| <AdminUsersHeader | |||
| myOffers | |||
| category | |||
| hideGrid | |||
| isAdmin | |||
| users | |||
| hideBackButton | |||
| /> | |||
| <AdminUsersList> | |||
| {allUsersToShow.map((singleUser) => ( | |||
| <BigProfileCard key={singleUser._id} profile={singleUser} /> | |||
| ))} | |||
| </AdminUsersList> | |||
| </> | |||
| </AdminUsersPageContainer> | |||
| ); | |||
| }; | |||
| @@ -1,13 +1,46 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import Header from "../../../components/MarketPlace/Header/Header"; | |||
| import SearchField from "../../../components/TextFields/SearchField/SearchField"; | |||
| export const AdminUsersPageContainer = styled(Box)` | |||
| padding: 60px; | |||
| /* display: flex; */ | |||
| position: relative; | |||
| padding-top: 38px; | |||
| padding-bottom: 100px; | |||
| min-height: 100vh; | |||
| flex-direction: column; | |||
| @media (max-width: 600px) { | |||
| padding: 18px; | |||
| min-height: (100vh - 72px); | |||
| padding-bottom: 54px; | |||
| top: 38px; | |||
| } | |||
| `; | |||
| export const AdminUsersHeader = styled(Header)` | |||
| top: 4px; | |||
| @media (max-width: 600px) { | |||
| top: 0px; | |||
| /* margin-top: 18px; */ | |||
| & > div { | |||
| margin-left: 60px; | |||
| margin-right: 60px; | |||
| margin-top: 43px; | |||
| margin-top: 0; | |||
| } | |||
| & > div > div:nth-child(2) { | |||
| top: 77px; | |||
| & > div > div > div { | |||
| left: 0; | |||
| top: 25px; | |||
| } | |||
| ` | |||
| & > div:nth-child(2) { | |||
| white-space: nowrap; | |||
| } | |||
| } | |||
| `; | |||
| export const AdminUsersSearchField = styled(SearchField)` | |||
| top: -15px; | |||
| @media (max-width: 600px) { | |||
| display: none; | |||
| } | |||
| `; | |||
| export const AdminUsersList = styled(Box)` | |||
| padding-top: 18px; | |||
| `; | |||
| @@ -15,6 +15,7 @@ export const variants = { | |||
| profileCard: "profileCard", | |||
| createReviewCard: "createReviewCard", | |||
| carousel: "carousel", | |||
| adminProfileCard: "reviewCard" | |||
| }; | |||
| const cloudFlareVariants = { | |||
| @@ -4,6 +4,7 @@ import { | |||
| ADMIN_LOCATIONS_PAGE, | |||
| ADMIN_LOGIN_PAGE, | |||
| ADMIN_PAYMENT_PAGE, | |||
| ADMIN_SINGLE_USER_PAGE, | |||
| ADMIN_SUBCATEGORIES_PAGE, | |||
| ADMIN_USERS_PAGE, | |||
| FORGOT_PASSWORD_MAIL_SENT, | |||
| @@ -55,7 +56,8 @@ export const isAdminRoute = () => { | |||
| routeMatches(ADMIN_CATEGORIES_PAGE) || | |||
| dynamicRouteMatches(ADMIN_SUBCATEGORIES_PAGE) || | |||
| routeMatches(ADMIN_LOCATIONS_PAGE) || | |||
| routeMatches(ADMIN_PAYMENT_PAGE) | |||
| routeMatches(ADMIN_PAYMENT_PAGE) || | |||
| dynamicRouteMatches(ADMIN_SINGLE_USER_PAGE) | |||
| ) | |||
| return true; | |||
| return false; | |||
| @@ -69,12 +71,6 @@ export const dynamicRouteMatches = (dynamicRoute) => { | |||
| }; | |||
| export const isInRoute = (routeToCheck) => { | |||
| console.log("routeToCheck", routeToCheck); | |||
| console.log( | |||
| "first Expression", | |||
| history.location.pathname.includes(routeToCheck) | |||
| ); | |||
| console.log("second expression", dynamicRouteMatches(routeToCheck)); | |||
| return ( | |||
| history.location.pathname.includes(routeToCheck) || | |||
| dynamicRouteMatches(routeToCheck) | |||