Przeglądaj źródła

Finished steps

feature/code-cleanup-joca
jovan.cirkovic 3 lat temu
rodzic
commit
4335342a74
36 zmienionych plików z 25010 dodań i 461 usunięć
  1. 24354
    37
      package-lock.json
  2. 3
    0
      src/assets/images/profile-picture.svg
  3. 0
    3
      src/components/Cards/CreateOfferCard/CreateOffer.js
  4. 6
    2
      src/components/Cards/CreateOfferCard/SecondPart/SecondPartCreateOffer.js
  5. 8
    23
      src/components/Cards/CreateOfferCard/SecondPart/SecondPartCreateOffer.styled.js
  6. 0
    6
      src/components/Cards/CreateOfferCard/ThirdPart/ThirdPartCreateOffer.js
  7. 1
    2
      src/components/Cards/ItemDetailsCard/ItemDetailsCard.js
  8. 9
    9
      src/components/Cards/ItemDetailsCard/ItemDetailsCard.styled.js
  9. 20
    11
      src/components/Cards/OfferCard/OfferCard.js
  10. 67
    74
      src/components/ImagePicker/ImagePicker.js
  11. 43
    0
      src/components/ImagePicker/ImagePicker.styled.js
  12. 15
    13
      src/components/ItemDetails/ItemDetails.js
  13. 39
    17
      src/components/ItemDetails/ItemDetailsHeaderCard/ItemDetailsHeaderCard.js
  14. 2
    2
      src/components/UserReviewsCard/UserReviewsCard.js
  15. 0
    4
      src/components/UserReviewsCard/UserReviewsCard.styled.js
  16. 3
    0
      src/i18n/resources/rs.js
  17. 8
    5
      src/layouts/ItemDetailsLayout/ItemDetailsLayout.js
  18. 17
    1
      src/pages/ForgotPasswordPage/ForgotPassword.styled.js
  19. 5
    1
      src/pages/ForgotPasswordPage/ForgotPasswordMailSent/MailSent.js
  20. 21
    12
      src/pages/ForgotPasswordPage/ForgotPasswordPage.js
  21. 32
    42
      src/pages/ItemDetailsPage/ItemDetailsPageMUI.js
  22. 1
    1
      src/pages/RegisterPages/Register/FirstPart/FirstPartOfRegistration.js
  23. 86
    55
      src/pages/RegisterPages/Register/Register.js
  24. 58
    12
      src/pages/RegisterPages/Register/Register.styled.js
  25. 112
    111
      src/request/apiEndpoints.js
  26. 5
    0
      src/request/offersRequest.js
  27. 6
    0
      src/store/actions/offers/offersActionConstants.js
  28. 21
    1
      src/store/actions/offers/offersActions.js
  29. 35
    0
      src/store/reducers/offers/offersReducer.js
  30. 2
    1
      src/store/saga/forgotPasswordSaga.js
  31. 3
    2
      src/store/saga/loginSaga.js
  32. 15
    1
      src/store/saga/offersSaga.js
  33. 1
    1
      src/store/saga/registerSaga.js
  34. 5
    0
      src/store/selectors/offersSelectors.js
  35. 1
    1
      src/themes/primaryTheme/primaryThemeColors.js
  36. 6
    11
      src/util/helpers/rejectErrorCodeHelper.js

+ 24354
- 37
package-lock.json
Plik diff jest za duży
Wyświetl plik


+ 3
- 0
src/assets/images/profile-picture.svg Wyświetl plik

@@ -0,0 +1,3 @@
<svg width="72" height="82" viewBox="0 0 72 82" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M55.9821 20.9284C55.9821 32.1726 46.8691 41.2856 35.625 41.2856C24.3809 41.2856 15.2679 32.1726 15.2679 20.9284C15.2679 9.68588 24.3809 0.571289 35.625 0.571289C46.8691 0.571289 55.9821 9.68588 55.9821 20.9284ZM33.2553 57.6985L27.9911 48.9195H43.2589L37.9947 57.6985L43.2907 77.4036L49.5728 51.7663C61.8507 53.6748 71.25 64.2987 71.25 77.1173C71.25 79.8051 69.0552 81.9999 66.3675 81.9999H4.88571C2.1868 81.9999 0 79.8051 0 77.1173C0 64.2987 9.39769 53.6748 21.6772 51.7663L27.9593 77.4036L33.2553 57.6985Z" fill="#D4D4D4"/>
</svg>

+ 0
- 3
src/components/Cards/CreateOfferCard/CreateOffer.js Wyświetl plik

