| @@ -1,4 +1,4 @@ | |||
| import React from "react"; | |||
| import React, { useEffect } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| CheckButton, | |||
| @@ -20,12 +20,16 @@ import { ReactComponent as Subcategory } from "../../../assets/images/svg/subcat | |||
| import { ReactComponent as Quantity } from "../../../assets/images/svg/quantity.svg"; | |||
| import { ReactComponent as Eye } from "../../../assets/images/svg/eye-striked.svg"; | |||
| import selectedTheme from "../../../themes"; | |||
| import { Offer as offer } from "./MockupOfferDetails"; | |||
| import { Offer as offerMock } from "./MockupOfferDetails"; | |||
| import HorizontalScroller from "../../Scroller/HorizontalScroller"; | |||
| import {ReactComponent as DummyImage1 } from "../../../assets/images/svg/dummyImages/offer-1.svg" | |||
| const ItemDetailsCard = (props) => { | |||
| useEffect(() => { | |||
| console.log(props.offer); | |||
| },[props.offer]); | |||
| return ( | |||
| <ItemDetailsCardContainer sponsored={props.sponsored.toString()} halfwidth={props.halfwidth ? 1 : 0}> | |||
| <OfferInfo> | |||
| @@ -34,31 +38,31 @@ const ItemDetailsCard = (props) => { | |||
| <InfoIcon color={selectedTheme.iconStrokeColor} component="span" size="16px"> | |||
| <Category width={"14px"} /> | |||
| </InfoIcon> | |||
| <InfoText>{offer.category}</InfoText> | |||
| <InfoText>{offerMock.category}</InfoText> | |||
| </InfoGroup> | |||
| <InfoGroup> | |||
| <InfoIcon color={selectedTheme.iconStrokeColor} component="span" size="16px"> | |||
| <Subcategory width={"14px"} /> | |||
| </InfoIcon> | |||
| <InfoText>{offer.subcategory}</InfoText> | |||
| <InfoText>{offerMock.subcategory}</InfoText> | |||
| </InfoGroup> | |||
| <InfoGroup> | |||
| <InfoIcon color={selectedTheme.iconStrokeColor} component="span" size="16px"> | |||
| <Quantity width={"22px"} height={"16px"} /> | |||
| </InfoIcon> | |||
| <InfoText>{offer.status}</InfoText> | |||
| <InfoText>{props.offer.condition}</InfoText> | |||
| </InfoGroup> | |||
| <InfoGroup> | |||
| <InfoIcon color={"black"} component="span" size="12px"> | |||
| <Eye width={"18px"} height={"20px"} /> | |||
| </InfoIcon> | |||
| <InfoText>{offer.numberOfViews}</InfoText> | |||
| <InfoText>{offerMock.numberOfViews}</InfoText> | |||
| </InfoGroup> | |||
| </Info> | |||
| <PostDate>Objavljeno: 04.04.2022</PostDate> | |||
| </OfferInfo> | |||
| <Details> | |||
| <OfferTitle>{offer.title}</OfferTitle> | |||
| <OfferTitle>{props.offer.name}</OfferTitle> | |||
| <HorizontalScroller> | |||
| <DummyImage1 /> | |||
| <DummyImage1 /> | |||
| @@ -72,7 +76,7 @@ const ItemDetailsCard = (props) => { | |||
| </HorizontalScroller> | |||
| <OfferDetails> | |||
| <OfferDescriptionTitle>Opis:</OfferDescriptionTitle> | |||
| <OfferDescriptionText>{offer.description}</OfferDescriptionText> | |||
| <OfferDescriptionText>{offerMock.description}</OfferDescriptionText> | |||
| </OfferDetails> | |||
| </Details> | |||
| {!props.halfwidth ? ( | |||
| @@ -117,6 +121,19 @@ ItemDetailsCard.propTypes = { | |||
| numberOfViews: PropTypes.number, | |||
| halfwidth: PropTypes.bool, | |||
| sponsored: PropTypes.bool, | |||
| offer: PropTypes.shape({ | |||
| images: PropTypes.any, | |||
| name:PropTypes.string, | |||
| description:PropTypes.string, | |||
| condition:PropTypes.string, | |||
| category:PropTypes.shape({ | |||
| name:PropTypes.string | |||
| }), | |||
| location:PropTypes.shape({ | |||
| city:PropTypes.string | |||
| }) | |||
| }) | |||
| }; | |||
| ItemDetailsCard.defaultProps = { | |||
| halfwidth: false, | |||
| @@ -48,6 +48,7 @@ export const InfoIcon = styled(Box)` | |||
| `; | |||
| export const InfoText = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| text-transform: capitalize; | |||
| `; | |||
| export const OfferTitle = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| @@ -1,4 +1,4 @@ | |||
| import React from "react"; | |||
| import React, { useEffect } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| CheckButton, | |||
| @@ -29,10 +29,15 @@ import selectedTheme from "../../../themes"; | |||
| import { useHistory } from "react-router-dom"; | |||
| const OfferCard = (props) => { | |||
| const id = 434; | |||
| const history = useHistory(); | |||
| const routeToItem = () => { | |||
| history.push(`/proizvodi/${id}`) | |||
| useEffect(() => { | |||
| console.log(props.offer._id); | |||
| }, []); | |||
| const routeToItem = (itemId) => { | |||
| history.push(`/proizvodi/${itemId}`) | |||
| } | |||
| return ( | |||
| <OfferCardContainer sponsored={props.offer.pinned.toString()} halfwidth={props.halfwidth ? 1 : 0}> | |||
| @@ -77,7 +82,7 @@ const OfferCard = (props) => { | |||
| buttoncolor={selectedTheme.primaryPurple} | |||
| textcolor={props.sponsored ? "white" : selectedTheme.primaryPurple} | |||
| style={{fontWeight: "600"}} | |||
| onClick = {routeToItem} | |||
| onClick = {() => routeToItem(props.offer._id)} | |||
| > | |||
| Pogledaj proizvod | |||
| </CheckButton> | |||
| @@ -105,7 +110,7 @@ const OfferCard = (props) => { | |||
| OfferCard.propTypes = { | |||
| children: PropTypes.node, | |||
| id: PropTypes.number, | |||
| _id: PropTypes.string, | |||
| title: PropTypes.string, | |||
| description: PropTypes.string, | |||
| category: PropTypes.string, | |||
| @@ -1,17 +1,21 @@ | |||
| import React from 'react'; | |||
| import Header from "./Header/Header"; | |||
| import { useSelector } from 'react-redux'; | |||
| import { ItemDetailsContainer } from './ItemDetails.styled'; | |||
| import ItemDetailsCard from "../Cards/ItemDetailsCard/ItemDetailsCard"; | |||
| import ItemDetailsHeaderCard from "./ItemDetailsHeaderCard/ItemDetailsHeaderCard"; | |||
| import { selectOffer } from '../../store/selectors/offersSelectors'; | |||
| const ItemDetails = () => { | |||
| const offer = useSelector(selectOffer); | |||
| return ( | |||
| <ItemDetailsContainer> | |||
| <Header/> | |||
| <ItemDetailsHeaderCard /> | |||
| <ItemDetailsCard/> | |||
| <ItemDetailsHeaderCard offer={offer} /> | |||
| <ItemDetailsCard offer={offer}/> | |||
| </ItemDetailsContainer> | |||
| ) | |||
| } | |||
| @@ -81,6 +81,18 @@ ItemDetailsHeaderCard.propTypes = { | |||
| numberOfViews: PropTypes.number, | |||
| halfwidth: PropTypes.bool, | |||
| sponsored: PropTypes.bool, | |||
| offer: PropTypes.shape({ | |||
| images: PropTypes.any, | |||
| name:PropTypes.string, | |||
| description:PropTypes.string, | |||
| category:PropTypes.shape({ | |||
| name:PropTypes.string | |||
| }), | |||
| location:PropTypes.shape({ | |||
| city:PropTypes.string | |||
| }) | |||
| }) | |||
| }; | |||
| ItemDetailsHeaderCard.defaultProps = { | |||
| halfwidth: false, | |||
| @@ -1,63 +1,26 @@ | |||
| import React, { useEffect } from "react"; | |||
| import { PropTypes } from "prop-types"; | |||
| import Navbar from "../../components/MUI/NavbarComponent"; | |||
| import { ItemDetailsPageContainer } from "./ItemDetailsPage.styled"; | |||
| import Mockupdata from "../../components/Cards/FilterCard/Mockupdata"; | |||
| import qs from "query-string"; | |||
| import { useHistory } from "react-router-dom"; | |||
| import { setFilters } from "../../store/actions/filters/filtersActions"; | |||
| import { useDispatch,useSelector } from "react-redux"; | |||
| import { useDispatch } from "react-redux"; | |||
| import ItemDetails from "../../components/ItemDetails/ItemDetails"; | |||
| import ItemDetailsLayout from "../../layouts/ItemDetailsLayout/ItemDetailsLayout"; | |||
| import UserReviewsCard from "../../components/UserReviewsCard/UserReviewsCard"; | |||
| import { fetchOneOffer } from "../../store/actions/offers/offersActions"; | |||
| import { selectOffer } from "../../store/selectors/offersSelectors"; | |||
| const ItemDetailsPage = () => { | |||
| const ItemDetailsPage = (props) => { | |||
| const dispatch = useDispatch(); | |||
| const offer = useSelector(selectOffer); | |||
| useEffect(() => { | |||
| dispatch(fetchOneOffer()); | |||
| console.log(offer); | |||
| }, []) | |||
| //const routetMatch = useRouteMatch(); | |||
| const history = useHistory(); | |||
| const offerId = props.match.params.idProizvod; | |||
| useEffect(() => { | |||
| const queryString = history.location.search.substring(1); | |||
| const queryObject = qs.parse(queryString); | |||
| let category = null; | |||
| if (queryObject.category) { | |||
| category = Mockupdata[1].find( | |||
| (item) => item.string === queryObject.category.toString() | |||
| ).id; | |||
| } | |||
| let cities = []; | |||
| if (queryObject.city) { | |||
| if (Array.isArray(queryObject.city)) { | |||
| queryObject.city.forEach((item) => { | |||
| cities.push(Mockupdata[0].find((p) => p.string === item).id); | |||
| }); | |||
| } else { | |||
| cities.push( | |||
| Mockupdata[0].find((p) => p.string === queryObject.city).id | |||
| ); | |||
| } | |||
| } | |||
| let subcategory = null; | |||
| if (queryObject.subcategory) { | |||
| subcategory = Mockupdata[1].find( | |||
| (item) => item.string === queryObject.subcategory.toString() | |||
| ).id; | |||
| } | |||
| console.log("iz useeffect: ", { category, subcategory, cities }); | |||
| dispatch(setFilters({ category, subcategory, cities })); | |||
| }, [history.location.search]); | |||
| dispatch(fetchOneOffer(offerId)); | |||
| }, []); | |||
| return ( | |||
| <ItemDetailsPageContainer> | |||
| @@ -90,4 +53,12 @@ const ItemDetailsPage = () => { | |||
| ); | |||
| }; | |||
| ItemDetailsPage.propTypes = { | |||
| match: PropTypes.shape({ | |||
| params: PropTypes.shape({ | |||
| idProizvod:PropTypes.string | |||
| }) | |||
| }) | |||
| }; | |||
| export default ItemDetailsPage; | |||
| @@ -159,7 +159,7 @@ export default { | |||
| }, | |||
| offers: { | |||
| getOffers: '/offers', | |||
| getOneOffer: '/offers/{id}', | |||
| getOneOffer: '/offers', | |||
| addOffer: '/offers', | |||
| } | |||
| }; | |||
| @@ -4,8 +4,10 @@ import apiEndpoints from "./apiEndpoints" | |||
| export const attemptFetchOffers = () => { | |||
| return getRequest(apiEndpoints.offers.getOffers) | |||
| } | |||
| export const attemptFetchOneOffer = () => { | |||
| return getRequest(apiEndpoints.offers.getOneOffer); | |||
| export const attemptFetchOneOffer = (payload) => { | |||
| // console.log(payload); | |||
| const url = `${apiEndpoints.offers.getOneOffer}/${payload.payload}`; | |||
| return getRequest(url); | |||
| } | |||
| export const attemptAddOffer = (payload) => { | |||
| return postRequest(apiEndpoints.offers.addOffer, payload) | |||
| @@ -13,5 +13,6 @@ export const ONE_OFFER_SUCCESS = createSuccessType(ONE_OFFER_FETCH); | |||
| export const ONE_OFFER_ERROR = createErrorType(ONE_OFFER_SCOPE); | |||
| export const OFFERS_SET = "OFFERS_SET"; | |||
| export const OFFER_SET = "OFFER_SET" | |||
| export const OFFERS_ADD = "OFFERS_ADD"; | |||
| export const OFFER_ADD = "OFFER_ADD"; | |||
| @@ -1,4 +1,4 @@ | |||
| import { OFFERS_ADD, OFFERS_CLEAR, OFFERS_ERROR, OFFERS_FETCH, OFFERS_SET, OFFERS_SUCCESS, OFFER_ADD, ONE_OFFER_FETCH, ONE_OFFER_SUCCESS, ONE_OFFER_ERROR } from "./offersActionConstants"; | |||
| import { OFFERS_ADD, OFFERS_CLEAR, OFFERS_ERROR, OFFERS_FETCH, OFFERS_SET, OFFERS_SUCCESS, OFFER_ADD, ONE_OFFER_FETCH, ONE_OFFER_SUCCESS, ONE_OFFER_ERROR, OFFER_SET } from "./offersActionConstants"; | |||
| export const fetchOffers = (payload) => ({ | |||
| type: OFFERS_FETCH, | |||
| @@ -41,4 +41,9 @@ export const fetchOneOfferError = (payload) => ({ | |||
| export const fetchOneOfferSuccess = (payload) => ({ | |||
| type: ONE_OFFER_SUCCESS, | |||
| payload | |||
| }) | |||
| export const setOffer = (payload) => ({ | |||
| type: OFFER_SET, | |||
| payload | |||
| }) | |||
| @@ -4,9 +4,10 @@ import { | |||
| OFFERS_ERROR, | |||
| OFFERS_SET, | |||
| OFFER_ADD, | |||
| OFFER_SET, | |||
| ONE_OFFER_FETCH, | |||
| ONE_OFFER_ERROR, | |||
| ONE_OFFER_SUCCESS | |||
| ONE_OFFER_SUCCESS, | |||
| } from "../../actions/offers/offersActionConstants"; | |||
| import createReducer from "../../utils/createReducer"; | |||
| @@ -24,6 +25,7 @@ export default createReducer( | |||
| [OFFERS_SET]: setOffers, | |||
| [OFFERS_ADD]: addOffers, | |||
| [OFFER_ADD]: addOffer, | |||
| [OFFER_SET]: setOffer, | |||
| [ONE_OFFER_ERROR]: fetchOneOfferError, | |||
| [ONE_OFFER_SUCCESS]: fetchOneOfferSuccess, | |||
| [ONE_OFFER_FETCH]: fetchOneOffer, | |||
| @@ -45,6 +47,12 @@ function setOffers(state, action) { | |||
| offers: action.payload, | |||
| }; | |||
| } | |||
| function setOffer(state, action) { | |||
| return { | |||
| ...state, | |||
| selectedOffer: action.payload, | |||
| }; | |||
| } | |||
| function addOffers(state, action) { | |||
| return { | |||
| ...state, | |||
| @@ -61,13 +69,13 @@ function addOffer(state, action) { | |||
| function fetchOneOffer(state,action) { | |||
| return { | |||
| ...state, | |||
| offer: action.payload | |||
| selectedOffer: action.payload | |||
| } | |||
| } | |||
| function fetchOneOfferSuccess( state, action) { | |||
| return { | |||
| ...state, | |||
| offer: action.payload | |||
| selectedOffer: action.payload | |||
| } | |||
| } | |||
| function fetchOneOfferError (state, action) { | |||
| @@ -1,7 +1,7 @@ | |||
| import { all, takeLatest, call, put } from "@redux-saga/core/effects"; | |||
| import { attemptAddOffer, attemptFetchOffers, attemptFetchOneOffer } from "../../request/offersRequest"; | |||
| import { OFFERS_FETCH, OFFER_ADD, ONE_OFFER_FETCH } from "../actions/offers/offersActionConstants"; | |||
| import { setOffers } from "../actions/offers/offersActions"; | |||
| import { setOffers, setOffer } from "../actions/offers/offersActions"; | |||
| function* fetchOffers() { | |||
| try { | |||
| @@ -13,10 +13,12 @@ function* fetchOffers() { | |||
| } | |||
| } | |||
| function* fetchOneOffer() { | |||
| function* fetchOneOffer(payload) { | |||
| try { | |||
| const data = yield call(attemptFetchOneOffer) | |||
| console.log(data); | |||
| console.log(payload); | |||
| const data = yield call(attemptFetchOneOffer, payload) | |||
| //console.log(data.data); | |||
| yield put(setOffer(data.data)) | |||
| } catch (e) { | |||
| console.log(e); | |||
| } | |||