| @@ -31,6 +31,7 @@ import { Label } from "../../CheckBox/Label"; | |||
| import FirstPartCreateOffer from "./FirstPart/FirstPartCreateOffer"; | |||
| import SecondPartCreateOffer from "./SecondPart/SecondPartCreateOffer"; | |||
| import ThirdPartCreateOffer from "./ThirdPart/ThirdPartCreateOffer"; | |||
| import { addOffer } from "../../../store/actions/offers/offersActions"; | |||
| const CreateOffer = ({ history }) => { | |||
| const dispatch = useDispatch(); | |||
| @@ -40,6 +41,9 @@ const CreateOffer = ({ history }) => { | |||
| const [currentStep, setCurrentStep] = useState(1); | |||
| const handleClickShowPassword = () => setShowPassword(!showPassword); | |||
| const handleMouseDownPassword = () => setShowPassword(!showPassword); | |||
| const categories = useSelector((state) => state.categories.categories); | |||
| console.log(informations); | |||
| // When user refreshes page | |||
| // useEffect(() => { | |||
| @@ -77,14 +81,51 @@ const CreateOffer = ({ history }) => { | |||
| }; | |||
| const handleNext = (values) => { | |||
| if (currentStep === 2) { | |||
| setInformations({ ...informations, images: [...values] }); | |||
| } else { | |||
| setInformations({ ...informations, ...values }); | |||
| } | |||
| setInformations({ ...informations, ...values }); | |||
| setCurrentStep((prevState) => prevState + 1); | |||
| }; | |||
| const newImgs = | |||
| informations.images && | |||
| informations.images | |||
| .filter((img) => img !== undefined) | |||
| .map((img) => | |||
| img | |||
| .replace("data:image/jpeg;base64,", "") | |||
| .replace("data:image/png;base64,", "") | |||
| ); | |||
| let subcategories = []; | |||
| for (const element of categories) { | |||
| if (element.name === informations.category) { | |||
| subcategories = element.subcategories.map((item) => item.name); | |||
| } | |||
| } | |||
| const offerData = { | |||
| name: informations.nameOfProduct, | |||
| description: informations.description, | |||
| location: { | |||
| city: informations.location, | |||
| }, | |||
| condition: informations.condition, | |||
| category: { | |||
| name: informations.category, | |||
| subcategories: subcategories, | |||
| }, | |||
| subcategory: informations.subcategory, | |||
| images: newImgs, | |||
| }; | |||
| const submitOffer = (values) => { | |||
| dispatch(addOffer(values)); | |||
| }; | |||
| const handleSubmitOffer = () => { | |||
| submitOffer(offerData); | |||
| console.log(offerData); | |||
| }; | |||
| return ( | |||
| <CreateOfferContainer> | |||
| <CreateOfferTitle component="h1" variant="h5"> | |||
| @@ -96,7 +137,7 @@ const CreateOffer = ({ history }) => { | |||
| {currentStep === 2 && <SecondPartCreateOffer handleNext={handleNext} />} | |||
| {currentStep === 3 && ( | |||
| <ThirdPartCreateOffer | |||
| handleNext={handleNext} | |||
| handleSubmitOffer={handleSubmitOffer} | |||
| informations={informations} | |||
| /> | |||
| )} | |||
| @@ -18,15 +18,10 @@ import { SelectField } from "../CreateOffer.styled"; | |||
| import { useSelector } from "react-redux"; | |||
| const FirstPartCreateOffer = (props) => { | |||
| const [subcat, setSubcat] = useState([]); | |||
| 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); | |||
| @@ -45,21 +40,28 @@ const FirstPartCreateOffer = (props) => { | |||
| description: Yup.string().required(t("login.descriptionRequired")).min(8), | |||
| location: Yup.string().oneOf(locations.map((l) => l.city)), | |||
| category: Yup.string().oneOf(categories.map((c) => c.name)), | |||
| // subcategory: Yup.string().oneOf(subcat[0].subcategories), | |||
| // subcategory: Yup.string().oneOf( | |||
| // subcat[0]?.subcategories ? subcat[0].subcategories : [] | |||
| // ), | |||
| }), | |||
| onSubmit: handleSubmit, | |||
| validateOnBlur: true, | |||
| enableReinitialize: true, | |||
| }); | |||
| const handleSubcategories = (category) => { | |||
| const filtered = categories.filter((cat) => cat.name === category); | |||
| setSubcat(filtered); | |||
| }; | |||
| return ( | |||
| <CreateOfferFormContainer component="form" onSubmit={formik.handleSubmit}> | |||
| {/* <Backdrop position="absolute" isLoading={isLoading} /> */} | |||
| <FieldLabel leftText={"NASLOV"} /> | |||
| <FieldLabel leftText={t("offer.title")} /> | |||
| <TitleField | |||
| name="nameOfProduct" | |||
| placeholder={"Naziv proizvoda..."} | |||
| placeholder={t("offer.productName")} | |||
| italicPlaceholder | |||
| margin="normal" | |||
| value={formik.values.nameOfProduct} | |||
| @@ -70,10 +72,10 @@ const FirstPartCreateOffer = (props) => { | |||
| fullWidth | |||
| /> | |||
| <FieldLabel leftText={"OPIS PROIZVODA"} /> | |||
| <FieldLabel leftText={t("offer.productDescription")} /> | |||
| <DescriptionField | |||
| name="description" | |||
| placeholder={"Opis..."} | |||
| placeholder={t("offer.description")} | |||
| margin="normal" | |||
| italicPlaceholder | |||
| value={formik.values.description} | |||
| @@ -86,14 +88,14 @@ const FirstPartCreateOffer = (props) => { | |||
| height={"100px"} | |||
| /> | |||
| <FieldLabel leftText={"LOKACIJA"} /> | |||
| <FieldLabel leftText={t("offer.location")} /> | |||
| <SelectField | |||
| defaultValue="default" | |||
| onChange={(value) => { | |||
| formik.setFieldValue("location", value.target.value.city); | |||
| }} | |||
| > | |||
| <Option value="default">Izaberi lokaciju</Option> | |||
| <Option value="default">{t("offer.choseLocation")}</Option> | |||
| {locations.map((loc) => { | |||
| return ( | |||
| <Option key={loc._if} value={loc}> | |||
| @@ -103,14 +105,14 @@ const FirstPartCreateOffer = (props) => { | |||
| })} | |||
| </SelectField> | |||
| <FieldLabel leftText={"KATEGORIJA"} /> | |||
| <FieldLabel leftText={t("offer.category")} /> | |||
| <SelectField | |||
| defaultValue="default" | |||
| onChange={(value) => { | |||
| formik.setFieldValue("category", value.target.value.name); | |||
| }} | |||
| > | |||
| <Option value="default">Izaberi kategoriju</Option> | |||
| <Option value="default">{t("offer.choseCategory")}</Option> | |||
| {categories.map((cat, i) => { | |||
| return ( | |||
| <Option | |||
| @@ -124,7 +126,7 @@ const FirstPartCreateOffer = (props) => { | |||
| })} | |||
| </SelectField> | |||
| <FieldLabel leftText={"PODKATEGORIJA"} /> | |||
| <FieldLabel leftText={t("offer.subcategory")} /> | |||
| <SelectField | |||
| defaultValue="default" | |||
| onChange={(value) => { | |||
| @@ -132,8 +134,9 @@ const FirstPartCreateOffer = (props) => { | |||
| console.log(value.target); | |||
| }} | |||
| > | |||
| <Option value="default">Izaberi podkategoriju</Option> | |||
| <Option value="default">{t("offer.choseSubcategory")}</Option> | |||
| {subcat?.length > 0 && | |||
| subcat[0]?.subcategories && | |||
| subcat[0].subcategories.map((sub, i) => { | |||
| return ( | |||
| <Option key={i} value={sub}> | |||
| @@ -141,10 +144,6 @@ const FirstPartCreateOffer = (props) => { | |||
| </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> */} | |||
| </SelectField> | |||
| <NextButton | |||
| @@ -4,18 +4,26 @@ import { | |||
| CreateOfferFormContainer, | |||
| FieldLabel, | |||
| Scroller, | |||
| InputButtonContainer, | |||
| // ImageListStyled, | |||
| } from "./SecondPartCreateOffer.styled"; | |||
| import ImagePicker from "../../../ImagePicker/ImagePicker"; | |||
| // import Select from "../../../Select/Select"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import Option from "../../../Select/Option/Option"; | |||
| import { SelectAltText, SelectField, SelectText } from "../CreateOffer.styled"; | |||
| import { NextButton } from "../FirstPart/FirstPartCreateOffer.styled"; | |||
| import selectedTheme from "../../../../themes"; | |||
| import { conditionSelectEnum } from "../../../../enums/conditionEnum"; | |||
| import { useFormik } from "formik"; | |||
| import * as Yup from "yup"; | |||
| const numberOfImages = 3; | |||
| const SecondPartCreateOffer = (props) => { | |||
| const [images, setImages] = useState([null, null, null]); // 3 images | |||
| const [images, setImages] = useState( | |||
| Array.apply(null, Array(numberOfImages)).map(() => {}) | |||
| ); // 3 images | |||
| const setImage = (index, image) => { | |||
| console.log(images); | |||
| setImages((prevState) => { | |||
| @@ -25,12 +33,25 @@ const SecondPartCreateOffer = (props) => { | |||
| }); | |||
| }; | |||
| const handleSubmit = () => { | |||
| props.handleNext(images); | |||
| const { t } = useTranslation(); | |||
| const handleSubmit = (values) => { | |||
| props.handleNext(values); | |||
| }; | |||
| const formik = useFormik({ | |||
| initialValues: { | |||
| images: images, | |||
| condition: "", | |||
| }, | |||
| validationSchema: Yup.object().shape({}), | |||
| onSubmit: handleSubmit, | |||
| validateOnBlur: true, | |||
| enableReinitialize: true, | |||
| }); | |||
| return ( | |||
| <CreateOfferFormContainer component="form" onSubmit={handleSubmit}> | |||
| <CreateOfferFormContainer component="form" onSubmit={formik.handleSubmit}> | |||
| <Scroller> | |||
| {images.map((item, index) => ( | |||
| <ImagePicker | |||
| @@ -41,33 +62,42 @@ const SecondPartCreateOffer = (props) => { | |||
| /> | |||
| ))} | |||
| </Scroller> | |||
| <FieldLabel leftText="STANJE" /> | |||
| <SelectField defaultValue={conditionSelectEnum.NEW.value}> | |||
| {Object.keys(conditionSelectEnum).map((key) => { | |||
| var item = conditionSelectEnum[key]; | |||
| return ( | |||
| <Option value={item.value} key={item.value}> | |||
| <SelectText>{item.mainText}</SelectText> | |||
| <SelectAltText>{item.altText}</SelectAltText> | |||
| </Option> | |||
| ); | |||
| })} | |||
| </SelectField> | |||
| <InputButtonContainer> | |||
| <FieldLabel leftText={t("offer.condition")} /> | |||
| <SelectField | |||
| defaultValue="default" | |||
| onChange={(value) => { | |||
| formik.setFieldValue("condition", value.target.value); | |||
| console.log(value.target); | |||
| }} | |||
| > | |||
| <Option value="default">{t("offer.choseCondition")}</Option> | |||
| {Object.keys(conditionSelectEnum).map((key) => { | |||
| var item = conditionSelectEnum[key]; | |||
| return ( | |||
| <Option value={item.mainText} key={item.value}> | |||
| <SelectText>{item.mainText}</SelectText> | |||
| <SelectAltText>{item.altText}</SelectAltText> | |||
| </Option> | |||
| ); | |||
| })} | |||
| </SelectField> | |||
| <NextButton | |||
| type="submit" | |||
| variant="contained" | |||
| height="48px" | |||
| fullWidth | |||
| buttoncolor={selectedTheme.primaryPurple} | |||
| textcolor="white" | |||
| // disabled={ | |||
| // formik.values.username.length === 0 || | |||
| // formik.values.password.length === 0 | |||
| // } | |||
| > | |||
| NASTAVI | |||
| </NextButton> | |||
| <NextButton | |||
| type="submit" | |||
| variant="contained" | |||
| height="48px" | |||
| fullWidth | |||
| buttoncolor={selectedTheme.primaryPurple} | |||
| textcolor="white" | |||
| // disabled={ | |||
| // formik.values.username.length === 0 || | |||
| // formik.values.password.length === 0 | |||
| // } | |||
| > | |||
| NASTAVI | |||
| </NextButton> | |||
| </InputButtonContainer> | |||
| </CreateOfferFormContainer> | |||
| ); | |||
| }; | |||
| @@ -6,9 +6,10 @@ import HorizontalScroller from "../../../Scroller/HorizontalScroller"; | |||
| import { ReactComponent as TrashIcon } from "../../../../assets/images/svg/trash.svg"; | |||
| export const CreateOfferFormContainer = styled(Box)` | |||
| width: 350px; | |||
| width: 585px; | |||
| height: 700px; | |||
| padding-top: 20px; | |||
| margin-top: 20px; | |||
| `; | |||
| export const ImageCard = styled.img` | |||
| @@ -36,6 +37,15 @@ export const FieldLabel = styled(Label)` | |||
| letter-spacing: 0.2px; | |||
| } | |||
| `; | |||
| export const InputButtonContainer = styled(Box)` | |||
| width: 332px; | |||
| margin: 25px auto; | |||
| display: flex; | |||
| flex-direction: column; | |||
| justify-content: center; | |||
| `; | |||
| export const Scroller = styled(HorizontalScroller)` | |||
| min-width: 640px; | |||
| position: relative; | |||
| @@ -1,120 +1,40 @@ | |||
| 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"; | |||
| import { CreateOfferFormContainer } from "./ThirdPartCreateOffer.styled"; | |||
| import ItemDetailsCard from "../../ItemDetailsCard/ItemDetailsCard"; | |||
| const ThirdPartCreateOffer = (props) => { | |||
| console.log(props.informations); | |||
| let date = new Date(); | |||
| let formatedDate = `${date.getDate()}.${ | |||
| date.getMonth() + 1 | |||
| }.${date.getFullYear()}.`; | |||
| const handleSubmit = (e) => { | |||
| e.preventDefault(); | |||
| props.handleSubmitOffer(); | |||
| }; | |||
| 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> | |||
| {props.informations.images.map((img, i) => { | |||
| return <OfferImage key={i} src={img} />; | |||
| })} | |||
| </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 component="form" onSubmit={handleSubmit}> | |||
| <ItemDetailsCard | |||
| category={props.informations.category} | |||
| subcategory={props.informations.subcategory} | |||
| condition={props.informations.condition} | |||
| showNumberOfViews={false} | |||
| date={formatedDate} | |||
| title={props.informations.nameOfProduct} | |||
| description={props.informations.description} | |||
| images={props.informations.images} | |||
| showBarterButton={false} | |||
| showPublishButton={true} | |||
| /> | |||
| </CreateOfferFormContainer> | |||
| ); | |||
| }; | |||
| ThirdPartCreateOffer.propTypes = { | |||
| children: PropTypes.any, | |||
| handleNext: PropTypes.func, | |||
| handleSubmitOffer: PropTypes.func, | |||
| informations: PropTypes.object, | |||
| }; | |||
| @@ -1,86 +1,7 @@ | |||
| import { Box, Typography } from "@mui/material"; | |||
| import { Box } 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; | |||
| `; | |||
| @@ -14,7 +14,10 @@ import { | |||
| OfferDescriptionTitle, | |||
| Details, | |||
| OfferDetails, | |||
| OfferImage, | |||
| PublishButtonContainer, | |||
| } from "./ItemDetailsCard.styled"; | |||
| import { NextButton } from "../CreateOfferCard/FirstPart/FirstPartCreateOffer.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"; | |||
| @@ -22,7 +25,7 @@ import { ReactComponent as Eye } from "../../../assets/images/svg/eye-striked.sv | |||
| 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"; | |||
| // import { ReactComponent as DummyImage1 } from "../../../assets/images/svg/dummyImages/offer-1.svg"; | |||
| const ItemDetailsCard = (props) => { | |||
| return ( | |||
| @@ -40,7 +43,7 @@ const ItemDetailsCard = (props) => { | |||
| > | |||
| <Category width={"14px"} /> | |||
| </InfoIcon> | |||
| <InfoText>{offer.category}</InfoText> | |||
| <InfoText>{props.category}</InfoText> | |||
| </InfoGroup> | |||
| <InfoGroup> | |||
| <InfoIcon | |||
| @@ -50,7 +53,7 @@ const ItemDetailsCard = (props) => { | |||
| > | |||
| <Subcategory width={"14px"} /> | |||
| </InfoIcon> | |||
| <InfoText>{offer.subcategory}</InfoText> | |||
| <InfoText>{props.subcategory}</InfoText> | |||
| </InfoGroup> | |||
| <InfoGroup> | |||
| <InfoIcon | |||
| @@ -60,20 +63,26 @@ const ItemDetailsCard = (props) => { | |||
| > | |||
| <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> | |||
| <InfoText>{props.condition}</InfoText> | |||
| </InfoGroup> | |||
| {props.showNumberOfViews && ( | |||
| <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> | |||
| <PostDate>Objavljeno: {props.date}</PostDate> | |||
| </OfferInfo> | |||
| <Details> | |||
| <OfferTitle>{offer.title}</OfferTitle> | |||
| <OfferTitle>{props.title}</OfferTitle> | |||
| <HorizontalScroller> | |||
| {props.images.map((img, i) => ( | |||
| <OfferImage src={img} key={i} /> | |||
| ))} | |||
| {/* <DummyImage1 /> | |||
| <DummyImage1 /> | |||
| <DummyImage1 /> | |||
| <DummyImage1 /> | |||
| @@ -81,15 +90,14 @@ const ItemDetailsCard = (props) => { | |||
| <DummyImage1 /> | |||
| <DummyImage1 /> | |||
| <DummyImage1 /> | |||
| <DummyImage1 /> | |||
| <DummyImage1 /> | |||
| <DummyImage1 /> */} | |||
| </HorizontalScroller> | |||
| <OfferDetails> | |||
| <OfferDescriptionTitle>Opis:</OfferDescriptionTitle> | |||
| <OfferDescriptionText>{offer.description}</OfferDescriptionText> | |||
| <OfferDescriptionText>{props.description}</OfferDescriptionText> | |||
| </OfferDetails> | |||
| </Details> | |||
| {!props.halfwidth ? ( | |||
| {props.showBarterButton && !props.halfwidth ? ( | |||
| <React.Fragment> | |||
| <CheckButton | |||
| variant={props.sponsored ? "contained" : "outlined"} | |||
| @@ -103,6 +111,24 @@ const ItemDetailsCard = (props) => { | |||
| ) : ( | |||
| <></> | |||
| )} | |||
| {props.showPublishButton && ( | |||
| <PublishButtonContainer> | |||
| <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> | |||
| </PublishButtonContainer> | |||
| )} | |||
| {/* {props.image} | |||
| {props.title} | |||
| @@ -123,14 +149,20 @@ ItemDetailsCard.propTypes = { | |||
| title: PropTypes.string, | |||
| description: PropTypes.string, | |||
| category: PropTypes.string, | |||
| subcategory: PropTypes.string, | |||
| condition: PropTypes.string, | |||
| showNumberOfViews: PropTypes.bool, | |||
| date: PropTypes.string, | |||
| author: PropTypes.string, | |||
| location: PropTypes.string, | |||
| image: PropTypes.node, | |||
| images: PropTypes.node, | |||
| quantity: PropTypes.number, | |||
| package: PropTypes.string, | |||
| numberOfViews: PropTypes.number, | |||
| halfwidth: PropTypes.bool, | |||
| sponsored: PropTypes.bool, | |||
| showBarterButton: PropTypes.bool, | |||
| showPublishButton: PropTypes.bool, | |||
| }; | |||
| ItemDetailsCard.defaultProps = { | |||
| halfwidth: false, | |||
| @@ -21,7 +21,13 @@ export const ItemDetailsCardContainer = styled(Container)` | |||
| max-width: 2000px; | |||
| position: relative; | |||
| `; | |||
| export const OfferImage = styled(Box)``; | |||
| export const OfferImage = styled.img` | |||
| width: 144px; | |||
| height: 144px; | |||
| margin-right: 18px; | |||
| object-fit: cover; | |||
| border-radius: 5px; | |||
| `; | |||
| export const OfferInfo = styled(Box)` | |||
| display: flex; | |||
| flex: 2; | |||
| @@ -163,3 +169,8 @@ export const Details = styled(Box)` | |||
| flex-direction: column; | |||
| gap: 12px; | |||
| `; | |||
| export const PublishButtonContainer = styled(Box)` | |||
| display: flex; | |||
| justify-content: center; | |||
| `; | |||
| @@ -6,7 +6,7 @@ import { ReactComponent as Plus } from "../../assets/images/svg/plus.svg"; | |||
| export const ImagePickerContainer = styled(Box)` | |||
| flex: 1; | |||
| display: flex; | |||
| flex-basis: 216px; | |||
| flex-basis: 144px; | |||
| flex-grow: 0; | |||
| flex-shrink: 0; | |||
| height: 144px; | |||
| @@ -55,9 +55,9 @@ export const AddFile = styled.input` | |||
| display: none; | |||
| `; | |||
| export const ImageUploaded = styled.img` | |||
| width: 216px; | |||
| width: 144px; | |||
| height: 144px; | |||
| object-fit: scale-down; | |||
| object-fit: cover; | |||
| `; | |||
| export const Tooltip = styled(Box)` | |||
| background-color: rgba(255, 255, 255, 0.5); | |||
| @@ -1,136 +1,155 @@ | |||
| export default { | |||
| app: { | |||
| title: 'Trampa' | |||
| }, | |||
| refresh: { | |||
| title: 'Jel si aktivan?', | |||
| cta: | |||
| "You were registered as not active, please confirm that you are active in the next minute, if you don't you will be logged out.", | |||
| }, | |||
| common: { | |||
| close: 'Zatvori', | |||
| send: "Pošalji", | |||
| sendAgain: "Pošalji ponovo.", | |||
| trademark: 'TM', | |||
| search: 'Pretraga', | |||
| error: 'Greška', | |||
| continue: 'Nastavi', | |||
| labelUsername: 'Username', | |||
| labelEmail: 'Email', | |||
| labelPassword: 'Lozinka', | |||
| labelFirm: "Ime Firme", | |||
| labelPIB: "PIB", | |||
| labelPhone: "Telefon", | |||
| labelLocation: "Lokacija", | |||
| labelWebsite: "Adresa Websajta", | |||
| next: 'Sledeće', | |||
| nextPage: 'Sledeća strana', | |||
| previousPage: 'Prethodna strana', | |||
| back: 'Nazad', | |||
| goBack: 'Idi nazad', | |||
| ok: 'Ok', | |||
| done: 'Gotovo', | |||
| confirm: 'Potvrdi', | |||
| printDownload: 'Print/Download', | |||
| cancel: 'Obustavi', | |||
| remove: 'Izbriši', | |||
| invite: 'Pozovi', | |||
| save: 'Sačuvaj', | |||
| complete: 'Završi', | |||
| download: 'Download', | |||
| yes: 'Da', | |||
| no: 'Ne', | |||
| to: 'do', | |||
| select: 'Izaberi...', | |||
| none: 'Ni jedan', | |||
| date: { | |||
| range: '{{start}} do {{end}}', | |||
| }, | |||
| }, | |||
| login: { | |||
| welcome: 'React template', | |||
| welcomeText: 'Trampa sa kolegama na dohvat ruke', | |||
| dontHaveAccount: "Nemate nalog? ", | |||
| emailFormat: 'Nevalidan format email adrese!', | |||
| emailRequired: 'Email adresa je obavezna!', | |||
| noUsers: 'Ne postoji korisnik sa zadatom email adresom.', | |||
| passwordStrength: 'Your password is {{strength}}.', | |||
| passwordLength: 'Lozinka mora imati najmanje 8 karaktera!', | |||
| signUpRecommendation: 'Registrujte se.', | |||
| email: 'Unesite email adresu kako biste se prijavili', | |||
| logInTitle: 'Uloguj se', | |||
| logIn: 'Uloguj se', | |||
| signUp: 'Registrujte se.', | |||
| usernameRequired: 'Username je obavezan!', | |||
| passwordRequired: 'Lozinka je obavezna!', | |||
| forgotYourPassword: 'Zaboravili ste lozinku?', | |||
| forgotPasswordEmail:'Email', | |||
| useDifferentEmail: 'Iskoristite drugačiju lozinku.', | |||
| wrongCredentials: 'Pogrešan mail ili lozinka!' | |||
| }, | |||
| password: { | |||
| weak: 'slaba', | |||
| average: 'srednja', | |||
| good: 'dobra', | |||
| strong: 'jaka', | |||
| }, | |||
| register: { | |||
| title: "Registruj se", | |||
| descriptionMain: "Trampa sa kolegama na dohvat ruke", | |||
| descriptionFirst: "Email i Lozinka biće Vam primarni način da se ulogujete u aplikaciju", | |||
| descriptionSecond: 'Ovaj korak nije obavezan za razgledanje artikla ali za proces trampe je obavezan. Uvek možete popuniti ova polja u podešavanjima naloga kasnije', | |||
| descriptionThird: 'Ovaj korak nije obavezan za razgledanje artikla ali za proces trampe je obavezan. Uvek možete popuniti ova polja u podešavanjima naloga kasnije', | |||
| loginText: "Već posedujete nalog?", | |||
| emailFormat: 'Nevalidan format email adrese!', | |||
| emailTaken: "E-mail je zauzet!", | |||
| login: "Ulogujte se.", | |||
| acceptTerms: `Pri klikom na dugme "Registruj se", prihvatate naše`, | |||
| 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: { | |||
| title: 'Povrati lozinku', | |||
| description: 'Molimo vas unesite email sa koji cemo vam poslati link za povratak lozinke', | |||
| label: 'Pošalji email', | |||
| emailRequired: 'Email je obavezan!', | |||
| emailFormat: 'Nevalidan format email adrese!', | |||
| mailSent: "E-Mail poslat!", | |||
| mailSentDescription: "Poslat vam je email sa instrukcijama kako da resetujete lozinku", | |||
| mailNotFound: "Mejl nije povezan ni sa jednim nalogom!", | |||
| notRecievedMail: "Niste dobili email?", | |||
| checkSpam: "U slučaju da Vam ne stigne email, pogledajte <strong>Spam</strong> folder email provajdera", | |||
| forgotPassword: { | |||
| title: 'Zaboravili ste lozinku', | |||
| subtitle: | |||
| 'Odgovorite na tajno pitanje kako biste povratili svoj nalog: ', | |||
| label: 'Obnovite lozinku', | |||
| }, | |||
| }, | |||
| resetPassword: { | |||
| title: "Unesite novu lozinku", | |||
| description: "Poslali ste zahtev za promenu lozinke, molimo Vas da unesete novu željenu lozinku", | |||
| passwordLabel: "Nova Lozinka", | |||
| passwordConfirmLabel: "Potvrdite Lozinku", | |||
| buttonText: "Postavi lozinku" | |||
| }, | |||
| filters: { | |||
| title: "Filteri", | |||
| cancel: "Poništi filtere", | |||
| usefilters: 'Primeni filtere', | |||
| categories: { | |||
| title: "Kategorija", | |||
| placeholder: 'Pretraži kategorije...' | |||
| }, | |||
| subcategories: { | |||
| title: "Podkategorija", | |||
| placeholder: "Pretraži podkategorije..." | |||
| }, | |||
| location: { | |||
| title: "Lokacija", | |||
| placeholder: "Pretraži gradove..." | |||
| } | |||
| } | |||
| } | |||
| app: { | |||
| title: "Trampa", | |||
| }, | |||
| refresh: { | |||
| title: "Jel si aktivan?", | |||
| cta: "You were registered as not active, please confirm that you are active in the next minute, if you don't you will be logged out.", | |||
| }, | |||
| common: { | |||
| close: "Zatvori", | |||
| send: "Pošalji", | |||
| sendAgain: "Pošalji ponovo.", | |||
| trademark: "TM", | |||
| search: "Pretraga", | |||
| error: "Greška", | |||
| continue: "Nastavi", | |||
| labelUsername: "Username", | |||
| labelEmail: "Email", | |||
| labelPassword: "Lozinka", | |||
| labelFirm: "Ime Firme", | |||
| labelPIB: "PIB", | |||
| labelPhone: "Telefon", | |||
| labelLocation: "Lokacija", | |||
| labelWebsite: "Adresa Websajta", | |||
| next: "Sledeće", | |||
| nextPage: "Sledeća strana", | |||
| previousPage: "Prethodna strana", | |||
| back: "Nazad", | |||
| goBack: "Idi nazad", | |||
| ok: "Ok", | |||
| done: "Gotovo", | |||
| confirm: "Potvrdi", | |||
| printDownload: "Print/Download", | |||
| cancel: "Obustavi", | |||
| remove: "Izbriši", | |||
| invite: "Pozovi", | |||
| save: "Sačuvaj", | |||
| complete: "Završi", | |||
| download: "Download", | |||
| yes: "Da", | |||
| no: "Ne", | |||
| to: "do", | |||
| select: "Izaberi...", | |||
| none: "Ni jedan", | |||
| date: { | |||
| range: "{{start}} do {{end}}", | |||
| }, | |||
| }, | |||
| login: { | |||
| welcome: "React template", | |||
| welcomeText: "Trampa sa kolegama na dohvat ruke", | |||
| dontHaveAccount: "Nemate nalog? ", | |||
| emailFormat: "Nevalidan format email adrese!", | |||
| emailRequired: "Email adresa je obavezna!", | |||
| noUsers: "Ne postoji korisnik sa zadatom email adresom.", | |||
| passwordStrength: "Your password is {{strength}}.", | |||
| passwordLength: "Lozinka mora imati najmanje 8 karaktera!", | |||
| signUpRecommendation: "Registrujte se.", | |||
| email: "Unesite email adresu kako biste se prijavili", | |||
| logInTitle: "Uloguj se", | |||
| logIn: "Uloguj se", | |||
| signUp: "Registrujte se.", | |||
| usernameRequired: "Username je obavezan!", | |||
| passwordRequired: "Lozinka je obavezna!", | |||
| forgotYourPassword: "Zaboravili ste lozinku?", | |||
| forgotPasswordEmail: "Email", | |||
| useDifferentEmail: "Iskoristite drugačiju lozinku.", | |||
| wrongCredentials: "Pogrešan mail ili lozinka!", | |||
| }, | |||
| password: { | |||
| weak: "slaba", | |||
| average: "srednja", | |||
| good: "dobra", | |||
| strong: "jaka", | |||
| }, | |||
| register: { | |||
| title: "Registruj se", | |||
| descriptionMain: "Trampa sa kolegama na dohvat ruke", | |||
| descriptionFirst: | |||
| "Email i Lozinka biće Vam primarni način da se ulogujete u aplikaciju", | |||
| descriptionSecond: | |||
| "Ovaj korak nije obavezan za razgledanje artikla ali za proces trampe je obavezan. Uvek možete popuniti ova polja u podešavanjima naloga kasnije", | |||
| descriptionThird: | |||
| "Ovaj korak nije obavezan za razgledanje artikla ali za proces trampe je obavezan. Uvek možete popuniti ova polja u podešavanjima naloga kasnije", | |||
| loginText: "Već posedujete nalog?", | |||
| emailFormat: "Nevalidan format email adrese!", | |||
| emailTaken: "E-mail je zauzet!", | |||
| login: "Ulogujte se.", | |||
| acceptTerms: `Pri klikom na dugme "Registruj se", prihvatate naše`, | |||
| 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: { | |||
| title: "Povrati lozinku", | |||
| description: | |||
| "Molimo vas unesite email sa koji cemo vam poslati link za povratak lozinke", | |||
| label: "Pošalji email", | |||
| emailRequired: "Email je obavezan!", | |||
| emailFormat: "Nevalidan format email adrese!", | |||
| mailSent: "E-Mail poslat!", | |||
| mailSentDescription: | |||
| "Poslat vam je email sa instrukcijama kako da resetujete lozinku", | |||
| mailNotFound: "Mejl nije povezan ni sa jednim nalogom!", | |||
| notRecievedMail: "Niste dobili email?", | |||
| checkSpam: | |||
| "U slučaju da Vam ne stigne email, pogledajte <strong>Spam</strong> folder email provajdera", | |||
| forgotPassword: { | |||
| title: "Zaboravili ste lozinku", | |||
| subtitle: "Odgovorite na tajno pitanje kako biste povratili svoj nalog: ", | |||
| label: "Obnovite lozinku", | |||
| }, | |||
| }, | |||
| resetPassword: { | |||
| title: "Unesite novu lozinku", | |||
| description: | |||
| "Poslali ste zahtev za promenu lozinke, molimo Vas da unesete novu željenu lozinku", | |||
| passwordLabel: "Nova Lozinka", | |||
| passwordConfirmLabel: "Potvrdite Lozinku", | |||
| buttonText: "Postavi lozinku", | |||
| }, | |||
| filters: { | |||
| title: "Filteri", | |||
| cancel: "Poništi filtere", | |||
| usefilters: "Primeni filtere", | |||
| categories: { | |||
| title: "Kategorija", | |||
| placeholder: "Pretraži kategorije...", | |||
| }, | |||
| subcategories: { | |||
| title: "Podkategorija", | |||
| placeholder: "Pretraži podkategorije...", | |||
| }, | |||
| location: { | |||
| title: "Lokacija", | |||
| placeholder: "Pretraži gradove...", | |||
| }, | |||
| }, | |||
| offer: { | |||
| title: "NASLOV", | |||
| productName: "Naziv proizvoda...", | |||
| productDescription: "OPIS PROIZVODA", | |||
| description: "Opis...", | |||
| location: "LOKACIJA", | |||
| choseLocation: "Izaberi lokaciju", | |||
| category: "KATEGORIJA", | |||
| choseCategory: "Izaberi kategoriju", | |||
| subcategory: "PODKATEGORIJA", | |||
| choseSubcategory: "Izaberi podkategoriju", | |||
| condition: "STANJE", | |||
| choseCondition: "Izaberi Stanje", | |||
| }, | |||
| }; | |||
| @@ -1,14 +1,20 @@ | |||
| import { all, takeLatest, call, put } from "@redux-saga/core/effects"; | |||
| import { attemptAddOffer, attemptFetchOffers } from "../../request/offersRequest"; | |||
| import { OFFERS_FETCH, OFFER_ADD } from "../actions/offers/offersActionConstants"; | |||
| import { | |||
| attemptAddOffer, | |||
| attemptFetchOffers, | |||
| } from "../../request/offersRequest"; | |||
| import { | |||
| OFFERS_FETCH, | |||
| OFFER_ADD, | |||
| } from "../actions/offers/offersActionConstants"; | |||
| import { setOffers } from "../actions/offers/offersActions"; | |||
| function* fetchOffers(payload) { | |||
| try { | |||
| console.log(payload); | |||
| const data = yield call(attemptFetchOffers, payload.payload); | |||
| console.log(data.data.items) | |||
| yield put(setOffers(data.data.items)) | |||
| console.log(data.data.items); | |||
| yield put(setOffers(data.data.items)); | |||
| } catch (e) { | |||
| console.log(e); | |||
| } | |||
| @@ -24,16 +30,17 @@ function* fetchOffers(payload) { | |||
| function* createOffer(payload) { | |||
| try { | |||
| const data = yield call(attemptAddOffer, payload); | |||
| console.log(payload); | |||
| const data = yield call(attemptAddOffer, payload.payload); | |||
| console.log(data); | |||
| } | |||
| catch (e) { | |||
| } catch (e) { | |||
| console.log(e); | |||
| } | |||
| } | |||
| export default function* offersSaga() { | |||
| yield all([takeLatest(OFFERS_FETCH, fetchOffers), | |||
| takeLatest(OFFER_ADD, createOffer)]); | |||
| yield all([ | |||
| takeLatest(OFFERS_FETCH, fetchOffers), | |||
| takeLatest(OFFER_ADD, createOffer), | |||
| ]); | |||
| } | |||