@@ -43,8 +43,6 @@ const CreateOffer = ({ history }) => {
const handleMouseDownPassword = () => setShowPassword(!showPassword);
const categories = useSelector((state) => state.categories.categories);

console.log(informations);

// When user refreshes page
// useEffect(() => {
// function redirectClient() {
@@ -123,7 +121,6 @@ const CreateOffer = ({ history }) => {

const handleSubmitOffer = () => {
submitOffer(offerData);
console.log(offerData);
};

return (

+ 6
- 2
src/components/Cards/CreateOfferCard/SecondPart/SecondPartCreateOffer.js Wyświetl plik

@@ -4,12 +4,13 @@ import {
CreateOfferFormContainer,
FieldLabel,
Scroller,
SupportedFormats,
InputButtonContainer,
// ImageListStyled,
} from "./SecondPartCreateOffer.styled";
import ImagePicker from "../../../ImagePicker/ImagePicker";
// import Select from "../../../Select/Select";
import { useTranslation } from "react-i18next";
import { useTranslation, Trans } from "react-i18next";
import Option from "../../../Select/Option/Option";
import { SelectAltText, SelectField, SelectText } from "../CreateOffer.styled";
import { NextButton } from "../FirstPart/FirstPartCreateOffer.styled";
@@ -59,16 +60,19 @@ const SecondPartCreateOffer = (props) => {
image={item}
setImage={(image) => setImage(index, image)}
deleteImage={() => setImage(index, null)}
showDeleteIcon
/>
))}
</Scroller>
<SupportedFormats>
<Trans i18nKey="offer.supportedImagesFormats" />
</SupportedFormats>
<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>

+ 8
- 23
src/components/Cards/CreateOfferCard/SecondPart/SecondPartCreateOffer.styled.js Wyświetl plik

@@ -1,9 +1,8 @@
import { Box, ImageList } from "@mui/material";
import { Box, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../../themes";
import { Label } from "../../../CheckBox/Label";
import HorizontalScroller from "../../../Scroller/HorizontalScroller";
import { ReactComponent as TrashIcon } from "../../../../assets/images/svg/trash.svg";

export const CreateOfferFormContainer = styled(Box)`
width: 585px;
@@ -12,19 +11,6 @@ export const CreateOfferFormContainer = styled(Box)`
margin-top: 20px;
`;

export const ImageCard = styled.img`
width: 216px;
height: 144px;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
`;
export const ImageListStyled = styled(ImageList)`
display: flex;
flex: 1;
overflow: hidden;
cursor: grab;
`;
export const FieldLabel = styled(Label)`
position: relative;
top: 12px;
@@ -52,12 +38,11 @@ export const Scroller = styled(HorizontalScroller)`
left: calc(-320px + 50%);
margin-bottom: 36px;
`;
export const Trash = styled(TrashIcon)`
cursor: pointer;
margin: auto;
width: 22px;
height: 22px;
& path {
stroke: white;
}

export const SupportedFormats = styled(Typography)`
font-size: 13px;
width: 100%;
text-align: center;
font-family: "Open Sans";
margin-top: 25px;
`;

+ 0
- 6
src/components/Cards/CreateOfferCard/ThirdPart/ThirdPartCreateOffer.js Wyświetl plik

@@ -4,11 +4,6 @@ import { CreateOfferFormContainer } from "./ThirdPartCreateOffer.styled";
import ItemDetailsCard from "../../ItemDetailsCard/ItemDetailsCard";

const ThirdPartCreateOffer = (props) => {
let date = new Date();
let formatedDate = `${date.getDate()}.${
date.getMonth() + 1
}.${date.getFullYear()}.`;

const handleSubmit = (e) => {
e.preventDefault();
props.handleSubmitOffer();
@@ -21,7 +16,6 @@ const ThirdPartCreateOffer = (props) => {
subcategory={props.informations.subcategory}
condition={props.informations.condition}
showNumberOfViews={false}
date={formatedDate}
title={props.informations.nameOfProduct}
description={props.informations.description}
images={props.informations.images}

+ 1
- 2
src/components/Cards/ItemDetailsCard/ItemDetailsCard.js Wyświetl plik

@@ -74,7 +74,7 @@ const ItemDetailsCard = (props) => {
</InfoGroup>
)}
</Info>
<PostDate>Objavljeno: {props.date}</PostDate>
<PostDate>Objavljeno: {offer.postDate}</PostDate>
</OfferInfo>
<Details>
<OfferTitle>{props.title}</OfferTitle>
@@ -152,7 +152,6 @@ ItemDetailsCard.propTypes = {
subcategory: PropTypes.string,
condition: PropTypes.string,
showNumberOfViews: PropTypes.bool,
date: PropTypes.string,
author: PropTypes.string,
location: PropTypes.string,
images: PropTypes.node,

+ 9
- 9
src/components/Cards/ItemDetailsCard/ItemDetailsCard.styled.js Wyświetl plik

@@ -21,13 +21,6 @@ export const ItemDetailsCardContainer = styled(Container)`
max-width: 2000px;
position: relative;
`;
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;
@@ -56,6 +49,7 @@ export const InfoIcon = styled(Box)`
`;
export const InfoText = styled(Typography)`
font-family: "Open Sans";
text-transform: capitalize;
`;
export const OfferTitle = styled(Typography)`
font-family: "Open Sans";
@@ -63,7 +57,13 @@ export const OfferTitle = styled(Typography)`
color: ${selectedTheme.primaryPurple};
font-weight: 700;
font-size: 24px;
padding: 0 72px;
padding: 0 60px;
`;
export const OfferImage = styled.img`
width: 144px;
height: 144px;
margin-right: 20px;
object-fit: cover;
`;
export const OfferAuthor = styled(Box)`
display: flex;
@@ -87,7 +87,7 @@ export const OfferDetails = styled(Box)`
flex-direction: column;
flex-wrap: ${(props) => (!props.halfwidth ? "no-wrap" : "wrap")};
justify-content: space-between;
padding: 0 72px;
padding: 0 60px;
`;
export const OfferCategory = styled(Box)`
font-family: "Open Sans";

+ 20
- 11
src/components/Cards/OfferCard/OfferCard.js Wyświetl plik

@@ -1,4 +1,4 @@
import React from "react";
import React, { useEffect } from "react";
import PropTypes from "prop-types";
import {
CheckButton,
@@ -27,13 +27,20 @@ import selectedTheme from "../../../themes";
import { useHistory } from "react-router-dom";

const OfferCard = (props) => {
const id = 434;
const history = useHistory();
const routeToItem = () => {
history.push(`/proizvodi/${id}`)
}

useEffect(() => {
console.log(props.offer._id);
}, []);

const routeToItem = (itemId) => {
history.push(`/proizvodi/${itemId}`);
};
return (
<OfferCardContainer sponsored={props.offer.pinned.toString()} halfwidth={props.halfwidth ? 1 : 0}>
<OfferCardContainer
sponsored={props.offer.pinned.toString()}
halfwidth={props.halfwidth ? 1 : 0}
>
<OfferImage src={props.offer.images[0]}></OfferImage>
<OfferInfo>
<OfferTitle>{props.offer.name}</OfferTitle>
@@ -58,18 +65,20 @@ const OfferCard = (props) => {
</OfferInfo>
{!props.halfwidth ? (
<React.Fragment>
<Line/>
<Line />
<OfferDescription>
<OfferDescriptionTitle>Opis:</OfferDescriptionTitle>
<OfferDescriptionText>{props.offer.description}</OfferDescriptionText>
<OfferDescriptionText>
{props.offer.description}
</OfferDescriptionText>
</OfferDescription>

<CheckButton
variant={props.sponsored ? "contained" : "outlined"}
buttoncolor={selectedTheme.primaryPurple}
textcolor={props.sponsored ? "white" : selectedTheme.primaryPurple}
style={{fontWeight: "600"}}
onClick = {routeToItem}
style={{ fontWeight: "600" }}
onClick={() => routeToItem(props.offer._id)}
>
Pogledaj proizvod
</CheckButton>
@@ -97,7 +106,7 @@ const OfferCard = (props) => {

OfferCard.propTypes = {
children: PropTypes.node,
id: PropTypes.number,
_id: PropTypes.string,
title: PropTypes.string,
description: PropTypes.string,
category: PropTypes.string,

+ 67
- 74
src/components/ImagePicker/ImagePicker.js Wyświetl plik

@@ -1,100 +1,92 @@
import React, { useRef, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import PropTypes from "prop-types";
import {
AddFile,
AddIcon,
ImageOverlay,
ImagePickerContainer,
ImageUploaded,
Tools,
} from "./ImagePicker.styled";
import { Tooltip } from "@mui/material";
import { Trash } from "../Cards/CreateOfferCard/SecondPart/SecondPartCreateOffer.styled";
import { Icon } from "../Icon/Icon";
import { IconButton } from "../Buttons/IconButton/IconButton";
import { ReactComponent as EditIcon } from "../../assets/images/svg/edit.svg";
import { ReactComponent as TrashIcon } from "../../assets/images/svg/trash.svg";

// import { Input } from "@mui/material";

const ImagePicker = (props) => {
const fileInputRef = useRef(null);
const [isOpened, setIsOpened] = useState(false);
const imageRef = useRef(null);
const [image, setImage] = useState("");
const [isEditing, setIsEditing] = useState(false);

let listener;
useEffect(() => {
listener = (event) => {
if (imageRef.current) {
if (imageRef.current.contains(event.target)) {
setIsEditing(true);
} else {
setIsEditing(false);
}
}
};
window.addEventListener("click", listener);
return () => window.removeEventListener("click", listener);
}, [imageRef]);

const handleChange = () => {
fileInputRef.current.value = "";
fileInputRef.current.click();
console.log(fileInputRef.current.click);
};
const handleImage = (event) => {
console.log("fileEvent: ", event.target.files[0]);
let reader = new FileReader();
reader.readAsDataURL(event.target.files[0]);
reader.onload = () => {
console.log(reader.result.toString());
props.setImage(reader.result);
if (props.setImage) props.setImage(reader.result);
setImage(reader.result);
};
reader.onerror = (error) => {
console.log(error);
};
reader.onerror = () => {};
};
// let timeoutObject = {
// timeoutFunctionSet: false,
// timeoutFunction: () => {},
// };
// const showMessage = (event) => {
// console.log(event);
// };
// const handleMouseEnter = (event) => {
// timeoutObject.timeoutFunctionSet = true;
// timeoutObject.timeoutFunction = setTimeout(() => {
// showMessage(event);
// }, 1000);
// };
// const handleMouseMove = (event) => {
// if (timeoutObject.timeoutFunctionSet) {
// clearTimeout(timeoutObject.timeoutFunction);
// timeoutObject.timeoutFunction = setTimeout(() => {
// showMessage(event);
// }, 1000);
// }
// };
// const handleMouseLeave = () => {
// if (timeoutObject.timeoutFunctionSet) {
// clearTimeout(timeoutObject.timeoutFunction);
// timeoutObject.timeoutFunctionSet = false;
// }
// };
const handleOpen = () => {
setIsOpened(true);
if (!props.image) setIsOpened(false);
};
const handleClose = () => {
setIsOpened(false);
};

const handleDelete = () => {
props.deleteImage();
setIsOpened(false)
}
if (props.deleteImage) props.deleteImage();
setImage("");
setIsEditing(false);
};
return (
<Tooltip
open={isOpened}
onOpen={handleOpen}
onClose={handleClose}
enterDelay={500}
enterNextDelay={500}
arrow
title={
<Icon style={{width: "50px", height: "42px", paddingTop: "10px"}}>
<Trash onClick={handleDelete} />
</Icon>
}
d
<ImagePickerContainer
className={props.className}
onClick={!image ? handleChange : () => {}}
hasImage={props.image}
>
<ImagePickerContainer
className={props.className}
onClick={!props.image ? handleChange : () => {}}
hasImage={props.image}
>
<AddFile type="file" ref={fileInputRef} onInput={handleImage} />
{props.image ? (
<ImageUploaded src={props.image} draggable={false}></ImageUploaded>
) : (
<AddIcon />
)}
</ImagePickerContainer>
</Tooltip>
<AddFile type="file" ref={fileInputRef} onInput={handleImage} />
{image ? (
<React.Fragment>
<ImageUploaded src={image} draggable={false} ref={imageRef} />
{isEditing && (
<React.Fragment>
<ImageOverlay />
<Tools showDeleteIcon={props.showDeleteIcon}>
<IconButton onClick={handleChange}>
<EditIcon />
</IconButton>
{props.showDeleteIcon && (
<IconButton onClick={handleDelete}>
<TrashIcon />
</IconButton>
)}
</Tools>
</React.Fragment>
)}
</React.Fragment>
) : (
<AddIcon />
)}
{props.children}
</ImagePickerContainer>
);
};

@@ -103,7 +95,8 @@ ImagePicker.propTypes = {
className: PropTypes.string,
setImage: PropTypes.func,
image: PropTypes.func,
deleteImage: PropTypes.func
deleteImage: PropTypes.func,
showDeleteIcon: PropTypes.bool,
};

export default ImagePicker;

+ 43
- 0
src/components/ImagePicker/ImagePicker.styled.js Wyświetl plik

@@ -2,6 +2,7 @@ import { Box } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../themes";
import { ReactComponent as Plus } from "../../assets/images/svg/plus.svg";
import { ReactComponent as TrashIcon } from "../../assets/images/svg/trash.svg";

export const ImagePickerContainer = styled(Box)`
flex: 1;
@@ -10,8 +11,10 @@ export const ImagePickerContainer = styled(Box)`
flex-grow: 0;
flex-shrink: 0;
height: 144px;
width: 144px;
margin: 0 9px;
border-radius: 4px;
position: relative;
cursor: pointer;
background-color: ${selectedTheme.imagePickerBackground};
background-image: linear-gradient(
@@ -50,6 +53,9 @@ export const ImagePickerContainer = styled(Box)`
`;
export const AddIcon = styled(Plus)`
margin: auto;
z-index: 1;
width: 60px;
height: 60px;
`;
export const AddFile = styled.input`
display: none;
@@ -57,7 +63,20 @@ export const AddFile = styled.input`
export const ImageUploaded = styled.img`
width: 144px;
height: 144px;
/* border-radius: 100px; */
/* object-fit: scale-down; */
object-fit: cover;
z-index: 1;
`;
export const ImageOverlay = styled(Box)`
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 3;
overflow: hidden;
`;
export const Tooltip = styled(Box)`
background-color: rgba(255, 255, 255, 0.5);
@@ -67,3 +86,27 @@ export const Tooltip = styled(Box)`
left: 0;
top: 0;
`;
export const Trash = styled(TrashIcon)`
cursor: pointer;
margin: auto;
width: 22px;
height: 22px;
& path {
stroke: white;
}
`;
export const Tools = styled(Box)`
position: absolute;
padding-top: 44px;
padding-left: ${(props) => (props.showDeleteIcon ? "16px" : "45px")};
z-index: 4;
flex-direction: row;
display: flex;
& div {
background-color: ${selectedTheme.primaryIconBackgroundColor};
border-radius: 100px;
display: flex;
flex: 1;
margin: 10px;
}
`;

+ 15
- 13
src/components/ItemDetails/ItemDetails.js Wyświetl plik

@@ -1,19 +1,21 @@
import React from 'react';
import React from "react";
import Header from "./Header/Header";
import { ItemDetailsContainer } from './ItemDetails.styled';
import { useSelector } from "react-redux";
import { ItemDetailsContainer } from "./ItemDetails.styled";
import ItemDetailsCard from "../Cards/ItemDetailsCard/ItemDetailsCard";
import ItemDetailsHeaderCard from "./ItemDetailsHeaderCard/ItemDetailsHeaderCard";


import { selectOffer } from "../../store/selectors/offersSelectors";

const ItemDetails = () => {
return (
<ItemDetailsContainer>
<Header/>
<ItemDetailsHeaderCard />
<ItemDetailsCard/>
</ItemDetailsContainer>
)
}
const offer = useSelector(selectOffer);

return (
<ItemDetailsContainer>
<Header />
<ItemDetailsHeaderCard offer={offer} />
<ItemDetailsCard offer={offer} />
</ItemDetailsContainer>
);
};

export default ItemDetails;
export default ItemDetails;

+ 39
- 17
src/components/ItemDetails/ItemDetailsHeaderCard/ItemDetailsHeaderCard.js Wyświetl plik

@@ -11,43 +11,54 @@ import {
HeaderTop,
HeaderDetails,
BottomDetails,
StatusText
StatusText,
} from "./ItemDetailsHeaderCard.styled";
import { ItemDetailsHeaderContainer } from "./ItemDetailsHeaderCard.styled";
import { ReactComponent as Category } from "../../../assets/images/svg/category.svg";
//import { ReactComponent as Quantity } from "../../../assets/images/svg/quantity.svg";
//import { ReactComponent as Eye } from "../../../assets/images/svg/eye-striked.svg";
import { ReactComponent as PIB} from "../../../assets/images/svg/pib.svg";
import { ReactComponent as PIB } from "../../../assets/images/svg/pib.svg";
import { ReactComponent as MessageColor } from "../../../assets/images/svg/mailColor.svg";
import selectedTheme from "../../../themes";
import { Author as author } from "../MockupdataDetails";

const ItemDetailsHeaderCard = (props) => {
return (
<ItemDetailsHeaderContainer sponsored={props.sponsored.toString()} halfwidth={props.halfwidth ? 1 : 0}>
<ItemDetailsHeaderContainer
sponsored={props.sponsored.toString()}
halfwidth={props.halfwidth ? 1 : 0}
>
<HeaderTop>
<OfferImage>{author.image}</OfferImage>
<OfferImage>{author.image}</OfferImage>
<OfferDetails>
<OfferTitle>{author.title}</OfferTitle>
<DetailContainer>
<DetailIcon color={selectedTheme.iconStrokeColor} component="span" size="22px">
<OfferTitle>{author.title}</OfferTitle>
<DetailContainer>
<DetailIcon
color={selectedTheme.iconStrokeColor}
component="span"
size="22px"
>
<PIB width={"22px"} />
</DetailIcon>
<DetailText>PIB - {author.pib}</DetailText>
</DetailContainer>
<DetailContainer>
<DetailIcon color={selectedTheme.iconStrokeColor} component="span" size="22px">
<DetailText>PIB - {author.pib}</DetailText>
</DetailContainer>
<DetailContainer>
<DetailIcon
color={selectedTheme.iconStrokeColor}
component="span"
size="22px"
>
<Category width={"22px"} />
</DetailIcon>
<DetailText>{author.location}</DetailText>
</DetailContainer>
</OfferDetails>
<DetailText>{author.location}</DetailText>
</DetailContainer>
</OfferDetails>
<MessageIcon>
<MessageColor />
<MessageColor />
</MessageIcon>
</HeaderTop>
<HeaderDetails>
<BottomDetails>
<BottomDetails>
<StatusText>
<b>{author.numberOfOffers}</b> objava
</StatusText>
@@ -62,7 +73,6 @@ const ItemDetailsHeaderCard = (props) => {
</StatusText>
</BottomDetails>
</HeaderDetails>
</ItemDetailsHeaderContainer>
);
};
@@ -81,6 +91,18 @@ ItemDetailsHeaderCard.propTypes = {
numberOfViews: PropTypes.number,
halfwidth: PropTypes.bool,
sponsored: PropTypes.bool,

offer: PropTypes.shape({
images: PropTypes.any,
name: PropTypes.string,
description: PropTypes.string,
category: PropTypes.shape({
name: PropTypes.string,
}),
location: PropTypes.shape({
city: PropTypes.string,
}),
}),
};
ItemDetailsHeaderCard.defaultProps = {
halfwidth: false,

+ 2
- 2
src/components/UserReviewsCard/UserReviewsCard.js Wyświetl plik

@@ -16,7 +16,7 @@ import Mockupdata from "./Mockupdata";
import ThumbUpIcon from "@mui/icons-material/ThumbUp";
import ThumbDownIcon from "@mui/icons-material/ThumbDown";
import StarBorderIcon from "@mui/icons-material/StarBorder";
import { PRIMARY_PURPLE_COLOR } from "../../constants/stylesConstants";
import selectedTheme from "../../themes";

const UserReviewsCard = (props) => {
var dataMockupdata = JSON.parse(JSON.stringify(Mockupdata));
@@ -44,7 +44,7 @@ const UserReviewsCard = (props) => {
<ListItemAvatar sx={{ mt: 0 }}>
<Avatar alt={review.name} src="/static/images/avatar/1.jpg" />
</ListItemAvatar>
<Typography sx={{ color: PRIMARY_PURPLE_COLOR }}>
<Typography sx={{ color: selectedTheme.primaryPurple }}>
<b>{review.name}</b>
</Typography>
</ListItem>

+ 0
- 4
src/components/UserReviewsCard/UserReviewsCard.styled.js Wyświetl plik

@@ -4,10 +4,6 @@ import { List, Box } from "@mui/material";

export const ReviewsBox = styledComponents(Box)`
width: 100%;
max-width: 360px;
position: fixed;
right: 0;
bottom: 0;
height: calc(100% - 90px);
`;


+ 3
- 0
src/i18n/resources/rs.js Wyświetl plik

@@ -92,6 +92,7 @@ export default {
PIBTaken: "PIB je zauzet!",
PIBnoOfCharacters: "PIB mora imati 9 karaktera!",
welcome: "Dobro došli na trampu, želimo vam uspešno trampovanje!",
imageError: "Slika je obavezna!",
},
forgotPassword: {
title: "Povrati lozinku",
@@ -151,5 +152,7 @@ export default {
choseSubcategory: "Izaberi podkategoriju",
condition: "STANJE",
choseCondition: "Izaberi Stanje",
supportedImagesFormats:
"Podržani formati fotografija: <strong>.JPG</strong> | <strong>.PNG</strong>",
},
};

+ 8
- 5
src/layouts/ItemDetailsLayout/ItemDetailsLayout.js Wyświetl plik

@@ -1,20 +1,23 @@
import React from "react";
import PropTypes from "prop-types";
import { Content, RightCard, ItemDetailsLayoutContainer } from "./ItemDetailsLayout.styled";
import {
Content,
RightCard,
ItemDetailsLayoutContainer,
} from "./ItemDetailsLayout.styled";
import { Grid } from "@mui/material";

const ItemDetailsLayout = (props) => {
return (
<ItemDetailsLayoutContainer>
{props.children}
<Grid container maxHeight="xl">
<Content item xs={10} lg={9} xl={9.6} md={8} >
<Grid container maxHeight="xl" spacing={2}>
<Content item xs={10} lg={9} xl={9.6} md={8}>
{props.content}
</Content>
<RightCard item xs={2} lg={3} xl={2.4} md={4} >
<RightCard item xs={2} lg={3} xl={2.4} md={4}>
{props.rightCard}
</RightCard>
</Grid>
</ItemDetailsLayoutContainer>
);

+ 17
- 1
src/pages/ForgotPasswordPage/ForgotPassword.styled.js Wyświetl plik

@@ -51,4 +51,20 @@ export const ErrorMessage = styled(Typography)`
position: relative;
top: -7px;
font-size: 14px;
`
`
export const LoginAltText = styled(Typography)`
font-family: "Poppins";
color: ${selectedTheme.primaryText};
font-size: 14px;
padding-right: 6px;
line-height: 14px;
`;
export const LoginTextContainer = styled(Box)`
display: flex;
flex-direction: row;
margin-top: 36px;
justify-content: center;
@media (max-height: 800px) {
margin-top: 26px;
}
`;

+ 5
- 1
src/pages/ForgotPasswordPage/ForgotPasswordMailSent/MailSent.js Wyświetl plik

@@ -28,7 +28,11 @@ const MailSent = () => {
const dispatch = useDispatch();

useEffect(() => {
setEmail(location.state.email);
if (location.state.email) {
setEmail(location.state.email);
} else {
history.push("/login");
}
}, []);

const navigateLogin = () => {

+ 21
- 12
src/pages/ForgotPasswordPage/ForgotPasswordPage.js Wyświetl plik

@@ -1,7 +1,6 @@
import React, { useState } from "react";
import { useFormik } from "formik";
import { useTranslation } from "react-i18next";
import * as Yup from "yup";
// import i18next from "i18next";
import { ReactComponent as Logo } from "../../assets/images/svg/logo-vertical.svg";
import {
@@ -10,14 +9,19 @@ import {
ForgotPasswordTitle,
FormContainer,
ErrorMessage,
LoginTextContainer,
LoginAltText,
} from "./ForgotPassword.styled";
import { TextField } from "../../components/TextFields/TextField/TextField";
import { PrimaryButton } from "../../components/Buttons/PrimaryButton/PrimaryButton";
import { useHistory } from "react-router-dom";
import { NavLink, useHistory } from "react-router-dom";
import { FORGOT_PASSWORD_MAIL_SENT } from "../../constants/pages";
import selectedTheme from "../../themes";
import { useDispatch } from "react-redux";
import { forgotPassword } from "../../store/actions/user/userActions";
import forgotPasswordValidation from "../../validations/forgotPasswordValidation";
import forgotPasswordInitialValues from "../../initialValues/forgotPasswordInitialValues";
import Link from "../../components/Link/Link";

const ForgotPasswordPage = () => {
const history = useHistory();
@@ -25,12 +29,6 @@ const ForgotPasswordPage = () => {
const dispatch = useDispatch();
const [emailNotFoundStatus, setEmailNotFoundStatus] = useState(false);

const forgotPasswordValidationSchema = Yup.object().shape({
email: Yup.string()
.required(t("forgotPassword.emailRequired"))
.email(t("forgotPassword.emailFormat")),
});

const handleResponseSuccess = () => {
history.push({
pathname: FORGOT_PASSWORD_MAIL_SENT,
@@ -52,10 +50,8 @@ const ForgotPasswordPage = () => {
};

const formik = useFormik({
initialValues: {
email: "",
},
validationSchema: forgotPasswordValidationSchema,
initialValues: forgotPasswordInitialValues,
validationSchema: forgotPasswordValidation,
onSubmit: handleSubmit,
validateOnBlur: true,
enableReinitialize: true,
@@ -109,6 +105,19 @@ const ForgotPasswordPage = () => {
>
{t("common.send")}
</PrimaryButton>

<LoginTextContainer>
<LoginAltText>{t("register.loginText")}</LoginAltText>

<Link
to="/login"
component={NavLink}
underline="hover"
align="center"
>
{t("register.login")}
</Link>
</LoginTextContainer>
</FormContainer>
</ForgotPasswordPageContainer>
);

+ 32
- 42
src/pages/ItemDetailsPage/ItemDetailsPageMUI.js Wyświetl plik

@@ -1,60 +1,42 @@
import React, { useEffect } from "react";
import { PropTypes } from "prop-types";
import Navbar from "../../components/MUI/NavbarComponent";
import { ItemDetailsPageContainer } from "./ItemDetailsPage.styled";
import { useDispatch } from "react-redux";
import { logoutUser } from "../../store/actions/login/loginActions";
import Mockupdata from "../../components/Cards/FilterCard/Mockupdata";
import qs from "query-string";
import { useHistory } from "react-router-dom";
import { setFilters } from "../../store/actions/filters/filtersActions";
import { useDispatch, useSelector } from "react-redux";
import ItemDetails from "../../components/ItemDetails/ItemDetails";
import ItemDetailsLayout from "../../layouts/ItemDetailsLayout/ItemDetailsLayout";
import UserReviewsCard from "../../components/UserReviewsCard/UserReviewsCard";
import { fetchOneOffer } from "../../store/actions/offers/offersActions";
import { selectOffer } from "../../store/selectors/offersSelectors";

const ItemDetailsPage = () => {
const ItemDetailsPage = (props) => {
const dispatch = useDispatch();
const offer = useSelector(selectOffer);

//const routetMatch = useRouteMatch();
const history = useHistory();
const offerId = props.match.params.idProizvod;

useEffect(() => {
const queryString = history.location.search.substring(1);
const queryObject = qs.parse(queryString);
let category = null;
if (queryObject.category) {
category = Mockupdata[1].find(
(item) => item.string === queryObject.category.toString()
).id;
}
let cities = [];
if (queryObject.city) {
if (Array.isArray(queryObject.city)) {
queryObject.city.forEach((item) => {
cities.push(Mockupdata[0].find((p) => p.string === item).id);
});
} else {
cities.push(
Mockupdata[0].find((p) => p.string === queryObject.city).id
);
}
}
let subcategory = null;
if (queryObject.subcategory) {
subcategory = Mockupdata[1].find(
(item) => item.string === queryObject.subcategory.toString()
).id;
dispatch(fetchOneOffer(offerId));
}, [offerId]);

useEffect(() => {
if (
typeof offer !== "undefined" &&
typeof offer.userId !== "undefined" &&
offer.userId !== ""
) {
console.log(offer.userId);
}
console.log("iz useeffect: ", { category, subcategory, cities });
dispatch(setFilters({ category, subcategory, cities }));
}, [history.location.search]);
const handleCl = () => {
dispatch(logoutUser());
};
}, [offer]);

return (
<ItemDetailsPageContainer>
<button onClick={handleCl}>Dugme</button>
<Navbar />
{/* right card mora mi bude Review Card */}
<ItemDetailsLayout content={<ItemDetails />} />
<ItemDetailsLayout
content={<ItemDetails />}
rightCard={<UserReviewsCard />}
/>

{/* <Box sx={{ mt: 4, mx: 4 }}>
<GridStyled container justifyContent="space-between">
@@ -81,4 +63,12 @@ const ItemDetailsPage = () => {
);
};

ItemDetailsPage.propTypes = {
match: PropTypes.shape({
params: PropTypes.shape({
idProizvod: PropTypes.string,
}),
}),
};

export default ItemDetailsPage;

+ 1
- 1
src/pages/RegisterPages/Register/FirstPart/FirstPartOfRegistration.js Wyświetl plik

@@ -83,7 +83,7 @@ const FirstPartOfRegistration = (props) => {
InputProps={{
endAdornment: (
<IconButton onClick={handleClickShowPassword}>
{showPassword ? <VisibilityOn /> : <VisibilityOff />}
{showPassword ? <VisibilityOff /> : <VisibilityOn />}
</IconButton>
),
}}

+ 86
- 55
src/pages/RegisterPages/Register/Register.js Wyświetl plik

@@ -9,6 +9,10 @@ import {
ProgressContainer,
RegisterDescription,
RegisterTitle,
ProfileImagePicker,
ProfilePicture,
RegisterPageContent,
ErrorMessage,
} from "./Register.styled";
import { ReactComponent as Logo } from "../../../assets/images/svg/logo-vertical.svg";
import { NavLink, useHistory } from "react-router-dom";
@@ -28,19 +32,21 @@ const Register = () => {
const dispatch = useDispatch();
const [currentStep, setCurrentStep] = useState(1);
const [informations, setInformations] = useState({}); // Values of fields typed in all steps
const [mailError, setMailError] = useState(""); // Wrong mail typed
const [mailErrorMessage, setMailErrorMessage] = useState(""); // Error message caused by typing wrong mail
const [PIBError, setPIBError] = useState(""); // Wrong PIB typed
const [PIBErrorMessage, setPIBErrorMessage] = useState(""); // Error message caused by typing wrong PIB
const [mailError, setMailError] = useState(""); // Wrong mail typed
const [mailErrorMessage, setMailErrorMessage] = useState(""); // Error message caused by typing wrong mail
const [PIBError, setPIBError] = useState(""); // Wrong PIB typed
const [PIBErrorMessage, setPIBErrorMessage] = useState(""); // Error message caused by typing wrong PIB
const [imageError, setImageError] = useState(false); // Not picked image

const handleResponseSuccess = () => {
history.push(REGISTER_SUCCESSFUL_PAGE);
};

const handleResponseError = (error) => {
console.log(error);
const { mail, password, PIB, image } = informations;
if (error.type === "mail") {
const { mail } = informations;
setInformations({});
setInformations({image});
setCurrentStep(1);
setMailError(mail);
if (
@@ -52,8 +58,7 @@ const Register = () => {
setMailErrorMessage(t("register.emailFormat"));
}
} else {
const { mail, password, PIB } = informations;
setInformations({ mail, password });
setInformations({ mail, password, image });
setCurrentStep(2);
setPIBError(PIB.toString());
setPIBErrorMessage(t("register.PIBTaken"));
@@ -70,67 +75,93 @@ const Register = () => {
if (currentStep !== 3) {
setCurrentStep((prevState) => prevState + 1);
} else {
registerUser({ ...informations, ...values });
if (!informations.image) {
setImageError(true);
} else {
registerUser({ ...informations, ...values });
}
}
setInformations({ ...informations, ...values });
};

const setImage = (image) => {
setImageError(false);
setInformations(prevInfo => ({
...prevInfo,
image
}))
}

const goStepBack = (stepNumber) => {
setCurrentStep(stepNumber);
const { mail, password, image } = informations;
if (stepNumber === 1) {
setInformations({});
setInformations({image});
}
if (stepNumber === 2) {
const { mail, password } = informations;
setInformations({ mail, password });
setInformations({ mail, password, image });
}
};

return (
<RegisterPageContainer currentstep={currentStep}>
<Logo />

<RegisterTitle component="h1" variant="h5">
{t("register.title")}
</RegisterTitle>

<RegisterDescription component="h1" variant="h6">
{t("register.descriptionMain")}
</RegisterDescription>

<ProgressContainer>
<StepProgress
functions={[() => goStepBack(1), () => goStepBack(2)]}
current={currentStep}
numberOfSteps={3}
/>
</ProgressContainer>

{currentStep === 1 && (
<FirstPartOfRegistration
handleSubmit={handleSubmit}
error={mailError}
errorMessage={mailErrorMessage}
/>
)}
{currentStep === 2 && (
<SecondPartOfRegistration
handleSubmit={handleSubmit}
error={PIBError}
errorMessage={PIBErrorMessage}
/>
)}
{currentStep === 3 && (
<ThirdPartOfRegistration handleSubmit={handleSubmit} />
)}

<LoginTextContainer>
<LoginAltText>{t("register.loginText")}</LoginAltText>

<Link to="/login" component={NavLink} underline="hover" align="center">
{t("register.login")}
</Link>
</LoginTextContainer>
<RegisterPageContent>
<Logo />

<RegisterTitle component="h1" variant="h5">
{t("register.title")}
</RegisterTitle>

<RegisterDescription component="h1" variant="h6">
{t("register.descriptionMain")}
</RegisterDescription>

<ProgressContainer>
<StepProgress
functions={[() => goStepBack(1), () => goStepBack(2)]}
current={currentStep}
numberOfSteps={3}
/>
</ProgressContainer>

<ProfileImagePicker setImage={setImage} >
<ProfilePicture />
</ProfileImagePicker>

{currentStep === 1 && (
<FirstPartOfRegistration
handleSubmit={handleSubmit}
error={mailError}
errorMessage={mailErrorMessage}
/>
)}
{currentStep === 2 && (
<SecondPartOfRegistration
handleSubmit={handleSubmit}
error={PIBError}
errorMessage={PIBErrorMessage}
/>
)}
{currentStep === 3 && (
<ThirdPartOfRegistration handleSubmit={handleSubmit} />
)}

{imageError && <ErrorMessage>{t("register.imageError")}</ErrorMessage>}

<LoginTextContainer>
<LoginAltText>{t("register.loginText")}</LoginAltText>

<Link
to="/login"
component={NavLink}
underline="hover"
align="center"
>
{t("register.login")}
</Link>
</LoginTextContainer>
</RegisterPageContent>

<Footer>
<FooterText>

+ 58
- 12
src/pages/RegisterPages/Register/Register.styled.js Wyświetl plik

@@ -1,9 +1,11 @@
import { Box, Container, Typography } from "@mui/material";
import styled from "styled-components";
import ImagePicker from "../../../components/ImagePicker/ImagePicker";
import selectedTheme from "../../../themes";
import { ReactComponent as ProfilePictureSVG } from "../../../assets/images/profile-picture.svg";

export const RegisterPageContainer = styled(Container)`
margin-top: 100px;
margin-top: 72px;
display: flex;
flex-direction: column;
align-items: center;
@@ -11,6 +13,8 @@ export const RegisterPageContainer = styled(Container)`
padding: 0;
flex: 1;
position: relative;
transition: 1s all;
${props => props.currentstep === 3 && `margin-top: 40px`};
@media (max-height: 900px) {
margin-top: 60px;
}
@@ -18,8 +22,8 @@ export const RegisterPageContainer = styled(Container)`
margin-top: 30px;
flex: none;
height: 95vh;
${props => props.currentstep === 3 && `height: 105vh`};
${props => props.currentstep === 2 && `height: 100vh`};
${(props) => props.currentstep === 3 && `height: 105vh`};
${(props) => props.currentstep === 2 && `height: 100vh`};
}
`;
export const RegisterTitle = styled(Typography)`
@@ -34,7 +38,7 @@ export const RegisterTitle = styled(Typography)`
color: ${selectedTheme.primaryPurple};
margin-top: 34px;
@media (max-height: 800px) {
margin-top: 26px;
margin-top: 26px;
}
`;
export const RegisterDescription = styled(Typography)`
@@ -51,8 +55,8 @@ export const RegisterDescription = styled(Typography)`
color: ${selectedTheme.primaryGrayText};
margin-bottom: 20px;
@media (max-height: 800px) {
margin-bottom: 14px;
margin-top: 6px;
margin-bottom: 14px;
margin-top: 6px;
}
`;
export const FormContainer = styled(Box)`
@@ -64,7 +68,7 @@ export const LoginAltText = styled(Typography)`
font-size: 14px;
padding-right: 6px;
line-height: 14px;
`
`;
export const LoginTextContainer = styled(Box)`
display: flex;
flex-direction: row;
@@ -73,11 +77,11 @@ export const LoginTextContainer = styled(Box)`
@media (max-height: 800px) {
margin-top: 26px;
}
`
`;
export const ProgressContainer = styled(Container)`
width: 100%;
padding: 0;
`
width: 100%;
padding: 0;
`;
export const Footer = styled(Box)`
position: absolute;
bottom: 36px;
@@ -88,7 +92,7 @@ export const Footer = styled(Box)`
@media (max-height: 800px) {
bottom: 10px;
}
`
`;
export const FooterText = styled(Typography)`
font-family: "Open Sans";
color: #505050;
@@ -98,4 +102,46 @@ export const FooterText = styled(Typography)`
font-weight: 400;
padding: 0;
font-size: 12px;
`;

export const ProfileImagePicker = styled(ImagePicker)`
background: none;
margin: 36px;
background: ${selectedTheme.primaryIconBackgroundColor};
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(ProfilePictureSVG)`
position: absolute;
left: 36px;
top: 24px;
z-index: 0;
`;
export const RegisterPageContent = styled(Box)`
display: flex;
flex-direction: column;
align-items: center;
width: 335px;
padding: 0;
flex: 1;
position: relative;
margin-bottom: 100px;
@media (max-height: 800px) {
flex: none;
height: 95vh;
${(props) => props.currentstep === 3 && `height: 105vh`};
${(props) => props.currentstep === 2 && `height: 100vh`};
}
`;
export const ErrorMessage = styled(Box)`
color: red;
font-family: "Open Sans";
position: relative;
top: 5px;
text-align: left;
font-size: 14px;
width: 100%;
`

+ 112
- 111
src/request/apiEndpoints.js Wyświetl plik

@@ -1,166 +1,167 @@
export default {
accounts: {
get: 'accounts/{accountUid}',
forgotPassword: 'forgot-password',
resetPassword: 'reset-password',
get: "accounts/{accountUid}",
forgotPassword: "forgot-password",
resetPassword: "reset-password",
getCurrentUserPermissions:
'accounts/{currentAccountUid}/users/{currentUserUid}/permissions',
getAddresses: 'accounts/{accountUid}/addresses',
updateAddress: 'account/{accountUid}/addresses/{addressUid}',
deleteAddress: 'accounts/{accountUid}/addresses/{addressUid}',
getUsers: 'accounts/{accountUid}/users',
register: 'users',
updateUser: 'account/{accountUid}/users/{userUid}?actionType={actionType}',
deleteUser: 'accounts/{accountUid}/users/{userUid}',
getSettings: 'accounts/{accountUid}/settings',
getIraSettings: 'accounts/{accountUid}/iraSettings',
getSettingsRegistration: 'application/settings',
agreement: 'accounts/agreement',
"accounts/{currentAccountUid}/users/{currentUserUid}/permissions",
getAddresses: "accounts/{accountUid}/addresses",
updateAddress: "account/{accountUid}/addresses/{addressUid}",
deleteAddress: "accounts/{accountUid}/addresses/{addressUid}",
getUsers: "accounts/{accountUid}/users",
register: "users",
updateUser: "account/{accountUid}/users/{userUid}?actionType={actionType}",
deleteUser: "accounts/{accountUid}/users/{userUid}",
getSettings: "accounts/{accountUid}/settings",
getIraSettings: "accounts/{accountUid}/iraSettings",
getSettingsRegistration: "application/settings",
agreement: "accounts/agreement",
},
authentications: {
getUsernames: 'authenticate/usernames',
login: 'auth/token',
logout: 'auth/logout',
getUserSecurityQuestion: 'users/username/securityquestion',
confirmSecurityQuestion: 'authenticate/confirm',
confirmForgotPassword: 'users/passwords/reset_token',
resetPassword: 'reset-password',
forgotPassword: 'forgot-password',
refreshToken: '/auth/refresh',
generateToken: '/authenticate/generate',
getUsernames: "authenticate/usernames",
login: "auth/token",
logout: "auth/logout",
getUserSecurityQuestion: "users/username/securityquestion",
confirmSecurityQuestion: "authenticate/confirm",
confirmForgotPassword: "users/passwords/reset_token",
resetPassword: "reset-password",
forgotPassword: "forgot-password",
refreshToken: "/auth/refresh",
generateToken: "/authenticate/generate",
authenticate:
'/authenticate?fp={fp}&offer={offer}&landingPageUrl={landingPageUrl}&registrationFlowType={registrationFlowType}',
"/authenticate?fp={fp}&offer={offer}&landingPageUrl={landingPageUrl}&registrationFlowType={registrationFlowType}",
confirmAuthentication:
'/authenticate/confirm?fp={fp}&offer={offer}&landingPageUrl={landingPageUrl}&registrationFlowType={registrationFlowType}',
"/authenticate/confirm?fp={fp}&offer={offer}&landingPageUrl={landingPageUrl}&registrationFlowType={registrationFlowType}",
},
bankAccounts: {
get: 'accounts/{accountUid}/bankaccounts',
get: "accounts/{accountUid}/bankaccounts",
getBankAccount:
'accounts/{accountUid}/bankaccounts/{bankAccountUid}?type={type}',
"accounts/{accountUid}/bankaccounts/{bankAccountUid}?type={type}",
getBankAccountsByType:
'accounts/{accountUid}/bankaccounts?type={type}&active=true',
getBankDetailsByRoutingNumber: 'banks/{routingNumber}',
newAccount: 'accounts/{accountUid}/bankaccounts',
"accounts/{accountUid}/bankaccounts?type={type}&active=true",
getBankDetailsByRoutingNumber: "banks/{routingNumber}",
newAccount: "accounts/{accountUid}/bankaccounts",
deleteAccount:
'accounts/{accountUid}/bankaccounts/{bankAccountUid}?type={type}',
verify: '/accounts/{accountUid}/bankaccountverification/{bankAccountUid}',
postBankAccountRegistration: '/accounts/{applicationUid}/bankaccounts',
getRegistration: 'banks/{applicationUid}/bankaccounts',
"accounts/{accountUid}/bankaccounts/{bankAccountUid}?type={type}",
verify: "/accounts/{accountUid}/bankaccountverification/{bankAccountUid}",
postBankAccountRegistration: "/accounts/{applicationUid}/bankaccounts",
getRegistration: "banks/{applicationUid}/bankaccounts",
},
documents: {
getDocuments: 'accounts/{accountUid}/documents?year={year}',
getDocument: 'accounts/{accountUid}/documents/{documentType}',
getDocuments: "accounts/{accountUid}/documents?year={year}",
getDocument: "accounts/{accountUid}/documents/{documentType}",
},
countries: '/countries',
countries: "/countries",
metalStream: {
getMetalStreamSettings: 'accounts/{accountUid}/metalstream',
getMetalStreamFundings: 'applications/{applicationUid}/metalStreamFunding',
getMetalStreamSettings: "accounts/{accountUid}/metalstream",
getMetalStreamFundings: "applications/{applicationUid}/metalStreamFunding",
},
orders: {
buyForStorage: '/accounts/{accountUid}/orders/buyForStorage',
buyForDelivery: '/accounts/{accountUid}/orders/buyForDelivery',
verifyBuyForDelivery: '/accounts/{accountUid}/orders/buyForDelivery/verify',
sellFromStorage: '/accounts/{accountUid}/orders/sellFromStorage',
fractionalConversion: '/accounts/{accountUid}/orders/fractionalConversion',
buyForStorage: "/accounts/{accountUid}/orders/buyForStorage",
buyForDelivery: "/accounts/{accountUid}/orders/buyForDelivery",
verifyBuyForDelivery: "/accounts/{accountUid}/orders/buyForDelivery/verify",
sellFromStorage: "/accounts/{accountUid}/orders/sellFromStorage",
fractionalConversion: "/accounts/{accountUid}/orders/fractionalConversion",
deliverFromStorageVerify:
'/accounts/{accountUid}/orders/deliverFromStorage/verify',
deliverFromStorage: '/accounts/{accountUid}/orders/deliverFromStorage',
iraCashDistribution: '/accounts/{accountUid}/orders/iraCashDistribution',
iraCashTransfer: '/accounts/{accountUid}/orders/iraCashTransfer',
iraFeeWithdrawal: 'accounts/{accountUid}/orders/iraFeeWithdrawal',
achDeposit: 'accounts/{accountUid}/orders/achDeposit',
wireWithdrawal: '/accounts/{accountUid}/orders/wireWithdrawal',
checkWithdrawal: '/accounts/{accountUid}/orders/checkWithdrawal',
"/accounts/{accountUid}/orders/deliverFromStorage/verify",
deliverFromStorage: "/accounts/{accountUid}/orders/deliverFromStorage",
iraCashDistribution: "/accounts/{accountUid}/orders/iraCashDistribution",
iraCashTransfer: "/accounts/{accountUid}/orders/iraCashTransfer",
iraFeeWithdrawal: "accounts/{accountUid}/orders/iraFeeWithdrawal",
achDeposit: "accounts/{accountUid}/orders/achDeposit",
wireWithdrawal: "/accounts/{accountUid}/orders/wireWithdrawal",
checkWithdrawal: "/accounts/{accountUid}/orders/checkWithdrawal",
},
portfolio: {
getPortfolioValuations: 'accounts/{accountUid}/portfolio/valuations',
getPortfolioMetalPrices: 'marketprices',
getPortfolioValuations: "accounts/{accountUid}/portfolio/valuations",
getPortfolioMetalPrices: "marketprices",
getPortfolioHoldings:
'accounts/{accountUid}/portfolio/products?valuation=true',
getPortfolioProductCodes: '/accounts/{accountUid}/portfolio/productcodes',
getPortfolioBalances: '/accounts/{accountUid}/portfolio/balances',
"accounts/{accountUid}/portfolio/products?valuation=true",
getPortfolioProductCodes: "/accounts/{accountUid}/portfolio/productcodes",
getPortfolioBalances: "/accounts/{accountUid}/portfolio/balances",
getPortfolioProductBySymbol:
'/accounts/{accountUid}/portfolio/products/{symbol}',
getPortfolioTransactions: '/accounts/{accountUid}/transactions',
"/accounts/{accountUid}/portfolio/products/{symbol}",
getPortfolioTransactions: "/accounts/{accountUid}/transactions",
getPortfolioSingleTransaction:
'/accounts/{accountUid}/transactions/{transactionUid}',
getProductPortoflioTransactions: 'accounts/{accountUid}/transactions',
"/accounts/{accountUid}/transactions/{transactionUid}",
getProductPortoflioTransactions: "accounts/{accountUid}/transactions",
getRecentPortfolioTransactions:
'accounts/{accountUid}/transactions?content=Recent',
getFinancialPortfolioTransactions: 'accounts/{accountUid}/transactions',
"accounts/{accountUid}/transactions?content=Recent",
getFinancialPortfolioTransactions: "accounts/{accountUid}/transactions",
getFinancialPortfolioPendingTransactions:
'accounts/{accountUid}/transactions/fundinghistory',
"accounts/{accountUid}/transactions/fundinghistory",
patchFinancialPortfolioPendingTransactions:
'/accounts/{accountUid}/transactions/fundinghistory/{depositKey}',
"/accounts/{accountUid}/transactions/fundinghistory/{depositKey}",
},
products: {
getPrices: '/accounts/{accountUid}/products/prices',
prices: 'accounts/{accountUid}/products/prices?side={side}',
getPrices: "/accounts/{accountUid}/products/prices",
prices: "accounts/{accountUid}/products/prices?side={side}",
tiers:
'/accounts/{accountUid}/products/prices/{symbol}/tiers?side={side}&location={location}',
symbolPrices: '/accounts/{accountUid}/products/{symbol}/prices?side={side}',
getPricesRegistration: 'applications/{applicationUid}/products/prices',
"/accounts/{accountUid}/products/prices/{symbol}/tiers?side={side}&location={location}",
symbolPrices: "/accounts/{accountUid}/products/{symbol}/prices?side={side}",
getPricesRegistration: "applications/{applicationUid}/products/prices",
},
settings: {
get: 'settings',
get: "settings",
},
taxForms: {
getTaxForms: 'settings/taxForms/{applicationType}',
getTaxForms: "settings/taxForms/{applicationType}",
},
users: {
getAccounts: '/users/{userUid}/accounts',
getRegistrationAccounts: '/users/{userUid}/accounts',
updateUser: '/users/{userUid}?updateUserActionType={actionType}',
updateUserPassword: '/users/{userUid}/passwords',
logout: '/auth/logout',
getUsernames: '/users/email',
getAccounts: "/users/{userUid}/accounts",
getRegistrationAccounts: "/users/{userUid}/accounts",
updateUser: "/users/{userUid}?updateUserActionType={actionType}",
updateUserPassword: "/users/{userUid}/passwords",
logout: "/auth/logout",
getUsernames: "/users/email",
createUser:
'/users?fp={fp}&offer={offer}&landingPageUrl={landingPageUrl}&registrationFlowType={registrationFlowType}',
updateUserRegistration: '/users/{userUid}',
invite: '/users/invite',
"/users?fp={fp}&offer={offer}&landingPageUrl={landingPageUrl}&registrationFlowType={registrationFlowType}",
updateUserRegistration: "/users/{userUid}",
invite: "/users/invite",
},
applications: {
application: '/applications/{applicationUid}',
addPerson: '/applications/{applicationUid}/persons',
updatePerson: '/applications/{applicationUid}/persons/{personUid}',
application: "/applications/{applicationUid}",
addPerson: "/applications/{applicationUid}/persons",
updatePerson: "/applications/{applicationUid}/persons/{personUid}",
addPersonWithGiftState:
'/applications/{applicationUid}/UTMA/persons?giftState={giftState}',
"/applications/{applicationUid}/UTMA/persons?giftState={giftState}",
updatePersonWithGiftState:
'/applications/{applicationUid}/UTMA/persons/{personUid}?giftState={giftState}',
"/applications/{applicationUid}/UTMA/persons/{personUid}?giftState={giftState}",
addPersonWithCompanyName:
'/applications/{applicationUid}/IRA/persons?companyName={companyName}',
"/applications/{applicationUid}/IRA/persons?companyName={companyName}",
updatePersonWithCompanyName:
'/applications/{applicationUid}/IRA/persons/{personUid}?companyName={companyName}',
submitLegalEntity: '/applications/{applicationUid}/legalEntities',
"/applications/{applicationUid}/IRA/persons/{personUid}?companyName={companyName}",
submitLegalEntity: "/applications/{applicationUid}/legalEntities",
updateLegalEntity:
'/applications/{applicationUid}/legalEntities/{personUid}',
postNonIraFunding: '/applications/{applicationUid}/funding',
postIraFunding: '/applications/{applicationUid}/iraFunding',
postMSFunding: '/applications/{applicationUid}/metalStreamFunding',
consent: '/applications/{applicationUid}/consents',
"/applications/{applicationUid}/legalEntities/{personUid}",
postNonIraFunding: "/applications/{applicationUid}/funding",
postIraFunding: "/applications/{applicationUid}/iraFunding",
postMSFunding: "/applications/{applicationUid}/metalStreamFunding",
consent: "/applications/{applicationUid}/consents",
updateConsent: `/applications/{applicationUid}/consents/{agreementConsentUid}`,
submitMetalStreamRegistration:
'/applications/{applicationUid}/metalStreamFunding',
"/applications/{applicationUid}/metalStreamFunding",
},
common: {
getCountries: '/countries/',
getTaxForms: '/taxForms/',
getContributionYears: 'contributionYears',
getCountryStates: '/countries/{iso3CountryCode}/states/',
getSecurityQuestions: '/registration/securityQuestions/',
getPortalSecurityQuestions: '/securityQuestions',
getCountries: "/countries/",
getTaxForms: "/taxForms/",
getContributionYears: "contributionYears",
getCountryStates: "/countries/{iso3CountryCode}/states/",
getSecurityQuestions: "/registration/securityQuestions/",
getPortalSecurityQuestions: "/securityQuestions",
},
plaid: {
getToken: '/bankaccounts/createplaidlinktoken',
getToken: "/bankaccounts/createplaidlinktoken",
},
affiliate: {
setCookie: '/affiliate/picture',
setFingerprint: '/affiliate/fingerprint',
setCookie: "/affiliate/picture",
setFingerprint: "/affiliate/fingerprint",
},
offers: {
getOffers: 'offers',
addOffer: 'offers',
categories: 'categories',
locations: 'locations'
}
getOffers: "/offers",
getOneOffer: "/offers",
addOffer: "/offers",
categories: "categories",
locations: "locations",
},
};

+ 5
- 0
src/request/offersRequest.js Wyświetl plik

@@ -5,6 +5,11 @@ export const attemptFetchOffers = (payload) => {
if (payload) return getRequest(apiEndpoints.offers.getOffers + payload + "&size=10")
return getRequest(apiEndpoints.offers.getOffers + "?size=10")
}
export const attemptFetchOneOffer = (payload) => {
// console.log(payload);
const url = `${apiEndpoints.offers.getOneOffer}/${payload.payload}`;
return getRequest(url);
}
export const attemptAddOffer = (payload) => {
return postRequest(apiEndpoints.offers.addOffer, payload)
}

+ 6
- 0
src/store/actions/offers/offersActionConstants.js Wyświetl plik

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

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

export const OFFERS_FETCH = createFetchType(OFFERS_SCOPE);
export const OFFERS_SUCCESS = createSuccessType(OFFERS_SCOPE);
export const OFFERS_ERROR = createErrorType(OFFERS_SCOPE);
export const OFFERS_CLEAR = createClearType(OFFERS_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_SET = "OFFERS_SET";
export const OFFER_SET = "OFFER_SET"
export const OFFERS_ADD = "OFFERS_ADD";
export const OFFER_ADD = "OFFER_ADD";

+ 21
- 1
src/store/actions/offers/offersActions.js Wyświetl plik

@@ -1,4 +1,4 @@
import { OFFERS_ADD, OFFERS_CLEAR, OFFERS_ERROR, OFFERS_FETCH, OFFERS_SET, OFFERS_SUCCESS, OFFER_ADD } from "./offersActionConstants";
import { OFFERS_ADD, OFFERS_CLEAR, OFFERS_ERROR, OFFERS_FETCH, OFFERS_SET, OFFERS_SUCCESS, OFFER_ADD, ONE_OFFER_FETCH, ONE_OFFER_SUCCESS, ONE_OFFER_ERROR, OFFER_SET } from "./offersActionConstants";

export const fetchOffers = (payload) => ({
type: OFFERS_FETCH,
@@ -26,4 +26,24 @@ export const addOffers = (payload) => ({
export const addOffer = (payload) => ({
type: OFFER_ADD,
payload
})

//

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

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

+ 35
- 0
src/store/reducers/offers/offersReducer.js Wyświetl plik

@@ -4,6 +4,10 @@ import {
OFFERS_ERROR,
OFFERS_SET,
OFFER_ADD,
OFFER_SET,
ONE_OFFER_FETCH,
ONE_OFFER_ERROR,
ONE_OFFER_SUCCESS,
} from "../../actions/offers/offersActionConstants";
import createReducer from "../../utils/createReducer";

@@ -11,6 +15,7 @@ const initialState = {
offers: [],
error: "",
newOffer: "",
selectedOffer:"",
};

export default createReducer(
@@ -20,6 +25,11 @@ export default createReducer(
[OFFERS_SET]: setOffers,
[OFFERS_ADD]: addOffers,
[OFFER_ADD]: addOffer,
[OFFER_SET]: setOffer,
[ONE_OFFER_ERROR]: fetchOneOfferError,
[ONE_OFFER_SUCCESS]: fetchOneOfferSuccess,
[ONE_OFFER_FETCH]: fetchOneOffer,

},
initialState
);
@@ -37,6 +47,12 @@ function setOffers(state, action) {
offers: action.payload,
};
}
function setOffer(state, action) {
return {
...state,
selectedOffer: action.payload,
};
}
function addOffers(state, action) {
return {
...state,
@@ -49,3 +65,22 @@ function addOffer(state, action) {
offer: action.payload
}
}

function fetchOneOffer(state,action) {
return {
...state,
selectedOffer: action.payload
}
}
function fetchOneOfferSuccess( state, action) {
return {
...state,
selectedOffer: action.payload
}
}
function fetchOneOfferError (state, action) {
return {
...state,
error: action.payload
}
}

+ 2
- 1
src/store/saga/forgotPasswordSaga.js Wyświetl plik

@@ -4,8 +4,8 @@ import { FORGOT_PASSWORD, RESET_PASSWORD } from "../actions/user/userActionConst

function* forgotPassword({payload}) {
try {
console.log(payload)
const data = yield call(forgotPasswordRequest, payload.email);
console.log(data);
if (data) {
if (payload.handleResponseSuccess) {
yield call(payload.handleResponseSuccess);
@@ -13,6 +13,7 @@ function* forgotPassword({payload}) {
}
}
catch(e) {
console.log(e);
if (payload.handleResponseError) {
yield call(payload.handleResponseError);
}

+ 3
- 2
src/store/saga/loginSaga.js Wyświetl plik

@@ -63,8 +63,9 @@ function* fetchUser({ payload }) {
if (payload.handleApiResponseError) {
yield call(payload.handleApiResponseError, e.response.status);
}
let errorMessage = yield call(rejectErrorCodeHelper, e);
if (e.response.status === 401) {
console.log(e.response.status);
let errorMessage = yield call(rejectErrorCodeHelper, e.response.status);
if (e.response.status === 400) {
errorMessage = i18next.t("login.wrongCredentials", {
lng: "rs"
});

+ 15
- 1
src/store/saga/offersSaga.js Wyświetl plik

@@ -2,12 +2,14 @@ import { all, takeLatest, call, put } from "@redux-saga/core/effects";
import {
attemptAddOffer,
attemptFetchOffers,
attemptFetchOneOffer,
} from "../../request/offersRequest";
import {
OFFERS_FETCH,
OFFER_ADD,
ONE_OFFER_FETCH,
} from "../actions/offers/offersActionConstants";
import { setOffers } from "../actions/offers/offersActions";
import { setOffers, setOffer } from "../actions/offers/offersActions";

function* fetchOffers(payload) {
try {
@@ -38,9 +40,21 @@ function* createOffer(payload) {
}
}

function* fetchOneOffer(payload) {
try {
console.log(payload);
const data = yield call(attemptFetchOneOffer, payload);
//console.log(data.data);
yield put(setOffer(data.data));
} catch (e) {
console.log(e);
}
}

export default function* offersSaga() {
yield all([
takeLatest(OFFERS_FETCH, fetchOffers),
takeLatest(OFFER_ADD, createOffer),
takeLatest(ONE_OFFER_FETCH, fetchOneOffer),
]);
}

+ 1
- 1
src/store/saga/registerSaga.js Wyświetl plik

@@ -4,13 +4,13 @@ import { REGISTER_USER_FETCH } from "../actions/register/registerActionConstants

function* fetchRegisterUser({ payload }) {
try {

const requestData = {
email: payload.values.mail.toString(),
password: payload.values.password.toString(),
roles: [
"User",
],
image: payload.values.image.replace("data:image/png;base64,", ""),
company: {
name: payload.values.nameOfFirm.toString(),
PIB: payload.values.PIB.toString(),

+ 5
- 0
src/store/selectors/offersSelectors.js Wyświetl plik

@@ -7,6 +7,11 @@ export const selectOffers = createSelector(
(state) => state.offers,
);

export const selectOffer = createSelector(
offersSelector,
(state) => state.selectedOffer,
);

export const selectOffersError = createSelector(
offersSelector,
(state) => state.error,

+ 1
- 1
src/themes/primaryTheme/primaryThemeColors.js Wyświetl plik

@@ -15,5 +15,5 @@ export const primaryThemeColors = {
selectOptionTextColor: "#1D1D1D",
primaryDarkText: "#505050",
iconStrokeColor: "#8C8C8C",
// iconStrokeDisabledColor: "#818181",
iconStrokeDisabledColor: "#818181",
};

+ 6
- 11
src/util/helpers/rejectErrorCodeHelper.js Wyświetl plik

@@ -1,14 +1,9 @@
import i18next from 'i18next';
import i18next from "i18next";

export const rejectErrorCodeHelper = (error) => {
if (error?.response?.data?.Errors) {
const errorCode = error?.response?.data?.Errors[0]?.Code;
const errorMessage = errorCode
? i18next.t(`apiErrors.${errorCode}`)
: i18next.t('apiErrors.SomethingWentWrong');
export const rejectErrorCodeHelper = (errorCode) => {
const errorMessage = errorCode
? i18next.t(`apiErrors.${errorCode}`)
: i18next.t("apiErrors.SomethingWentWrong");

return errorMessage;
}

return i18next.t('apiErrors.SomethingWentWrong');
return errorMessage;
};

Ładowanie…
Anuluj
Zapisz