Quellcode durchsuchen

Minor changes, started creating createOffer page, started connecting with backend, making some pages responsive

pull/2/head
Djordje Mitrovic vor 3 Jahren
Ursprung
Commit
af597b3f36
40 geänderte Dateien mit 470 neuen und 173 gelöschten Zeilen
  1. 7
    0
      src/assets/images/svg/coffee.svg
  2. 4
    0
      src/assets/images/svg/home.svg
  3. 6
    0
      src/assets/images/svg/truck.svg
  4. 7
    92
      src/components/Cards/CreateOfferCard/CreateOffer.js
  5. 14
    0
      src/components/Cards/CreateOfferCard/CreateOffer.styled.js
  6. 104
    0
      src/components/Cards/CreateOfferCard/FirstPart/FirstPartCreateOffer.js
  7. 50
    0
      src/components/Cards/CreateOfferCard/FirstPart/FirstPartCreateOffer.styled.js
  8. 4
    3
      src/components/Cards/OfferCard/OfferCard.js
  9. 1
    1
      src/components/Cards/OfferCard/OfferCard.styled.js
  10. 11
    2
      src/components/CheckBox/Label.js
  11. 11
    9
      src/components/MarketPlace/Offers/Offers.js
  12. 27
    0
      src/components/Select/Option/Option.js
  13. 13
    0
      src/components/Select/Option/Option.styled.js
  14. 35
    0
      src/components/Select/Select.js
  15. 12
    0
      src/components/Select/Select.styled.js
  16. 1
    0
      src/components/TextFields/TextField/TextField.js
  17. 10
    4
      src/components/TextFields/TextField/TextField.styled.js
  18. 6
    0
      src/pages/ForgotPasswordPage/ForgotPassword.styled.js
  19. 7
    2
      src/pages/ForgotPasswordPage/ForgotPasswordMailSent/MailSent.js
  20. 6
    0
      src/pages/ForgotPasswordPage/ForgotPasswordMailSent/MailSent.styled.js
  21. 3
    5
      src/pages/ForgotPasswordPage/ForgotPasswordPageMUI.js
  22. 0
    1
      src/pages/HomePage/HomePageMUI.js
  23. 6
    0
      src/pages/LoginPage/Login.styled.js
  24. 4
    1
      src/pages/RegisterPages/Register/FirstPart/FirstPartOfRegistration.js
  25. 8
    0
      src/pages/RegisterPages/Register/FirstPart/FirstPartOfRegistration.styled.js
  26. 11
    2
      src/pages/RegisterPages/Register/Register.js
  27. 25
    10
      src/pages/RegisterPages/Register/Register.styled.js
  28. 4
    0
      src/pages/RegisterPages/Register/SecondPart/SecondPartOfRegistration.js
  29. 7
    0
      src/pages/RegisterPages/Register/SecondPart/SecondPartOfRegistration.styled.js
  30. 3
    0
      src/pages/RegisterPages/Register/ThirdPart/ThirdPartOfRegistration.styled.js
  31. 6
    0
      src/pages/ResetPasswordPage/ResetPasswordPage.styled.js
  32. 5
    3
      src/request/forgotPasswordRequest.js
  33. 2
    1
      src/store/actions/offers/offersActionConstants.js
  34. 5
    1
      src/store/actions/offers/offersActions.js
  35. 8
    0
      src/store/reducers/offers/offersReducer.js
  36. 2
    3
      src/store/saga/forgotPasswordSaga.js
  37. 0
    2
      src/store/saga/loginSaga.js
  38. 4
    2
      src/store/saga/offersSaga.js
  39. 30
    29
      src/store/saga/registerSaga.js
  40. 1
    0
      src/themes/primaryTheme/primaryThemeColors.js

+ 7
- 0
src/assets/images/svg/coffee.svg Datei anzeigen

@@ -0,0 +1,7 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 4H9.5C10.0304 4 10.5391 4.21071 10.9142 4.58579C11.2893 4.96086 11.5 5.46957 11.5 6C11.5 6.53043 11.2893 7.03914 10.9142 7.41421C10.5391 7.78929 10.0304 8 9.5 8H9" stroke="#FEB005" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M1 4H9V8.5C9 9.03043 8.78929 9.53914 8.41421 9.91421C8.03914 10.2893 7.53043 10.5 7 10.5H3C2.46957 10.5 1.96086 10.2893 1.58579 9.91421C1.21071 9.53914 1 9.03043 1 8.5V4Z" stroke="#FEB005" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 0.5V2" stroke="#FEB005" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5 0.5V2" stroke="#FEB005" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7 0.5V2" stroke="#FEB005" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

+ 4
- 0
src/assets/images/svg/home.svg Datei anzeigen

@@ -0,0 +1,4 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.5 4.5L6 1L10.5 4.5V10C10.5 10.2652 10.3946 10.5196 10.2071 10.7071C10.0196 10.8946 9.76522 11 9.5 11H2.5C2.23478 11 1.98043 10.8946 1.79289 10.7071C1.60536 10.5196 1.5 10.2652 1.5 10V4.5Z" stroke="#5A3984" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.5 11V6H7.5V11" stroke="#5A3984" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

