| @@ -17,6 +17,9 @@ import { | |||
| RemoveIconContainer, | |||
| RemoveIcon, | |||
| ButtonContainer, | |||
| PinIconContainer, | |||
| PinIcon, | |||
| UnpinIcon, | |||
| // EditDeleteButtons, | |||
| } from "./ItemDetailsCard.styled"; | |||
| import selectedTheme from "../../../themes"; | |||
| @@ -85,6 +88,17 @@ const ItemDetailsCard = (props) => { | |||
| const showEditOfferModalHandler = () => { | |||
| dispatch(toggleEditOfferModal({ editOffer: true, offer: offer.offer })); | |||
| }; | |||
| const showPinOfferModalHandler = () => { | |||
| console.log(offer); | |||
| dispatch( | |||
| toggleDeleteOfferModal({ | |||
| offer: offer?.offer, | |||
| pin: true, | |||
| pinnedOffer: offer?.offer?.pinned, | |||
| deleteOffer: false, | |||
| }) | |||
| ); | |||
| }; | |||
| return ( | |||
| <> | |||
| @@ -132,6 +146,9 @@ const ItemDetailsCard = (props) => { | |||
| <DateButtonsContainer> | |||
| {props.isMyOffer && ( | |||
| <ButtonsContainer> | |||
| <PinIconContainer onClick={showPinOfferModalHandler}> | |||
| {offer?.offer?.pinned ? <UnpinIcon /> : <PinIcon />} | |||
| </PinIconContainer> | |||
| <EditIconContainer onClick={showEditOfferModalHandler}> | |||
| <EditIcon /> | |||
| </EditIconContainer> | |||
| @@ -10,6 +10,8 @@ import { ReactComponent as Quantity } from "../../../assets/images/svg/quantity. | |||
| import { ReactComponent as Eye } from "../../../assets/images/svg/eye-striked.svg"; | |||
| import { IconButton } from "../../Buttons/IconButton/IconButton"; | |||
| import { ReactComponent as Edit } from "../../../assets/images/svg/edit.svg"; | |||
| import { ReactComponent as Pin } from "../../../assets/images/svg/pin-outlined.svg"; | |||
| import { ReactComponent as Unpin } from "../../../assets/images/svg/unpin-outlined.svg"; | |||
| import { ReactComponent as Remove } from "../../../assets/images/svg/trash.svg"; | |||
| export const ItemDetailsCardContainer = styled(Container)` | |||
| @@ -97,7 +99,7 @@ export const EditIconContainer = styled(IconButton)` | |||
| border-radius: 100%; | |||
| padding-top: 2px; | |||
| text-align: center; | |||
| margin-left: 18px; | |||
| /* margin-left: 18px; */ | |||
| @media screen and (max-width: 600px) { | |||
| width: 32px; | |||
| @@ -132,7 +134,6 @@ export const RemoveIconContainer = styled(IconButton)` | |||
| height: 32px; | |||
| } | |||
| `; | |||
| export const RemoveIcon = styled(Remove)` | |||
| @media screen and (max-width: 600px) { | |||
| width: 16px; | |||
| @@ -142,6 +143,42 @@ export const RemoveIcon = styled(Remove)` | |||
| left: -2px; | |||
| } | |||
| `; | |||
| export const PinIconContainer = styled(IconButton)` | |||
| width: 40px; | |||
| height: 40px; | |||
| position: relative; | |||
| top: 4px; | |||
| background-color: ${selectedTheme.colors.primaryIconBackgroundColor}; | |||
| border-radius: 100%; | |||
| padding-top: 2px; | |||
| text-align: center; | |||
| /* margin-left: 18px; */ | |||
| @media screen and (max-width: 600px) { | |||
| width: 32px; | |||
| top: 0; | |||
| height: 32px; | |||
| } | |||
| `; | |||
| export const PinIcon = styled(Pin)` | |||
| @media screen and (max-width: 600px) { | |||
| width: 20px; | |||
| height: 20px; | |||
| position: relative; | |||
| top: -4px; | |||
| left: -2px; | |||
| } | |||
| `; | |||
| export const UnpinIcon = styled(Unpin)` | |||
| @media screen and (max-width: 600px) { | |||
| width: 20px; | |||
| height: 20px; | |||
| position: relative; | |||
| top: -4px; | |||
| left: -2px; | |||
| } | |||
| `; | |||
| export const DateButtonsContainer = styled(Box)` | |||
| display: flex; | |||
| @@ -50,6 +50,11 @@ import { | |||
| } from "../../../store/actions/modal/modalActions"; | |||
| import { Tooltip } from "@mui/material"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { replaceInRoute } from "../../../util/helpers/routeHelpers"; | |||
| import { | |||
| ADMIN_ITEM_DETAILS_PAGE, | |||
| ITEM_DETAILS_PAGE, | |||
| } from "../../../constants/pages"; | |||
| const OfferCard = (props) => { | |||
| const dispatch = useDispatch(); | |||
| @@ -72,7 +77,19 @@ const OfferCard = (props) => { | |||
| }; | |||
| const routeToItem = (itemId) => { | |||
| if (!props.disabledCheckButton) { | |||
| history.push(`/proizvodi/${itemId}`); | |||
| if (props.isAdmin) { | |||
| history.push( | |||
| replaceInRoute(ADMIN_ITEM_DETAILS_PAGE, { | |||
| idProizvod: itemId, | |||
| }) | |||
| ); | |||
| } else { | |||
| history.push( | |||
| replaceInRoute(ITEM_DETAILS_PAGE, { | |||
| idProizvod: itemId, | |||
| }) | |||
| ); | |||
| } | |||
| } | |||
| }; | |||
| const messageUser = (event) => { | |||
| @@ -25,9 +25,13 @@ const ItemDetails = (props) => { | |||
| selectIsLoadingByActionType(ONE_OFFER_SCOPE) | |||
| ); | |||
| let isMyProfile = useMemo(() => { | |||
| if (offer?.offer?.userId?.toString() === userId?.toString()) return true; | |||
| if ( | |||
| offer?.offer?.userId?.toString() === userId?.toString() || | |||
| props.isAdmin | |||
| ) | |||
| return true; | |||
| return false; | |||
| }, [offer, userId]); | |||
| }, [offer, userId, props.isAdmin]); | |||
| return ( | |||
| <ItemDetailsContainer> | |||
| @@ -45,7 +49,7 @@ const ItemDetails = (props) => { | |||
| <OfferIconText>{t("offer.product")}</OfferIconText> | |||
| </OfferIconContainer> | |||
| )} | |||
| <ItemDetailsCard offer={offer} isMyOffer={isMyProfile} singleOffer /> | |||
| <ItemDetailsCard offer={offer} isMyOffer={isMyProfile} isAdmin={props.isAdmin} singleOffer /> | |||
| </> | |||
| )} | |||
| </ItemDetailsContainer> | |||
| @@ -54,6 +58,7 @@ const ItemDetails = (props) => { | |||
| ItemDetails.propTypes = { | |||
| singleOffer: PropTypes.any, | |||
| isAdmin: PropTypes.bool, | |||
| }; | |||
| export default ItemDetails; | |||
| @@ -86,7 +86,7 @@ const ItemDetailsHeaderCard = (props) => { | |||
| ) : ( | |||
| <Tooltip title={t("messages.tooltip")}> | |||
| <TooltipInnerContainer> | |||
| <MessageIcon onClick={() => messageUser(offer)}> | |||
| <MessageIcon disabled onClick={() => messageUser(offer)}> | |||
| <MessageColor /> | |||
| </MessageIcon> | |||
| </TooltipInnerContainer> | |||
| @@ -1,5 +1,5 @@ | |||
| import { Box, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import styled, { css } from "styled-components"; | |||
| import selectedTheme from "../../../themes"; | |||
| import { IconButton } from "../../Buttons/IconButton/IconButton"; | |||
| import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton"; | |||
| @@ -159,6 +159,16 @@ export const MessageIcon = styled(IconButton)` | |||
| background-color: ${selectedTheme.colors.primaryPurple}; | |||
| border-radius: 100%; | |||
| padding-top: 2px; | |||
| ${(props) => | |||
| props.disabled && | |||
| css` | |||
| border: 1px solid ${selectedTheme.colors.borderNormal}; | |||
| background-color: ${selectedTheme.colors.primaryIconBackgroundColor}; | |||
| & button svg path { | |||
| stroke: ${selectedTheme.colors.iconStrokePurpleDisabledColor}; | |||
| padding-top: 1px; | |||
| } | |||
| `} | |||
| text-align: center; | |||
| @media (max-width: 600px) { | |||
| width: 32px; | |||
| @@ -167,8 +177,8 @@ export const MessageIcon = styled(IconButton)` | |||
| width: 16px; | |||
| height: 16px; | |||
| position: relative; | |||
| top: -4px; | |||
| left: -2px; | |||
| top: ${(props) => (props.disabled ? "-5px" : "-4px")}; | |||
| left: ${(props) => (props.disabled ? "-3px" : "-2px")}; | |||
| } | |||
| } | |||
| `; | |||
| @@ -21,6 +21,7 @@ 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_ITEM_DETAILS_PAGE = "/admin/proizvodi/:idProizvod"; | |||
| export const ADMIN_CATEGORIES_PAGE = "/admin/categories"; | |||
| export const ADMIN_LOCATIONS_PAGE = "/admin/locations"; | |||
| export const ADMIN_PAYMENT_PAGE = "/admin/payment"; | |||
| @@ -8,10 +8,10 @@ const AdminLayout = (props) => { | |||
| <AdminLayoutContainer className={props.className}> | |||
| {props.children} | |||
| <Grid container maxHeight="xl"> | |||
| <LeftCard item xs={0} sm={0} md={3} lg={3} xl={3}> | |||
| <LeftCard item xs={0} sm={0} md={3} lg={3} xl={2.4}> | |||
| {props.leftCard} | |||
| </LeftCard> | |||
| <Content item xs={12} sm={12} md={9} lg={9} xl={9}> | |||
| <Content item xs={12} sm={12} md={9} lg={9} xl={9.6}> | |||
| {props.content} | |||
| </Content> | |||
| </Grid> | |||
| @@ -11,6 +11,7 @@ import { selectMineProfile } from "../../store/selectors/profileSelectors"; | |||
| import { Switch, useHistory } from "react-router-dom"; | |||
| import { | |||
| ADMIN_CATEGORIES_PAGE, | |||
| ADMIN_ITEM_DETAILS_PAGE, | |||
| ADMIN_LOCATIONS_PAGE, | |||
| ADMIN_PAYMENT_PAGE, | |||
| ADMIN_SINGLE_USER_PAGE, | |||
| @@ -26,6 +27,7 @@ import AdminLocationsPage from "./AdminLocationsPage/AdminLocationsPage"; | |||
| import AdminPaymentPage from "./AdminPaymentPage/AdminPaymentPage"; | |||
| import AdminSingleUserPage from "./AdminUsersPage/AdminSingleUserPage/AdminSingleUserPage"; | |||
| import { AdminLayoutHomePage } from "./AdminHomePage.styled"; | |||
| import AdminItemDetailsPage from "./AdminItemDetailsPage/AdminItemDetailsPage"; | |||
| const AdminHomePage = () => { | |||
| const profile = useSelector(selectMineProfile); | |||
| @@ -59,8 +61,8 @@ const AdminHomePage = () => { | |||
| component={AdminSingleUserPage} | |||
| /> | |||
| <AdminRoute | |||
| path={ADMIN_SUBCATEGORIES_PAGE} | |||
| component={AdminSubcategoriesPage} | |||
| path={ADMIN_ITEM_DETAILS_PAGE} | |||
| component={AdminItemDetailsPage} | |||
| /> | |||
| <AdminRoute | |||
| path={ADMIN_SUBCATEGORIES_PAGE} | |||
| @@ -0,0 +1,61 @@ | |||
| import React from 'react' | |||
| import PropTypes from 'prop-types' | |||
| import { useDispatch, useSelector } from 'react-redux'; | |||
| import { selectOffer } from '../../../store/selectors/offersSelectors'; | |||
| import { useState } from 'react'; | |||
| import { useEffect } from 'react'; | |||
| import { clearSelectedOffer, fetchOneOffer } from '../../../store/actions/offers/offersActions'; | |||
| import { AdminItemDetailsPageContainer } from './AdminItemDetailsPage.styled'; | |||
| import ItemDetailsLayout from '../../../layouts/ItemDetailsLayout/ItemDetailsLayout'; | |||
| import ItemDetails from '../../../components/ItemDetails/ItemDetails'; | |||
| import ProfileMini from '../../../components/ProfileMini/ProfileMini'; | |||
| import UserReviews from '../../../components/UserReviews/UserReviews'; | |||
| const AdminItemDetailsPage = (props) => { | |||
| const dispatch = useDispatch(); | |||
| const selectedOffer = useSelector(selectOffer); | |||
| const [isInitiallyLoaded, setIsInitiallyLoaded] = useState(false); | |||
| const offerId = props.match.params.idProizvod; | |||
| useEffect(() => { | |||
| dispatch(fetchOneOffer(offerId)); | |||
| () => dispatch(clearSelectedOffer()); | |||
| }, []); | |||
| useEffect(() => { | |||
| if (!selectedOffer?.offer && isInitiallyLoaded) { | |||
| dispatch(fetchOneOffer(offerId)); | |||
| } | |||
| if (selectedOffer?.offer) { | |||
| setIsInitiallyLoaded(true); | |||
| } | |||
| }, [selectedOffer?.offer]); | |||
| useEffect(() => { | |||
| window.scrollTo({ top: 0, behaviour: "smooth" }); | |||
| }, []); | |||
| return ( | |||
| <AdminItemDetailsPageContainer> | |||
| <ItemDetailsLayout | |||
| singleOffer | |||
| content={<ItemDetails singleOffer isAdmin />} | |||
| rightCard={ | |||
| <> | |||
| <ProfileMini /> <UserReviews rightReviews /> | |||
| </> | |||
| } | |||
| /> | |||
| </AdminItemDetailsPageContainer> | |||
| ); | |||
| }; | |||
| AdminItemDetailsPage.propTypes = { | |||
| match: PropTypes.shape({ | |||
| params: PropTypes.shape({ | |||
| idProizvod: PropTypes.string, | |||
| }), | |||
| }), | |||
| }; | |||
| export default AdminItemDetailsPage | |||
| @@ -0,0 +1,19 @@ | |||
| import styled from "styled-components"; | |||
| import { Box, Grid } from "@mui/material"; | |||
| import selectedTheme from "../../../themes"; | |||
| export const AdminItemDetailsPageContainer = styled(Box)` | |||
| padding: 0; | |||
| margin: 0; | |||
| height: 100%; | |||
| width: 100%; | |||
| max-width: none; | |||
| flex: 1; | |||
| display: flex; | |||
| flex-direction: column; | |||
| background-color: ${selectedTheme.colors.offerBackgroundColor}; | |||
| @media screen and (max-width: 600px) { | |||
| margin-top: 65px; | |||
| } | |||
| `; | |||
| export const GridStyled = styled(Grid)``; | |||
| @@ -1,6 +1,7 @@ | |||
| import { | |||
| ADMIN_CATEGORIES_PAGE, | |||
| ADMIN_HOME_PAGE, | |||
| ADMIN_ITEM_DETAILS_PAGE, | |||
| ADMIN_LOCATIONS_PAGE, | |||
| ADMIN_LOGIN_PAGE, | |||
| ADMIN_PAYMENT_PAGE, | |||
| @@ -58,6 +59,7 @@ export const isAdminRoute = () => { | |||
| routeMatches(ADMIN_LOCATIONS_PAGE) || | |||
| routeMatches(ADMIN_PAYMENT_PAGE) || | |||
| dynamicRouteMatches(ADMIN_SINGLE_USER_PAGE) || | |||
| dynamicRouteMatches(ADMIN_ITEM_DETAILS_PAGE) || | |||
| isInRoute(ADMIN_HOME_PAGE) | |||
| ) | |||
| return true; | |||