Преглед изворни кода

Edit Delete modals finished

bugfix/520
jovan.cirkovic пре 3 година
родитељ
комит
660d068a4a

+ 4
- 0
src/assets/images/svg/trash-gold.svg Прегледај датотеку

@@ -0,0 +1,4 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.25 4.5H3.75H15.75" stroke="#FEB005" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M6 4.5V3C6 2.60218 6.15804 2.22064 6.43934 1.93934C6.72064 1.65804 7.10218 1.5 7.5 1.5H10.5C10.8978 1.5 11.2794 1.65804 11.5607 1.93934C11.842 2.22064 12 2.60218 12 3V4.5M14.25 4.5V15C14.25 15.3978 14.092 15.7794 13.8107 16.0607C13.5294 16.342 13.1478 16.5 12.75 16.5H5.25C4.85218 16.5 4.47064 16.342 4.18934 16.0607C3.90804 15.7794 3.75 15.3978 3.75 15V4.5H14.25Z" stroke="#FEB005" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

+ 45
- 14
src/components/Cards/CreateOfferCard/CreateOffer.js Прегледај датотеку

@@ -3,7 +3,7 @@ import React, { useEffect, useState } from "react";
import PropTypes from "prop-types";
import { useFormik } from "formik";
import { useDispatch, useSelector } from "react-redux";
import { NavLink } from "react-router-dom";
import { useHistory } from "react-router-dom";
import * as Yup from "yup";
import { useTranslation } from "react-i18next";
import { fetchLogin } from "../../../store/actions/login/loginActions";
@@ -36,12 +36,16 @@ 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";
import {
addOffer,
fetchProfileOffers,
} from "../../../store/actions/offers/offersActions";
import { editOneOffer } from "../../../store/actions/offers/offersActions";
import { ReactComponent as ArrowBack } from "../../../assets/images/svg/arrow-back.svg";
import { ReactComponent as CloseButton } from "../../../assets/images/svg/close-modal.svg";
import BackdropComponent from "../../MUI/BackdropComponent";