+ 6
- 0
src/assets/images/svg/truck.svg Datei anzeigen

@@ -0,0 +1,6 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 1.5H0.5V8H8V1.5Z" stroke="#5A3984" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 4H10L11.5 5.5V8H8V4Z" stroke="#5A3984" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.75 10.5C3.44036 10.5 4 9.94036 4 9.25C4 8.55964 3.44036 8 2.75 8C2.05964 8 1.5 8.55964 1.5 9.25C1.5 9.94036 2.05964 10.5 2.75 10.5Z" stroke="#5A3984" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.25 10.5C9.94036 10.5 10.5 9.94036 10.5 9.25C10.5 8.55964 9.94036 8 9.25 8C8.55964 8 8 8.55964 8 9.25C8 9.94036 8.55964 10.5 9.25 10.5Z" stroke="#5A3984" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

+ 7
- 92
src/components/Cards/CreateOfferCard/CreateOffer.js Datei anzeigen

@@ -6,9 +6,7 @@ import { useDispatch, useSelector } from "react-redux";
import { NavLink } from "react-router-dom";
import * as Yup from "yup";
import { useTranslation } from "react-i18next";
import {
fetchUser,
} from "../../../store/actions/login/loginActions";
import { fetchUser } from "../../../store/actions/login/loginActions";
import { FORGOT_PASSWORD_PAGE, HOME_PAGE } from "../../../constants/pages";
import { ReactComponent as VisibilityOn } from "../../../assets/images/svg/eye-striked.svg";
import { ReactComponent as VisibilityOff } from "../../../assets/images/svg/eye.svg";
@@ -25,9 +23,12 @@ import {
CreateOfferFormContainer,
RegisterAltText,
RegisterTextContainer,
FieldLabel,
} from "./CreateOffer.styled";
import selectedTheme from "../../../themes";
import StepProgress from "../../StepProgress/StepProgress";
import { Label } from "../../CheckBox/Label";
import FirstPartCreateOffer from "./FirstPart/FirstPartCreateOffer";

const CreateOffer = ({ history }) => {
const dispatch = useDispatch();
@@ -72,101 +73,15 @@ const CreateOffer = ({ history }) => {
);
};

const formik = useFormik({
initialValues: {
nameOfProduct: "",
description: "",
},
validationSchema: Yup.object().shape({
nameOfProduct: Yup.string().required(t("login.nameOfProductRequired")),
description: Yup.string().required(t("login.descriptionRequired")).min(8),
}),
onSubmit: handleSubmit,
validateOnBlur: true,
enableReinitialize: true,
});

return (
<CreateOfferContainer>

<CreateOfferTitle component="h1" variant="h5">
Nova Objava
</CreateOfferTitle>

<StepProgress current={1} numberOfSteps={3}/>

<CreateOfferFormContainer component="form" onSubmit={formik.handleSubmit}>
{/* <Backdrop position="absolute" isLoading={isLoading} /> */}

<TextField
name="nameOfProduct"
placeholder={"Naziv proizvoda..."}
italicPlaceholder
margin="normal"
value={formik.values.nameOfProduct}
onChange={formik.handleChange}
error={(formik.touched.nameOfProduct && formik.errors.nameOfProduct)}
helperText={formik.touched.nameOfProduct && formik.errors.nameOfProduct}
autoFocus
fullWidth
/>

<TextField
name="description"
placeholder={"Opis..."}
margin="normal"
italicPlaceholder
value={formik.values.description}
onChange={formik.handleChange}
error={(formik.touched.description && formik.errors.description)}
helperText={formik.touched.description && formik.errors.description}
fullWidth
multiline
minRows={4}
height={"100px"}
/>

<Link
to={FORGOT_PASSWORD_PAGE}
textsize="12px"
component={NavLink}
underline="hover"
align="right"
style={{ marginTop: "18px", marginBottom: "18px" }}
>
{t("login.forgotYourPassword")}
</Link>

<PrimaryButton
type="submit"
variant="contained"
height="48px"
fullWidth={true}
buttoncolor={selectedTheme.primaryPurple}
textcolor="white"
// disabled={
// formik.values.username.length === 0 ||
// formik.values.password.length === 0
// }
>
{t("login.logIn")}
</PrimaryButton>

<RegisterTextContainer>
<RegisterAltText>
{t("login.dontHaveAccount").padEnd(2, " ")}
</RegisterAltText>

<Link
to="/register"
component={NavLink}
underline="hover"
align="center"
>
{t("login.signUp")}
</Link>
</RegisterTextContainer>
</CreateOfferFormContainer>
<StepProgress current={1} numberOfSteps={3} />
<FirstPartCreateOffer />
</CreateOfferContainer>
);
};

+ 14
- 0
src/components/Cards/CreateOfferCard/CreateOffer.styled.js Datei anzeigen

