| @@ -13,6 +13,7 @@ import { | |||
| REGISTER_SUCCESSFUL_PAGE, | |||
| RESET_PASSWORD_PAGE, | |||
| CREATE_OFFER_PAGE, | |||
| ITEM_DETAILS_PAGE | |||
| } from './constants/pages'; | |||
| import LoginPage from './pages/LoginPage/LoginPage'; | |||
| import HomePage from './pages/HomePage/HomePageMUI'; | |||
| @@ -25,6 +26,7 @@ import Register from './pages/RegisterPages/Register/Register'; | |||
| import RegisterSuccessful from './pages/RegisterPages/RegisterSuccessful.js/RegisterSuccessful'; | |||
| import ResetPasswordPage from './pages/ResetPasswordPage/ResetPasswordPage'; | |||
| import CreateOffer from './pages/CreateOffer/CreateOffer'; | |||
| import ItemDetailsPage from './pages/ItemDetailsPage/ItemDetailsPageMUI'; | |||
| const AppRoutes = () => { | |||
| @@ -40,6 +42,7 @@ const AppRoutes = () => { | |||
| <Route path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} /> | |||
| <Route path={RESET_PASSWORD_PAGE} component={ResetPasswordPage}/> | |||
| <Route path={CREATE_OFFER_PAGE} component={CreateOffer}/> | |||
| <Route path={ITEM_DETAILS_PAGE} component={ItemDetailsPage} /> | |||
| <PrivateRoute | |||
| exact | |||
| @@ -1,4 +1,4 @@ | |||
| <svg width="22" height="16" viewBox="0 0 22 16" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||
| <path d="M13.9999 7.99994C13.9999 8.79557 13.6838 9.55862 13.1212 10.1212C12.5586 10.6838 11.7956 10.9999 10.9999 10.9999C10.2043 10.9999 9.44126 10.6838 8.87866 10.1212C8.31606 9.55862 8 8.79557 8 7.99994C8 7.20431 8.31606 6.44126 8.87866 5.87866C9.44126 5.31606 10.2043 5 10.9999 5C11.7956 5 12.5586 5.31606 13.1212 5.87866C13.6838 6.44126 13.9999 7.20431 13.9999 7.99994V7.99994Z" stroke="#5A3984" stroke-linecap="round" stroke-linejoin="round"/> | |||
| <path d="M1.45898 7.99986C2.73296 3.94294 6.52388 1 11.0008 1C15.4787 1 19.2686 3.94294 20.5426 7.99986C19.2686 12.0568 15.4787 14.9997 11.0008 14.9997C6.52388 14.9997 2.73296 12.0568 1.45898 7.99986Z" stroke="#5A3984" stroke-linecap="round" stroke-linejoin="round"/> | |||
| <svg width="22" height="16" viewBox="0 0 22 16" fill="none" stroke="black" xmlns="http://www.w3.org/2000/svg"> | |||
| <path d="M13.9999 7.99994C13.9999 8.79557 13.6838 9.55862 13.1212 10.1212C12.5586 10.6838 11.7956 10.9999 10.9999 10.9999C10.2043 10.9999 9.44126 10.6838 8.87866 10.1212C8.31606 9.55862 8 8.79557 8 7.99994C8 7.20431 8.31606 6.44126 8.87866 5.87866C9.44126 5.31606 10.2043 5 10.9999 5C11.7956 5 12.5586 5.31606 13.1212 5.87866C13.6838 6.44126 13.9999 7.20431 13.9999 7.99994V7.99994Z" stroke-linecap="round" stroke-linejoin="round"/> | |||
| <path d="M1.45898 7.99986C2.73296 3.94294 6.52388 1 11.0008 1C15.4787 1 19.2686 3.94294 20.5426 7.99986C19.2686 12.0568 15.4787 14.9997 11.0008 14.9997C6.52388 14.9997 2.73296 12.0568 1.45898 7.99986Z" stroke-linecap="round" stroke-linejoin="round"/> | |||
| </svg> | |||
| @@ -0,0 +1,4 @@ | |||
| <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||
| <path d="M3.33366 3.33334H16.667C17.5837 3.33334 18.3337 4.08334 18.3337 5.00001V15C18.3337 15.9167 17.5837 16.6667 16.667 16.6667H3.33366C2.41699 16.6667 1.66699 15.9167 1.66699 15V5.00001C1.66699 4.08334 2.41699 3.33334 3.33366 3.33334Z" stroke="#FEB005" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/> | |||
| <path d="M18.3337 5L10.0003 10.8333L1.66699 5" stroke="#FEB005" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/> | |||
| </svg> | |||
| @@ -0,0 +1,4 @@ | |||
| <svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||
| <path d="M3.66634 2.75H18.333C18.8192 2.75 19.2856 2.94315 19.6294 3.28697C19.9732 3.63079 20.1663 4.0971 20.1663 4.58333V10.0833C20.1663 12.5145 19.2006 14.8461 17.4815 16.5651C15.7624 18.2842 13.4308 19.25 10.9997 19.25C9.79589 19.25 8.60389 19.0129 7.49174 18.5522C6.37959 18.0916 5.36907 17.4163 4.51786 16.5651C2.79878 14.8461 1.83301 12.5145 1.83301 10.0833V4.58333C1.83301 4.0971 2.02616 3.63079 2.36998 3.28697C2.7138 2.94315 3.18011 2.75 3.66634 2.75V2.75Z" stroke="#C4C4C4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/> | |||
| <path d="M7.33301 9.16666L10.9997 12.8333L14.6663 9.16666" stroke="#C4C4C4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/> | |||
| </svg> | |||
| @@ -0,0 +1,17 @@ | |||
| import React from 'react' | |||
| import { ArrowContainer, ArrowIcon } from "./ArrowButton.styled" | |||
| import PropTypes from "prop-types"; | |||
| export const ArrowButton = (props) => { | |||
| return <ArrowContainer onClick={props.onClick} className={props.className} disabled={props.disabled}> | |||
| <ArrowIcon side={props.side} disabled={props.disabled}/> | |||
| </ArrowContainer> | |||
| } | |||
| ArrowButton.propTypes = { | |||
| onClick: PropTypes.func, | |||
| className: PropTypes.string, | |||
| side:PropTypes.string, | |||
| disabled:PropTypes.bool, | |||
| } | |||
| @@ -0,0 +1,53 @@ | |||
| import IconButton from "../../IconButton/IconButton" | |||
| import {ReactComponent as DownArrow} from "../../../assets/images/svg/arrow-down.svg" | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../themes"; | |||
| export const ArrowIcon = styled(DownArrow)` | |||
| ${props => props.side === 'left' && ` | |||
| transform: rotate(180deg); | |||
| `} | |||
| width: 18px; | |||
| height: 18px; | |||
| & path { | |||
| ${props => props.disabled && ` | |||
| stroke: ${selectedTheme.iconStrokeDisabledColor} | |||
| `} | |||
| } | |||
| ` | |||
| export const ArrowContainer = styled(IconButton)` | |||
| border: 1px solid ${selectedTheme.primaryPurple}; | |||
| border-radius: 100%; | |||
| min-width: 40px; | |||
| width: 40px; | |||
| height: 40px; | |||
| display: flex; | |||
| box-sizing: border-box; | |||
| cursor: pointer; | |||
| margin-top: auto; | |||
| margin-bottom: auto; | |||
| transition: 0.2s all ease; | |||
| &:hover { | |||
| background-color: ${selectedTheme.primaryPurple}; | |||
| & svg path { | |||
| stroke: white; | |||
| } | |||
| } | |||
| ${props => props.disabled && ` | |||
| border 1px solid ${selectedTheme.iconStrokeDisabledColor}; | |||
| &:hover { | |||
| background-color: inherit; | |||
| & svg path { | |||
| stroke: ${selectedTheme.iconStrokeDisabledColor}; | |||
| } | |||
| } | |||
| & svg path { | |||
| stroke: ${selectedTheme.iconStrokeDisabledColor}; | |||
| transition: 0.2s all ease; | |||
| } | |||
| `} | |||
| ` | |||
| @@ -1,5 +1,6 @@ | |||
| import { Box, IconButton } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../themes"; | |||
| export const IconButtonContainer = styled(Box)` | |||
| ` | |||
| @@ -13,4 +14,5 @@ export const IconButtonStyled = styled(IconButton)` | |||
| stroke: ${props.iconcolor}; | |||
| } | |||
| `} | |||
| border: ${props => props.border ? "1px solid " + selectedTheme.backgroundSponsoredColor : "none"} | |||
| ` | |||
| @@ -30,6 +30,7 @@ import StepProgress from "../../StepProgress/StepProgress"; | |||
| import { Label } from "../../CheckBox/Label"; | |||
| import FirstPartCreateOffer from "./FirstPart/FirstPartCreateOffer"; | |||
| import SecondPartCreateOffer from "./SecondPart/SecondPartCreateOffer"; | |||
| import ThirdPartCreateOffer from "./ThirdPart/ThirdPartCreateOffer"; | |||
| const CreateOffer = ({ history }) => { | |||
| const dispatch = useDispatch(); | |||
| @@ -76,20 +77,29 @@ const CreateOffer = ({ history }) => { | |||
| }; | |||
| const handleNext = (values) => { | |||
| setInformations({...values}); | |||
| setCurrentStep(prevState => prevState+1) | |||
| } | |||
| if (currentStep === 2) { | |||
| setInformations({ ...informations, images: [...values] }); | |||
| } else { | |||
| setInformations({ ...informations, ...values }); | |||
| } | |||
| setCurrentStep((prevState) => prevState + 1); | |||
| }; | |||
| return ( | |||
| <CreateOfferContainer> | |||
| <CreateOfferTitle component="h1" variant="h5"> | |||
| Nova Objava | |||
| {currentStep === 3 ? "Pregled" : "Nova Objava"} | |||
| </CreateOfferTitle> | |||
| <StepProgress current={currentStep} numberOfSteps={3} /> | |||
| {currentStep === 1 && <FirstPartCreateOffer handleNext={handleNext}/>} | |||
| {currentStep === 1 && <FirstPartCreateOffer handleNext={handleNext} />} | |||
| {currentStep === 2 && <SecondPartCreateOffer handleNext={handleNext} />} | |||
| {currentStep === 3 && ( | |||
| <ThirdPartCreateOffer | |||
| handleNext={handleNext} | |||
| informations={informations} | |||
| /> | |||
| )} | |||
| </CreateOfferContainer> | |||
| ); | |||
| }; | |||
| @@ -1,4 +1,4 @@ | |||
| import React from "react"; | |||
| import React, { useState } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { useFormik } from "formik"; | |||
| import { | |||
| @@ -15,8 +15,18 @@ import selectedTheme from "../../../../themes"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import Option from "../../../Select/Option/Option"; | |||
| import { SelectField } from "../CreateOffer.styled"; | |||
| import { useSelector } from "react-redux"; | |||
| const FirstPartCreateOffer = (props) => { | |||
| const [subcat, setSubcat] = useState([]); | |||
| const locations = useSelector((state) => state.locations.locations); | |||
| const categories = useSelector((state) => state.categories.categories); | |||
| const handleSubcategories = (category) => { | |||
| const filtered = categories.filter((cat) => cat.name === category); | |||
| setSubcat(filtered); | |||
| }; | |||
| const { t } = useTranslation(); | |||
| const handleSubmit = (values) => { | |||
| console.log(values); | |||
| @@ -26,15 +36,18 @@ const FirstPartCreateOffer = (props) => { | |||
| initialValues: { | |||
| nameOfProduct: "", | |||
| description: "", | |||
| category: "", | |||
| }, | |||
| validationSchema: Yup.object().shape({ | |||
| nameOfProduct: Yup.string().required(t("login.nameOfProductRequired")), | |||
| description: Yup.string().required(t("login.descriptionRequired")).min(8), | |||
| category: Yup.string().oneOf(["Automobili", "Audio", "Racunari"]), | |||
| }), | |||
| onSubmit: handleSubmit, | |||
| validateOnBlur: true, | |||
| enableReinitialize: true, | |||
| }); | |||
| return ( | |||
| <CreateOfferFormContainer component="form" onSubmit={formik.handleSubmit}> | |||
| {/* <Backdrop position="absolute" isLoading={isLoading} /> */} | |||
| @@ -71,26 +84,58 @@ const FirstPartCreateOffer = (props) => { | |||
| <FieldLabel leftText={"LOKACIJA"} /> | |||
| <SelectField defaultValue={1}> | |||
| <Option value={1}>Opcija 1</Option> | |||
| {locations.map((location, i) => { | |||
| return ( | |||
| <Option key={location._if} value={i + 1}> | |||
| {location.city} | |||
| </Option> | |||
| ); | |||
| })} | |||
| {/* <Option value={1}>Opcija 1</Option> | |||
| <Option value={2}>Opcija 2</Option> | |||
| <Option value={3}>Opcija 3</Option> | |||
| <Option value={4}>Opcija 4</Option> | |||
| <Option value={4}>Opcija 4</Option> */} | |||
| </SelectField> | |||
| <FieldLabel leftText={"KATEGORIJA"} /> | |||
| <SelectField defaultValue={1}> | |||
| <Option value={1}>Opcija 1</Option> | |||
| <SelectField | |||
| defaultValue={1} | |||
| onChange={(value) => { | |||
| formik.setFieldValue("category", value.target.value.name); | |||
| console.log(value.target); | |||
| }} | |||
| > | |||
| {categories.map((cat, i) => { | |||
| return ( | |||
| <Option | |||
| key={i} | |||
| value={cat} | |||
| onClick={() => handleSubcategories(cat.name)} | |||
| > | |||
| {cat.name} | |||
| </Option> | |||
| ); | |||
| })} | |||
| {/* <Option value={1}>Opcija 1</Option> | |||
| <Option value={2}>Opcija 2</Option> | |||
| <Option value={3}>Opcija 3</Option> | |||
| <Option value={4}>Opcija 4</Option> | |||
| <Option value={4}>Opcija 4</Option> */} | |||
| </SelectField> | |||
| <FieldLabel leftText={"PODKATEGORIJA"} /> | |||
| <SelectField defaultValue={1}> | |||
| <Option value={1}>Opcija 1</Option> | |||
| {subcat?.length > 0 && | |||
| subcat[0].subcategories.map((sub, i) => { | |||
| return ( | |||
| <Option key={i} value={i + 1}> | |||
| {sub.name} | |||
| </Option> | |||
| ); | |||
| })} | |||
| {/* <Option value={1}>Opcija 1</Option> | |||
| <Option value={2}>Opcija 2</Option> | |||
| <Option value={3}>Opcija 3</Option> | |||
| <Option value={4}>Opcija 4</Option> | |||
| <Option value={4}>Opcija 4</Option> */} | |||
| </SelectField> | |||
| <NextButton | |||
| @@ -50,13 +50,11 @@ export const FieldLabel = styled(Label)` | |||
| cursor: auto; | |||
| letter-spacing: 0.2px; | |||
| } | |||
| ` | |||
| `; | |||
| export const DescriptionField = styled(TextField)` | |||
| margin-bottom: 4px; | |||
| ` | |||
| export const TitleField = styled(TextField)` | |||
| ` | |||
| `; | |||
| export const TitleField = styled(TextField)``; | |||
| export const NextButton = styled(PrimaryButton)` | |||
| margin-top: 16px; | |||
| ` | |||
| `; | |||
| @@ -14,7 +14,7 @@ import { NextButton } from "../FirstPart/FirstPartCreateOffer.styled"; | |||
| import selectedTheme from "../../../../themes"; | |||
| import { conditionSelectEnum } from "../../../../enums/conditionEnum"; | |||
| const SecondPartCreateOffer = () => { | |||
| const SecondPartCreateOffer = (props) => { | |||
| const [images, setImages] = useState([null, null, null]); // 3 images | |||
| const setImage = (index, image) => { | |||
| console.log(images); | |||
| @@ -25,8 +25,12 @@ const SecondPartCreateOffer = () => { | |||
| }); | |||
| }; | |||
| const handleSubmit = () => { | |||
| props.handleNext(images); | |||
| }; | |||
| return ( | |||
| <CreateOfferFormContainer> | |||
| <CreateOfferFormContainer component="form" onSubmit={handleSubmit}> | |||
| <Scroller> | |||
| {images.map((item, index) => ( | |||
| <ImagePicker | |||
| @@ -70,7 +74,7 @@ const SecondPartCreateOffer = () => { | |||
| SecondPartCreateOffer.propTypes = { | |||
| children: PropTypes.node, | |||
| handleOffer: PropTypes.func, | |||
| handleNext: PropTypes.func, | |||
| }; | |||
| export default SecondPartCreateOffer; | |||
| @@ -46,9 +46,8 @@ export const Trash = styled(TrashIcon)` | |||
| cursor: pointer; | |||
| margin: auto; | |||
| width: 22px; | |||
| height: 22px; | |||
| height: 22px; | |||
| & path { | |||
| stroke: white; | |||
| } | |||
| `; | |||
| @@ -0,0 +1,121 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { NextButton } from "../FirstPart/FirstPartCreateOffer.styled"; | |||
| import selectedTheme from "../../../../themes"; | |||
| import { | |||
| CreateOfferFormContainer, | |||
| HeaderInfo, | |||
| HeaderItem, | |||
| HeaderItemIcon, | |||
| HeaderItemText, | |||
| HeaderOfferContainer, | |||
| HeaderPostDate, | |||
| OfferDetails, | |||
| OfferDetailsTitle, | |||
| OfferImage, | |||
| OfferDescriptionContainer, | |||
| OfferDescriptionTitle, | |||
| OfferDescription, | |||
| ButtonContainer, | |||
| } from "./ThirdPartCreateOffer.styled"; | |||
| import { ReactComponent as Category } from "../../../../assets/images/svg/category.svg"; | |||
| import { ReactComponent as Subcategory } from "../../../../assets/images/svg/subcategory.svg"; | |||
| import { ReactComponent as Quantity } from "../../../../assets/images/svg/quantity.svg"; | |||
| import { ReactComponent as Eye } from "../../../../assets/images/svg/eye-striked.svg"; | |||
| import HorizontalScroller from "../../../Scroller/HorizontalScroller"; | |||
| const ThirdPartCreateOffer = (props) => { | |||
| console.log(props.informations); | |||
| let date = new Date(); | |||
| return ( | |||
| <CreateOfferFormContainer> | |||
| <HeaderOfferContainer> | |||
| <HeaderInfo> | |||
| <HeaderItem> | |||
| <HeaderItemIcon | |||
| color={selectedTheme.iconStrokeColor} | |||
| component="span" | |||
| size="16px" | |||
| > | |||
| <Category width={"14px"} /> | |||
| </HeaderItemIcon> | |||
| <HeaderItemText>Automobili</HeaderItemText> | |||
| </HeaderItem> | |||
| <HeaderItem> | |||
| <HeaderItemIcon | |||
| color={selectedTheme.iconStrokeColor} | |||
| component="span" | |||
| size="16px" | |||
| > | |||
| <Subcategory width={"14px"} /> | |||
| </HeaderItemIcon> | |||
| <HeaderItemText>Novi</HeaderItemText> | |||
| </HeaderItem> | |||
| <HeaderItem> | |||
| <HeaderItemIcon | |||
| color={selectedTheme.iconStrokeColor} | |||
| component="span" | |||
| size="16px" | |||
| > | |||
| <Quantity width={"14px"} /> | |||
| </HeaderItemIcon> | |||
| <HeaderItemText>Novo</HeaderItemText> | |||
| </HeaderItem> | |||
| <HeaderItem> | |||
| <HeaderItemIcon | |||
| color={selectedTheme.iconStrokeColor} | |||
| component="span" | |||
| size="16px" | |||
| > | |||
| <Eye width={"14px"} /> | |||
| </HeaderItemIcon> | |||
| <HeaderItemText>45</HeaderItemText> | |||
| </HeaderItem> | |||
| </HeaderInfo> | |||
| <HeaderPostDate> | |||
| Objavljeno: | |||
| {" " + | |||
| `${date.getDate()}.${date.getMonth() + 1}.${date.getFullYear()}.`} | |||
| </HeaderPostDate> | |||
| </HeaderOfferContainer> | |||
| <OfferDetails> | |||
| <OfferDetailsTitle> | |||
| {props.informations.nameOfProduct} | |||
| </OfferDetailsTitle> | |||
| <HorizontalScroller> | |||
| <OfferImage src={props.informations[0] && props.informations[0]} /> | |||
| <OfferImage src={props.informations[1] && props.informations[1]} /> | |||
| <OfferImage src={props.informations[2] && props.informations[2]} /> | |||
| </HorizontalScroller> | |||
| <OfferDescriptionContainer> | |||
| <OfferDescriptionTitle>Opis:</OfferDescriptionTitle> | |||
| <OfferDescription>{props.informations.description}</OfferDescription> | |||
| </OfferDescriptionContainer> | |||
| </OfferDetails> | |||
| <ButtonContainer> | |||
| <NextButton | |||
| type="submit" | |||
| variant="contained" | |||
| height="48px" | |||
| width="350px" | |||
| buttoncolor={selectedTheme.primaryPurple} | |||
| textcolor="white" | |||
| // disabled={ | |||
| // formik.values.username.length === 0 || | |||
| // formik.values.password.length === 0 | |||
| // } | |||
| > | |||
| OBJAVI | |||
| </NextButton> | |||
| </ButtonContainer> | |||
| </CreateOfferFormContainer> | |||
| ); | |||
| }; | |||
| ThirdPartCreateOffer.propTypes = { | |||
| children: PropTypes.any, | |||
| handleNext: PropTypes.func, | |||
| informations: PropTypes.object, | |||
| }; | |||
| export default ThirdPartCreateOffer; | |||
| @@ -0,0 +1,86 @@ | |||
| import { Box, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../../themes"; | |||
| export const CreateOfferFormContainer = styled(Box)` | |||
| width: 650px; | |||
| padding-top: 20px; | |||
| margin-top: 20px; | |||
| `; | |||
| export const HeaderOfferContainer = styled(Box)` | |||
| display: flex; | |||
| justify-content: space-between; | |||
| `; | |||
| export const HeaderInfo = styled(Box)` | |||
| display: flex; | |||
| gap: 18px; | |||
| `; | |||
| export const HeaderItem = styled(Box)` | |||
| display: flex; | |||
| flex-direction: row; | |||
| align-items: center; | |||
| gap: 4px; | |||
| `; | |||
| export const HeaderItemIcon = styled(Box)` | |||
| display: flex; | |||
| align-items: center; | |||
| `; | |||
| export const HeaderItemText = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| font-size: 14px; | |||
| `; | |||
| export const HeaderPostDate = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| font-size: 12px; | |||
| `; | |||
| export const OfferDetails = styled(Box)` | |||
| display: flex; | |||
| flex-direction: column; | |||
| margin-top: 20px; | |||
| `; | |||
| export const OfferDetailsTitle = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryPurple}; | |||
| font-weight: 700; | |||
| font-size: 24px; | |||
| padding: 0 60px; | |||
| margin-bottom: 10px; | |||
| `; | |||
| export const OfferImage = styled.img` | |||
| width: 144px; | |||
| height: 144px; | |||
| margin-right: 10px; | |||
| object-fit: cover; | |||
| border-radius: 5px; | |||
| `; | |||
| export const OfferDescriptionContainer = styled(Box)` | |||
| display: flex; | |||
| flex-direction: column; | |||
| padding: 0 60px; | |||
| margin-top: 20px; | |||
| `; | |||
| export const OfferDescriptionTitle = styled(Box)` | |||
| font-family: "Open Sans"; | |||
| font-size: 12px; | |||
| `; | |||
| export const OfferDescription = styled(Box)` | |||
| font-family: "Open Sans"; | |||
| font-size: 16px; | |||
| `; | |||
| export const ButtonContainer = styled(Box)` | |||
| display: flex; | |||
| justify-content: center; | |||
| `; | |||
| @@ -32,16 +32,16 @@ const FilterCard = () => { | |||
| } else { | |||
| setIsDisabled(false); | |||
| } | |||
| }, [filters.selectedCategory]) | |||
| }, [filters.selectedCategory]); | |||
| const handleSelectCategory = (category) => { | |||
| filters.setSelectedCategory(category); | |||
| filters.setSelectedSubcategory(); | |||
| } | |||
| }; | |||
| const handleOpen = () => { | |||
| setIsOpened(prevState => !prevState); | |||
| } | |||
| setIsOpened((prevState) => !prevState); | |||
| }; | |||
| const handleFilters = () => { | |||
| filters.applyFilters(); | |||
| @@ -105,7 +105,11 @@ const FilterCard = () => { | |||
| <FilterCheckboxDropdown | |||
| searchPlaceholder={t("filters.location.placeholder")} | |||
| data={[...filters.locations]} | |||
| filters={[...filters.selectedLocations]} | |||
| filters={ | |||
| filters?.selectedLocations?.length > 0 | |||
| ? [filters.selectedLocations] | |||
| : [] | |||
| } | |||
| icon={<Location />} | |||
| title={t("filters.location.title")} | |||
| setItemsSelected={filters.setSelectedLocations} | |||
| @@ -0,0 +1,140 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| CheckButton, | |||
| ItemDetailsCardContainer, | |||
| OfferInfo, | |||
| Info, | |||
| PostDate, | |||
| InfoIcon, | |||
| InfoText, | |||
| InfoGroup, | |||
| OfferTitle, | |||
| OfferDescriptionText, | |||
| OfferDescriptionTitle, | |||
| Details, | |||
| OfferDetails, | |||
| } from "./ItemDetailsCard.styled"; | |||
| import { ReactComponent as Category } from "../../../assets/images/svg/category.svg"; | |||
| import { ReactComponent as Subcategory } from "../../../assets/images/svg/subcategory.svg"; | |||
| 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 HorizontalScroller from "../../Scroller/HorizontalScroller"; | |||
| import { ReactComponent as DummyImage1 } from "../../../assets/images/svg/dummyImages/offer-1.svg"; | |||
| const ItemDetailsCard = (props) => { | |||
| return ( | |||
| <ItemDetailsCardContainer | |||
| sponsored={props.sponsored.toString()} | |||
| halfwidth={props.halfwidth ? 1 : 0} | |||
| > | |||
| <OfferInfo> | |||
| <Info> | |||
| <InfoGroup> | |||
| <InfoIcon | |||
| color={selectedTheme.iconStrokeColor} | |||
| component="span" | |||
| size="16px" | |||
| > | |||
| <Category width={"14px"} /> | |||
| </InfoIcon> | |||
| <InfoText>{offer.category}</InfoText> | |||
| </InfoGroup> | |||
| <InfoGroup> | |||
| <InfoIcon | |||
| color={selectedTheme.iconStrokeColor} | |||
| component="span" | |||
| size="16px" | |||
| > | |||
| <Subcategory width={"14px"} /> | |||
| </InfoIcon> | |||
| <InfoText>{offer.subcategory}</InfoText> | |||
| </InfoGroup> | |||
| <InfoGroup> | |||
| <InfoIcon | |||
| color={selectedTheme.iconStrokeColor} | |||
| component="span" | |||
| size="16px" | |||
| > | |||
| <Quantity width={"22px"} height={"16px"} /> | |||
| </InfoIcon> | |||
| <InfoText>{offer.status}</InfoText> | |||
| </InfoGroup> | |||
| <InfoGroup> | |||
| <InfoIcon color={"black"} component="span" size="12px"> | |||
| <Eye width={"18px"} height={"20px"} /> | |||
| </InfoIcon> | |||
| <InfoText>{offer.numberOfViews}</InfoText> | |||
| </InfoGroup> | |||
| </Info> | |||
| <PostDate>Objavljeno: 04.04.2022</PostDate> | |||
| </OfferInfo> | |||
| <Details> | |||
| <OfferTitle>{offer.title}</OfferTitle> | |||
| <HorizontalScroller> | |||
| <DummyImage1 /> | |||
| <DummyImage1 /> | |||
| <DummyImage1 /> | |||
| <DummyImage1 /> | |||
| <DummyImage1 /> | |||
| <DummyImage1 /> | |||
| <DummyImage1 /> | |||
| <DummyImage1 /> | |||
| <DummyImage1 /> | |||
| </HorizontalScroller> | |||
| <OfferDetails> | |||
| <OfferDescriptionTitle>Opis:</OfferDescriptionTitle> | |||
| <OfferDescriptionText>{offer.description}</OfferDescriptionText> | |||
| </OfferDetails> | |||
| </Details> | |||
| {!props.halfwidth ? ( | |||
| <React.Fragment> | |||
| <CheckButton | |||
| variant={props.sponsored ? "contained" : "outlined"} | |||
| buttoncolor={selectedTheme.primaryPurple} | |||
| textcolor={props.sponsored ? "white" : selectedTheme.primaryPurple} | |||
| style={{ fontWeight: "600" }} | |||
| > | |||
| Trampi | |||
| </CheckButton> | |||
| </React.Fragment> | |||
| ) : ( | |||
| <></> | |||
| )} | |||
| {/* {props.image} | |||
| {props.title} | |||
| {props.description} | |||
| {props.category} | |||
| {props.author} | |||
| {props.location} | |||
| {props.quantity} | |||
| {props.package} | |||
| {props.numberOfViews} */} | |||
| </ItemDetailsCardContainer> | |||
| ); | |||
| }; | |||
| ItemDetailsCard.propTypes = { | |||
| children: PropTypes.node, | |||
| id: PropTypes.number, | |||
| title: PropTypes.string, | |||
| description: PropTypes.string, | |||
| category: PropTypes.string, | |||
| author: PropTypes.string, | |||
| location: PropTypes.string, | |||
| image: PropTypes.node, | |||
| quantity: PropTypes.number, | |||
| package: PropTypes.string, | |||
| numberOfViews: PropTypes.number, | |||
| halfwidth: PropTypes.bool, | |||
| sponsored: PropTypes.bool, | |||
| }; | |||
| ItemDetailsCard.defaultProps = { | |||
| halfwidth: false, | |||
| sponsored: false, | |||
| }; | |||
| export default ItemDetailsCard; | |||
| @@ -0,0 +1,165 @@ | |||
| import { Box, Container, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../themes"; | |||
| //import { IconButton } from "../../Buttons/IconButton/IconButton"; | |||
| import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton"; | |||
| import { Icon } from "../../Icon/Icon"; | |||
| export const ItemDetailsCardContainer = styled(Container)` | |||
| display: flex; | |||
| flex-direction: column; | |||
| width: ${(props) => (!props.halfwidth ? "100%" : "49%")}; | |||
| box-sizing: border-box; | |||
| margin: 10px 0; | |||
| border: 1px solid ${selectedTheme.borderNormal}; | |||
| background-color: ${(props) => | |||
| props.sponsored === "true" | |||
| ? selectedTheme.backgroundSponsoredColor | |||
| : "white"}; | |||
| border-radius: 4px; | |||
| padding: 18px; | |||
| max-width: 2000px; | |||
| position: relative; | |||
| `; | |||
| export const OfferImage = styled(Box)``; | |||
| export const OfferInfo = styled(Box)` | |||
| display: flex; | |||
| flex: 2; | |||
| flex-direction: row; | |||
| justify-content: space-between; | |||
| margin: 18px 0; | |||
| `; | |||
| export const InfoGroup = styled(Box)` | |||
| display: flex; | |||
| flex-direction: row; | |||
| align-items: center; | |||
| gap: 4px; | |||
| `; | |||
| export const PostDate = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| font-size: 12px; | |||
| color: ${selectedTheme.primaryText}; | |||
| `; | |||
| export const Info = styled(Box)` | |||
| display: flex; | |||
| gap: 18px; | |||
| `; | |||
| export const InfoIcon = styled(Box)` | |||
| display: flex; | |||
| align-items: center; | |||
| `; | |||
| export const InfoText = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| `; | |||
| export const OfferTitle = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| flex: 1; | |||
| color: ${selectedTheme.primaryPurple}; | |||
| font-weight: 700; | |||
| font-size: 24px; | |||
| padding: 0 72px; | |||
| `; | |||
| export const OfferAuthor = styled(Box)` | |||
| display: flex; | |||
| flex: 1; | |||
| flex-direction: column; | |||
| `; | |||
| export const OfferAuthorName = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| line-height: 22px; | |||
| font-size: 16px; | |||
| color: ${selectedTheme.primaryDarkText}; | |||
| `; | |||
| export const OfferLocation = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryText}; | |||
| line-height: 16px; | |||
| font-size: 12px; | |||
| `; | |||
| export const OfferDetails = styled(Box)` | |||
| display: flex; | |||
| flex-direction: column; | |||
| flex-wrap: ${(props) => (!props.halfwidth ? "no-wrap" : "wrap")}; | |||
| justify-content: space-between; | |||
| padding: 0 72px; | |||
| `; | |||
| export const OfferCategory = styled(Box)` | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryText}; | |||
| line-height: 16px; | |||
| font-size: 12px; | |||
| width: 33%; | |||
| `; | |||
| export const OfferPackage = styled(Box)` | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryText}; | |||
| line-height: 16px; | |||
| font-size: 12px; | |||
| width: 34%; | |||
| `; | |||
| export const OfferViews = styled(Box)` | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryText}; | |||
| line-height: 16px; | |||
| font-size: 12px; | |||
| width: 34%; | |||
| `; | |||
| export const OfferDescriptionTitle = styled(Box)` | |||
| font-family: "Open Sans"; | |||
| font-size: 12px; | |||
| color: ${selectedTheme.primaryDarkText}; | |||
| line-height: 16px; | |||
| `; | |||
| export const OfferDescriptionText = styled(Box)` | |||
| font-family: "Open Sans"; | |||
| font-size: 16px; | |||
| color: ${selectedTheme.primaryDarkText}; | |||
| line-height: 22px; | |||
| max-width: calc(100% - 230px); | |||
| max-height: 120px; | |||
| overflow: hidden; | |||
| display: -webkit-box; | |||
| -webkit-line-clamp: 5; | |||
| -webkit-box-orient: vertical; | |||
| `; | |||
| export const OfferDescription = styled(Box)` | |||
| flex: 3; | |||
| `; | |||
| export const Line = styled(Box)` | |||
| border-left: 1px solid rgba(0, 0, 0, 0.15); | |||
| height: 100px; | |||
| width: 0; | |||
| margin: auto 0; | |||
| `; | |||
| export const DetailIcon = styled(Icon)` | |||
| & svg { | |||
| width: 14px; | |||
| position: relative; | |||
| top: -1px; | |||
| } | |||
| `; | |||
| export const DetailText = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryText}; | |||
| line-height: 16px; | |||
| font-size: 12px; | |||
| position: relative; | |||
| top: -2px; | |||
| left: 3px; | |||
| `; | |||
| export const CheckButton = styled(PrimaryButton)` | |||
| width: 180px; | |||
| height: 48px; | |||
| position: absolute; | |||
| bottom: 9px; | |||
| right: 9px; | |||
| &:hover button { | |||
| background-color: ${selectedTheme.primaryPurple} !important; | |||
| color: white !important; | |||
| } | |||
| `; | |||
| export const Details = styled(Box)` | |||
| display: flex; | |||
| flex-direction: column; | |||
| gap: 12px; | |||
| `; | |||
| @@ -0,0 +1,36 @@ | |||
| import React from "react" | |||
| import {ReactComponent as DummyImage1 } from "../../../assets/images/svg/dummyImages/offer-1.svg" | |||
| export const Offer = { | |||
| id: 0, | |||
| title: "Vino", | |||
| category: "Hrana i pice", | |||
| subcategory:"Farbe", | |||
| status:"novo", | |||
| quantity:150, | |||
| numberOfViews:45, | |||
| description: "Vinarija Aleksić osnovana je u Vranju 2006. godine, otvorivši time put oživljavanju vinogradarstva na jugu Srbije.Vinarija Aleksić osnovana je u Vranju 2006. godine, otvorivši time put oživljavanju vinogradarstva na jugu Srbije.Vinarija Aleksić osnovana je u Vranju 2006. godine, otvorivši time put oživljavanju vinogradarstva na jugu Srbije.Vinarija Aleksić osnovana je u Vranju 2006. godine, otvorivši time put oživljavanju vinogradarstva na jugu Srbije.", | |||
| images: [ | |||
| { | |||
| id:0, | |||
| image: <DummyImage1 /> | |||
| }, | |||
| { | |||
| id:1, | |||
| image: <DummyImage1 /> | |||
| }, | |||
| { | |||
| id:2, | |||
| image: <DummyImage1 /> | |||
| }, | |||
| { | |||
| id:3, | |||
| image: <DummyImage1 /> | |||
| }, | |||
| { | |||
| id:4, | |||
| image: <DummyImage1 /> | |||
| }, | |||
| ], | |||
| postDate: "12.04.2022", | |||
| } | |||
| @@ -24,8 +24,14 @@ import { ReactComponent as Category } from "../../../assets/images/svg/category. | |||
| import { ReactComponent as Eye } from "../../../assets/images/svg/eye-striked.svg"; | |||
| import { ReactComponent as Message } from "../../../assets/images/svg/mail.svg"; | |||
| 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}`) | |||
| } | |||
| return ( | |||
| <OfferCardContainer sponsored={props.offer.pinned.toString()} halfwidth={props.halfwidth ? 1 : 0}> | |||
| <OfferImage src={props.offer.images[0]}></OfferImage> | |||
| @@ -63,6 +69,7 @@ const OfferCard = (props) => { | |||
| buttoncolor={selectedTheme.primaryPurple} | |||
| textcolor={props.sponsored ? "white" : selectedTheme.primaryPurple} | |||
| style={{fontWeight: "600"}} | |||
| onClick = {routeToItem} | |||
| > | |||
| Pogledaj proizvod | |||
| </CheckButton> | |||
| @@ -1,7 +1,7 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../themes"; | |||
| import {ReactComponent as Plus} from "../../assets/images/svg/plus.svg"; | |||
| import { ReactComponent as Plus } from "../../assets/images/svg/plus.svg"; | |||
| export const ImagePickerContainer = styled(Box)` | |||
| flex: 1; | |||
| @@ -41,27 +41,29 @@ export const ImagePickerContainer = styled(Box)` | |||
| &:last-of-type { | |||
| margin-right: 0; | |||
| } | |||
| ${props => props.hasImage && ` | |||
| ${(props) => | |||
| props.hasImage && | |||
| ` | |||
| background-image: none; | |||
| border: 1px solid ${selectedTheme.primaryPurple}; | |||
| `} | |||
| `; | |||
| export const AddIcon = styled(Plus)` | |||
| margin: auto; | |||
| ` | |||
| margin: auto; | |||
| `; | |||
| export const AddFile = styled.input` | |||
| display: none; | |||
| ` | |||
| display: none; | |||
| `; | |||
| export const ImageUploaded = styled.img` | |||
| width: 216px; | |||
| height: 144px; | |||
| object-fit: scale-down; | |||
| ` | |||
| width: 216px; | |||
| height: 144px; | |||
| object-fit: scale-down; | |||
| `; | |||
| export const Tooltip = styled(Box)` | |||
| background-color: rgba(255, 255, 255, 0.5); | |||
| width: 100px; | |||
| height: 100px; | |||
| position: absolute; | |||
| left: 0; | |||
| top: 0; | |||
| ` | |||
| background-color: rgba(255, 255, 255, 0.5); | |||
| width: 100px; | |||
| height: 100px; | |||
| position: absolute; | |||
| left: 0; | |||
| top: 0; | |||
| `; | |||
| @@ -0,0 +1,44 @@ | |||
| import React from 'react'; | |||
| import PropTypes from "prop-types"; | |||
| import { useHistory } from "react-router-dom"; | |||
| //import { IconButton } from "../../Buttons/IconButton/IconButton"; | |||
| import { HeaderContainer, HeaderText, ButtonContainer } from './Header.styled'; | |||
| import { ArrowButton } from '../../Buttons/ArrowButton/ArrowButton'; | |||
| // const DownArrow = (props) => ( | |||
| // <IconStyled {...props}> | |||
| // <Down /> | |||
| // </IconStyled> | |||
| // ); | |||
| const Header = () => { | |||
| const history = useHistory(); | |||
| const handleBackButton = () => { | |||
| history.push('/home'); | |||
| }; | |||
| return ( | |||
| <HeaderContainer onClick={handleBackButton}> | |||
| <ButtonContainer> | |||
| <ArrowButton side={"left"}></ArrowButton> | |||
| <HeaderText>Nazad na objave</HeaderText> | |||
| </ButtonContainer> | |||
| </HeaderContainer> | |||
| ); | |||
| }; | |||
| Header.propTypes = { | |||
| children: PropTypes.node, | |||
| setIsGrid: PropTypes.func, | |||
| isGrid: PropTypes.bool, | |||
| filters: PropTypes.array, | |||
| category: PropTypes.string, | |||
| }; | |||
| Header.defaultProps = { | |||
| isGrid: false, | |||
| }; | |||
| export default Header; | |||
| @@ -0,0 +1,22 @@ | |||
| import { Box, Link, Typography} from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../themes"; | |||
| export const HeaderContainer = styled(Box)` | |||
| margin-top: 20px; | |||
| ` | |||
| export const ButtonContainer = styled(Link)` | |||
| width:fit-content; | |||
| cursor:pointer; | |||
| display: flex; | |||
| justify-content: start; | |||
| align-items:center; | |||
| gap:12px; | |||
| ` | |||
| export const HeaderText = styled(Typography) ` | |||
| font-family: "Open Sans"; | |||
| line-height: 22px; | |||
| font-size: 16px; | |||
| color: ${selectedTheme.primaryPurple}; | |||
| text-decoration: underline; | |||
| ` | |||
| @@ -0,0 +1,19 @@ | |||
| import React from 'react'; | |||
| import Header from "./Header/Header"; | |||
| import { ItemDetailsContainer } from './ItemDetails.styled'; | |||
| import ItemDetailsCard from "../Cards/ItemDetailsCard/ItemDetailsCard"; | |||
| import ItemDetailsHeaderCard from "./ItemDetailsHeaderCard/ItemDetailsHeaderCard"; | |||
| const ItemDetails = () => { | |||
| return ( | |||
| <ItemDetailsContainer> | |||
| <Header/> | |||
| <ItemDetailsHeaderCard /> | |||
| <ItemDetailsCard/> | |||
| </ItemDetailsContainer> | |||
| ) | |||
| } | |||
| export default ItemDetails; | |||
| @@ -0,0 +1,6 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const ItemDetailsContainer = styled(Box)` | |||
| `; | |||
| @@ -0,0 +1,90 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| DetailIcon, | |||
| DetailText, | |||
| MessageIcon, | |||
| OfferDetails, | |||
| OfferImage, | |||
| OfferTitle, | |||
| DetailContainer, | |||
| HeaderTop, | |||
| HeaderDetails, | |||
| BottomDetails, | |||
| StatusText | |||
| } from "./ItemDetailsHeaderCard.styled"; | |||
| import { ItemDetailsHeaderContainer } from "./ItemDetailsHeaderCard.styled"; | |||
| import { ReactComponent as Category } from "../../../assets/images/svg/category.svg"; | |||
| //import { ReactComponent as Quantity } from "../../../assets/images/svg/quantity.svg"; | |||
| //import { ReactComponent as Eye } from "../../../assets/images/svg/eye-striked.svg"; | |||
| import { ReactComponent as PIB} from "../../../assets/images/svg/pib.svg"; | |||
| import { ReactComponent as MessageColor } from "../../../assets/images/svg/mailColor.svg"; | |||
| import selectedTheme from "../../../themes"; | |||
| import { Author as author } from "../MockupdataDetails"; | |||
| const ItemDetailsHeaderCard = (props) => { | |||
| return ( | |||
| <ItemDetailsHeaderContainer sponsored={props.sponsored.toString()} halfwidth={props.halfwidth ? 1 : 0}> | |||
| <HeaderTop> | |||
| <OfferImage>{author.image}</OfferImage> | |||
| <OfferDetails> | |||
| <OfferTitle>{author.title}</OfferTitle> | |||
| <DetailContainer> | |||
| <DetailIcon color={selectedTheme.iconStrokeColor} component="span" size="22px"> | |||
| <PIB width={"22px"} /> | |||
| </DetailIcon> | |||
| <DetailText>PIB - {author.pib}</DetailText> | |||
| </DetailContainer> | |||
| <DetailContainer> | |||
| <DetailIcon color={selectedTheme.iconStrokeColor} component="span" size="22px"> | |||
| <Category width={"22px"} /> | |||
| </DetailIcon> | |||
| <DetailText>{author.location}</DetailText> | |||
| </DetailContainer> | |||
| </OfferDetails> | |||
| <MessageIcon> | |||
| <MessageColor /> | |||
| </MessageIcon> | |||
| </HeaderTop> | |||
| <HeaderDetails> | |||
| <BottomDetails> | |||
| <StatusText> | |||
| <b>{author.numberOfOffers}</b> objava | |||
| </StatusText> | |||
| <StatusText> | |||
| <b>{author.numberOfViews}</b> ukupnih pregleda | |||
| </StatusText> | |||
| <StatusText> | |||
| <b>{author.successSwapsProcent}</b> uspesnih trampi | |||
| </StatusText> | |||
| <StatusText> | |||
| <b>{author.goodCommunicationProcent}</b> korektna komunikacija | |||
| </StatusText> | |||
| </BottomDetails> | |||
| </HeaderDetails> | |||
| </ItemDetailsHeaderContainer> | |||
| ); | |||
| }; | |||
| ItemDetailsHeaderCard.propTypes = { | |||
| children: PropTypes.node, | |||
| id: PropTypes.number, | |||
| title: PropTypes.string, | |||
| description: PropTypes.string, | |||
| category: PropTypes.string, | |||
| author: PropTypes.string, | |||
| location: PropTypes.string, | |||
| image: PropTypes.node, | |||
| quantity: PropTypes.number, | |||
| package: PropTypes.string, | |||
| numberOfViews: PropTypes.number, | |||
| halfwidth: PropTypes.bool, | |||
| sponsored: PropTypes.bool, | |||
| }; | |||
| ItemDetailsHeaderCard.defaultProps = { | |||
| halfwidth: false, | |||
| sponsored: false, | |||
| }; | |||
| export default ItemDetailsHeaderCard; | |||
| @@ -0,0 +1,186 @@ | |||
| import { Box, Grid, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import selectedTheme from "../../../themes"; | |||
| import { IconButton } from "../../Buttons/IconButton/IconButton"; | |||
| import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton"; | |||
| import { Icon } from "../../Icon/Icon"; | |||
| export const ItemDetailsHeaderContainer = styled(Box)` | |||
| display: flex; | |||
| flex-direction: column; | |||
| width: ${(props) => (!props.halfwidth ? "100%" : "49%")}; | |||
| box-sizing: border-box; | |||
| margin: 10px 0; | |||
| background-color: ${(props) => | |||
| props.sponsored === 'true' ? selectedTheme.backgroundSponsoredColor : "white"}; | |||
| border-radius: 4px; | |||
| border: 1px solid ${selectedTheme.borderNormal}; | |||
| max-width: 2000px; | |||
| position: relative; | |||
| `; | |||
| export const DetailContainer = styled(Box)` | |||
| display: flex; | |||
| flex-direction: row; | |||
| align-items: center; | |||
| gap:7px; | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryText}; | |||
| line-height: 16px; | |||
| font-size: 12px; | |||
| `; | |||
| export const HeaderTop = styled(Box)` | |||
| display:flex; | |||
| flex-direction: row; | |||
| padding:18px; | |||
| gap:18px; | |||
| `; | |||
| export const HeaderDetails = styled(Box)` | |||
| background-color: ${selectedTheme.primaryIconBackgroundColor}; | |||
| `; | |||
| export const BottomDetails = styled(Box)` | |||
| max-width:fit-content; | |||
| display: grid; | |||
| grid-template-columns: repeat(2, 1fr); | |||
| grid-template-rows: repeat(2, 1fr); | |||
| grid-column-gap: 12px; | |||
| grid-row-gap: 12px; | |||
| padding: 18px; | |||
| `; | |||
| export const OfferImage = styled(Box)` | |||
| border-radius: 50%; | |||
| `; | |||
| export const OfferInfo = styled(Box)` | |||
| display: flex; | |||
| flex: 2; | |||
| flex-direction: column; | |||
| justify-content: space-between; | |||
| margin-left: 18px; | |||
| `; | |||
| export const OfferTitle = styled(Typography)` | |||
| margin-bottom:12px; | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryPurple}; | |||
| font-weight: 700; | |||
| font-size: 24px; | |||
| `; | |||
| export const OfferAuthor = styled(Box)` | |||
| display: flex; | |||
| flex: 1; | |||
| flex-direction: column; | |||
| `; | |||
| export const OfferAuthorName = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| line-height: 22px; | |||
| font-size: 16px; | |||
| color: ${selectedTheme.primaryDarkText}; | |||
| `; | |||
| export const OfferLocation = styled(Box)` | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryText}; | |||
| line-height: 16px; | |||
| font-size: 12px; | |||
| `; | |||
| export const OfferPIB = styled(Box)` | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryText}; | |||
| line-height: 16px; | |||
| font-size: 12px; | |||
| `; | |||
| export const OfferDetails = styled(Box)` | |||
| display: flex; | |||
| flex-direction: column; | |||
| flex-wrap: ${(props) => (!props.halfwidth ? "no-wrap" : "wrap")}; | |||
| justify-content: start; | |||
| `; | |||
| export const StatusText = styled(Grid)` | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryText}; | |||
| ` | |||
| export const OfferCategory = styled(Box)` | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryText}; | |||
| line-height: 16px; | |||
| font-size: 12px; | |||
| width: 33%; | |||
| `; | |||
| export const OfferPackage = styled(Box)` | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryText}; | |||
| line-height: 16px; | |||
| font-size: 12px; | |||
| width: 34%; | |||
| `; | |||
| export const OfferViews = styled(Box)` | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryText}; | |||
| line-height: 16px; | |||
| font-size: 12px; | |||
| width: 34%; | |||
| `; | |||
| export const OfferDescriptionTitle = styled(Box)` | |||
| font-family: "Open Sans"; | |||
| font-size: 12px; | |||
| color: ${selectedTheme.primaryDarkText}; | |||
| line-height: 16px; | |||
| `; | |||
| export const OfferDescriptionText = styled(Box)` | |||
| font-family: "Open Sans"; | |||
| font-size: 16px; | |||
| color: ${selectedTheme.primaryDarkText}; | |||
| line-height: 22px; | |||
| max-width: calc(100% - 230px); | |||
| max-height: 120px; | |||
| overflow: hidden; | |||
| display: -webkit-box; | |||
| -webkit-line-clamp: 5; | |||
| -webkit-box-orient: vertical; | |||
| `; | |||
| export const OfferDescription = styled(Box)` | |||
| flex: 3; | |||
| margin: auto 0; | |||
| padding-left: 35px; | |||
| `; | |||
| export const Line = styled(Box)` | |||
| border-left: 1px solid rgba(0, 0, 0, 0.15); | |||
| height: 100px; | |||
| width: 0; | |||
| margin: auto 0; | |||
| `; | |||
| export const DetailIcon = styled(Icon)` | |||
| display:flex; | |||
| align-items:center; | |||
| & svg { | |||
| width: 22px; | |||
| position: relative; | |||
| } | |||
| `; | |||
| export const DetailText = styled(Typography)` | |||
| font-family: "Open Sans"; | |||
| color: ${selectedTheme.primaryText}; | |||
| line-height: 16px; | |||
| font-size: 16px; | |||
| position: relative; | |||
| `; | |||
| export const CheckButton = styled(PrimaryButton)` | |||
| width: 180px; | |||
| height: 48px; | |||
| position: absolute; | |||
| bottom: 9px; | |||
| right: 9px; | |||
| &:hover button { | |||
| background-color: ${selectedTheme.primaryPurple} !important; | |||
| color: white !important; | |||
| } | |||
| `; | |||
| export const MessageIcon = styled(IconButton)` | |||
| width: 40px; | |||
| height: 40px; | |||
| position: absolute; | |||
| top: 10px; | |||
| right: 10px; | |||
| background-color: ${selectedTheme.primaryPurple}; | |||
| border-radius: 100%; | |||
| padding-top: 2px; | |||
| text-align: center; | |||
| `; | |||
| @@ -0,0 +1,59 @@ | |||
| import React from 'react' | |||
| import {ReactComponent as DummyImage1 } from "../../assets/images/svg/dummyImages/offer-1.svg" | |||
| import {ReactComponent as DummyAuthorImage1} from "../../assets/images/svg/dummyImages/DummyAuthorImage1.svg" | |||
| // import {ReactComponent as DummyImage2 } from "../../assets/images/svg/dummyImages/offer-2.svg" | |||
| // import {ReactComponent as DummyImage3 } from "../../assets/images/svg/dummyImages/offer-3.svg" | |||
| // import {ReactComponent as DummyImage4 } from "../../assets/images/svg/dummyImages/offer-4.svg" | |||
| export const packageEnum = { | |||
| package: "PACKAGE", | |||
| palette: "PALETTE", | |||
| piece: "PIECE" | |||
| } | |||
| export const Author = { | |||
| id: 0, | |||
| image: <DummyAuthorImage1 />, | |||
| title: "Women's Beauty House", | |||
| pib: 123456789, | |||
| location: "Nis, Serbia", | |||
| numberOfOffers: 9, | |||
| numberOfViews: 1200, | |||
| successSwapsProcent: "75%", | |||
| goodCommunicationProcent: "90%", | |||
| } | |||
| export const Offer = { | |||
| id: 0, | |||
| title: "Vino", | |||
| category: "Hrana i pice", | |||
| subcategory:"Farbe", | |||
| status:"novo", | |||
| quantity:150, | |||
| numberOfViews:45, | |||
| description: "Vinarija Aleksić osnovana je u Vranju 2006. godine, otvorivši time put oživljavanju vinogradarstva na jugu Srbije.Vinarija Aleksić osnovana je u Vranju 2006. godine, otvorivši time put oživljavanju vinogradarstva na jugu Srbije.Vinarija Aleksić osnovana je u Vranju 2006. godine, otvorivši time put oživljavanju vinogradarstva na jugu Srbije.Vinarija Aleksić osnovana je u Vranju 2006. godine, otvorivši time put oživljavanju vinogradarstva na jugu Srbije.", | |||
| images: [ | |||
| { | |||
| id:0, | |||
| image: <DummyImage1 /> | |||
| }, | |||
| { | |||
| id:1, | |||
| image: <DummyImage1 /> | |||
| }, | |||
| { | |||
| id:2, | |||
| image: <DummyImage1 /> | |||
| }, | |||
| { | |||
| id:3, | |||
| image: <DummyImage1 /> | |||
| }, | |||
| { | |||
| id:4, | |||
| image: <DummyImage1 /> | |||
| }, | |||
| ], | |||
| package: packageEnum.package, | |||
| postDate: "12.04.2022", | |||
| } | |||
| @@ -2,10 +2,9 @@ import React, { useRef, useState } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| HorizontalScrollerContainer, | |||
| Arrow, | |||
| ListContainer, | |||
| ArrowIcon, | |||
| } from "./HorizontalScroller.styled"; | |||
| import { ArrowButton } from "../Buttons/ArrowButton/ArrowButton"; | |||
| const HorizontalScroller = (props) => { | |||
| const scrollRef = useRef(null); | |||
| @@ -55,10 +54,12 @@ const HorizontalScroller = (props) => { | |||
| scrollRef.current.scrollBy({ left: -50, behaviour: "smooth" }); | |||
| }; | |||
| return ( | |||
| <HorizontalScrollerContainer style={props.containerStyle} className={props.className}> | |||
| <Arrow onClick={handleLeft} disabled={isDisabledLeftButton}> | |||
| <ArrowIcon side={"left"} /> | |||
| </Arrow> | |||
| <HorizontalScrollerContainer style={props.containerStyle}> | |||
| <ArrowButton | |||
| onClick={handleLeft} | |||
| disabled={isDisabledLeftButton} | |||
| side={"left"} | |||
| ></ArrowButton> | |||
| <ListContainer | |||
| innerRef={scrollRef} | |||
| style={props.listStyle} | |||
| @@ -66,9 +67,11 @@ const HorizontalScroller = (props) => { | |||
| > | |||
| {props.children} | |||
| </ListContainer> | |||
| <Arrow onClick={handleRight} disabled={isDisabledRightButton}> | |||
| <ArrowIcon side={"right"} /> | |||
| </Arrow> | |||
| <ArrowButton | |||
| onClick={handleRight} | |||
| disabled={isDisabledRightButton} | |||
| side={"right"} | |||
| ></ArrowButton> | |||
| </HorizontalScrollerContainer> | |||
| ); | |||
| }; | |||
| @@ -1,8 +1,9 @@ | |||
| import { Box, Button } from "@mui/material"; | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import {ReactComponent as DownArrow} from "../../assets/images/svg/arrow-down.svg" | |||
| import selectedTheme from "../../themes"; | |||
| import ScrollContainer from 'react-indiana-drag-scroll' | |||
| import { IconButton } from "../Buttons/IconButton/IconButton"; | |||
| export const HorizontalScrollerContainer = styled(Box)` | |||
| @@ -12,7 +13,7 @@ export const HorizontalScrollerContainer = styled(Box)` | |||
| flex-wrap: nowrap; | |||
| overflow: hidden; | |||
| ` | |||
| export const Arrow = styled(Button)` | |||
| export const Arrow = styled(IconButton)` | |||
| border: 1px solid ${selectedTheme.primaryPurple}; | |||
| border-radius: 100%; | |||
| min-width: 40px; | |||
| @@ -0,0 +1,24 @@ | |||
| export default [{ | |||
| id: 0, | |||
| name: "Coca-Cola", | |||
| quote: "Odlična saradnja. Sve preporuke za kompaniju", | |||
| isGood: true, | |||
| isGoodCommunication: "DA", | |||
| isSuccessfulSwap: "DA" | |||
| } | |||
| ,{ | |||
| id: 1, | |||
| name: "Voda Vrnjci", | |||
| quote: "Sasvim korektna saradnja, rado bih ponovio poslovanje sa Vama.", | |||
| isGood: true, | |||
| isGoodCommunication: "DA", | |||
| isSuccessfulSwap: "DA" | |||
| } | |||
| ,{ | |||
| id: 2, | |||
| name: "Women's Beauty House", | |||
| quote: "Nismo se najbolje razumeli, ali generalno ok", | |||
| isGood: false, | |||
| isGoodCommunication: "NE", | |||
| isSuccessfulSwap: "NE" | |||
| }]; | |||
| @@ -0,0 +1,103 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { ReviewList, ReviewsBox } from "./UserReviewsCard.styled"; | |||
| import { | |||
| Avatar, | |||
| Grid, | |||
| ListItem, | |||
| ListItemAvatar, | |||
| Typography, | |||
| Divider, | |||
| } from "@mui/material"; | |||
| import Mockupdata from "./Mockupdata"; | |||
| import ThumbUpIcon from "@mui/icons-material/ThumbUp"; | |||
| import ThumbDownIcon from "@mui/icons-material/ThumbDown"; | |||
| import StarBorderIcon from "@mui/icons-material/StarBorder"; | |||
| import { PRIMARY_PURPLE_COLOR } from "../../constants/stylesConstants"; | |||
| const UserReviewsCard = (props) => { | |||
| var dataMockupdata = JSON.parse(JSON.stringify(Mockupdata)); | |||
| return ( | |||
| <> | |||
| <ReviewsBox> | |||
| <Grid | |||
| container | |||
| direction="row" | |||
| justifyContent="start" | |||
| alignItems="center" | |||
| sx={{ mb: 1.4 }} | |||
| > | |||
| <StarBorderIcon color="action" sx={{ mr: 0.9 }} /> | |||
| <Typography>{props.heading}</Typography> | |||
| </Grid> | |||
| <ReviewList> | |||
| {dataMockupdata.map((review) => ( | |||
| <> | |||
| <ListItem | |||
| alignItems="flex-start" | |||
| sx={{ alignItems: "center", mt: 2 }} | |||
| > | |||
| <ListItemAvatar sx={{ mt: 0 }}> | |||
| <Avatar alt={review.name} src="/static/images/avatar/1.jpg" /> | |||
| </ListItemAvatar> | |||
| <Typography sx={{ color: PRIMARY_PURPLE_COLOR }}> | |||
| <b>{review.name}</b> | |||
| </Typography> | |||
| </ListItem> | |||
| <Grid | |||
| container | |||
| direction="row" | |||
| justifyContent="start" | |||
| alignItems="center" | |||
| spacing={2} | |||
| sx={{ pl: 2, py: 2 }} | |||
| > | |||
| <Grid item xs={1}> | |||
| {review.isGood ? ( | |||
| <ThumbUpIcon color="success" /> | |||
| ) : ( | |||
| <ThumbDownIcon color="error" /> | |||
| )} | |||
| </Grid> | |||
| <Grid item xs={11}> | |||
| <Typography | |||
| sx={{ display: "inline" }} | |||
| component="span" | |||
| variant="body2" | |||
| color="text.primary" | |||
| > | |||
| "{review.quote}" | |||
| </Typography> | |||
| </Grid> | |||
| </Grid> | |||
| <Grid sx={{ pl: 2, pb: 2 }}> | |||
| <Typography variant="body2" sx={{ display: "block" }}> | |||
| Korektna komunikacija: <b>{review.isGoodCommunication}</b> | |||
| </Typography> | |||
| <Typography variant="body2" sx={{ display: "block" }}> | |||
| Uspešna trampa: <b>{review.isSuccessfulSwap}</b> | |||
| </Typography> | |||
| </Grid> | |||
| {review.id < dataMockupdata.length - 1 ? ( | |||
| <Divider variant="inset" component="li" sx={{ ml: 0 }} /> | |||
| ) : ( | |||
| <></> | |||
| )} | |||
| </> | |||
| ))} | |||
| </ReviewList> | |||
| </ReviewsBox> | |||
| </> | |||
| ); | |||
| }; | |||
| UserReviewsCard.propTypes = { | |||
| children: PropTypes.node, | |||
| heading: PropTypes.string, | |||
| }; | |||
| export default UserReviewsCard; | |||
| @@ -0,0 +1,31 @@ | |||
| import styledComponents from "styled-components"; | |||
| import { List, Box } from "@mui/material"; | |||
| //import { PRIMARY_PURPLE_COLOR, PRIMARY_YELLOW_COLOR } from '../../constants/stylesConstants'; | |||
| export const ReviewsBox = styledComponents(Box)` | |||
| width: 100%; | |||
| max-width: 360px; | |||
| position: fixed; | |||
| right: 0; | |||
| bottom: 0; | |||
| height: calc(100% - 90px); | |||
| `; | |||
| export const ReviewList = styledComponents(List)` | |||
| background: white; | |||
| padding: 2rem; | |||
| border-radius: 4px 0 0 4px; | |||
| height: 100%; | |||
| overflow-y: auto; | |||
| &::-webkit-scrollbar { | |||
| width: 5px; | |||
| } | |||
| &::-webkit-scrollbar-track { | |||
| background: #ddd; | |||
| } | |||
| &::-webkit-scrollbar-thumb { | |||
| background: #777; | |||
| } | |||
| scrollbar-width: thin; | |||
| scrollbar-color: #ddd; | |||
| `; | |||
| @@ -4,8 +4,9 @@ export const FORGOT_PASSWORD_PAGE = '/forgot-password'; | |||
| export const HOME_PAGE = '/home'; | |||
| export const ERROR_PAGE = '/error-page'; | |||
| export const NOT_FOUND_PAGE = '/not-found'; | |||
| export const FORGOT_PASSWORD_MAIL_SENT = '/forgot-password/mail-sent' | |||
| export const REGISTER_PAGE = "/register" | |||
| export const FORGOT_PASSWORD_MAIL_SENT = '/forgot-password/mail-sent'; | |||
| export const REGISTER_PAGE = "/register"; | |||
| export const REGISTER_SUCCESSFUL_PAGE = "/register/success"; | |||
| export const RESET_PASSWORD_PAGE = "/reset-password/:token" | |||
| export const CREATE_OFFER_PAGE = "/create-offer" | |||
| export const RESET_PASSWORD_PAGE = "/reset-password/:token"; | |||
| export const CREATE_OFFER_PAGE = "/create-offer"; | |||
| export const ITEM_DETAILS_PAGE = "/proizvodi/:idProizvod"; | |||
| @@ -88,6 +88,7 @@ export default { | |||
| terms: "Uslove Korišćenja", | |||
| success: 'Registracija Uspešna', | |||
| PIBTaken: "PIB je zauzet!", | |||
| PIBnoOfCharacters: "PIB mora imati 9 karaktera!", | |||
| welcome: 'Dobro došli na trampu, želimo vam uspešno trampovanje!', | |||
| }, | |||
| forgotPassword: { | |||
| @@ -0,0 +1,3 @@ | |||
| export default { | |||
| email: "", | |||
| }; | |||
| @@ -0,0 +1,4 @@ | |||
| export default { | |||
| email: "", | |||
| password: "", | |||
| }; | |||
| @@ -0,0 +1,4 @@ | |||
| export default { | |||
| mail: "", | |||
| password: "", | |||
| }; | |||
| @@ -0,0 +1,4 @@ | |||
| export default { | |||
| nameOfFirm: "", | |||
| PIB: "", | |||
| }; | |||
| @@ -0,0 +1,5 @@ | |||
| export default { | |||
| phoneNumber: "", | |||
| location: "", | |||
| website: "", | |||
| }; | |||
| @@ -0,0 +1,4 @@ | |||
| export default { | |||
| password: "", | |||
| passwordConfirm: "", | |||
| }; | |||
| @@ -0,0 +1,30 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { Content, RightCard, ItemDetailsLayoutContainer } from "./ItemDetailsLayout.styled"; | |||
| import { Grid } from "@mui/material"; | |||
| const ItemDetailsLayout = (props) => { | |||
| return ( | |||
| <ItemDetailsLayoutContainer> | |||
| {props.children} | |||
| <Grid container maxHeight="xl"> | |||
| <Content item xs={10} lg={9} xl={9.6} md={8} > | |||
| {props.content} | |||
| </Content> | |||
| <RightCard item xs={2} lg={3} xl={2.4} md={4} > | |||
| {props.rightCard} | |||
| </RightCard> | |||
| </Grid> | |||
| </ItemDetailsLayoutContainer> | |||
| ); | |||
| }; | |||
| ItemDetailsLayout.propTypes = { | |||
| children: PropTypes.node, | |||
| leftCard: PropTypes.node, | |||
| content: PropTypes.node, | |||
| rightCard: PropTypes.node, | |||
| }; | |||
| export default ItemDetailsLayout; | |||
| @@ -0,0 +1,20 @@ | |||
| import { Container, Grid } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const ItemDetailsLayoutContainer = styled(Container)` | |||
| padding-left: 60px; | |||
| padding-right: 0; | |||
| margin: 0; | |||
| width: 100%; | |||
| max-width: none; | |||
| display: flex; | |||
| flex: 1; | |||
| height: 100%; | |||
| ` | |||
| export const RightCard = styled(Grid)` | |||
| margin-top: 30px; | |||
| border-top-right-radius: 4px; | |||
| ` | |||
| export const Content = styled(Grid)` | |||
| ` | |||
| @@ -0,0 +1,17 @@ | |||
| import styled from "styled-components"; | |||
| import { Container, Grid } from "@mui/material"; | |||
| import selectedTheme from "../../themes"; | |||
| export const ItemDetailsPageContainer = styled(Container)` | |||
| padding: 0; | |||
| margin: 0; | |||
| height: 100%; | |||
| width: 100%; | |||
| max-width: none; | |||
| flex: 1; | |||
| display: flex; | |||
| flex-direction: column; | |||
| background-color: ${selectedTheme.offerBackgroundColor}; | |||
| `; | |||
| export const GridStyled = styled(Grid)` | |||
| `; | |||
| @@ -0,0 +1,84 @@ | |||
| import React, { useEffect } from "react"; | |||
| import Navbar from "../../components/MUI/NavbarComponent"; | |||
| import { ItemDetailsPageContainer } from "./ItemDetailsPage.styled"; | |||
| import { useDispatch } from "react-redux"; | |||
| import { logoutUser } from "../../store/actions/login/loginActions"; | |||
| 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 ItemDetails from "../../components/ItemDetails/ItemDetails"; | |||
| import ItemDetailsLayout from "../../layouts/ItemDetailsLayout/ItemDetailsLayout"; | |||
| const ItemDetailsPage = () => { | |||
| const dispatch = useDispatch(); | |||
| //const routetMatch = useRouteMatch(); | |||
| const history = useHistory(); | |||
| 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]); | |||
| const handleCl = () => { | |||
| dispatch(logoutUser()); | |||
| }; | |||
| return ( | |||
| <ItemDetailsPageContainer> | |||
| <button onClick={handleCl}>Dugme</button> | |||
| <Navbar /> | |||
| {/* right card mora mi bude Review Card */} | |||
| <ItemDetailsLayout content={<ItemDetails />} /> | |||
| {/* <Box sx={{ mt: 4, mx: 4 }}> | |||
| <GridStyled container justifyContent="space-between"> | |||
| <GridStyled item xs={12} md={3}> | |||
| asdasdasd | |||
| </GridStyled> | |||
| <GridStyled item xs={12} md={6}> | |||
| <GridStyled xs={12} md={12}> | |||
| <HomeListCard></HomeListCard> | |||
| </GridStyled> | |||
| </GridStyled> */} | |||
| {/* <GridStyled item xs={12} md={9}> | |||
| <PagingSortingFiltering /> | |||
| </GridStyled> | |||
| <GridStyled item xs={12} md={9}> | |||
| {/* Move to higher components? */} | |||
| {/* <RandomDataProvider> | |||
| <PagingSortingFilteringServerSide /> | |||
| </RandomDataProvider> | |||
| </GridStyled> */} | |||
| {/* </GridStyled> | |||
| </Box> */} | |||
| </ItemDetailsPageContainer> | |||
| ); | |||
| }; | |||
| export default ItemDetailsPage; | |||
| @@ -32,6 +32,8 @@ import { | |||
| ErrorMessage, | |||
| } from "./Login.styled"; | |||
| import selectedTheme from "../../themes"; | |||
| import loginValidation from "../../validations/loginValidation"; | |||
| import loginInitialValues from "../../initialValues/loginInitialValues"; | |||
| const LoginPage = ({ history }) => { | |||
| const dispatch = useDispatch(); | |||
| @@ -83,16 +85,8 @@ const LoginPage = ({ history }) => { | |||
| }; | |||
| const formik = useFormik({ | |||
| initialValues: { | |||
| email: "", | |||
| password: "", | |||
| }, | |||
| validationSchema: Yup.object().shape({ | |||
| email: Yup.string().required(t("login.mailRequired")), | |||
| password: Yup.string() | |||
| .required(t("login.passwordRequired")) | |||
| .min(8, t("login.passwordLength")), | |||
| }), | |||
| initialValues: loginInitialValues, | |||
| validationSchema: loginValidation, | |||
| onSubmit: handleSubmit, | |||
| validateOnBlur: true, | |||
| enableReinitialize: true, | |||
| @@ -68,12 +68,6 @@ const FirstPartOfRegistration = (props) => { | |||
| fullWidth | |||
| /> | |||
| {formik.errors.mail && formik.touched.mail ? ( | |||
| <ErrorMessage>{formik.errors.mail}</ErrorMessage> | |||
| ) : ( | |||
| <></> | |||
| )} | |||
| <TextField | |||
| name="password" | |||
| placeholder={t("common.labelPassword")} | |||
| @@ -94,11 +88,17 @@ const FirstPartOfRegistration = (props) => { | |||
| ), | |||
| }} | |||
| /> | |||
| {formik.errors.password && formik.touched.password ? ( | |||
| {formik.errors.mail && formik.touched.mail ? ( | |||
| <ErrorMessage>{formik.errors.mail}</ErrorMessage> | |||
| ) : formik.errors.password && formik.touched.password ? ( | |||
| <ErrorMessage>{formik.errors.password}</ErrorMessage> | |||
| ) : ( | |||
| <></> | |||
| )} | |||
| {props.error && <ErrorMessage>{props.errorMessage}</ErrorMessage>} | |||
| <PrimaryButton | |||
| @@ -2,8 +2,8 @@ import axios from "axios"; | |||
| import queryString from "qs"; | |||
| const request = axios.create({ | |||
| // baseURL: "http://192.168.88.150:3001/", | |||
| baseURL: "http://192.168.88.176:3001/", | |||
| baseURL: "http://192.168.88.150:3001/", | |||
| // baseURL: "http://192.168.88.176:3001/", | |||
| headers: { | |||
| "Content-Type": "application/json", | |||
| }, | |||
| @@ -13,9 +13,9 @@ const request = axios.create({ | |||
| }); | |||
| export const getRequest = (url, params = null, options = null) => { | |||
| console.log('url: ', url); | |||
| console.log("url: ", url); | |||
| return request.get(url, { params, ...options }); | |||
| } | |||
| }; | |||
| export const postRequest = (url, data, params = null, options = null) => | |||
| request.post(url, data, { params, ...options }); | |||
| @@ -13,8 +13,8 @@ import { logoutUser, refreshUserToken } from "../actions/login/loginActions"; | |||
| // import { setUserAccessToken } from "../actions/user/userActions"; | |||
| //Change URL with .env | |||
| //const baseURL = "http://192.168.88.150:3001/"; | |||
| const baseURL = "http://192.168.88.175:3005/"; | |||
| const baseURL = "http://192.168.88.150:3001/"; | |||
| // const baseURL = "http://192.168.88.175:3005/"; | |||
| //Interceptor unique name | |||
| export const accessTokensMiddlewareInterceptorName = "ACCESS_TOKEN_INTERCEPTOR"; | |||
| @@ -31,7 +31,7 @@ export default ({ dispatch }) => | |||
| if (!response.headers?.Authorization) { | |||
| response.headers.Authorization = `Bearer ${jwtToken}`; | |||
| } | |||
| // If refresh token is expired, log out user | |||
| if (new Date() > new Date(refreshTokenDecoded?.exp * 1000)) { | |||
| dispatch(logoutUser()); | |||
| @@ -45,7 +45,7 @@ export default ({ dispatch }) => | |||
| const newToken = axiosResponse.data.token; | |||
| dispatch(refreshUserToken(newToken)); | |||
| } | |||
| return Promise.resolve(response); | |||
| }, accessTokensMiddlewareInterceptorName); | |||
| @@ -1,19 +1,19 @@ | |||
| export const primaryThemeColors = { | |||
| primaryPurple: "#5A3984", | |||
| primaryYellow: "#f7b126", | |||
| primaryPurpleDisabled: "#4D4D4D", | |||
| primaryBackgroundColor: "#F1F1F1", | |||
| primaryTextDisabled: "#F1F1F1", | |||
| primaryText: "#4D4D4D", | |||
| primaryGrayText: "#818181", | |||
| primaryDarkGrayText: "#DCDCDC", | |||
| primaryIconBackgroundColor: "#E4E4E4", | |||
| borderSponsoredColor: "#E5D0FF", | |||
| backgroundSponsoredColor: "#F5EDFF", | |||
| offerBackgroundColor: "#F5F5F5", | |||
| selectOptionTextColor: "#1D1D1D", | |||
| primaryDarkText: "#505050", | |||
| iconStrokeColor: "#8C8C8C", | |||
| iconStrokeDisabledColor: '#C4C4C4', | |||
| imagePickerBackground: "#E4E4E4" | |||
| } | |||
| primaryPurple: "#5A3984", | |||
| primaryYellow: "#f7b126", | |||
| primaryPurpleDisabled: "#4D4D4D", | |||
| primaryBackgroundColor: "#F1F1F1", | |||
| primaryTextDisabled: "#F1F1F1", | |||
| primaryText: "#4D4D4D", | |||
| primaryGrayText: "#818181", | |||
| primaryDarkGrayText: "#DCDCDC", | |||
| primaryIconBackgroundColor: "#E4E4E4", | |||
| borderNormal: "#D4D4D4", | |||
| borderSponsoredColor: "#E5D0FF", | |||
| backgroundSponsoredColor: "#F5EDFF", | |||
| offerBackgroundColor: "#F5F5F5", | |||
| selectOptionTextColor: "#1D1D1D", | |||
| primaryDarkText: "#505050", | |||
| iconStrokeColor: "#8C8C8C", | |||
| // iconStrokeDisabledColor: "#818181", | |||
| }; | |||
| @@ -0,0 +1,8 @@ | |||
| import * as Yup from "yup"; | |||
| import i18n from "../i18n"; | |||
| export default Yup.object().shape({ | |||
| email: Yup.string() | |||
| .required(i18n.t("forgotPassword.emailRequired")) | |||
| .email(i18n.t("forgotPassword.emailFormat")), | |||
| }); | |||
| @@ -0,0 +1,9 @@ | |||
| import * as Yup from "yup"; | |||
| import i18n from "../i18n"; | |||
| export default Yup.object().shape({ | |||
| email: Yup.string().email(i18n.t("login.emailFormat")).required(i18n.t("login.mailRequired")), | |||
| password: Yup.string() | |||
| .required(i18n.t("login.passwordRequired")) | |||
| .min(8, i18n.t("login.passwordLength")), | |||
| }); | |||
| @@ -0,0 +1,10 @@ | |||
| import * as Yup from "yup"; | |||
| import i18n from "../../i18n"; | |||
| export default Yup.object().shape({ | |||
| mail: Yup.string() | |||
| .email(i18n.t("forgotPassword.emailFormat")) | |||
| .required(i18n.t("login.usernameRequired")), | |||
| password: Yup.string() | |||
| .required(i18n.t("login.passwordRequired")) | |||
| .min(8, i18n.t("login.passwordLength")), | |||
| }); | |||
| @@ -0,0 +1,10 @@ | |||
| import * as Yup from "yup"; | |||
| import i18n from "../../i18n"; | |||
| export default Yup.object().shape({ | |||
| nameOfFirm: Yup.string().required(i18n.t("login.usernameRequired")), | |||
| PIB: Yup.number() | |||
| .required(i18n.t("login.passwordRequired")) | |||
| .min(100000000, i18n.t("register.PIBnoOfCharacters")) | |||
| .max(999999999, i18n.t("register.PIBnoOfCharacters")), | |||
| }); | |||
| @@ -0,0 +1,10 @@ | |||
| import * as Yup from "yup"; | |||
| import i18n from "../../i18n"; | |||
| export default Yup.object().shape({ | |||
| phoneNumber: Yup.number().required(i18n.t("login.usernameRequired")), | |||
| location: Yup.string().required(i18n.t("login.passwordRequired")), | |||
| website: Yup.string().matches( | |||
| /^((ftp|http|https):\/\/)?(www.)?(?!.*(ftp|http|https|www.))[a-zA-Z0-9_-]+(\.[a-zA-Z]+)+((\/)[\w#]+)*(\/\w+\?[a-zA-Z0-9_]+=\w+(&[a-zA-Z0-9_]+=\w+)*)?$/gm | |||
| ), | |||
| }); | |||
| @@ -0,0 +1,6 @@ | |||
| import * as Yup from "yup"; | |||
| export default Yup.object().shape({ | |||
| password: Yup.string().required().min(8), | |||
| passwordConfirm: Yup.string().oneOf([Yup.ref("password"), null]), | |||
| }); | |||
| @@ -3778,6 +3778,11 @@ | |||
| "isobject" "^3.0.0" | |||
| "static-extend" "^0.1.1" | |||
| "classnames@^2.2.6": | |||
| "integrity" "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" | |||
| "resolved" "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz" | |||
| "version" "2.3.1" | |||
| "clean-css@^4.2.3": | |||
| "integrity" "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==" | |||
| "resolved" "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz" | |||
| @@ -4485,6 +4490,11 @@ | |||
| "resolved" "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz" | |||
| "version" "2.28.0" | |||
| "debounce@^1.2.0": | |||
| "integrity" "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" | |||
| "resolved" "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz" | |||
| "version" "1.2.1" | |||
| "debug@*", "debug@^4.0.1", "debug@^4.1.0", "debug@^4.1.1", "debug@^4.3.1", "debug@4": | |||
| "integrity" "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==" | |||
| "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz" | |||
| @@ -4880,6 +4890,11 @@ | |||
| "readable-stream" "^2.0.0" | |||
| "stream-shift" "^1.0.0" | |||
| "easy-bem@^1.1.1": | |||
| "integrity" "sha512-GJRqdiy2h+EXy6a8E6R+ubmqUM08BK0FWNq41k24fup6045biQ8NXxoXimiwegMQvFFV3t1emADdGNL1TlS61A==" | |||
| "resolved" "https://registry.npmjs.org/easy-bem/-/easy-bem-1.1.1.tgz" | |||
| "version" "1.1.1" | |||
| "ecdsa-sig-formatter@1.0.11": | |||
| "integrity" "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==" | |||
| "resolved" "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz" | |||
| @@ -5710,6 +5725,11 @@ | |||
| dependencies: | |||
| "to-regex-range" "^5.0.1" | |||
| "filter-obj@^1.1.0": | |||
| "integrity" "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==" | |||
| "resolved" "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz" | |||
| "version" "1.1.0" | |||
| "finalhandler@~1.1.2": | |||
| "integrity" "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==" | |||
| "resolved" "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz" | |||
| @@ -10107,13 +10127,23 @@ | |||
| "version" "6.7.0" | |||
| "query-string@^4.1.0": | |||
| "integrity" "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=" | |||
| "integrity" "sha512-O2XLNDBIg1DnTOa+2XrIwSiXEV8h2KImXUnjhhn2+UsvZ+Es2uyd5CCRTNQlDGbzUQOW3aYCBx9rVA6dzsiY7Q==" | |||
| "resolved" "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz" | |||
| "version" "4.3.4" | |||
| dependencies: | |||
| "object-assign" "^4.1.0" | |||
| "strict-uri-encode" "^1.0.0" | |||
| "query-string@^7.1.1": | |||
| "integrity" "sha512-MplouLRDHBZSG9z7fpuAAcI7aAYjDLhtsiVZsevsfaHWDS2IDdORKbSd1kWUA+V4zyva/HZoSfpwnYMMQDhb0w==" | |||
| "resolved" "https://registry.npmjs.org/query-string/-/query-string-7.1.1.tgz" | |||
| "version" "7.1.1" | |||
| dependencies: | |||
| "decode-uri-component" "^0.2.0" | |||
| "filter-obj" "^1.1.0" | |||
| "split-on-first" "^1.0.0" | |||
| "strict-uri-encode" "^2.0.0" | |||
| "querystring-es3@^0.2.0": | |||
| "integrity" "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" | |||
| "resolved" "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz" | |||
| @@ -10228,7 +10258,7 @@ | |||
| "strip-ansi" "6.0.0" | |||
| "text-table" "0.2.0" | |||
| "react-dom@*", "react-dom@^16.6.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0", "react-dom@^17.0.0 || ^18.0.0", "react-dom@^17.0.2", "react-dom@>= 16.8.0", "react-dom@>=16.6.0": | |||
| "react-dom@*", "react-dom@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.6.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.0 || ^17.0.0", "react-dom@^17.0.0 || ^18.0.0", "react-dom@^17.0.2", "react-dom@>= 16.8.0", "react-dom@>=16.6.0": | |||
| "integrity" "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==" | |||
| "resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" | |||
| "version" "17.0.2" | |||
| @@ -10272,6 +10302,15 @@ | |||
| "html-escaper" "^2.0.2" | |||
| "html-parse-stringify" "^3.0.1" | |||
| "react-indiana-drag-scroll@^2.2.0": | |||
| "integrity" "sha512-+W/3B2OQV0FrbdnsoIo4dww/xpH0MUQJz6ziQb7H+oBko3OCbXuzDFYnho6v6yhGrYDNWYPuFUewb89IONEl/A==" | |||
| "resolved" "https://registry.npmjs.org/react-indiana-drag-scroll/-/react-indiana-drag-scroll-2.2.0.tgz" | |||
| "version" "2.2.0" | |||
| dependencies: | |||
| "classnames" "^2.2.6" | |||
| "debounce" "^1.2.0" | |||
| "easy-bem" "^1.1.1" | |||
| "react-input-autosize@^3.0.0": | |||
| "integrity" "sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==" | |||
| "resolved" "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz" | |||
| @@ -10439,7 +10478,7 @@ | |||
| "loose-envify" "^1.4.0" | |||
| "prop-types" "^15.6.2" | |||
| "react@*", "react@^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", "react@^16.3.0 || ^17.0.0", "react@^16.6.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0", "react@^16.8.3 || ^17 || ^18", "react@^16.9.0 || ^17.0.0 || ^18", "react@^17.0.0 || ^18.0.0", "react@^17.0.2", "react@^17.0.2 || ^18.0.0", "react@>= 16", "react@>= 16.8.0", "react@>=15", "react@>=16.6.0", "react@>=16.8.0", "react@17.0.2": | |||
| "react@*", "react@^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", "react@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.3.0 || ^17.0.0", "react@^16.6.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.0", "react@^16.8.3 || ^17 || ^18", "react@^16.9.0 || ^17.0.0 || ^18", "react@^17.0.0 || ^18.0.0", "react@^17.0.2", "react@^17.0.2 || ^18.0.0", "react@>= 16", "react@>= 16.8.0", "react@>=15", "react@>=16.6.0", "react@>=16.8.0", "react@17.0.2": | |||
| "integrity" "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==" | |||
| "resolved" "https://registry.npmjs.org/react/-/react-17.0.2.tgz" | |||
| "version" "17.0.2" | |||
| @@ -11607,6 +11646,11 @@ | |||
| "select-hose" "^2.0.0" | |||
| "spdy-transport" "^3.0.0" | |||
| "split-on-first@^1.0.0": | |||
| "integrity" "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==" | |||
| "resolved" "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz" | |||
| "version" "1.1.0" | |||
| "split-string@^3.0.1", "split-string@^3.0.2": | |||
| "integrity" "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==" | |||
| "resolved" "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz" | |||
| @@ -11703,10 +11747,15 @@ | |||
| "version" "1.0.1" | |||
| "strict-uri-encode@^1.0.0": | |||
| "integrity" "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" | |||
| "integrity" "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==" | |||
| "resolved" "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz" | |||
| "version" "1.1.0" | |||
| "strict-uri-encode@^2.0.0": | |||
| "integrity" "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==" | |||
| "resolved" "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz" | |||
| "version" "2.0.0" | |||
| "string_decoder@^1.0.0", "string_decoder@~1.1.1": | |||
| "integrity" "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==" | |||
| "resolved" "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" | |||