const CreateOffer = ({ history, closeCreateOfferModal }) => {
const CreateOffer = ({ history, closeCreateOfferModal, editOffer, offer }) => {
const dispatch = useDispatch();
const { t } = useTranslation();
const [informations, setInformations] = useState({});
@@ -50,7 +54,7 @@ const CreateOffer = ({ history, closeCreateOfferModal }) => {
const handleClickShowPassword = () => setShowPassword(!showPassword);
const handleMouseDownPassword = () => setShowPassword(!showPassword);
const categories = useSelector((state) => state.categories.categories);
const historyRouter = useHistory();

// When user refreshes page
// useEffect(() => {
@@ -68,12 +72,22 @@ const CreateOffer = ({ history, closeCreateOfferModal }) => {
);

const handleApiResponseSuccess = (status) => {
history.push({
pathname: HOME_PAGE,
state: {
from: history.location.pathname,
},
});
if (editOffer === undefined) {
const userId = historyRouter.location.pathname.slice(
9,
historyRouter.location.pathname.length
);
dispatch(fetchProfileOffers(userId));
history.push({
pathname: HOME_PAGE,
state: {
from: history.location.pathname,
},
});
} else {
const userId = offer.userId;
dispatch(fetchProfileOffers(userId));
}
};

const handleSubmit = (values) => {
@@ -92,6 +106,8 @@ const CreateOffer = ({ history, closeCreateOfferModal }) => {
setCurrentStep((prevState) => prevState + 1);
};

console.log(informations);

const newImgs =
informations.images &&
informations.images
@@ -110,6 +126,8 @@ const CreateOffer = ({ history, closeCreateOfferModal }) => {
}
}

console.log(informations);

const offerData = {
name: informations.nameOfProduct,
description: informations.description,
@@ -129,8 +147,17 @@ const CreateOffer = ({ history, closeCreateOfferModal }) => {
dispatch(addOffer(values));
};

const submitEditOffer = (id, values) => {
dispatch(editOneOffer(id, values));
};

const handleSubmitOffer = () => {
submitOffer(offerData);
if (editOffer === undefined) {
submitOffer({ offerData, handleApiResponseSuccess });
} else {
const offerId = offer._id;
submitEditOffer({ offerId, offerData, handleApiResponseSuccess });
}
closeCreateOfferModal(false);
};

@@ -182,7 +209,11 @@ const CreateOffer = ({ history, closeCreateOfferModal }) => {
{currentStep !== 1 ? <ArrowBack /> : ""}
</BackIcon>
<CreateOfferTitle component="h1" variant="h5">
{currentStep === 3 ? "Pregled" : "Nova Objava"}
{currentStep === 3
? "Pregled"
: `${
editOffer !== undefined ? "Izmena Objave" : "Nova Objava"
}`}
</CreateOfferTitle>
<CloseIcon onClick={closeModalHandler}>
<CloseButton />
@@ -195,10 +226,10 @@ const CreateOffer = ({ history, closeCreateOfferModal }) => {
functions={[() => goStepBack(1), () => goStepBack(2)]}
/>
{currentStep === 1 && (
<FirstPartCreateOffer handleNext={handleNext} />
<FirstPartCreateOffer handleNext={handleNext} offer={offer} />
)}
{currentStep === 2 && (
<SecondPartCreateOffer handleNext={handleNext} />
<SecondPartCreateOffer handleNext={handleNext} offer={offer} />
)}
{currentStep === 3 && (
<ThirdPartCreateOffer

+ 45
- 21
src/components/Cards/CreateOfferCard/FirstPart/FirstPartCreateOffer.js Прегледај датотеку

@@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import PropTypes from "prop-types";
import { useFormik } from "formik";
import {
@@ -17,23 +17,39 @@ import { useSelector } from "react-redux";
import useScreenDimensions from "../../../../hooks/useScreenDimensions";

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 dimensions = useScreenDimensions();


const { t } = useTranslation();

useEffect(() => {
if (props.offer !== undefined) {
let scat = categories.filter(
(cat) => cat.name === props.offer.category.name
);

console.log(categories);
console.log(scat[0].subcategories.map((x) => x.name));
setSubcat(scat[0].subcategories.map((x) => x.name));
}
}, [props.offer]);

const handleSubmit = (values) => {
props.handleNext(values);
};
const formik = useFormik({
initialValues: {
nameOfProduct: "",
description: "",
location: "",
category: "",
subcategory: "",
nameOfProduct: `${props.offer === undefined ? "" : props.offer.name}`,
description: `${
props.offer === undefined ? "" : props.offer.description
}`,
location: `${props.offer === undefined ? "" : props.offer.location.city}`,
category: `${props.offer === undefined ? "" : props.offer.category.name}`,
subcategory: `${
props.offer === undefined ? "" : props.offer.subcategory
}`,
},
validationSchema: Yup.object().shape({
nameOfProduct: Yup.string().required(t("login.nameOfProductRequired")),
@@ -51,7 +67,8 @@ const FirstPartCreateOffer = (props) => {

const handleSubcategories = (category) => {
const filtered = categories.filter((cat) => cat.name === category);
setSubcat(filtered);
console.log(filtered[0].subcategories.map((c) => c.name));
setSubcat(filtered[0].subcategories.map((c) => c.name));
};

return (
@@ -104,15 +121,17 @@ const FirstPartCreateOffer = (props) => {

<FieldLabel leftText={t("offer.location")} />
<SelectField
defaultValue="default"
defaultValue={
props.offer === undefined ? "default" : props.offer.location.city
}
onChange={(value) => {
formik.setFieldValue("location", value.target.value.city);
formik.setFieldValue("location", value.target.value);
}}
>
<Option value="default">{t("offer.choseLocation")}</Option>
{locations.map((loc) => {
return (
<Option key={loc._if} value={loc}>
<Option key={loc._if} value={loc.city}>
{loc.city}
</Option>
);
@@ -121,9 +140,11 @@ const FirstPartCreateOffer = (props) => {

<FieldLabel leftText={t("offer.category")} />
<SelectField
defaultValue="default"
defaultValue={
props.offer === undefined ? "default" : props.offer.category.name
}
onChange={(value) => {
formik.setFieldValue("category", value.target.value.name);
formik.setFieldValue("category", value.target.value);
}}
>
<Option value="default">{t("offer.choseCategory")}</Option>
@@ -131,7 +152,7 @@ const FirstPartCreateOffer = (props) => {
return (
<Option
key={i}
value={cat}
value={cat.name}
onClick={() => handleSubcategories(cat.name)}
>
{cat.name}
@@ -142,18 +163,20 @@ const FirstPartCreateOffer = (props) => {

<FieldLabel leftText={t("offer.subcategory")} />
<SelectField
defaultValue="default"
defaultValue={
props.offer === undefined ? "default" : props.offer.subcategory
}
// defaultValue="default"
onChange={(value) => {
formik.setFieldValue("subcategory", value.target.value.name);
formik.setFieldValue("subcategory", value.target.value);
}}
>
<Option value="default">{t("offer.choseSubcategory")}</Option>
{subcat?.length > 0 &&
subcat[0]?.subcategories &&
subcat[0].subcategories.map((sub, i) => {
{subcat &&
subcat.map((sub, i) => {
return (
<Option key={i} value={sub}>
{sub.name}
{sub}
</Option>
);
})}
@@ -180,6 +203,7 @@ const FirstPartCreateOffer = (props) => {
FirstPartCreateOffer.propTypes = {
children: PropTypes.any,
handleNext: PropTypes.func,
offer: PropTypes.node,
};

export default FirstPartCreateOffer;

+ 75
- 16
src/components/Cards/CreateOfferCard/SecondPart/SecondPartCreateOffer.js Прегледај датотеку

@@ -1,4 +1,4 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import {
CreateOfferFormContainer,
@@ -23,6 +23,35 @@ const SecondPartCreateOffer = (props) => {
const [images, setImages] = useState(
Array.apply(null, Array(numberOfImages)).map(() => {})
); // 3 images

useEffect(() => {
// let editedImages = [];

// if (props.offer !== undefined && props.offer.images.length === 1) {
// editedImages.push(props.offer.images[0]);
// editedImages.push("");
// editedImages.push("");
// } else if (props.offer !== undefined && props.offer.images.length === 2) {
// editedImages.push(props.offer.images[0]);
// editedImages.push(props.offer.images[1]);
// editedImages.push("");
// }
setImages((prevState) => {
let editedImages = [...prevState];
if (props.offer !== undefined && props.offer.images.length === 1) {
editedImages[0] = props.offer.images[0];
}

if (props.offer !== undefined && props.offer.images.length === 2) {
editedImages[0] = props.offer.images[0];

editedImages[1] = props.offer.images[1];
}

return [...editedImages];
});
}, [props.offer]);

const setImage = (index, image) => {
setImages((prevState) => {
let newState = [...prevState];
@@ -33,9 +62,9 @@ const SecondPartCreateOffer = (props) => {
const { t } = useTranslation();

let imagesEmpty = 0;
images.forEach(item => {
if (item === null || item === undefined) imagesEmpty++;
})
images.forEach((item) => {
if (item === null || item === undefined) imagesEmpty++;
});

const handleSubmit = (values) => {
props.handleNext(values);
@@ -44,7 +73,7 @@ const SecondPartCreateOffer = (props) => {
const formik = useFormik({
initialValues: {
images: images,
condition: "",
condition: `${props.offer === undefined ? "" : props.offer.condition}`,
},
validationSchema: Yup.object().shape({}),
onSubmit: handleSubmit,
@@ -52,18 +81,42 @@ const SecondPartCreateOffer = (props) => {
enableReinitialize: true,
});

console.log("slike", images);

return (
<CreateOfferFormContainer component="form" onSubmit={formik.handleSubmit}>
<Scroller>
{images.map((item, index) => (
<ImagePicker
key={index}
image={item}
setImage={(image) => setImage(index, image)}
deleteImage={() => setImage(index, null)}
showDeleteIcon
/>
))}
{images.map((item, index) => {
console.log(item);
return (
<ImagePicker
key={index}
image={item}
setImage={(image) => setImage(index, image)}
deleteImage={() => setImage(index, null)}
showDeleteIcon
/>
);
})}
{/* {props.offer === undefined
? images.map((item, index) => (
<ImagePicker
key={index}
image={item}
setImage={(image) => setImage(index, image)}
deleteImage={() => setImage(index, null)}
showDeleteIcon
/>
))
: editedImages.map((item, index) => (
<ImagePicker
key={index}
image={item}
setImage={(image) => setImage(index, image)}
deleteImage={() => setImage(index, null)}
showDeleteIcon
/>
))} */}
</Scroller>
<SupportedFormats>
<Trans i18nKey="offer.supportedImagesFormats" />
@@ -71,7 +124,9 @@ const SecondPartCreateOffer = (props) => {
<InputButtonContainer>
<FieldLabel leftText={t("offer.condition")} />
<SelectField
defaultValue="default"
defaultValue={
props.offer === undefined ? "default" : props.offer.condition
}
onChange={(value) => {
formik.setFieldValue("condition", value.target.value);
}}
@@ -95,7 +150,10 @@ const SecondPartCreateOffer = (props) => {
fullWidth
buttoncolor={selectedTheme.primaryPurple}
textcolor="white"
disabled={imagesEmpty === numberOfImages}
// disabled={imagesEmpty === numberOfImages}
disabled={
props.offer === undefined ? imagesEmpty === numberOfImages : false
}
>
{t("offer.continue")}
</NextButton>
@@ -107,6 +165,7 @@ const SecondPartCreateOffer = (props) => {
SecondPartCreateOffer.propTypes = {
children: PropTypes.node,
handleNext: PropTypes.func,
offer: PropTypes.node,
};

export default SecondPartCreateOffer;

+ 9
- 10
src/components/Cards/CreateOfferCard/ThirdPart/ThirdPartCreateOffer.js Прегледај датотеку

@@ -1,6 +1,9 @@
import React from "react";
import PropTypes from "prop-types";
import { CreateOfferFormContainer, PreviewCard } from "./ThirdPartCreateOffer.styled";
import {
CreateOfferFormContainer,
PreviewCard,
} from "./ThirdPartCreateOffer.styled";

const ThirdPartCreateOffer = (props) => {
const offer = {
@@ -11,11 +14,11 @@ const ThirdPartCreateOffer = (props) => {
subcategory: props.informations.subcategory,
condition: props.informations.condition,
_created: new Date().toString(),
images: props.informations.images.filter(item => item !== undefined),
images: props.informations.images.filter((item) => item !== undefined),
name: props.informations.nameOfProduct,
description: props.informations.description
}
}
description: props.informations.description,
},
};
const handleSubmit = (e) => {
e.preventDefault();
props.handleSubmitOffer();
@@ -23,11 +26,7 @@ const ThirdPartCreateOffer = (props) => {

return (
<CreateOfferFormContainer component="form" onSubmit={handleSubmit}>
<PreviewCard
offer={offer}
showBarterButton={false}
showPublishButton
/>
<PreviewCard offer={offer} showBarterButton={false} showPublishButton />
</CreateOfferFormContainer>
);
};

+ 110
- 0
src/components/Cards/OfferCard/DeleteOffer.js Прегледај датотеку

@@ -0,0 +1,110 @@
import React from "react";
import PropTypes from "prop-types";
import {
ButtonsContainer,
DeleteOfferContainer,
DeleteQuestion,
OfferInfo,
OfferImageContainer,
OfferImage,
OfferDescription,
OfferDescriptionTitle,
OfferDescriptionCategory,
CancelButton,
RemoveIconContainer,
RemoveIcon,
SaveButton,
CategoryIcon,
} from "./DeleteOffer.styles";
import selectedTheme from "../../../themes";
import { ReactComponent as Category } from "../../../assets/images/svg/category.svg";
import BackdropComponent from "../../MUI/BackdropComponent";
import { useDispatch } from "react-redux";
import {
fetchProfileOffers,
removeOffer,
} from "../../../store/actions/offers/offersActions";
import { useTranslation, Trans } from "react-i18next";

const DeleteOffer = (props) => {
const dispatch = useDispatch();
const { t } = useTranslation();
const userId = props.offer.userId;
const offerId = props.offer._id;
const closeDeleteModalHandler = () => {
props.closeModalHandler();
};

const handleApiResponseSuccess = () => {
dispatch(fetchProfileOffers(userId));
};

const removeOfferHandler = () => {
dispatch(removeOffer({ offerId, handleApiResponseSuccess }));
props.closeModalHandler();
};

return (
<>
<BackdropComponent
isLoading
position="fixed"
handleClose={closeDeleteModalHandler}
/>
<DeleteOfferContainer>
<OfferInfo>
<OfferImageContainer>
<OfferImage src={props.offer.images[0]} />
</OfferImageContainer>
<OfferDescription>
<OfferDescriptionTitle>{props.offer.name}</OfferDescriptionTitle>
<OfferDescriptionCategory>
<CategoryIcon color="#c4c4c4" component="span" size="16px">
<Category />
</CategoryIcon>
{props.offer.category.name}
</OfferDescriptionCategory>
</OfferDescription>
<RemoveIconContainer>
<RemoveIcon />
</RemoveIconContainer>
</OfferInfo>
<DeleteQuestion>
<Trans i18nKey="deleteOffer.areYouSure" />
</DeleteQuestion>
<ButtonsContainer>
<CancelButton
variant="contained"
height="48px"
width="180px"
fullWidth
buttoncolor={selectedTheme.primaryPurple}
textcolor="white"
onClick={closeDeleteModalHandler}
>
{t("deleteOffer.cancel")}
</CancelButton>
<SaveButton
type="submit"
variant="outlined"
height="48px"
width="180px"
fullWidth
buttoncolor={selectedTheme.primaryPurple}
textcolor={selectedTheme.primaryPurple}
onClick={removeOfferHandler}
>
{t("deleteOffer.delete")}
</SaveButton>
</ButtonsContainer>
</DeleteOfferContainer>
</>
);
};

DeleteOffer.propTypes = {
offer: PropTypes.node,
closeModalHandler: PropTypes.func,
};

export default DeleteOffer;

+ 134
- 0
src/components/Cards/OfferCard/DeleteOffer.styles.js Прегледај датотеку

@@ -0,0 +1,134 @@
import { Typography } from "@mui/material";
import { Box } from "@mui/system";
import styled from "styled-components";
import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton";
import { Icon } from "../../Icon/Icon";
import { ReactComponent as Remove } from "../../../assets/images/svg/trash-gold.svg";
import selectedTheme from "../../../themes";
import { IconButton } from "../../Buttons/IconButton/IconButton";

export const DeleteOfferContainer = styled(Box)`
width: 537px;
height: 309px;
position: fixed;
top: calc(50% - 155px);
left: calc(50% - 268px);
background-color: #fff;
display: flex;
flex-direction: column;
align-items: center;
padding: 0 80px;
z-index: 150;

@media screen and (max-width: 600px) {
width: 350px;
display: block;
padding: 0 18px;
left: calc(50% - 175px);
}
`;

export const OfferInfo = styled(Box)`
width: 211px;
height: 90px;
border: 1px solid #d4d4d4;
display: flex;
align-items: center;
padding: 18px;
margin-top: 36px;

@media screen and (max-width: 600px) {
margin-left: calc(50% - 105px) !important;
}
`;

export const OfferImageContainer = styled(Box)`
width: 54px;
height: 54px;
border-radius: 2px;

@media screen and (max-width: 600px) {
margin-right: 13px;
}
`;

export const OfferImage = styled.img`
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 2px;
`;

export const OfferDescription = styled(Box)`
display: flex;
flex-direction: column;
margin-left: 9px;
`;

export const OfferDescriptionTitle = styled(Typography)`
font-size: 16px;
font-weight: 600;
color: ${selectedTheme.primaryPurple};
`;

export const OfferDescriptionCategory = styled(Typography)`
font-size: 12px;
`;

export const CategoryIcon = styled(Icon)`
& svg {
width: 14px;
position: relative;
top: -1px;
}
`;

export const DeleteQuestion = styled(Typography)`
font-family: "Open Sans";
font-size: 16px;
font-weight: 600;
text-align: center;
margin: 36px 0;

@media screen and (max-width: 600px) {
margin-left: calc(50% - 104px);
}
`;

export const RemoveIconBorder = styled(IconButton)`
width: 40px;
height: 40px;
position: absolute;
top: 16px;
right: 143px;
background-color: ${selectedTheme.primaryPurple};
border-radius: 100%;
padding-top: 2px;
text-align: center;

@media screen and (max-width: 600px) {
right: 50px;
}
`;

export const RemoveIconContainer = styled(RemoveIconBorder)``;

export const RemoveIcon = styled(Remove)``;

export const ButtonsContainer = styled(Box)`
display: flex;
width: 100%;
justify-content: space-between;
`;

export const CancelButton = styled(PrimaryButton)`
@media screen and (max-width: 600px) {
width: 140px;
}
`;

export const SaveButton = styled(PrimaryButton)`
@media screen and (max-width: 600px) {
width: 140px;
}
`;

+ 46
- 7
src/components/Cards/OfferCard/OfferCard.js Прегледај датотеку

@@ -1,4 +1,4 @@
import React from "react";
import React, { useState } from "react";
import PropTypes from "prop-types";
import {
CheckButton,
@@ -28,17 +28,37 @@ import {
RemoveIcon,
RemoveIconContainer,
} from "./OfferCard.styled";
import DeleteOffer from "./DeleteOffer";
import { ReactComponent as Category } from "../../../assets/images/svg/category.svg";
import { ReactComponent as Message } from "../../../assets/images/svg/mail.svg";
import selectedTheme from "../../../themes";
import { useHistory } from "react-router-dom";
import CreateOffer from "../CreateOfferCard/CreateOffer";

const OfferCard = (props) => {
const [deleteOfferModal, setDeleteOfferModal] = useState(false);
const [editOfferModal, setEditOfferModal] = useState(false);
const history = useHistory();

const routeToItem = (itemId) => {
history.push(`/proizvodi/${itemId}`);
};

const closeModalHandler = () => {
setDeleteOfferModal(false);
};

const closeCreateOfferModal = () => {
setEditOfferModal(false);
};

if (deleteOfferModal || editOfferModal) {
document.body.style.overflow = "hidden";
} else {
document.body.style.overflow = "auto";
}

console.log(props.offer);
return (
<React.Fragment>
<OfferCardContainer
@@ -121,12 +141,18 @@ const OfferCard = (props) => {

{props.isMyOffer ? (
<>
<RemoveIconContainer vertical={props.vertical}>
<RemoveIcon />
</RemoveIconContainer>
<EditIconContainer vertical={props.vertical}>
<EditIcon />
</EditIconContainer>
<RemoveIconContainer
vertical={props.vertical}
onClick={() => setDeleteOfferModal(true)}
>
<RemoveIcon />
</RemoveIconContainer>
<EditIconContainer
vertical={props.vertical}
onClick={() => setEditOfferModal(true)}
>
<EditIcon />
</EditIconContainer>
</>
) : (
<MessageIcon vertical={props.vertical}>
@@ -135,6 +161,19 @@ const OfferCard = (props) => {
)}
</OfferFlexContainer>
</OfferCardContainer>
{deleteOfferModal && (
<DeleteOffer
offer={props.offer}
closeModalHandler={closeModalHandler}
/>
)}
{editOfferModal && (
<CreateOffer
editOffer
closeCreateOfferModal={closeCreateOfferModal}
offer={props.offer}
/>
)}
</React.Fragment>
);
};

+ 21
- 13
src/components/Cards/OfferCard/OfferCard.styled.js Прегледај датотеку

@@ -8,8 +8,6 @@ import { ReactComponent as Eye } from "../../../assets/images/svg/eye-striked.sv
import { ReactComponent as Remove } from "../../../assets/images/svg/trash.svg";
import { ReactComponent as Edit } from "../../../assets/images/svg/edit.svg";



export const OfferCardContainer = styled(Container)`
display: flex;
flex-direction: column;
@@ -93,6 +91,7 @@ export const OfferTitle = styled(Typography)`
width: calc(100% - 120px);
cursor: pointer;
@media (max-width: 550px) {
width: 100%;
font-size: 18px;
display: none;
${(props) =>
@@ -290,13 +289,14 @@ export const OfferImageContainer = styled(Box)`
height: 144px;
@media (max-width: 600px) {
${(props) =>
!props.vertical ?
`
!props.vertical
? `
min-width: 108px;
min-height: 108px;
width: 108px;
height: 108px;
` : `margin-top: 4px;`}
`
: `margin-top: 4px;`}
border-radius: 4px;
overflow: hidden;
box-shadow: 4px 4px 9px rgba(0, 0, 0, 0.12);
@@ -321,14 +321,22 @@ export const EyeIcon = styled(Eye)`
}
`;
export const RemoveIconContainer = styled(MessageIcon)`

`
export const RemoveIcon = styled(Remove)`

`
@media screen and (max-width: 600px) {
position: absolute;
display: block;
right: 20px;
top: 75%;
}
`;
export const RemoveIcon = styled(Remove)``;
export const EditIconContainer = styled(MessageIcon)`
right: 70px;
`
export const EditIcon = styled(Edit)`

`
@media screen and (max-width: 600px) {
position: absolute;
display: block;
right: 20px;
top: 60%;
}
`;
export const EditIcon = styled(Edit)``;

+ 7
- 0
src/components/ImagePicker/ImagePicker.js Прегледај датотеку

@@ -20,6 +20,13 @@ const ImagePicker = (props) => {
const [image, setImage] = useState("");
const [isEditing, setIsEditing] = useState(false);

useEffect(() => {
console.log("image", props);
if (props.image) {
setImage(props.image);
}
}, [props.image]);

let listener;
useEffect(() => {
listener = (event) => {

+ 318
- 0
src/components/ProfileCard/EditProfile.js Прегледај датотеку

@@ -0,0 +1,318 @@
import React, { useState } from "react";
import PropTypes from "prop-types";
import { FieldLabel } from "../Cards/CreateOfferCard/FirstPart/FirstPartCreateOffer.styled";
import BackdropComponent from "../MUI/BackdropComponent";
import {
EditProfileContainer,
ProfileImageContainer,
InputField,
BackButton,
CloseButton,
SaveButton,
ProfileHeader,
BasicInfo,
DetailsInfo,
ButtonsContainer,
MobileInfo,
ErrorMessage,
ProfileImagePicker,
} from "./EditProfile.styled";
import selectedTheme from "../../themes";
import { useFormik } from "formik";
import * as Yup from "yup";
import { ReactComponent as ArrowBack } from "../../assets/images/svg/arrow-back.svg";
import { ReactComponent as CloseIcon } from "../../assets/images/svg/close-modal.svg";
import { useTranslation } from "react-i18next";
import {
editMineProfile,
fetchMineProfile,
} from "../../store/actions/profile/profileActions";
import { useDispatch } from "react-redux";
import useScreenDimensions from "../../hooks/useScreenDimensions";
import { useRouteMatch } from "react-router-dom";

const EditProfile = (props) => {
const [profileImage, setProfileImage] = useState(props.profile.image);
const [showDetails, setShowDetails] = useState(false);
const { t } = useTranslation();
const dispatch = useDispatch();
const dimensions = useScreenDimensions();
const routeMatch = useRouteMatch();
const userId = routeMatch.params.idProfile;

const handleApiResponseSuccess = () => {
dispatch(fetchMineProfile(userId));
props.reFetchProfile();
};

const handleSubmit = (values) => {
dispatch(editMineProfile({ ...values, handleApiResponseSuccess }));
props.closeModalHandler();
};

const formik = useFormik({
initialValues: {
firmName: `${props.profile.company.name}`,
firmPIB: `${props.profile.company.PIB}`,
firmLocation: `${props.profile.company.contacts.location}`,
firmWebsite: `${props.profile.company.contacts.web}`,
firmApplink: "",
firmPhone: `${props.profile.company.contacts.telephone}`,
firmLogo: profileImage,
},
validationSchema: Yup.object().shape({
firmName: Yup.string().required(t("editProfile.labelNameRequired")),
firmPIB: Yup.string()
.required(t("editProfile.labelPIBRequired"))
.min(9, t("register.PIBnoOfCharacters")),
firmLocation: Yup.string().required(
t("editProfile.labelLocationRequired")
),
firmWebsite: Yup.string(),
firmApplink: Yup.string(),
firmPhone: Yup.string().required(t("editProfile.labelPhoneRequired")),
}),
onSubmit: handleSubmit,
validateOnBlur: true,
enableReinitialize: true,
});

const closeEditModalHandler = () => {
props.closeModalHandler();
};

const showDetailsHandler = () => {
setShowDetails(!showDetails);
};

const setImage = (image) => {
setProfileImage(image);
};

return (
<>
<BackdropComponent
handleClose={closeEditModalHandler}
isLoading
position="fixed"
/>
<EditProfileContainer component="form" onSubmit={formik.handleSubmit}>
{showDetails && (
<BackButton onClick={showDetailsHandler}>
<ArrowBack />
</BackButton>
)}
<ProfileImageContainer>
<ProfileImagePicker
image={profileImage}
setImage={setImage}
></ProfileImagePicker>
<ProfileHeader>{props.profile.company.name}</ProfileHeader>
</ProfileImageContainer>
<CloseButton onClick={closeEditModalHandler}>
<CloseIcon />
</CloseButton>
{dimensions.width > 600 ? (
<>
<FieldLabel leftText={t("common.labelFirm").toUpperCase()} />
<InputField
name="firmName"
value={formik.values.firmName}
onChange={formik.handleChange}
error={formik.touched.firmName && formik.errors.firmName}
// helperText={formik.touched.firmName && formik.errors.firmName}
margin="normal"
fullWidth
/>
<FieldLabel leftText={t("common.labelPIB")} />
<InputField
name="firmPIB"
value={formik.values.firmPIB}
onChange={formik.handleChange}
error={formik.touched.firmPIB && formik.errors.firmPIB}
// helperText={formik.touched.firmPIB && formik.errors.firmPIB}
margin="normal"
fullWidth
/>
<FieldLabel leftText={t("common.labelLocation").toUpperCase()} />
<InputField
name="firmLocation"
value={formik.values.firmLocation}
onChange={formik.handleChange}
error={formik.touched.firmLocation && formik.errors.firmLocation}
// helperText={
// formik.touched.firmLocation && formik.errors.firmLocation
// }
margin="normal"
fullWidth
/>
<FieldLabel leftText={t("editProfile.website").toUpperCase()} />
<InputField
name="firmWebsite"
value={formik.values.firmWebsite}
onChange={formik.handleChange}
margin="normal"
fullWidth
/>
<FieldLabel leftText={t("editProfile.applink").toUpperCase()} />
<InputField
name="firmApplink"
values={formik.values.firmApplink}
margin="normal"
fullWidth
/>
<FieldLabel leftText={t("editProfile.phoneNumber").toUpperCase()} />
<InputField
name="firmPhone"
value={formik.values.firmPhone}
onChange={formik.handleChange}
error={formik.touched.firmPhone && formik.errors.firmPhone}
// helperText={formik.touched.firmPhone && formik.errors.firmPhone}
margin="normal"
fullWidth
/>
</>
) : (
<MobileInfo>
{!showDetails && (
<BasicInfo>
<FieldLabel leftText={t("common.labelFirm").toUpperCase()} />
<InputField
name="firmName"
value={formik.values.firmName}
onChange={formik.handleChange}
error={formik.touched.firmName && formik.errors.firmName}
// helperText={formik.touched.firmName && formik.errors.firmName}
margin="normal"
fullWidth
/>
<FieldLabel leftText={t("common.labelPIB")} />
<InputField
name="firmPIB"
value={formik.values.firmPIB}
onChange={formik.handleChange}
error={formik.touched.firmPIB && formik.errors.firmPIB}
// helperText={formik.touched.firmPIB && formik.errors.firmPIB}
margin="normal"
fullWidth
/>
<FieldLabel
leftText={t("common.labelLocation").toUpperCase()}
/>
<InputField
name="firmLocation"
value={formik.values.firmLocation}
onChange={formik.handleChange}
error={
formik.touched.firmLocation && formik.errors.firmLocation
}
// helperText={
// formik.touched.firmLocation && formik.errors.firmLocation
// }
margin="normal"
fullWidth
/>
</BasicInfo>
)}
{showDetails && (
<DetailsInfo>
<FieldLabel leftText={t("editProfile.website").toUpperCase()} />
<InputField
name="firmWebsite"
value={formik.values.firmWebsite}
onChange={formik.handleChange}
margin="normal"
fullWidth
/>
<FieldLabel leftText={t("editProfile.applink").toUpperCase()} />
<InputField
name="firmApplink"
values={formik.values.firmApplink}
margin="normal"
fullWidth
/>
<FieldLabel
leftText={t("editProfile.phoneNumber").toUpperCase()}
/>
<InputField
name="firmPhone"
value={formik.values.firmPhone}
onChange={formik.handleChange}
error={formik.touched.firmPhone && formik.errors.firmPhone}
// helperText={
// formik.touched.firmPhone && formik.errors.firmPhone
// }
margin="normal"
fullWidth
/>
</DetailsInfo>
)}
</MobileInfo>
)}

{formik.errors.firmName && formik.touched.firmName ? (
<ErrorMessage>{formik.errors.firmName}</ErrorMessage>
) : formik.errors.firmPIB && formik.touched.firmPIB ? (
<ErrorMessage>{formik.errors.firmPIB}</ErrorMessage>
) : formik.errors.firmLocation && formik.touched.firmLocation ? (
<ErrorMessage>{formik.errors.firmLocation}</ErrorMessage>
) : formik.errors.firmPhone && formik.touched.firmPhone ? (
<ErrorMessage>{formik.errors.firmPhone}</ErrorMessage>
) : (
<></>
)}

{dimensions.width > 600 ? (
<SaveButton
type="submit"
variant="contained"
height="48px"
fullWidth
buttoncolor={selectedTheme.primaryPurple}
textcolor="white"
>
{t("editProfile.saveChanges")}
</SaveButton>
) : (
<ButtonsContainer>
<SaveButton
// type="submit"
// variant="outlined"
height="48px"
width="155px"
buttoncolor={selectedTheme.primaryPurple}
textcolor={selectedTheme.primaryPurple}
onClick={showDetailsHandler}
>
{showDetails
? t("editProfile.showBasic")
: t("editProfile.showDetails")}
</SaveButton>
<SaveButton
type="submit"
variant="contained"
height="48px"
width="155px"
buttoncolor={selectedTheme.primaryPurple}
textcolor="white"
>
{t("common.save")}
</SaveButton>
</ButtonsContainer>
)}
</EditProfileContainer>
</>
);
};

EditProfile.propTypes = {
children: PropTypes.node,
profile: PropTypes.any,
closeModalHandler: PropTypes.func,
setImage: PropTypes.func,
reFetchProfile: PropTypes.func,
// error: PropTypes.string,
// errorMessage: PropTypes.string,
};

export default EditProfile;

+ 120
- 0
src/components/ProfileCard/EditProfile.styled.js Прегледај датотеку

@@ -0,0 +1,120 @@
import styled from "styled-components";
import { Box, TextField, Typography } from "@mui/material";
import ImagePicker from "../ImagePicker/ImagePicker";
import { PrimaryButton } from "../Buttons/PrimaryButton/PrimaryButton";

export const EditProfileContainer = styled(Box)`
background-color: #fff;
position: fixed;
top: 50px;
left: calc(50% - 310px);
z-index: 150;
padding: 0 144px;
width: 600px;
max-height: 90vh;
overflow-y: auto;

@media screen and (max-width: 600px) {
width: 375px;
padding: 0 30px;
top: 60px;
left: calc(50% - 187px);
}
`;

export const ProfileImageContainer = styled(Box)`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
`;

export const ProfileImagePicker = styled(ImagePicker)`
background: none;
margin: 36px;
background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' rx='100' ry='100' stroke='%235A3984FF' stroke-width='2' stroke-dasharray='7%2c 12' stroke-dashoffset='44' stroke-linecap='square'/%3e%3c/svg%3e");
border-radius: 100px;
overflow: hidden;
position: relative;
margin-bottom: 5px;
`;
export const ProfilePicture = styled.img`
position: absolute;
left: 36px;
top: 24px;
z-index: 0;
`;

export const ProfileImage = styled.img`
width: 144px;
height: 144px;
border-radius: 100%;
`;

export const ProfileHeader = styled(Typography)`
font-family: "Open Sans";
font-size: 24px;
font-weight: bold;
margin-top: 6px;

@media screen and (max-width: 600px) {
font-size: 18px;
}
`;

export const BackButton = styled(Box)`
cursor: pointer;
position: absolute;
top: 40px;
left: 40px;

@media screen and (max-width: 600px) {
svg {
width: 20px;
height: 20px;
}
}
`;

export const CloseButton = styled(Box)`
cursor: pointer;
position: absolute;
top: 40px;
right: 40px;

@media screen and (max-width: 600px) {
svg {
width: 20px;
height: 20px;
}
}
`;

export const InputField = styled(TextField)`
& input {
padding: 10px 16px;
}
`;

export const SaveButton = styled(PrimaryButton)`
margin: 16px 0;
`;

export const ButtonsContainer = styled(Box)`
display: flex;
margin-top: 108px;
`;

export const ErrorMessage = styled(Typography)`
color: red;
font-family: "Open Sans";
position: relative;
top: 20px;
font-size: 14px;
`;

export const MobileInfo = styled(Box)``;

export const BasicInfo = styled(Box)``;

export const DetailsInfo = styled(Box)``;

+ 61
- 16
src/components/ProfileCard/ProfileCard.js Прегледај датотеку

@@ -26,11 +26,36 @@ import {
import { Grid, Stack } from "@mui/material";

import PersonOutlineIcon from "@mui/icons-material/PersonOutline";
import { useSelector } from "react-redux";
import { useRouteMatch } from "react-router-dom";
import { fetchProfile } from "../../store/actions/profile/profileActions";
import { useDispatch, useSelector } from "react-redux";
import { useEffect } from "react";
import { selectProfile } from "../../store/selectors/profileSelectors";
import { selectUserId } from "../../store/selectors/loginSelectors";
import { useState } from "react";
import { fetchProfileOffers } from "../../store/actions/offers/offersActions";
import EditProfile from "./EditProfile";

const ProfileCard = (props) => {
const ProfileCard = () => {
const [isMyProfile, setIsMyProfile] = useState(false);
const [editProfileModal, setEditProfileModal] = useState(false);
const routeMatch = useRouteMatch();
const dispatch = useDispatch();
const profile = useSelector(selectProfile);
const userId = useSelector(selectUserId);
const idProfile = routeMatch.params.idProfile;
console.log(idProfile);
useEffect(() => {
if (idProfile?.length > 0) {
reFetchProfile();
}
}, [idProfile]);

const reFetchProfile = () => {
dispatch(fetchProfile(idProfile));
dispatch(fetchProfileOffers(idProfile));
if (userId === idProfile) setIsMyProfile(true);
};

let percentOfSucceededExchanges;
if (profile?.statistics?.exchanges?.succeeded === 0) {
@@ -42,6 +67,18 @@ const ProfileCard = (props) => {
100
);
}

const closeModalHandler = () => {
setEditProfileModal(false);
};

if (editProfileModal) {
document.body.style.overflow = "hidden";
} else {
document.body.style.overflow = "auto";
}

console.log(profile);
return (
<>
<ProfileCardContainer>
@@ -53,12 +90,14 @@ const ProfileCard = (props) => {
sx={{ mb: 1.4 }}
>
<PersonOutlineIcon color="action" sx={{ mr: 0.9 }} />
<HeaderTitle>{props.isMyProfile ? "Moj profil" : "Profil kompanije"}</HeaderTitle>
<HeaderTitle>Moj Profil</HeaderTitle>
</Grid>
<ProfileCardWrapper variant="outlined" isMyProfile={props.isMyProfile}>
{props.isMyProfile ? (<EditButton>
<EditIcon />
</EditButton>) : (
<ProfileCardWrapper variant="outlined" isMyProfile={isMyProfile}>
{isMyProfile ? (
<EditButton onClick={() => setEditProfileModal(true)}>
<EditIcon />
</EditButton>
) : (
<MessageButton>
<MessageIcon />
</MessageButton>
@@ -89,7 +128,7 @@ const ProfileCard = (props) => {
alignItems="start"
sx={{ ml: 2 }}
>
<ProfileName isMyProfile={props.isMyProfile} variant="h5">
<ProfileName isMyProfile={isMyProfile} variant="h5">
{profile?.company?.name}
</ProfileName>
<ProfilePIBContainer
@@ -99,7 +138,7 @@ const ProfileCard = (props) => {
alignItems="center"
>
<PocketIcon />
<ProfilePIB isMyProfile={props.isMyProfile} variant="subtitle2">
<ProfilePIB isMyProfile={isMyProfile} variant="subtitle2">
PIB: {profile?.company?.PIB}
</ProfilePIB>
</ProfilePIBContainer>
@@ -113,20 +152,20 @@ const ProfileCard = (props) => {
alignItems={{ xs: "start", sm: "center" }}
>
<Stack direction="row">
<LocationIcon isMyProfile={props.isMyProfile} />
<ContactItem isMyProfile={props.isMyProfile} variant="subtitle2">
<LocationIcon isMyProfile={isMyProfile} />
<ContactItem isMyProfile={isMyProfile} variant="subtitle2">
{profile?.company?.contacts?.location}
</ContactItem>
</Stack>
<Stack direction="row">
<MailIcon isMyProfile={props.isMyProfile} />
<ContactItem isMyProfile={props.isMyProfile} variant="subtitle2">
<MailIcon isMyProfile={isMyProfile} />
<ContactItem isMyProfile={isMyProfile} variant="subtitle2">
{profile?.email}
</ContactItem>
</Stack>
<Stack direction="row">
<GlobeIcon isMyProfile={props.isMyProfile} />
<ContactItem isMyProfile={props.isMyProfile} variant="subtitle2">
<GlobeIcon isMyProfile={isMyProfile} />
<ContactItem isMyProfile={isMyProfile} variant="subtitle2">
{profile?.company?.contacts?.web}
</ContactItem>
</Stack>
@@ -171,13 +210,19 @@ const ProfileCard = (props) => {
</Grid>
</ProfileCardWrapper>
</ProfileCardContainer>
{editProfileModal && (
<EditProfile
profile={profile}
closeModalHandler={closeModalHandler}
reFetchProfile={reFetchProfile}
/>
)}
</>
);
};

ProfileCard.propTypes = {
children: PropTypes.node,
isMyProfile: PropTypes.bool,
};

export default ProfileCard;

+ 1
- 1
src/components/Select/Option/Option.js Прегледај датотеку

@@ -20,7 +20,7 @@ Option.propTypes = {
color: PropTypes.any,
startIcon: PropTypes.any,
value: PropTypes.any,
// selected: PropTypes.bool,
selected: PropTypes.bool,
};
Option.defaultProps = {
// selected: true

+ 3
- 3
src/components/Select/Select.js Прегледај датотеку

@@ -8,8 +8,8 @@ import { ReactComponent as Down } from "../../assets/images/svg/down-arrow.svg";
const Select = (props) => {
const [isOpened, setIsOpened] = useState(false);
const handleOpen = () => {
setIsOpened(prevState => !prevState);
}
setIsOpened((prevState) => !prevState);
};
return (
<SelectStyled
defaultValue={props.defaultValue}
@@ -37,7 +37,7 @@ Select.propTypes = {
width: PropTypes.string,
height: PropTypes.string,
fullwidth: PropTypes.bool,
defaultValue: PropTypes.number,
defaultValue: PropTypes.any,
className: PropTypes.string,
onChange: PropTypes.func,
value: PropTypes.any,

+ 19
- 2
src/i18n/resources/rs.js Прегледај датотеку

@@ -173,6 +173,23 @@ export default {
},
reviews: {
title: "Ova kompanija još uvek nema ocenu.",
altTitle: "Budite prvi da je ocenite"
}
altTitle: "Budite prvi da je ocenite",
},
editProfile: {
website: "Web Sajt*",
applink: "App Link*",
phoneNumber: "Broj Telefona",
saveChanges: "Sačuvaj Promene",
showDetails: "Prikaži Detalje",
showBasic: "Prikaži osnovno",
labelNameRequired: "Ime firme je obavezno!",
labelPIBRequired: "PIB firme je obavezan!",
labelLocationRequired: "Lokacija je obavezna!",
labelPhoneRequired: "Broj telefona je obavezan!",
},
deleteOffer: {
areYouSure: "Da li ste sigurni da želite da <br /> obrišete proizvod?",
cancel: "Otkaži",
delete: "Obriši",
},
};

+ 10
- 7
src/request/apiEndpoints.js Прегледај датотеку

@@ -119,6 +119,7 @@ export default {
updateUserRegistration: "/users/{userUid}",
invite: "/users/invite",
getProfile: "users/",
editProfile: "users",
},
applications: {
application: "/applications/{applicationUid}",
@@ -159,11 +160,13 @@ export default {
setFingerprint: "/affiliate/fingerprint",
},
offers: {
getOneOffer: 'offers',
getOffers: 'offers',
addOffer: 'offers',
categories: 'categories',
locations: 'locations',
mineOffers: 'users'
}
getOneOffer: "offers",
getOffers: "offers",
addOffer: "offers",
categories: "categories",
locations: "locations",
mineOffers: "users",
removeOffer: "offers",
editOffer: "offers",
},
};

+ 24
- 15
src/request/offersRequest.js Прегледај датотеку

@@ -1,21 +1,30 @@
import { getRequest, postRequest } from "."
import apiEndpoints from "./apiEndpoints"
import { deleteRequest, getRequest, postRequest, putRequest } from ".";
import apiEndpoints from "./apiEndpoints";

export const attemptFetchOffers = (payload) => {
if (payload) return getRequest(apiEndpoints.offers.getOffers + payload)
return getRequest(apiEndpoints.offers.getOffers)
}
if (payload) return getRequest(apiEndpoints.offers.getOffers + payload);
return getRequest(apiEndpoints.offers.getOffers);
};
export const attemptFetchOneOffer = (payload) => {
const url = `${apiEndpoints.offers.getOneOffer}/${payload.payload}/frontend`;
return getRequest(url);
}
const url = `${apiEndpoints.offers.getOneOffer}/${payload.payload}/frontend`;
return getRequest(url);
};
export const attemptFetchMoreOffers = (page, payload) => {
if (payload) return getRequest(apiEndpoints.offers.getOffers + payload + `&size=10&page=${page}`);
return getRequest(apiEndpoints.offers.getOffers + `?size=10&page=${page}`);
}
if (payload)
return getRequest(
apiEndpoints.offers.getOffers + payload + `&size=10&page=${page}`
);
return getRequest(apiEndpoints.offers.getOffers + `?size=10&page=${page}`);
};
export const attemptAddOffer = (payload) => {
return postRequest(apiEndpoints.offers.addOffer, payload)
}
return postRequest(apiEndpoints.offers.addOffer, payload);
};
export const attemptFetchProfileOffers = (payload) => {
return getRequest(`${apiEndpoints.offers.mineOffers}/${payload}/offers`)
}
return getRequest(`${apiEndpoints.offers.mineOffers}/${payload}/offers`);
};
export const attemptRemoveOffer = (payload) => {
return deleteRequest(apiEndpoints.offers.removeOffer + "/" + payload);
};
export const attemptEditOffer = (payload, editedData) => {
return putRequest(apiEndpoints.offers.editOffer + "/" + payload, editedData);
};

+ 4
- 1
src/request/profileRequest.js Прегледај датотеку

@@ -1,5 +1,8 @@
import { getRequest } from ".";
import { getRequest, putRequest } from ".";
import apiEndpoints from "./apiEndpoints";

export const attemptFetchProfile = (payload) =>
getRequest(apiEndpoints.users.getProfile + payload);

export const attemptEditProfile = (payload, requestData) =>
putRequest(apiEndpoints.users.editProfile + "/" + payload, requestData);

+ 12
- 7
src/store/actions/offers/offersActionConstants.js Прегледај датотеку

@@ -1,7 +1,12 @@
import { createClearType, createErrorType, createFetchType, createSuccessType } from "../actionHelpers";
import {
createClearType,
createErrorType,
createFetchType,
createSuccessType,
} from "../actionHelpers";

const OFFERS_SCOPE = "OFFERS_SCOPE";
const ONE_OFFER_SCOPE = "ONE_OFFER_SCOPE"
const ONE_OFFER_SCOPE = "ONE_OFFER_SCOPE";

const OFFERS_MORE_SCOPE = "OFFERS_MORE_SCOPE";
export const OFFERS_FETCH_MORE = createFetchType(OFFERS_MORE_SCOPE);
@@ -16,21 +21,21 @@ export const OFFERS_CLEAR = createClearType(OFFERS_SCOPE);
const OFFERS_PROFILE_SCOPE = "OFFERS_PROFILE_SCOPE";
export const OFFERS_PROFILE_FETCH = createFetchType(OFFERS_PROFILE_SCOPE);



export const ONE_OFFER_FETCH = createFetchType(ONE_OFFER_SCOPE);
export const ONE_OFFER_SUCCESS = createSuccessType(ONE_OFFER_FETCH);
export const ONE_OFFER_ERROR = createErrorType(ONE_OFFER_SCOPE);



export const OFFERS_PINNED_SET = "OFFERS_PINNED_SET";
export const OFFERS_PINNED_ADD = "OFFERS_PINNED_ADD";
export const OFFERS_SET = "OFFERS_SET";
export const OFFER_SET = "OFFER_SET"
export const OFFER_SET = "OFFER_SET";
export const OFFERS_ADD = "OFFERS_ADD";
export const OFFERS_NO_MORE = "OFFERS_NO_MORE";
export const OFFERS_SET_TOTAL = "OFFERS_SET_TOTAL";
export const OFFERS_MINE_SET = "OFFERS_MY_ADD";
export const OFFER_ADD = "OFFER_ADD";
export const OFFERS_PROFILE_SET = "OFFERS_PROFILE_SET";

export const OFFER_REMOVE = "OFFER_REMOVE";

export const OFFER_EDIT = "OFFER_EDIT";

+ 30
- 20
src/store/actions/offers/offersActions.js Прегледај датотеку

@@ -15,6 +15,8 @@ import {
OFFERS_SET_TOTAL,
OFFERS_SUCCESS,
OFFER_ADD,
OFFER_EDIT,
OFFER_REMOVE,
OFFER_SET,
ONE_OFFER_ERROR,
ONE_OFFER_FETCH,
@@ -49,33 +51,41 @@ export const addPinnedOffers = (payload) => ({
payload,
});
export const addOffers = (payload) => ({
type: OFFERS_ADD,
payload
})
type: OFFERS_ADD,
payload,
});
export const addOffer = (payload) => ({
type: OFFER_ADD,
payload
})
type: OFFER_ADD,
payload,
});
export const removeOffer = (payload) => ({
type: OFFER_REMOVE,
payload,
});
export const editOneOffer = (payload) => ({
type: OFFER_EDIT,
payload,
});

//

export const fetchOneOffer = (payload) => ({
type: ONE_OFFER_FETCH,
payload
})
type: ONE_OFFER_FETCH,
payload,
});
export const fetchOneOfferError = (payload) => ({
type: ONE_OFFER_ERROR,
payload
})
type: ONE_OFFER_ERROR,
payload,
});
export const fetchOneOfferSuccess = (payload) => ({
type: ONE_OFFER_SUCCESS,
payload
})
type: ONE_OFFER_SUCCESS,
payload,
});

export const setOffer = (payload) => ({
type: OFFER_SET,
payload
})
type: OFFER_SET,
payload,
});

export const fetchMoreOffers = (payload) => ({
type: OFFERS_FETCH_MORE,
@@ -99,8 +109,8 @@ export const setMineOffers = (payload) => ({
export const fetchProfileOffers = (payload) => ({
type: OFFERS_PROFILE_FETCH,
payload,
})
});
export const setProfileOffers = (payload) => ({
type: OFFERS_PROFILE_SET,
payload,
})
});

+ 10
- 2
src/store/actions/profile/profileActionConstants.js Прегледај датотеку

@@ -1,4 +1,9 @@
import { createErrorType, createFetchType, createSuccessType } from "../actionHelpers";
import {
createErrorType,
createFetchType,
createSuccessType,
createUpdateType,
} from "../actionHelpers";

const PROFILE_SCOPE = "PROFILE_SCOPE";
export const PROFILE_FETCH = createFetchType(PROFILE_SCOPE);
@@ -9,4 +14,7 @@ const PROFILE_MINE_SCOPE = "PROFILE_MINE_SCOPE";
export const PROFILE_MINE_FETCH = createFetchType(PROFILE_MINE_SCOPE);

export const PROFILE_SET = "PROFILE_SET";
export const PROFILE_MINE_SET = "PROFILE_MINE_SET";
export const PROFILE_MINE_SET = "PROFILE_MINE_SET";

const PROFILE_EDIT_SCOPE = "PROFILE_EDIT_SCOPE";
export const PROFILE_EDIT = createUpdateType(PROFILE_EDIT_SCOPE);

+ 30
- 18
src/store/actions/profile/profileActions.js Прегледај датотеку

@@ -1,26 +1,38 @@
import { PROFILE_ERROR, PROFILE_FETCH, PROFILE_MINE_FETCH, PROFILE_MINE_SET, PROFILE_SET, PROFILE_SUCCESS } from "./profileActionConstants";
import {
PROFILE_ERROR,
PROFILE_FETCH,
PROFILE_MINE_FETCH,
PROFILE_MINE_SET,
PROFILE_SET,
PROFILE_SUCCESS,
PROFILE_EDIT,
} from "./profileActionConstants";

export const fetchProfile = (payload) => ({
type: PROFILE_FETCH,
payload
})
type: PROFILE_FETCH,
payload,
});
export const fetchSuccessProfile = (payload) => ({
type: PROFILE_SUCCESS,
payload,
})
type: PROFILE_SUCCESS,
payload,
});

export const fetchErrorProfile = (payload) => ({
type: PROFILE_ERROR,
payload,
})
type: PROFILE_ERROR,
payload,
});
export const setProfile = (payload) => ({
type: PROFILE_SET,
payload,
})
type: PROFILE_SET,
payload,
});
export const setMineProfile = (payload) => ({
type: PROFILE_MINE_SET,
payload,
})
type: PROFILE_MINE_SET,
payload,
});
export const fetchMineProfile = () => ({
type: PROFILE_MINE_FETCH,
})
type: PROFILE_MINE_FETCH,
});
export const editMineProfile = (payload) => ({
type: PROFILE_EDIT,
payload,
});

+ 67
- 17
src/store/saga/offersSaga.js Прегледај датотеку

@@ -1,6 +1,23 @@
import { attemptAddOffer, attemptFetchOffers, attemptFetchOneOffer } from "../../request/offersRequest";
import { OFFERS_FETCH, OFFERS_PROFILE_FETCH, OFFER_ADD, ONE_OFFER_FETCH } from "../actions/offers/offersActionConstants";
import { setOffers, setOffer, setProfileOffers } from "../actions/offers/offersActions";
import {
attemptAddOffer,
attemptEditOffer,
attemptFetchOffers,
attemptFetchOneOffer,
attemptRemoveOffer,
} from "../../request/offersRequest";
import {
OFFERS_FETCH,
OFFERS_PROFILE_FETCH,
OFFER_ADD,
OFFER_EDIT,
OFFER_REMOVE,
ONE_OFFER_FETCH,
} from "../actions/offers/offersActionConstants";
import {
setOffers,
setOffer,
setProfileOffers,
} from "../actions/offers/offersActions";
import { all, takeLatest, call, put, select } from "@redux-saga/core/effects";
import {
attemptFetchProfileOffers,
@@ -87,9 +104,13 @@ function* fetchMoreOffers(payload) {
}

function* createOffer(payload) {
console.log(payload);
try {
const data = yield call(attemptAddOffer, payload.payload);
const data = yield call(attemptAddOffer, payload.payload.offerData);
console.log(data);
if (payload.payload.handleApiResponseSuccess) {
yield call(payload.payload.handleApiResponseSuccess);
}
} catch (e) {
console.log(e);
}
@@ -98,9 +119,9 @@ function* createOffer(payload) {
function* fetchOneOffer(payload) {
try {
console.log(payload);
const data = yield call(attemptFetchOneOffer, payload)
const data = yield call(attemptFetchOneOffer, payload);
console.log(data.data);
yield put(setOffer(data.data))
yield put(setOffer(data.data));
} catch (e) {
console.log(e);
}
@@ -120,21 +141,50 @@ function* fetchMineOffers() {
function* fetchProfileOffers(payload) {
try {
const userId = payload.payload;
const data = yield call(attemptFetchProfileOffers, userId)
yield put (setProfileOffers(data.data));
const data = yield call(attemptFetchProfileOffers, userId);
yield put(setProfileOffers(data.data));
} catch (e) {
console.log(e);
}
}

function* removeOffer(payload) {
console.log(payload);
try {
const offerId = payload.payload.offerId;
yield call(attemptRemoveOffer, offerId);
if (payload.payload.handleApiResponseSuccess) {
yield call(payload.payload.handleApiResponseSuccess);
}
} catch (e) {
console.log(e);
}
}

function* editOffer(payload) {
yield console.log(payload);

try {
const offerId = payload.payload.offerId;
const editedData = payload.payload.offerData;
yield call(attemptEditOffer, offerId, editedData);
if (payload.payload.handleApiResponseSuccess) {
yield call(payload.payload.handleApiResponseSuccess);
}
} catch (e) {
console.log(e);
}
}

export default function* offersSaga() {
yield all(
[
takeLatest(OFFERS_FETCH, fetchOffers),
takeLatest(OFFER_ADD, createOffer),
takeLatest(ONE_OFFER_FETCH, fetchOneOffer),
takeLatest(OFFERS_FETCH_MORE, fetchMoreOffers),
takeLatest(OFFERS_MINE_FETCH, fetchMineOffers),
takeLatest(OFFERS_PROFILE_FETCH, fetchProfileOffers)
]);
yield all([
takeLatest(OFFERS_FETCH, fetchOffers),
takeLatest(OFFER_ADD, createOffer),
takeLatest(ONE_OFFER_FETCH, fetchOneOffer),
takeLatest(OFFERS_FETCH_MORE, fetchMoreOffers),
takeLatest(OFFERS_MINE_FETCH, fetchMineOffers),
takeLatest(OFFERS_PROFILE_FETCH, fetchProfileOffers),
takeLatest(OFFER_REMOVE, removeOffer),
takeLatest(OFFER_EDIT, editOffer),
]);
}

+ 75
- 24
src/store/saga/profileSaga.js Прегледај датотеку

@@ -1,36 +1,87 @@
import { all, call, put, takeLatest, select } from "@redux-saga/core/effects";
import { attemptFetchProfile } from "../../request/profileRequest";
import { PROFILE_FETCH, PROFILE_MINE_FETCH } from "../actions/profile/profileActionConstants";
import { setMineProfile, setProfile } from "../actions/profile/profileActions";
import {
attemptEditProfile,
attemptFetchProfile,
} from "../../request/profileRequest";
import {
PROFILE_FETCH,
PROFILE_MINE_FETCH,
PROFILE_EDIT,
} from "../actions/profile/profileActionConstants";
import {
// editMineProfile,
setMineProfile,
setProfile,
} from "../actions/profile/profileActions";
import { selectUserId } from "../selectors/loginSelectors";

function* fetchProfile(payload) {
try {
console.log(payload);
const data = yield call(attemptFetchProfile, payload.payload);
console.log(data.data);
if (data) yield put(setProfile(data.data));
}
catch(e) {
console.log(e);
}
try {
console.log(payload);
const data = yield call(attemptFetchProfile, payload.payload);
console.log(data.data);
if (data) yield put(setProfile(data.data));
} catch (e) {
console.log(e);
}
}

function* fetchMineProfile() {
try {
const userId = yield select(selectUserId);
const data = yield call(attemptFetchProfile, userId);
console.log(data);
if (data) yield put(setMineProfile(data.data));
try {
const userId = yield select(selectUserId);
const data = yield call(attemptFetchProfile, userId);
console.log(data);
if (data) yield put(setMineProfile(data.data));
} catch (e) {
console.log(e);
}
}

function* changeMineProfile(payload) {
try {
yield console.log(payload);

let image;

if (payload.payload.firmLogo.includes("data:image")) {
image = payload.payload.firmLogo
.replace("data:image/jpeg;base64,", "")
.replace("data:image/jpg;base64,", "")
.replace("data:image/png;base64,", "");
} else if (payload.payload.firmLogo === "") {
image = "";
}
catch (e) {
console.log(e);

const reqData = {
company: {
name: payload.payload.firmName,
PIB: payload.payload.firmPIB,
contacts: {
telephone: payload.payload.firmPhone,
location: payload.payload.firmLocation,
web: payload.payload.firmWebsite,
},
},
image: image,
};

if (payload.payload.firmLogo.includes("https")) delete reqData.image;

const userId = yield select(selectUserId);
const data = yield call(attemptEditProfile, userId, reqData);
if (payload.payload.handleApiResponseSuccess) {
yield call(payload.payload.handleApiResponseSuccess);
}
console.log(data);
} catch (e) {
console.log(e);
}
}

export default function* profileSaga() {
yield all([
takeLatest(PROFILE_FETCH, fetchProfile),
takeLatest(PROFILE_MINE_FETCH, fetchMineProfile)
])
}
yield all([
takeLatest(PROFILE_FETCH, fetchProfile),
takeLatest(PROFILE_MINE_FETCH, fetchMineProfile),
takeLatest(PROFILE_EDIT, changeMineProfile),
]);
}

Loading…
Откажи
Сачувај