@@ -1,6 +1,7 @@
import { Box, Container, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../themes";
import { Label } from "../../CheckBox/Label";

export const CreateOfferContainer = styled(Container)`
margin-top: 0px;
@@ -40,6 +41,7 @@ export const CreateOfferDescription = styled(Typography)`
export const CreateOfferFormContainer = styled(Box)`
width: 335px;
height: 700px;
padding-top: 20px;
`;
export const RegisterAltText = styled(Typography)`
font-family: "Poppins";
@@ -53,4 +55,16 @@ export const RegisterTextContainer = styled(Box)`
flex-direction: row;
margin-top: 36px;
justify-content: center;
`
export const FieldLabel = styled(Label)`
position: relative;
bottom: -14px;
& label {
font-size: 12px;
font-weight: 600;
line-height: 20px;
color: ${selectedTheme.primaryGrayText};
cursor: auto;
letter-spacing: 0.2px;
}
`

+ 104
- 0
src/components/Cards/CreateOfferCard/FirstPart/FirstPartCreateOffer.js Datei anzeigen

@@ -0,0 +1,104 @@
import React from 'react'
import PropTypes from 'prop-types'
import {useFormik} from "formik";
import { CreateOfferFormContainer, FieldLabel } from './FirstPartCreateOffer.styled'
import { TextField } from '../../../TextFields/TextField/TextField'
import { PrimaryButton } from '../../../Buttons/PrimaryButton/PrimaryButton'
import * as Yup from "yup"
import selectedTheme from '../../../../themes';
import { useTranslation } from 'react-i18next';
import Select from '../../../Select/Select';
import Option from '../../../Select/Option/Option';

const FirstPartCreateOffer = () => {
const {t} = useTranslation();
const handleSubmit = (values) => {
console.log(values)
}
const formik = useFormik({
initialValues: {
nameOfProduct: "",
description: "",
},
validationSchema: Yup.object().shape({
nameOfProduct: Yup.string().required(t("login.nameOfProductRequired")),
description: Yup.string().required(t("login.descriptionRequired")).min(8),
}),
onSubmit: handleSubmit,
validateOnBlur: true,
enableReinitialize: true,
});
return (
<CreateOfferFormContainer component="form" onSubmit={formik.handleSubmit}>
{/* <Backdrop position="absolute" isLoading={isLoading} /> */}

<FieldLabel
leftText={"NASLOV"}
/>
<TextField
name="nameOfProduct"
placeholder={"Naziv proizvoda..."}
italicPlaceholder
margin="normal"
value={formik.values.nameOfProduct}
onChange={formik.handleChange}
error={formik.touched.nameOfProduct && formik.errors.nameOfProduct}
helperText={
formik.touched.nameOfProduct && formik.errors.nameOfProduct
}
autoFocus
fullWidth
/>

<FieldLabel
leftText={"OPIS PROIZVODA"}
/>
<TextField
name="description"
placeholder={"Opis..."}
margin="normal"
italicPlaceholder
value={formik.values.description}
onChange={formik.handleChange}
error={formik.touched.description && formik.errors.description}
helperText={formik.touched.description && formik.errors.description}
fullWidth
multiline
minRows={4}
height={"100px"}
/>

<Select defaultValue={1}>
<Option value={1}>Opcija 1</Option>
<Option value={2}>Opcija 2</Option>
<Option value={3}>Opcija 3</Option>
<Option value={4}>Opcija 4</Option>

</Select>



<PrimaryButton
type="submit"
variant="contained"
height="48px"
fullWidth={true}
buttoncolor={selectedTheme.primaryPurple}
textcolor="white"
// disabled={
// formik.values.username.length === 0 ||
// formik.values.password.length === 0
// }
>
NASTAVI
</PrimaryButton>

</CreateOfferFormContainer>
)
}

FirstPartCreateOffer.propTypes = {
children: PropTypes.any,
}

export default FirstPartCreateOffer

+ 50
- 0
src/components/Cards/CreateOfferCard/FirstPart/FirstPartCreateOffer.styled.js Datei anzeigen

@@ -0,0 +1,50 @@
import { Box, Typography } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../../themes";
import { Label } from "../../../CheckBox/Label";

export const CreateOfferTitle = styled(Typography)`
font-family: "Open Sans";
width: 328px;
height: 33px;
text-align: center;
flex: 1;
font-style: normal;
font-weight: 700;
font-size: 24px;
line-height: 33px;
color: ${selectedTheme.primaryPurple};
margin-top: 36px;
margin-bottom: 40px;
`;
export const CreateOfferDescription = styled(Typography)`
font-family: "Open Sans";
margin-top: 9px;
width: 221px;
font-style: normal;
font-weight: 400;
font-size: 16px;
line-height: 22px;
display: flex;
align-items: center;
text-align: center;
color: ${selectedTheme.primaryGrayText};
margin-bottom: 20px;
`;
export const CreateOfferFormContainer = styled(Box)`
width: 335px;
height: 700px;
padding-top: 20px;
`;
export const FieldLabel = styled(Label)`
position: relative;
bottom: -14px;
& label {
font-size: 12px;
font-weight: 600;
line-height: 20px;
color: ${selectedTheme.primaryGrayText};
cursor: auto;
letter-spacing: 0.2px;
}
`

+ 4
- 3
src/components/Cards/OfferCard/OfferCard.js Datei anzeigen

@@ -29,8 +29,8 @@ import selectedTheme from "../../../themes";

const OfferCard = (props) => {
return (
<OfferCardContainer sponsored={props.sponsored.toString()} halfwidth={props.halfwidth ? 1 : 0}>
<OfferImage>{props.image}</OfferImage>
<OfferCardContainer sponsored={props.offer.pinned.toString()} halfwidth={props.halfwidth ? 1 : 0}>
<OfferImage src={props.offer.images[0]}></OfferImage>
<OfferInfo>
<OfferTitle>{props.title}</OfferTitle>
<OfferAuthor>
@@ -54,7 +54,7 @@ const OfferCard = (props) => {
<DetailIcon color="black" component="span" size="16px">
<Eye width={"12px"} height={"11px"} />
</DetailIcon>
<DetailText>{props.numberOfViews} pregleda</DetailText>
<DetailText>{props.offer.views.viewers.length} pregleda</DetailText>
</OfferViews>
</OfferDetails>
</OfferInfo>
@@ -110,6 +110,7 @@ OfferCard.propTypes = {
numberOfViews: PropTypes.number,
halfwidth: PropTypes.bool,
sponsored: PropTypes.bool,
offer: PropTypes.any,
};
OfferCard.defaultProps = {
halfwidth: false,

+ 1
- 1
src/components/Cards/OfferCard/OfferCard.styled.js Datei anzeigen

@@ -22,7 +22,7 @@ export const OfferCardContainer = styled(Container)`
height: 180px;
position: relative;
`;
export const OfferImage = styled(Box)``;
export const OfferImage = styled.img``;
export const OfferInfo = styled(Box)`
display: flex;
flex: 2;

+ 11
- 2
src/components/CheckBox/Label.js Datei anzeigen

@@ -4,8 +4,13 @@ import PropTypes from "prop-types";

export const Label = (props) => {
return (
<LabelContainer onClick={props.onClick} maxWidth={props.maxWidth}>
<LeftLabel>{props.leftText}</LeftLabel>
<LabelContainer
onClick={props.onClick}
maxWidth={props.maxWidth}
style={props.containerStyle}
className={props.className}
>
<LeftLabel style={props.leftTextStyle}>{props.leftText}</LeftLabel>
{props.rightText && <RightLabel>{props.rightText}</RightLabel>}
</LabelContainer>
);
@@ -16,4 +21,8 @@ Label.propTypes = {
leftText: PropTypes.string,
rightText: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
maxWidth: PropTypes.string,
leftTextStyle: PropTypes.any,
rightTextStyle: PropTypes.any,
containerStyle: PropTypes.any,
className: PropTypes.any,
};

+ 11
- 9
src/components/MarketPlace/Offers/Offers.js Datei anzeigen

@@ -1,8 +1,10 @@
import React from "react";
import React, { useEffect } from "react";
import PropTypes from "prop-types";
import { OffersContainer } from "./Offers.styled";
import OfferCard from "../../Cards/OfferCard/OfferCard";
import MockupdataOffers from "../MockupdataOffers";
import { fetchOffers } from "../../../store/actions/offers/offersActions";
import { useDispatch, useSelector } from "react-redux";
import { selectOffers } from "../../../store/selectors/offersSelectors";
// import { fetchOffers } from "../../../store/actions/offers/offersActions";
// import { useDispatch, useSelector } from "react-redux";
// import { selectOffers } from "../../../store/selectors/offersSelectors";
@@ -11,17 +13,17 @@ const Offers = (props) => {

// Market place nije zavrsen
// Koriste se Mockup podaci
// const dispatch = useDispatch();
// const offers = useSelector(selectOffers);
const dispatch = useDispatch();
const offers = useSelector(selectOffers);

// useEffect(() => {
// dispatch(fetchOffers());
// }, [])
useEffect(() => {
dispatch(fetchOffers());
}, [])

return (
<OffersContainer>
{MockupdataOffers.map((item) => {
return <OfferCard {...item} key={item.id} halfwidth={props.isGrid} />;
{offers.map((item) => {
return <OfferCard key={item._id} offer={item} halfwidth={props.isGrid} />;
})}
</OffersContainer>
);

+ 27
- 0
src/components/Select/Option/Option.js Datei anzeigen

@@ -0,0 +1,27 @@
import React from 'react'
import PropTypes from 'prop-types'
import { OptionIcon, OptionStyled } from './Option.styled'

const Option = props => {
console.log(props)
return (
<OptionStyled {...props}>
{props.startIcon ? (
<OptionIcon color={props.color}>
{props.startIcon}
</OptionIcon>
) :(<>

</>)}
{props.children}
</OptionStyled>
)
}

Option.propTypes = {
children: PropTypes.node,
color: PropTypes.any,
startIcon: PropTypes.any,
}

export default Option

+ 13
- 0
src/components/Select/Option/Option.styled.js Datei anzeigen

@@ -0,0 +1,13 @@
import { Box, MenuItem } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../themes";

export const OptionStyled = styled(MenuItem)`
background-color: ${props => props.selected ? selectedTheme.primaryPurple : "white"} !important;
color: ${props => props.selected ? "white" : selectedTheme.selectOptionTextColor};
&:hover {
background-color: ${selectedTheme.primaryPurple} !important;
}
`
export const OptionIcon = styled(Box)`
`

+ 35
- 0
src/components/Select/Select.js Datei anzeigen

@@ -0,0 +1,35 @@
import React from "react";
import PropTypes from "prop-types";
import { SelectIcon, SelectStyled } from "./Select.styled";
import { ReactComponent as Down } from "../../assets/images/svg/down-arrow.svg";

// import {Select as SelectMUI} from "@mui/material";

const Select = (props) => {
console.log(props);
return (
<SelectStyled
defaultValue={props.defaultValue}
fullWidth={props.fullwidth}
IconComponent={(iconProps) => (
<SelectIcon {...iconProps}>
<Down />
</SelectIcon>
)}
>
{props.children}
</SelectStyled>
);
};

Select.propTypes = {
children: PropTypes.node,
width: PropTypes.string,
fullwidth: PropTypes.bool,
defaultValue: PropTypes.number,
};
Select.defaultProps = {
fullwidth: true,
};

export default Select;

+ 12
- 0
src/components/Select/Select.styled.js Datei anzeigen

@@ -0,0 +1,12 @@
import { Box, Select } from "@mui/material";
import styled from "styled-components";

export const SelectStyled = styled(Select)`
width: ${props => props.width};
height: ${props => props.height};
`
export const SelectIcon = styled(Box)`
position: relative;
top: 0px;
left: -15px;
`

+ 1
- 0
src/components/TextFields/TextField/TextField.js Datei anzeigen

@@ -42,6 +42,7 @@ export const TextField = (props) => {
sx={props.style}
label={props.showAnimation ? props.placeholder : ""}
italicplaceholder={props.italicPlaceholder && isFieldEmpty}
ref={textInputRef}
focused={props.focused}

+ 10
- 4
src/components/TextFields/TextField/TextField.styled.js Datei anzeigen

@@ -20,6 +20,7 @@ export const TextFieldStyled = styled(TextField)`
padding: 0;
height: ${(props) => props.height};
box-sizing: border-box;
overflow-y: hidden;

& div {
padding-left: 2px;
@@ -28,16 +29,21 @@ export const TextFieldStyled = styled(TextField)`
`
padding: 10px 16px;
max-height: ${props.height};
overflow-y: auto;
& fieldset {
border: 1px solid rgba(0, 0, 0, 0.23);
border-radius: 4px;
position: relative;
height: 100%;
& textarea {
height: 100% !important;
width: 100% ;
overflow: auto;
font-size: 16px;
}
`}
}
& div input {
height: ${(props) => props.height};
box-sizing: border-box;

font-size: ${(props) =>
props.textsize ? props.textsize : "16px"} !important;
font-family: ${(props) => (props.font ? props.font : "")};

+ 6
- 0
src/pages/ForgotPasswordPage/ForgotPassword.styled.js Datei anzeigen

@@ -7,6 +7,12 @@ export const ForgotPasswordPageContainer = styled(Container)`
display: flex;
flex-direction: column;
align-items: center;
@media (max-height: 900px) {
margin-top: 160px;
}
@media (max-height: 800px) {
margin-top: 120px;
}
`;
export const ForgotPasswordTitle = styled(Typography)`
font-family: "Open Sans";

+ 7
- 2
src/pages/ForgotPasswordPage/ForgotPasswordMailSent/MailSent.js Datei anzeigen

@@ -1,4 +1,4 @@
import React from "react";
import React, { useEffect, useState } from "react";
import PropTypes from "prop-types";
import {
MailSentContainer,
@@ -21,17 +21,22 @@ import { useDispatch } from "react-redux";
import { forgotPassword } from "../../../store/actions/user/userActions";

const MailSent = () => {
const [mail, setEmail] = useState("");
const { t } = useTranslation();
const history = useHistory();
const location = useLocation();
const dispatch = useDispatch();

useEffect(() => {
setEmail(location.state.email);
}, [])

const navigateLogin = () => {
history.replace(LOGIN_PAGE);
};

const handleResend = () => {
dispatch(forgotPassword(location.state.email))
dispatch(forgotPassword({email: mail}))
}

return (

+ 6
- 0
src/pages/ForgotPasswordPage/ForgotPasswordMailSent/MailSent.styled.js Datei anzeigen

@@ -7,6 +7,12 @@ export const MailSentContainer = styled(Container)`
display: flex;
flex-direction: column;
align-items: center;
@media (max-height: 900px) {
margin-top: 200px;
}
@media (max-height: 800px) {
margin-top: 150px;
}
`;
export const Title = styled(Typography)`
font-family: "Open Sans";

+ 3
- 5
src/pages/ForgotPasswordPage/ForgotPasswordPageMUI.js Datei anzeigen

@@ -35,16 +35,14 @@ const ForgotPasswordPage = () => {
pathname: FORGOT_PASSWORD_MAIL_SENT,
state: {email: formik.values.email}
});
}
const handleResponseError = () => {
setEmailNotFoundStatus(true);
}
// const handleResponseError = () => {
// setEmailNotFoundStatus(true);
// console.log("greska!");
// }

const handleSubmit = (values) => {
// validate email
dispatch(forgotPassword({email: values.email, handleResponseSuccess, handleResponseError: handleResponseSuccess}));
dispatch(forgotPassword({email: values.email, handleResponseSuccess, handleResponseError}));
};

const formik = useFormik({

+ 0
- 1
src/pages/HomePage/HomePageMUI.js Datei anzeigen

@@ -42,7 +42,6 @@ const HomePage = () => {
(item) => item.string === queryObject.subcategory.toString()
).id;
}
console.log("iz useeffect: ", { category, subcategory, cities });
dispatch(setFilters({ category, subcategory, cities }));
}, [history.location.search]);
const handleCl = () => {

+ 6
- 0
src/pages/LoginPage/Login.styled.js Datei anzeigen

@@ -7,6 +7,12 @@ export const LoginPageContainer = styled(Container)`
display: flex;
flex-direction: column;
align-items: center;
@media (max-height: 900px) {
margin-top: 110px;
}
@media (max-height: 800px) {
margin-top: 70px;
}
`;
export const LoginTitle = styled(Typography)`
font-family: "Open Sans";

+ 4
- 1
src/pages/RegisterPages/Register/FirstPart/FirstPartOfRegistration.js Datei anzeigen

@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react";
import PropTypes from "prop-types";
import {
ErrorMessage,
FormContainer,
RegisterDescription,
} from "./FirstPartOfRegistration.styled";
@@ -20,7 +21,6 @@ const FirstPartOfRegistration = (props) => {
const { t } = useTranslation();

useEffect(() => {
console.log(props.error);
if (props.error.length > 0) {
setEmailTakenStatus(true);
}
@@ -90,6 +90,8 @@ const FirstPartOfRegistration = (props) => {
}}
/>

{props.error && (<ErrorMessage>{props.errorMessage}</ErrorMessage>)}

<PrimaryButton
type="submit"
variant="contained"
@@ -113,6 +115,7 @@ FirstPartOfRegistration.propTypes = {
children: PropTypes.node,
handleSubmit: PropTypes.func,
error: PropTypes.string,
errorMessage: PropTypes.string,
};

export default FirstPartOfRegistration;

+ 8
- 0
src/pages/RegisterPages/Register/FirstPart/FirstPartOfRegistration.styled.js Datei anzeigen

@@ -19,4 +19,12 @@ export const RegisterDescription = styled(Typography)`
margin-top: 31px;
margin-bottom: 2px;
letter-spacing: 0.02em;
`;
export const ErrorMessage = styled(Typography)`
color: red;
font-family: "Open Sans";
position: relative;
top: -7px;
font-size: 14px;
`

+ 11
- 2
src/pages/RegisterPages/Register/Register.js Datei anzeigen

@@ -29,6 +29,8 @@ const Register = () => {
const [currentStep, setCurrentStep] = useState(1);
const [informations, setInformations] = useState({});
const [mailError, setMailError] = useState("");
const [mailErrorMessage, setMailErrorMessage] = useState("");
const [PIBErrorMessage, setPIBErrorMessage] = useState("");
const [PIBError, setPIBError] = useState("");

const handleResponseSuccess = () => {
@@ -36,17 +38,22 @@ const Register = () => {
};

const handleResponseError = (error) => {
console.log("handleResponse: ", error);
if (error.type === "mail") {
const { mail } = informations;
setInformations({});
setCurrentStep(1);
setMailError(mail);
if (error.error.response.data.toString() === 'User with email already exists') {
setMailErrorMessage("Vec postoji korisnik sa zadatim mail-om!");
} else {
setMailErrorMessage("Nevalidan format mail-a!")
}
} else {
const { mail, password, PIB } = informations;
setInformations({ mail, password });
setCurrentStep(2);
setPIBError(PIB.toString());
setPIBErrorMessage("PIB broj je zauzet!");
}
};

@@ -65,7 +72,7 @@ const Register = () => {
setInformations({ ...informations, ...values });
};
return (
<RegisterPageContainer>
<RegisterPageContainer currentStep={currentStep}>
<Logo />

<RegisterTitle component="h1" variant="h5">
@@ -84,12 +91,14 @@ const Register = () => {
<FirstPartOfRegistration
handleSubmit={handleSubmit}
error={mailError}
errorMessage={mailErrorMessage}
/>
)}
{currentStep === 2 && (
<SecondPartOfRegistration
handleSubmit={handleSubmit}
error={PIBError}
errorMessage={PIBErrorMessage}
/>
)}
{currentStep === 3 && (

+ 25
- 10
src/pages/RegisterPages/Register/Register.styled.js Datei anzeigen

@@ -9,19 +9,33 @@ export const RegisterPageContainer = styled(Container)`
align-items: center;
width: 335px;
padding: 0;
flex: 1;
position: relative;
@media (max-height: 900px) {
margin-top: 60px;
}
@media (max-height: 800px) {
margin-top: 30px;
flex: none;
height: 95vh;
${props => props.currentStep === 3 && `height: 105vh`};
${props => props.currentStep === 2 && `height: 100vh`};
}
`;
export const RegisterTitle = styled(Typography)`
font-family: "Open Sans";
width: 328px;
height: 33px;
text-align: center;
flex: 1;
font-style: normal;
font-weight: 400;
font-size: 24px;
line-height: 33px;
color: ${selectedTheme.primaryPurple};
margin-top: 34px;
@media (max-height: 800px) {
margin-top: 26px;
}
`;
export const RegisterDescription = styled(Typography)`
font-family: "Open Sans";
@@ -36,6 +50,10 @@ export const RegisterDescription = styled(Typography)`
text-align: center;
color: ${selectedTheme.primaryGrayText};
margin-bottom: 20px;
@media (max-height: 800px) {
margin-bottom: 14px;
margin-top: 6px;
}
`;
export const FormContainer = styled(Box)`
width: 335px;
@@ -52,6 +70,9 @@ export const LoginTextContainer = styled(Box)`
flex-direction: row;
margin-top: 36px;
justify-content: center;
@media (max-height: 800px) {
margin-top: 26px;
}
`
export const ProgressContainer = styled(Container)`
width: 100%;
@@ -64,6 +85,9 @@ export const Footer = styled(Box)`
width: 100%;
flex-direction: row;
justify-content: center;
@media (max-height: 800px) {
bottom: 10px;
}
`
export const FooterText = styled(Typography)`
font-family: "Open Sans";
@@ -75,12 +99,3 @@ export const FooterText = styled(Typography)`
padding: 0;
font-size: 12px;
`
export const RegisterDescriptionPart = styled(RegisterDescription)`
font-size: 12px;
width: 100%;
text-align: left;
line-height: 16px;
margin-top: 31px;
margin-bottom: 2px;
letter-spacing: 0.02em;
`

+ 4
- 0
src/pages/RegisterPages/Register/SecondPart/SecondPartOfRegistration.js Datei anzeigen

@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react";
import PropTypes from "prop-types";
import {
ErrorMessage,
FormContainer,
RegisterDescription,
} from "./SecondPartOfRegistration.styled";
@@ -64,6 +65,8 @@ const SecondPartOfRegistration = (props) => {
fullWidth={true}
/>

{props.error && (<ErrorMessage>{props.errorMessage}</ErrorMessage>)}

<PrimaryButton
type="submit"
variant="contained"
@@ -87,6 +90,7 @@ SecondPartOfRegistration.propTypes = {
children: PropTypes.node,
handleSubmit: PropTypes.func,
error: PropTypes.string,
errorMessage: PropTypes.string,
};

export default SecondPartOfRegistration;

+ 7
- 0
src/pages/RegisterPages/Register/SecondPart/SecondPartOfRegistration.styled.js Datei anzeigen

@@ -21,3 +21,10 @@ export const RegisterDescription = styled(Typography)`
margin-bottom: 2px;
letter-spacing: 0.02em;
`;
export const ErrorMessage = styled(Typography)`
color: red;
font-family: "Open Sans";
position: relative;
top: -7px;
font-size: 14px;
`

+ 3
- 0
src/pages/RegisterPages/Register/ThirdPart/ThirdPartOfRegistration.styled.js Datei anzeigen

@@ -19,4 +19,7 @@ export const RegisterDescription = styled(Typography)`
margin-top: 31px;
margin-bottom: 2px;
letter-spacing: 0.02em;
@media (max-height: 800px) {
margin-top: 21px;
}
`;

+ 6
- 0
src/pages/ResetPasswordPage/ResetPasswordPage.styled.js Datei anzeigen

@@ -7,6 +7,12 @@ export const ResetPasswordPageContainer = styled(Container)`
display: flex;
flex-direction: column;
align-items: center;
@media (max-height: 900px) {
margin-top: 140px;
}
@media (max-height: 800px) {
margin-top: 70px;
}
`;
export const ResetPasswordTitle = styled(Typography)`
font-family: "Open Sans";

+ 5
- 3
src/request/forgotPasswordRequest.js Datei anzeigen

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

export const forgotPasswordRequest = (payload) =>
postRequest(apiEndpoints.accounts.forgotPassword, payload);
export const forgotPasswordRequest = (payload) => {
const encodedString = encodeURIComponent(payload);
return getRequest(`${apiEndpoints.accounts.forgotPassword}` + '/' + `${encodedString}`);
}

export const resetPasswordRequest = (payload) =>
postRequest(apiEndpoints.accounts.resetPassword, payload);

+ 2
- 1
src/store/actions/offers/offersActionConstants.js Datei anzeigen

@@ -7,4 +7,5 @@ export const OFFERS_SUCCESS = createSuccessType(OFFERS_SCOPE);
export const OFFERS_ERROR = createErrorType(OFFERS_SCOPE);
export const OFFERS_CLEAR = createClearType(OFFERS_SCOPE);

export const OFFERS_SET = "OFFERS_SET";
export const OFFERS_SET = "OFFERS_SET";
export const OFFERS_ADD = "OFFERS_ADD";

+ 5
- 1
src/store/actions/offers/offersActions.js Datei anzeigen

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

export const fetchOffers = (payload) => ({
type: OFFERS_FETCH,
@@ -18,4 +18,8 @@ export const clearOffers = () => ({
export const setOffers = (payload) => ({
type: OFFERS_SET,
payload,
})
export const addOffers = (payload) => ({
type: OFFERS_ADD,
payload
})

+ 8
- 0
src/store/reducers/offers/offersReducer.js Datei anzeigen

@@ -1,4 +1,5 @@
import {
OFFERS_ADD,
OFFERS_CLEAR,
OFFERS_ERROR,
OFFERS_SET,
@@ -15,6 +16,7 @@ export default createReducer(
[OFFERS_ERROR]: fetchOffersError,
[OFFERS_CLEAR]: clearOffers,
[OFFERS_SET]: setOffers,
[OFFERS_ADD]: addOffers,
},
initialState
);
@@ -32,3 +34,9 @@ function setOffers(state, action) {
offers: action.payload,
};
}
function addOffers(state, action) {
return {
...state,
offers: [...state.offers, ...action.payload]
}
}

+ 2
- 3
src/store/saga/forgotPasswordSaga.js Datei anzeigen

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

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

+ 0
- 2
src/store/saga/loginSaga.js Datei anzeigen

@@ -43,13 +43,11 @@ import {
function* fetchUser({ payload }) {
try {
const { data } = yield call(attemptLogin, payload);
console.log(data);
if (data.tokens) {
const token = data.tokens[data.tokens.length - 1].token.toString();

// cemu sluzi?
const user = jwt.decode(token);
console.log("userJWT: ", user);

yield call(authScopeSetHelper, JWT_TOKEN, token);
// yield call(authScopeSetHelper, JWT_REFRESH_TOKEN, data.JwtRefreshToken);

+ 4
- 2
src/store/saga/offersSaga.js Datei anzeigen

@@ -1,11 +1,13 @@
import { all, takeLatest, call } from "@redux-saga/core/effects";
import { all, takeLatest, call, put } from "@redux-saga/core/effects";
import { attemptFetchOffers } from "../../request/offersRequest";
import { OFFERS_FETCH } from "../actions/offers/offersActionConstants";
import { setOffers } from "../actions/offers/offersActions";

function* fetchOffers() {
try {
const data = yield call(attemptFetchOffers);
console.log(data);
console.log(data.data.items)
yield put(setOffers(data.data.items))
} catch (e) {
console.log(e);
}

+ 30
- 29
src/store/saga/registerSaga.js Datei anzeigen

@@ -2,46 +2,47 @@ import { all, takeLatest, call } from "@redux-saga/core/effects";
import { attemptRegister } from "../../request/registerRequest";
import { REGISTER_USER_FETCH } from "../actions/register/registerActionConstants";

function* fetchRegisterUser({payload}) {
function* fetchRegisterUser({ payload }) {
try {
console.log("payload: ", payload)

const requestData = {
email: payload.values.mail.toString(),
password: payload.values.password.toString(),
roles: [
{
role: "User"
}
],
company: {
name: payload.values.nameOfFirm.toString(),
PIB: payload.values.PIB.toString(),
contacts: {
telephone: payload.values.phoneNumber.toString(),
location: payload.values.location.toString(),
web: payload.values.website.toString()
}
}
}
console.log(requestData);
const data = yield call(attemptRegister, requestData);
console.log(data);
email: payload.values.mail.toString(),
password: payload.values.password.toString(),
roles: [
{
role: "User",
},
],
company: {
name: payload.values.nameOfFirm.toString(),
PIB: payload.values.PIB.toString(),
contacts: {
telephone: payload.values.phoneNumber.toString(),
location: payload.values.location.toString(),
web: payload.values.website.toString(),
},
},
};
yield call(attemptRegister, requestData);
if (payload.handleResponseSuccess) {
yield call(payload.handleResponseSuccess);
}
} catch (e) {
console.log(e.response.data);
let type;
if (e.response?.data?.toString() === 'User with email already exists') {
type = 'mail'
} else if (e.response?.data?.toString() === 'Company with PIB already exists') {
type = "PIB"
if (
e.response?.data?.toString() === "User with email already exists" ||
e.response?.data?.toString() === '"email" must be a valid email'
) {
type = "mail";
} else if (
e.response?.data?.toString() === "Company with PIB already exists"
) {
type = "PIB";
}
const error = {
error: e,
type
}
type,
};
if (payload.handleResponseError) {
yield call(payload.handleResponseError, error);
}

+ 1
- 0
src/themes/primaryTheme/primaryThemeColors.js Datei anzeigen

@@ -11,6 +11,7 @@ export const primaryThemeColors = {
borderSponsoredColor: "#E5D0FF",
backgroundSponsoredColor: "#F5EDFF",
offerBackgroundColor: "#F5F5F5",
selectOptionTextColor: "#1D1D1D",
primaryDarkText: "#505050",
iconStrokeColor: "#8C8C8C"
}

Laden…
Abbrechen
Speichern