Procházet zdrojové kódy

Added icons, added Create offer page, added and edited reducers for login/register/forgot password, added Reset password page, Connected some features to backend

pull/2/head
Djordje Mitrovic před 3 roky
rodič
revize
75f276da0b
61 změnil soubory, kde provedl 1165 přidání a 195 odebrání
  1. 6
    0
      src/AppRoutes.js
  2. 1
    1
      src/components/Buttons/IconButton/IconButton.js
  3. 2
    2
      src/components/Buttons/IconButton/IconButton.styled.js
  4. 183
    0
      src/components/Cards/CreateOfferCard/CreateOffer.js
  5. 56
    0
      src/components/Cards/CreateOfferCard/CreateOffer.styled.js
  6. 9
    3
      src/components/Cards/FilterCard/FilterCard.js
  7. 7
    3
      src/components/Cards/FilterCard/FilterCard.styled.js
  8. 6
    2
      src/components/Cards/FilterCard/FilterDropdown/Checkbox/FilterCheckboxDropdown.js
  9. 7
    6
      src/components/Cards/OfferCard/OfferCard.js
  10. 45
    29
      src/components/Cards/OfferCard/OfferCard.styled.js
  11. 1
    1
      src/components/CheckBox/CheckBox.js
  12. 1
    1
      src/components/CheckBox/CheckBox.styled.js
  13. 1
    1
      src/components/Dropdown/DropdownList/DropdownList.js
  14. 1
    1
      src/components/Dropdown/DropdownList/DropdownList.styled.js
  15. 1
    1
      src/components/MUI/DialogComponent.js
  16. 53
    10
      src/components/MarketPlace/Header/Header.js
  17. 2
    1
      src/components/MarketPlace/MarketPlace.js
  18. 14
    17
      src/components/MarketPlace/Offers/Offers.js
  19. 2
    2
      src/components/Radio/Button/RadioButton.js
  20. 2
    2
      src/components/Radio/Button/RadioButton.styled.js
  21. 5
    1
      src/components/TextFields/TextField/TextField.js
  22. 20
    6
      src/components/TextFields/TextField/TextField.styled.js
  23. 3
    1
      src/constants/pages.js
  24. 3
    0
      src/constants/sessionStorage.js
  25. 7
    0
      src/i18n/resources/rs.js
  26. 2
    2
      src/layouts/GridLayout/GridLayout.js
  27. 1
    1
      src/layouts/GridLayout/GridLayout.styled.js
  28. 2
    2
      src/layouts/MainLayout/MainLayout.js
  29. 1
    0
      src/layouts/MainLayout/MainLayout.styled.js
  30. 2
    2
      src/layouts/ProfileLayout/ProfileLayout.js
  31. 26
    0
      src/pages/CreateOffer/CreateOffer.js
  32. 56
    0
      src/pages/CreateOffer/CreateOffer.styled.js
  33. 10
    2
      src/pages/ForgotPasswordPage/ForgotPasswordMailSent/MailSent.js
  34. 21
    4
      src/pages/ForgotPasswordPage/ForgotPasswordPageMUI.js
  35. 1
    0
      src/pages/HomePage/HomePage.styled.js
  36. 47
    11
      src/pages/HomePage/HomePageMUI.js
  37. 13
    13
      src/pages/LoginPage/LoginPageMUI.js
  38. 17
    7
      src/pages/RegisterPages/Register/FirstPart/FirstPartOfRegistration.js
  39. 12
    5
      src/pages/RegisterPages/Register/Register.js
  40. 14
    4
      src/pages/RegisterPages/Register/SecondPart/SecondPartOfRegistration.js
  41. 13
    3
      src/pages/RegisterPages/Register/ThirdPart/ThirdPartOfRegistration.js
  42. 150
    0
      src/pages/ResetPasswordPage/ResetPasswordPage.js
  43. 61
    0
      src/pages/ResetPasswordPage/ResetPasswordPage.styled.js
  44. 5
    3
      src/request/apiEndpoints.js
  45. 8
    0
      src/request/forgotPasswordRequest.js
  46. 3
    2
      src/request/index.js
  47. 4
    8
      src/request/loginRequest.js
  48. 6
    0
      src/request/registerRequest.js
  49. 8
    0
      src/store/actions/filters/filtersActionConstants.js
  50. 21
    0
      src/store/actions/filters/filtersActions.js
  51. 4
    0
      src/store/actions/register/registerActionConstants.js
  52. 6
    0
      src/store/actions/register/registerActions.js
  53. 3
    1
      src/store/actions/user/userActionConstants.js
  54. 10
    0
      src/store/actions/user/userActions.js
  55. 68
    0
      src/store/reducers/filters/filtersReducer.js
  56. 3
    1
      src/store/reducers/index.js
  57. 43
    0
      src/store/saga/forgotPasswordSaga.js
  58. 4
    0
      src/store/saga/index.js
  59. 41
    33
      src/store/saga/loginSaga.js
  60. 32
    0
      src/store/saga/registerSaga.js
  61. 9
    0
      src/store/selectors/filtersSelectors.js

+ 6
- 0
src/AppRoutes.js Zobrazit soubor

@@ -11,6 +11,8 @@ import {
FORGOT_PASSWORD_MAIL_SENT,
REGISTER_PAGE,
REGISTER_SUCCESSFUL_PAGE,
RESET_PASSWORD_PAGE,
CREATE_OFFER_PAGE,
} from './constants/pages';
import LoginPage from './pages/LoginPage/LoginPageMUI';
import HomePage from './pages/HomePage/HomePageMUI';
@@ -21,6 +23,8 @@ import PrivateRoute from './components/Router/PrivateRoute';
import MailSent from './pages/ForgotPasswordPage/ForgotPasswordMailSent/MailSent';
import Register from './pages/RegisterPages/Register/Register';
import RegisterSuccessful from './pages/RegisterPages/RegisterSuccessful.js/RegisterSuccessful';
import ResetPasswordPage from './pages/ResetPasswordPage/ResetPasswordPage';
import CreateOffer from './pages/CreateOffer/CreateOffer';


const AppRoutes = () => {
@@ -34,6 +38,8 @@ const AppRoutes = () => {
<Route path={ERROR_PAGE} component={ErrorPage} />
<Route path={FORGOT_PASSWORD_MAIL_SENT} component={MailSent} />
<Route path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} />
<Route path={RESET_PASSWORD_PAGE} component={ResetPasswordPage}/>
<Route path={CREATE_OFFER_PAGE} component={CreateOffer}/>
<PrivateRoute
exact

+ 1
- 1
src/components/Buttons/IconButton/IconButton.js Zobrazit soubor

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

export const IconButton = (props) => {
return <IconButtonContainer style={props.containerStyle} className={props.className}>
<IconButtonStyled onClick={props.onClick} sx={props.style} iconColor={props.iconColor}>
<IconButtonStyled onClick={props.onClick} sx={props.style} iconcolor={props.iconColor}>
{props.children}
</IconButtonStyled>
</IconButtonContainer>

+ 2
- 2
src/components/Buttons/IconButton/IconButton.styled.js Zobrazit soubor

@@ -8,9 +8,9 @@ export const IconButtonStyled = styled(IconButton)`
height: ${props => props.height ? props.height : "36px"};
width: ${props => props.width ? props.width : "36px"};
padding: 0;
${props => props.iconColor && `
${props => props.iconcolor && `
& svg path {
stroke: ${props.iconColor};
stroke: ${props.iconcolor};
}
`}
`

+ 183
- 0
src/components/Cards/CreateOfferCard/CreateOffer.js Zobrazit soubor

@@ -0,0 +1,183 @@
/* eslint-disable */
import React, { useEffect, useState } from "react";
import PropTypes from "prop-types";
import { useFormik } from "formik";
import { useDispatch, useSelector } from "react-redux";
import { NavLink } from "react-router-dom";
import * as Yup from "yup";
import { useTranslation } from "react-i18next";
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";
import Backdrop from "../../MUI/BackdropComponent";
import { selectIsLoadingByActionType } from "../../../store/selectors/loadingSelectors";
import { LOGIN_USER_LOADING } from "../../../store/actions/login/loginActionConstants";
import { TextField } from "../../TextFields/TextField/TextField";
import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton";
import { IconButton } from "../../Buttons/IconButton/IconButton";
import Link from "../../Link/Link";
import {
CreateOfferContainer,
CreateOfferTitle,
CreateOfferFormContainer,
RegisterAltText,
RegisterTextContainer,
} from "./CreateOffer.styled";
import selectedTheme from "../../../themes";
import StepProgress from "../../StepProgress/StepProgress";

const CreateOffer = ({ history }) => {
const dispatch = useDispatch();
const { t } = useTranslation();

const [showPassword, setShowPassword] = useState(false);
const handleClickShowPassword = () => setShowPassword(!showPassword);
const handleMouseDownPassword = () => setShowPassword(!showPassword);

// When user refreshes page
// useEffect(() => {
// function redirectClient() {
// if (!tokens.RefreshToken && !tokens.JwtToken) {
// return;
// }
// }

// redirectClient();
// }, [history, tokens]);

const isLoading = useSelector(
selectIsLoadingByActionType(LOGIN_USER_LOADING)
);

const handleApiResponseSuccess = (status) => {
history.push({
pathname: HOME_PAGE,
state: {
from: history.location.pathname,
},
});
};

const handleSubmit = (values) => {
const { username: email, password: password } = values;
dispatch(
fetchUser({
email,
password,
handleApiResponseSuccess,
})
);
};

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>
</CreateOfferContainer>
);
};

CreateOffer.propTypes = {
history: PropTypes.shape({
replace: PropTypes.func,
push: PropTypes.func,
location: PropTypes.shape({
pathname: PropTypes.string,
}),
}),
};
export default CreateOffer;

+ 56
- 0
src/components/Cards/CreateOfferCard/CreateOffer.styled.js Zobrazit soubor

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

export const CreateOfferContainer = styled(Container)`
margin-top: 0px;
display: flex;
width: 380px;
flex-direction: column;
align-items: center;
`;
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;
`;
export const RegisterAltText = styled(Typography)`
font-family: "Poppins";
color: ${selectedTheme.primaryText};
font-size: 14px;
padding-right: 6px;
line-height: 14px;
`
export const RegisterTextContainer = styled(Box)`
display: flex;
flex-direction: row;
margin-top: 36px;
justify-content: center;
`

+ 9
- 3
src/components/Cards/FilterCard/FilterCard.js Zobrazit soubor

@@ -50,9 +50,15 @@ const FilterCard = () => {
}
if (queryObject.city) {
let filters = [];
queryObject.city.forEach((item) => {
filters.push(Mockupdata[0].find((p) => p.string === item).id);
});
if (Array.isArray(queryObject.city)) {
queryObject.city.forEach((item) => {
filters.push(Mockupdata[0].find((p) => p.string === item).id);
});
} else {
filters.push(
Mockupdata[0].find((p) => p.string === queryObject.city).id
);
}
setAppliedFilters([...filters]);
}
}, []);

+ 7
- 3
src/components/Cards/FilterCard/FilterCard.styled.js Zobrazit soubor

@@ -5,11 +5,11 @@ import selectedTheme from "../../../themes";
export const FilterCardContainer = styled(Box)`
border-radius: 0;
border-top-right-radius: 4px;
height: 100%;
height: calc(100% - 90px);
padding: 36px;
background-color: white;
width: 100%;
position: "fixed";
width: calc(100% / 12 * 2.4);
position: fixed;
left: 0;
display: flex;
flex-direction: column;
@@ -22,6 +22,7 @@ export const Title = styled(Typography)`
font-weight: 900;
font-family: "Open Sans";
padding-left: 15px;
padding-top: 4px;
color: ${selectedTheme.primaryText};
position: relative;
top: -12px;
@@ -46,5 +47,8 @@ export const Footer = styled(Box)`
}
`;
export const ContentContainer = styled(Box)`
overflow-y: auto;
margin-bottom: 10px;
${() => window.scrollbars.visible && `padding-right: 15px;`}
`


+ 6
- 2
src/components/Cards/FilterCard/FilterDropdown/Checkbox/FilterCheckboxDropdown.js Zobrazit soubor

@@ -24,6 +24,9 @@ const FilterCheckboxDropdown = (props) => {
useEffect(() => {
setDataToShow([...data]);
}, []);
useEffect(() => {
console.log("props.filters: ", props.filters);
}, [props.filters])

useEffect(() => {
if (toSearch.length > 0) {
@@ -34,6 +37,7 @@ const FilterCheckboxDropdown = (props) => {
);
} else {
setDataToShow([...data]);
}
}, [toSearch]);

@@ -41,7 +45,7 @@ const FilterCheckboxDropdown = (props) => {
if (props.oneValueAllowed) {
props.setItemsSelected[item.id];
} else {
if (props.filters.find((p) => p.id === item.id)) {
if (props.filters.includes(item.id)) {
props.setItemsSelected((itemsSelected) => [
...itemsSelected.filter((p) => p !== item.id),
]);
@@ -117,7 +121,7 @@ const FilterCheckboxDropdown = (props) => {
leftText={item.string}
rightText={item.numberOfProducts}
value={item.id}
checked={props.filters.includes(item.id, 0)}
checked={props.filters.includes(item.id)}
onChange={() => handleChange(item)}
fullWidth
/>

+ 7
- 6
src/components/Cards/OfferCard/OfferCard.js Zobrazit soubor

@@ -4,6 +4,7 @@ import {
CheckButton,
DetailIcon,
DetailText,
Line,
MessageIcon,
OfferAuthor,
OfferAuthorName,
@@ -28,7 +29,7 @@ import selectedTheme from "../../../themes";

const OfferCard = (props) => {
return (
<OfferCardContainer sponsored={props.sponsored} halfWidth={props.halfWidth}>
<OfferCardContainer sponsored={props.sponsored ? 1 : 0} halfwidth={props.halfwidth ? 1 : 0}>
<OfferImage>{props.image}</OfferImage>
<OfferInfo>
<OfferTitle>{props.title}</OfferTitle>
@@ -43,7 +44,6 @@ const OfferCard = (props) => {
</DetailIcon>
<DetailText>{props.category}</DetailText>
</OfferCategory>

<OfferPackage>
<DetailIcon color="black" component="span" size="16px">
<Quantity width={"12px"} height={"12px"} />
@@ -58,8 +58,9 @@ const OfferCard = (props) => {
</OfferViews>
</OfferDetails>
</OfferInfo>
{!props.halfWidth ? (
{!props.halfwidth ? (
<React.Fragment>
<Line/>
<OfferDescription>
<OfferDescriptionTitle>Opis:</OfferDescriptionTitle>
<OfferDescriptionText>{props.description}</OfferDescriptionText>
@@ -107,12 +108,12 @@ OfferCard.propTypes = {
quantity: PropTypes.number,
package: PropTypes.string,
numberOfViews: PropTypes.number,
halfWidth: PropTypes.bool,
halfwidth: PropTypes.bool,
sponsored: PropTypes.bool,
};
OfferCard.defaultProps = {
halfWidth: false,
sponsored: false,
halfwidth: false,
sponsored: true,
};

export default OfferCard;

+ 45
- 29
src/components/Cards/OfferCard/OfferCard.styled.js Zobrazit soubor

@@ -8,12 +8,15 @@ import { Icon } from "../../Icon/Icon";
export const OfferCardContainer = styled(Container)`
display: flex;
flex-direction: row;
width: ${props => !props.halfWidth ? "100%" : "49%"};
width: ${(props) => (!props.halfwidth ? "100%" : "49%")};
box-sizing: border-box;
margin: 10px 0;
background-color: ${props => props.sponsored ? selectedTheme.backgroundSponsoredColor : "white"};
border: 1px solid ${selectedTheme.borderColor};
background-color: ${(props) =>
props.sponsored ? selectedTheme.backgroundSponsoredColor : "white"};
border-radius: 4px;
${(props) =>
props.sponsored &&
`border: 1px solid ${selectedTheme.borderSponsoredColor};`}
padding: 16px;
max-width: 2000px;
height: 180px;
@@ -54,23 +57,24 @@ export const OfferLocation = styled(Typography)`
export const OfferDetails = styled(Box)`
display: flex;
flex-direction: row;
flex-wrap: ${props => !props.halfWidth ? "no-wrap" : "wrap"};
flex-wrap: ${(props) => (!props.halfwidth ? "no-wrap" : "wrap")};
justify-content: space-between;
`;
export const OfferCategory = styled(Typography)`
export const OfferCategory = styled(Box)`
font-family: "Open Sans";
color: ${selectedTheme.primaryText};
line-height: 16px;
font-size: 12px;
width: 33%;
`;
export const OfferPackage = styled(Typography)`
export const OfferPackage = styled(Box)`
font-family: "Open Sans";
color: ${selectedTheme.primaryText};
line-height: 16px;
font-size: 12px;
width: 34%;
`;
export const OfferViews = styled(Typography)`
export const OfferViews = styled(Box)`
font-family: "Open Sans";
color: ${selectedTheme.primaryText};
line-height: 16px;
@@ -82,17 +86,29 @@ export const OfferDescriptionTitle = styled(Box)`
font-size: 12px;
color: ${selectedTheme.primaryDarkText};
line-height: 16px;
padding-top: 20px;
`;
export const OfferDescriptionText = styled(Box)`
font-family: "Open Sans";
font-size: 16px;
color: ${selectedTheme.primaryDarkText};
line-height: 22px;
max-width: 250px;
max-width: calc(100% - 230px);
max-height: 120px;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 5;
-webkit-box-orient: vertical;
`;
export const OfferDescription = styled(Box)`
flex: 3;
margin: auto 0;
padding-left: 35px;
`;
export const Line = styled(Box)`
border-left: 1px solid rgba(0, 0, 0, 0.15);
height: 100px;
width: 0;
margin: auto 0;
`;
export const DetailIcon = styled(Icon)`
& svg {
@@ -111,24 +127,24 @@ export const DetailText = styled(Typography)`
left: 3px;
`;
export const CheckButton = styled(PrimaryButton)`
width: 180px;
height: 48px;
position: absolute;
bottom: 9px;
right: 9px;
&:hover button {
background-color: ${selectedTheme.primaryPurple} !important;
color: white !important;
}
`
width: 180px;
height: 48px;
position: absolute;
bottom: 9px;
right: 9px;
&:hover button {
background-color: ${selectedTheme.primaryPurple} !important;
color: white !important;
}
`;
export const MessageIcon = styled(IconButton)`
width: 40px;
height: 40px;
position: absolute;
top: 10px;
right: 10px;
background-color: ${selectedTheme.primaryIconBackgroundColor};
border-radius: 100%;
padding-top: 2px;
text-align: center;
`
width: 40px;
height: 40px;
position: absolute;
top: 10px;
right: 10px;
background-color: ${selectedTheme.primaryIconBackgroundColor};
border-radius: 100%;
padding-top: 2px;
text-align: center;
`;

+ 1
- 1
src/components/CheckBox/CheckBox.js Zobrazit soubor

@@ -23,7 +23,7 @@ export const CheckBox = (props) => {
className={props.className}
>
<FormControlLabelStyled
fullWidth={props.fullWidth}
fullwidth={props.fullWidth ? 1 : 0}
control={
<CheckBoxStyled
sx={props.checkBoxStyle}

+ 1
- 1
src/components/CheckBox/CheckBox.styled.js Zobrazit soubor

@@ -17,7 +17,7 @@ export const CheckBoxStyled = styled(Checkbox)`
`;
export const FormControlLabelStyled = styled(FormControlLabel)`
${(props) =>
props.fullWidth &&
props.fullwidth &&
`
width: 100%;
display: flex;

+ 1
- 1
src/components/Dropdown/DropdownList/DropdownList.js Zobrazit soubor

@@ -15,7 +15,7 @@ import PropTypes from "prop-types";
const DropdownList = (props) => {
const [listShown, setListShown] = useState(props.defaultOpen);
return (
<DropdownListContainer fullWidth={props.fullWidth}>
<DropdownListContainer fullwidth={props.fullWidth ? 1 : 0}>
<DropdownHeader>
{props.dropdownIcon && (
<DropdownIcon onClick={() => setListShown((prevState) => !prevState)}>

+ 1
- 1
src/components/Dropdown/DropdownList/DropdownList.styled.js Zobrazit soubor

@@ -5,7 +5,7 @@ import { IconButton } from "../../Buttons/IconButton/IconButton";

export const DropdownListContainer = styled(Box)`
width: ${(props) =>
props.fullWidth ? "100%" : props.width ? props.width : "250px"};
props.fullwidth ? "100%" : props.width ? props.width : "250px"};
padding: 8px 0;
`;


+ 1
- 1
src/components/MUI/DialogComponent.js Zobrazit soubor

@@ -49,7 +49,7 @@ DialogComponent.propTypes = {
open: PropTypes.bool.isRequired,
content: PropTypes.any,
onClose: PropTypes.func.isRequired,
maxWidth: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
maxWidth: PropTypes.any,
fullWidth: PropTypes.bool,
responsive: PropTypes.bool,
};

+ 53
- 10
src/components/MarketPlace/Header/Header.js Zobrazit soubor

@@ -1,4 +1,4 @@
import React from "react";
import React, { useEffect, useState } from "react";
import PropTypes from "prop-types";
import {
HeaderButton,
@@ -14,6 +14,9 @@ import { ReactComponent as GridLine } from "../../../assets/images/svg/offer-gri
import { ReactComponent as Down } from "../../../assets/images/svg/down-arrow.svg";
import { MenuItem } from "@mui/material";
import selectedTheme from "../../../themes";
import { useSelector } from "react-redux";
import { selectFilters } from "../../../store/selectors/filtersSelectors";
import Mockupdata from "../../Cards/FilterCard/Mockupdata";

const DownArrow = (props) => (
<IconStyled {...props}>
@@ -37,19 +40,57 @@ const MockupdataForSelect = [
];

const Header = (props) => {
const category = "Gradjevinski materijal";
const city = "Nis";
const locationString = category + " | " + city;
const [categoryString, setCategoryString] = useState("");
const [filtersString, setFiltersString] = useState("");
const { category, cities } = useSelector(selectFilters);

useEffect(() => {
let categorystring = "";
if (category) {
categorystring = Mockupdata[1].find(
(item) => item.id === category
).string;
} else {
categorystring = "Sve kategorije";
}
let filtersstring = " | ";
if (cities) {
cities.forEach((item) => {
filtersstring = filtersstring.concat(
Mockupdata[0].find((p) => p.id === item).string + ", "
);
});
filtersstring = filtersstring.substring(0, filtersstring.length - 2);
}
console.log("categorysstring: ", categorystring);
console.log(filtersstring);
setCategoryString(categorystring);
setFiltersString(filtersstring);
}, [category, cities]);
return (
<HeaderContainer>
<HeaderLocation>{locationString}</HeaderLocation>
<HeaderLocation>{categoryString + filtersString} </HeaderLocation>
<HeaderOptions>
<HeaderButtons>
<HeaderButton iconColor={props.isGrid ? selectedTheme.iconStrokeColor : selectedTheme.primaryPurple}>
<GridLine onClick={() => props.setIsGrid(false)}/>
<HeaderButton
iconColor={
props.isGrid
? selectedTheme.iconStrokeColor
: selectedTheme.primaryPurple
}
onClick={() => props.setIsGrid(false)}
>
<GridLine />
</HeaderButton>
<HeaderButton iconColor={props.isGrid ? selectedTheme.primaryPurple : selectedTheme.iconStrokeColor}>
<GridSquare onClick={() => props.setIsGrid(true)}/>
<HeaderButton
iconColor={
props.isGrid
? selectedTheme.primaryPurple
: selectedTheme.iconStrokeColor
}
onClick={() => props.setIsGrid(true)}
>
<GridSquare />
</HeaderButton>
</HeaderButtons>
<HeaderSelect defaultValue={0} IconComponent={DownArrow}>
@@ -72,9 +113,11 @@ Header.propTypes = {
children: PropTypes.node,
setIsGrid: PropTypes.func,
isGrid: PropTypes.bool,
filters: PropTypes.array,
category: PropTypes.string,
};
Header.defaultProps = {
isGrid: false,
}
};

export default Header;

+ 2
- 1
src/components/MarketPlace/MarketPlace.js Zobrazit soubor

@@ -6,9 +6,10 @@ import Offers from "./Offers/Offers";

const MarketPlace = () => {
const [isGrid, setIsGrid] = useState(false);

return (
<MarketPlaceContainer>
<Header isGrid={isGrid} setIsGrid={setIsGrid}/>
<Header isGrid={isGrid} setIsGrid={setIsGrid} />
<Offers isGrid={isGrid} />
</MarketPlaceContainer>
);

+ 14
- 17
src/components/MarketPlace/Offers/Offers.js Zobrazit soubor

@@ -1,25 +1,22 @@
import React from 'react'
import PropTypes from 'prop-types'
import { OffersContainer } from './Offers.styled'
import MockupdataOffers from '../MockupdataOffers'
import OfferCard from '../../Cards/OfferCard/OfferCard'
import React from "react";
import PropTypes from "prop-types";
import { OffersContainer } from "./Offers.styled";
import MockupdataOffers from "../MockupdataOffers";
import OfferCard from "../../Cards/OfferCard/OfferCard";

const Offers = (props) => {
return (
<OffersContainer>
{MockupdataOffers.map((item) => {
console.log(item);
return (
<OfferCard {...item} key={item.id} halfWidth={props.isGrid} />
)
})}
{MockupdataOffers.map((item) => {
return <OfferCard {...item} key={item.id} halfwidth={props.isGrid} />;
})}
</OffersContainer>
)
}
);
};

Offers.propTypes = {
children: PropTypes.node,
isGrid: PropTypes.bool,
}
children: PropTypes.node,
isGrid: PropTypes.bool,
};

export default Offers
export default Offers;

+ 2
- 2
src/components/Radio/Button/RadioButton.js Zobrazit soubor

@@ -11,10 +11,10 @@ import { Label } from "../../CheckBox/Label";

const RadioButton = (props) => {
return (
<RadioButtonContainer fullWidth={props.fullWidth}>
<RadioButtonContainer fullwidth={props.fullWidth ? 1 : 0}>
<FormControlLabelStyled
value={props.value}
fullWidth={props.fullWidth}
fullwidth={props.fullWidth ? 1 : 0}
control={
<RadioButtonStyled
icon={<RadioUnchecked />}

+ 2
- 2
src/components/Radio/Button/RadioButton.styled.js Zobrazit soubor

@@ -3,7 +3,7 @@ import styled from "styled-components";

export const RadioButtonContainer = styled(Box)`
${(props) =>
props.fullWidth &&
props.fullwidth &&
`
width: 100%;
display: flex;
@@ -19,7 +19,7 @@ export const RadioButtonStyled = styled(Radio)`
`;
export const FormControlLabelStyled = styled(FormControlLabel)`
${(props) =>
props.fullWidth &&
props.fullwidth &&
`
width: 100%;
display: flex;

+ 5
- 1
src/components/TextFields/TextField/TextField.js Zobrazit soubor

@@ -29,6 +29,8 @@ export const TextField = (props) => {
value={props.value}
onChange={props.onChange}
error={props.error}
multiline={props.multiline}
minRows={props.minRows}
// helperText={props.helperText}
autoFocus={props.autoFocus}
fullWidth={props.fullWidth}
@@ -39,7 +41,7 @@ export const TextField = (props) => {
sx={props.style}
label={props.showAnimation ? props.placeholder : ""}
italic={props.italicPlaceholder && isFieldEmpty}
italicplaceholder={props.italicPlaceholder && isFieldEmpty}
ref={textInputRef}
focused={props.focused}
>
@@ -78,6 +80,8 @@ TextField.propTypes = {
textsize: PropTypes.string,
font: PropTypes.string,
ref: PropTypes.any,
minRows: PropTypes.number,
multiline: PropTypes.bool,
focused: PropTypes.bool,
InputProps: PropTypes.shape({
startAdornment: PropTypes.node,

+ 20
- 6
src/components/TextFields/TextField/TextField.styled.js Zobrazit soubor

@@ -4,7 +4,7 @@ import selectedTheme from "../../../themes";

export const TextFieldContainer = styled(Box)`
width: 100%;
height: ${props => props.height};
height: ${(props) => props.height};
box-sizing: border-box;
margin: 16px 0;
padding-left: 0;
@@ -13,19 +13,33 @@ export const TextFieldContainer = styled(Box)`
export const TextFieldStyled = styled(TextField)`
background-color: ${selectedTheme.primaryBackgroundColor};
width: ${(props) => props.width};
font-style: ${(props) => (props.italic === true ? "italic" : "normal")};
font-style: ${(props) =>
props.italicplaceholder === true ? "italic" : "normal"};
padding-left: 0;
margin: 0;
padding: 0;
height: ${props => props.height};
height: ${(props) => props.height};
box-sizing: border-box;

& div {
padding-left: 2px;
${(props) =>
props.multiline &&
`
padding: 10px 16px;
max-height: ${props.height};
overflow-y: auto;
& fieldset {
border: 1px solid rgba(0, 0, 0, 0.23);
border-radius: 4px;
}
`}
}
& div input {
height: ${props => props.height};
height: ${(props) => props.height};
box-sizing: border-box;
font-size: ${props => props.textsize ? props.textsize : "16px"} !important;
font-family: ${props => props.font ? props.font : ""}
font-size: ${(props) =>
props.textsize ? props.textsize : "16px"} !important;
font-family: ${(props) => (props.font ? props.font : "")};
}
`;

+ 3
- 1
src/constants/pages.js Zobrazit soubor

@@ -6,4 +6,6 @@ export const ERROR_PAGE = '/error-page';
export const NOT_FOUND_PAGE = '/not-found';
export const FORGOT_PASSWORD_MAIL_SENT = '/forgot-password/mail-sent'
export const REGISTER_PAGE = "/register"
export const REGISTER_SUCCESSFUL_PAGE = "/register/success";
export const REGISTER_SUCCESSFUL_PAGE = "/register/success";
export const RESET_PASSWORD_PAGE = "/reset-password"
export const CREATE_OFFER_PAGE = "/create-offer"

+ 3
- 0
src/constants/sessionStorage.js Zobrazit soubor

@@ -0,0 +1,3 @@
export const SESSION_STORAGE_SCOPE = "AUTH";
export const IMPERSONATE_USER_UID = "IMPERSONATE_USER_UID";
export const REGISTRATION_USER_UID = "REGISTRATION_USER_UID";

+ 7
- 0
src/i18n/resources/rs.js Zobrazit soubor

@@ -103,6 +103,13 @@ export default {
label: 'Obnovite lozinku',
},
},
resetPassword: {
title: "Unesite novu lozinku",
description: "Poslali ste zahtev za promenu lozinke, molimo Vas da unesete novu željenu lozinku",
passwordLabel: "Nova Lozinka",
passwordConfirmLabel: "Potvrdite Lozinku",
buttonText: "Postavi lozinku"
},
filters: {
title: "Filteri",
cancel: "Poništi filtere",

+ 2
- 2
src/layouts/GridLayout/GridLayout.js Zobrazit soubor

@@ -5,9 +5,9 @@ import { Grid } from "@mui/material";

const GridLayout = (props) => {
return (
<GridLayoutContainer maxWidth={true}>
<GridLayoutContainer>
{props.children}
<Grid container lg={12} maxHeight="lg">
<Grid container maxHeight="lg">
<LeftCard item xs={2} lg={2.5} xl={2.4} md={3}>
{props.leftCard}
</LeftCard>

+ 1
- 1
src/layouts/GridLayout/GridLayout.styled.js Zobrazit soubor

@@ -1,7 +1,7 @@
import { Box, Container, Grid } from "@mui/material";
import styled from "styled-components";

export const ProfileLayoutContainer = styled(Container)`
export const GridLayoutContainer = styled(Container)`
padding-left: 0;
padding-right: 0;
margin: 0;

+ 2
- 2
src/layouts/MainLayout/MainLayout.js Zobrazit soubor

@@ -5,9 +5,9 @@ import { Grid } from "@mui/material";

const MainLayout = (props) => {
return (
<MainLayoutContainer maxWidth={true}>
<MainLayoutContainer>
{props.children}
<Grid container lg={12} maxHeight="lg">
<Grid container maxHeight="xl">
<LeftCard item xs={2} lg={3} xl={2.4} md={4} >
{props.leftCard}
</LeftCard>

+ 1
- 0
src/layouts/MainLayout/MainLayout.styled.js Zobrazit soubor

@@ -6,6 +6,7 @@ export const MainLayoutContainer = styled(Container)`
padding-right: 0;
margin: 0;
width: 100%;
max-width: none;
display: flex;
flex: 1;
height: 100%;

+ 2
- 2
src/layouts/ProfileLayout/ProfileLayout.js Zobrazit soubor

@@ -5,9 +5,9 @@ import { Grid } from "@mui/material";

const ProfileLayout = (props) => {
return (
<ProfileLayoutContainer maxWidth={true}>
<ProfileLayoutContainer>
{props.children}
<Grid container lg={12} maxHeight="lg">
<Grid container maxHeight="xl">
<LeftCard item xs={2} lg={2.5} xl={2.4} md={3}>
{props.leftCard}
</LeftCard>

+ 26
- 0
src/pages/CreateOffer/CreateOffer.js Zobrazit soubor

@@ -0,0 +1,26 @@
/* eslint-disable */
import React, { useEffect, useState } from "react";
import PropTypes from "prop-types";
import {
CreateOfferContainer,
} from "./CreateOffer.styled";
import CreateOffer from "../../components/Cards/CreateOfferCard/CreateOffer";

const CreateOfferPage = ({ history }) => {
return (
<CreateOfferContainer>
<CreateOffer/>
</CreateOfferContainer>
);
};

CreateOfferPage.propTypes = {
history: PropTypes.shape({
replace: PropTypes.func,
push: PropTypes.func,
location: PropTypes.shape({
pathname: PropTypes.string,
}),
}),
};
export default CreateOfferPage;

+ 56
- 0
src/pages/CreateOffer/CreateOffer.styled.js Zobrazit soubor

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

export const CreateOfferContainer = styled(Container)`
margin-top: 0px;
display: flex;
width: 380px;
flex-direction: column;
align-items: center;
`;
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: 216px;
`;
export const RegisterAltText = styled(Typography)`
font-family: "Poppins";
color: ${selectedTheme.primaryText};
font-size: 14px;
padding-right: 6px;
line-height: 14px;
`
export const RegisterTextContainer = styled(Box)`
display: flex;
flex-direction: row;
margin-top: 36px;
justify-content: center;
`

+ 10
- 2
src/pages/ForgotPasswordPage/ForgotPasswordMailSent/MailSent.js Zobrazit soubor

@@ -12,20 +12,28 @@ import {
} from "./MailSent.styled";
import { ReactComponent as MailSentImage } from "../../../assets/images/svg/mail-sent.svg";
import { PrimaryButton } from "../../../components/Buttons/PrimaryButton/PrimaryButton";
import { NavLink, useHistory } from "react-router-dom";
import { NavLink, useHistory, useLocation } from "react-router-dom";
import Link from "../../../components/Link/Link";
import { Trans, useTranslation } from "react-i18next";
import { LOGIN_PAGE } from "../../../constants/pages";
import selectedTheme from "../../../themes";
import { useDispatch } from "react-redux";
import { forgotPassword } from "../../../store/actions/user/userActions";

const MailSent = () => {
const { t } = useTranslation();
const history = useHistory();
const location = useLocation();
const dispatch = useDispatch();

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

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

return (
<MailSentContainer>

@@ -59,7 +67,7 @@ const MailSent = () => {
{t("forgotPassword.notRecievedMail")}
</StandardText>

<Link to="#" component={NavLink} underline="hover" align="center" textsize="16px">
<Link to="#" component={NavLink} underline="hover" align="center" textsize="16px" onClick={handleResend}>
{t("common.sendAgain")}
</Link>


+ 21
- 4
src/pages/ForgotPasswordPage/ForgotPasswordPageMUI.js Zobrazit soubor

@@ -1,4 +1,4 @@
import React from "react";
import React, { useState } from "react";
import { useFormik } from "formik";
import { useTranslation } from "react-i18next";
import * as Yup from "yup";
@@ -15,6 +15,8 @@ import { PrimaryButton } from "../../components/Buttons/PrimaryButton/PrimaryBut
import { 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";

const forgotPasswordValidationSchema = Yup.object().shape({
email: Yup.string()
@@ -25,9 +27,24 @@ const forgotPasswordValidationSchema = Yup.object().shape({
const ForgotPasswordPage = () => {
const history = useHistory();
const { t } = useTranslation();
const dispatch = useDispatch();
const [emailNotFoundStatus, setEmailNotFoundStatus] = useState(false);

const handleSubmit = () => {
history.push(FORGOT_PASSWORD_MAIL_SENT);
const handleResponseSuccess = () => {
history.push({
pathname: FORGOT_PASSWORD_MAIL_SENT,
state: {email: formik.values.email}
});
setEmailNotFoundStatus(true);
}
// const handleResponseError = () => {
// setEmailNotFoundStatus(true);
// console.log("greska!");
// }

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

const formik = useFormik({
@@ -60,7 +77,7 @@ const ForgotPasswordPage = () => {
placeholder={t("common.labelEmail")}
margin="normal"
value={formik.values.email}
error={formik.touched.email && Boolean(formik.errors.email)}
error={(formik.touched.email && Boolean(formik.errors.email)) || emailNotFoundStatus}
helperText={formik.touched.email && formik.errors.email}
onChange={formik.handleChange}
autoFocus

+ 1
- 0
src/pages/HomePage/HomePage.styled.js Zobrazit soubor

@@ -6,6 +6,7 @@ export const HomePageContainer = styled(Container)`
margin: 0;
height: 100%;
width: 100%;
max-width: none;
flex: 1;
display: flex;
flex-direction: column;

+ 47
- 11
src/pages/HomePage/HomePageMUI.js Zobrazit soubor

@@ -1,23 +1,59 @@
import React from "react";
// import { Box } from "@mui/material";
import React, { useEffect } from "react";
import Navbar from "../../components/MUI/NavbarComponent";
//import Modals from '../../components/MUI/Examples/ModalsExample';
//import DataGrid from '../../components/MUI/Examples/DataGridExample';
//import PagingSortingFiltering from '../../components/MUI/Examples/PagingSortingFilteringExample';
//import PagingSortingFilteringServerSide from '../../components/MUI/Examples/PagingSortingFilteringExampleServerSide';
//import RandomDataProvider from '../../context/RandomDataContext';
// import { GridStyled } from "./HomePage.styled";
// import HomeListCard from "../../components/Cards/HomeListCard/HomeListCard";
import FilterCard from "../../components/Cards/FilterCard/FilterCard";
import { HomePageContainer } from "./HomePage.styled";
import MarketPlace from "../../components/MarketPlace/MarketPlace";
import MainLayout from "../../layouts/MainLayout/MainLayout";
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";

const HomePage = () => {
const dispatch = useDispatch();

const history = useHistory();
useEffect(() => {
const queryString = history.location.search.substring(1);
const queryObject = qs.parse(queryString);
let category = null;
if (queryObject.category) {
category = Mockupdata[1].find(
(item) => item.string === queryObject.category.toString()
).id;
}
let cities = [];
if (queryObject.city) {
if (Array.isArray(queryObject.city)) {
queryObject.city.forEach((item) => {
cities.push(Mockupdata[0].find((p) => p.string === item).id);
});
} else {
cities.push(
Mockupdata[0].find((p) => p.string === queryObject.city).id
);
}
}
let subcategory = null;
if (queryObject.subcategory) {
subcategory = Mockupdata[1].find(
(item) => item.string === queryObject.subcategory.toString()
).id;
}
console.log("iz useeffect: ", { category, subcategory, cities });
dispatch(setFilters({ category, subcategory, cities }));
}, [history.location.search]);
const handleCl = () => {
dispatch(logoutUser());
};
return (
<HomePageContainer maxWidth={true}>
<HomePageContainer>
<button onClick={handleCl}>Dugme</button>
<Navbar />
<MainLayout leftCard={<FilterCard />} content={<MarketPlace />}/>
<MainLayout leftCard={<FilterCard />} content={<MarketPlace />} />

{/* <Box sx={{ mt: 4, mx: 4 }}>
<GridStyled container justifyContent="space-between">
<GridStyled item xs={12} md={3}>

+ 13
- 13
src/pages/LoginPage/LoginPageMUI.js Zobrazit soubor

@@ -12,8 +12,8 @@ import {
} from "../../store/actions/login/loginActions";
import { selectLoginError } from "../../store/selectors/loginSelectors";
import { FORGOT_PASSWORD_PAGE, HOME_PAGE } from "../../constants/pages";
import { ReactComponent as VisibilityOn } from "../../assets/images/svg/eye.svg";
import { ReactComponent as VisibilityOff } from "../../assets/images/svg/eye-striked.svg";
import { ReactComponent as VisibilityOn } from "../../assets/images/svg/eye-striked.svg";
import { ReactComponent as VisibilityOff } from "../../assets/images/svg/eye.svg";
import Backdrop from "../../components/MUI/BackdropComponent";
import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors";
import { LOGIN_USER_LOADING } from "../../store/actions/login/loginActionConstants";
@@ -56,7 +56,11 @@ const LoginPage = ({ history }) => {
selectIsLoadingByActionType(LOGIN_USER_LOADING)
);

const handleApiResponseSuccess = () => {
useEffect(() => {
dispatch(clearLoginErrors());
}, []);

const handleApiResponseSuccess = (status) => {
history.push({
pathname: HOME_PAGE,
state: {
@@ -66,12 +70,12 @@ const LoginPage = ({ history }) => {
};

const handleSubmit = (values) => {
const { username: Username, password: Password } = values;
const { username: email, password: password } = values;
dispatch(clearLoginErrors());
dispatch(
fetchUser({
Username,
Password,
email,
password,
handleApiResponseSuccess,
})
);
@@ -84,7 +88,7 @@ const LoginPage = ({ history }) => {
},
validationSchema: Yup.object().shape({
username: Yup.string().required(t("login.usernameRequired")),
password: Yup.string().required(t("login.passwordRequired")),
password: Yup.string().required(t("login.passwordRequired")).min(8),
}),
onSubmit: handleSubmit,
validateOnBlur: true,
@@ -112,7 +116,7 @@ const LoginPage = ({ history }) => {
margin="normal"
value={formik.values.username}
onChange={formik.handleChange}
error={formik.touched.username && Boolean(formik.errors.username)}
error={(formik.touched.password && formik.errors.password) || error.length > 0}
helperText={formik.touched.username && formik.errors.username}
autoFocus
fullWidth
@@ -125,7 +129,7 @@ const LoginPage = ({ history }) => {
type={showPassword ? "text" : "password"}
value={formik.values.password}
onChange={formik.handleChange}
error={formik.touched.password && Boolean(formik.errors.password)}
error={(formik.touched.password && formik.errors.password) || error.length > 0}
helperText={formik.touched.password && formik.errors.password}
fullWidth={true}
InputProps={{
@@ -167,7 +171,6 @@ const LoginPage = ({ history }) => {
</PrimaryButton>

<RegisterTextContainer>

<RegisterAltText>
{t("login.dontHaveAccount").padEnd(2, " ")}
</RegisterAltText>
@@ -180,11 +183,8 @@ const LoginPage = ({ history }) => {
>
{t("login.signUp")}
</Link>

</RegisterTextContainer>

</LoginFormContainer>

</LoginPageContainer>
);
};

+ 17
- 7
src/pages/RegisterPages/Register/FirstPart/FirstPartOfRegistration.js Zobrazit soubor

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

const FirstPartOfRegistration = (props) => {
const [showPassword, setShowPassword] = useState(false);
const [emailTakenStatus, setEmailTakenStatus] = useState(false);
const { t } = useTranslation();

const handleForm = (values) => {
// validate email
if (true) { // eslint-disable-line
props.handleSubmit(values)
} else {
setEmailTakenStatus(true);
}
}

const formik = useFormik({
initialValues: {
mail: "",
@@ -25,9 +35,9 @@ const FirstPartOfRegistration = (props) => {
},
validationSchema: Yup.object().shape({
mail: Yup.string().email().required(t("login.usernameRequired")),
password: Yup.string().required(t("login.passwordRequired")),
password: Yup.string().required(t("login.passwordRequired")).min(8),
}),
onSubmit: props.handleSubmit,
onSubmit: handleForm,
validateOnBlur: true,
enableReinitialize: true,
});
@@ -49,7 +59,7 @@ const FirstPartOfRegistration = (props) => {
onChange={(value) =>
formik.setFieldValue("mail", value.target.value)
}
error={formik.touched.mail && Boolean(formik.errors.mail)}
error={(formik.touched.mail && Boolean(formik.errors.mail)) || emailTakenStatus}
helperText={formik.touched.mail && formik.errors.mail}
autoFocus
fullWidth
@@ -65,12 +75,12 @@ const FirstPartOfRegistration = (props) => {
formik.setFieldValue("password", value.target.value)
}
error={
formik.touched.passwordRegistration &&
Boolean(formik.errors.passwordRegistration)
formik.touched.password &&
Boolean(formik.errors.password)
}
helperText={
formik.touched.passwordRegistration &&
formik.errors.passwordRegistration
formik.touched.password &&
formik.errors.password
}
fullWidth
InputProps={{

+ 12
- 5
src/pages/RegisterPages/Register/Register.js Zobrazit soubor

@@ -11,28 +11,35 @@ import {
RegisterTitle,
} from "./Register.styled";
import { ReactComponent as Logo } from "../../../assets/images/svg/logo-vertical.svg";
import { NavLink, useHistory } from "react-router-dom";
import { NavLink } from "react-router-dom";
import { Trans, useTranslation } from "react-i18next";
import Link from "../../../components/Link/Link";
import StepProgress from "../../../components/StepProgress/StepProgress";
import { REGISTER_SUCCESSFUL_PAGE } from "../../../constants/pages";
// import { REGISTER_SUCCESSFUL_PAGE } from "../../../constants/pages";
import FirstPartOfRegistration from "./FirstPart/FirstPartOfRegistration";
import SecondPartOfRegistration from "./SecondPart/SecondPartOfRegistration";
import ThirdPartOfRegistration from "./ThirdPart/ThirdPartOfRegistration";
import { useDispatch } from "react-redux";
import { fetchRegisterUser } from "../../../store/actions/register/registerActions";

const Register = () => {
const { t } = useTranslation();
const history = useHistory();
// const history = useHistory();
const dispatch = useDispatch();
const [currentStep, setCurrentStep] = useState(1);
const [informations, setInformations] = useState({});

const registerUser = (values) => {
dispatch(fetchRegisterUser(values));
}

const handleSubmit = (values) => {
setInformations({ ...informations, ...values });
if (currentStep !== 3) {
setCurrentStep((prevState) => prevState + 1);
} else {
history.push(REGISTER_SUCCESSFUL_PAGE);
registerUser({...informations, ...values});
}
setInformations({ ...informations, ...values });
};
return (
<RegisterPageContainer>

+ 14
- 4
src/pages/RegisterPages/Register/SecondPart/SecondPartOfRegistration.js Zobrazit soubor

@@ -1,4 +1,4 @@
import React from "react";
import React, { useState } from "react";
import PropTypes from "prop-types";
import {
FormContainer,
@@ -13,6 +13,16 @@ import selectedTheme from "../../../../themes";

const SecondPartOfRegistration = (props) => {
const { t } = useTranslation();
const [PIBTakenStatus, setPIBTakenStatus] = useState(false);

const handleForm = (values) => {
// validate email
if (true) { // eslint-disable-line
props.handleSubmit(values)
} else {
setPIBTakenStatus(true);
}
}

const formik = useFormik({
initialValues: {
@@ -21,9 +31,9 @@ const SecondPartOfRegistration = (props) => {
},
validationSchema: Yup.object().shape({
nameOfFirm: Yup.string().required(t("login.usernameRequired")),
PIB: Yup.number().required(t("login.passwordRequired")),
PIB: Yup.number().required(t("login.passwordRequired")).min(100000000).max(999999999),
}),
onSubmit: props.handleSubmit,
onSubmit: handleForm,
validateOnBlur: true,
enableReinitialize: true,
});
@@ -52,7 +62,7 @@ const SecondPartOfRegistration = (props) => {
type="number"
value={formik.values.PIB}
onChange={formik.handleChange}
error={formik.touched.PIB && Boolean(formik.errors.PIB)}
error={(formik.touched.PIB && Boolean(formik.errors.PIB)) || PIBTakenStatus}
helperText={formik.touched.PIB && formik.errors.PIB}
fullWidth={true}
/>

+ 13
- 3
src/pages/RegisterPages/Register/ThirdPart/ThirdPartOfRegistration.js Zobrazit soubor

@@ -1,4 +1,4 @@
import React from "react";
import React, { useState } from "react";
import PropTypes from "prop-types";
import {
FormContainer,
@@ -13,6 +13,16 @@ import selectedTheme from "../../../../themes";

const ThirdPartOfRegistration = (props) => {
const { t } = useTranslation();
const [phoneNumberTakenStatus, setPhoneNumberTakenStatus] = useState(false);

const handleForm = (values) => {
// validate email
if (true) { // eslint-disable-line
props.handleSubmit(values)
} else {
setPhoneNumberTakenStatus(true);
}
}

const formik = useFormik({
initialValues: {
@@ -27,7 +37,7 @@ const ThirdPartOfRegistration = (props) => {
/^((ftp|http|https):\/\/)?(www.)?(?!.*(ftp|http|https|www.))[a-zA-Z0-9_-]+(\.[a-zA-Z]+)+((\/)[\w#]+)*(\/\w+\?[a-zA-Z0-9_]+=\w+(&[a-zA-Z0-9_]+=\w+)*)?$/gm
),
}),
onSubmit: props.handleSubmit,
onSubmit: handleForm,
validateOnBlur: true,
enableReinitialize: true,
});
@@ -45,7 +55,7 @@ const ThirdPartOfRegistration = (props) => {
type="number"
value={formik.values.phoneNumber}
onChange={formik.handleChange}
error={formik.touched.phoneNumber && Boolean(formik.errors.phoneNumber)}
error={(formik.touched.phoneNumber && Boolean(formik.errors.phoneNumber)) || phoneNumberTakenStatus}
helperText={formik.touched.phoneNumber && formik.errors.phoneNumber}
autoFocus
fullWidth

+ 150
- 0
src/pages/ResetPasswordPage/ResetPasswordPage.js Zobrazit soubor

@@ -0,0 +1,150 @@
import React, { useState } from "react";
import { useFormik } from "formik";
import { useTranslation } from "react-i18next";
import * as Yup from "yup";
import { ReactComponent as Logo } from "../../assets/images/svg/logo-vertical.svg";
import {
ResetPasswordPageContainer,
ResetPasswordDescription,
ResetPasswordTitle,
FormContainer,
Footer,
FooterText,
} from "./ResetPasswordPage.styled";
import { TextField } from "../../components/TextFields/TextField/TextField";
import { PrimaryButton } from "../../components/Buttons/PrimaryButton/PrimaryButton";
import { useHistory } from "react-router-dom";
import { LOGIN_PAGE } from "../../constants/pages";
import selectedTheme from "../../themes";
import { useDispatch } from "react-redux";
import { resetPassword } from "../../store/actions/user/userActions";
import { Trans } from "react-i18next";
import { ReactComponent as VisibilityOn } from "../../assets/images/svg/eye-striked.svg";
import { ReactComponent as VisibilityOff } from "../../assets/images/svg/eye.svg";
import { IconButton } from "../../components/Buttons/IconButton/IconButton";


const ResetPasswordPage = () => {
const history = useHistory();
const { t } = useTranslation();
const dispatch = useDispatch();
const [showPassword, setShowPassword] = useState(false);
const [showPasswordConfirm, setShowPasswordConfirm] = useState(false);

const handleClickShowPassword = () => {
setShowPassword((prevState) => !prevState);
};
const handleClickShowPasswordConfirm = () => {
setShowPasswordConfirm((prevState) => !prevState);
};
const handleResponseSuccess = () => {
history.push(LOGIN_PAGE);
}
const handleResponseError = () => {
console.log("error");
}

const handleSubmit = (values) => {
// validate email
dispatch(
resetPassword({
password: values.password,
password2: values.passwordConfirm,
handleResponseSuccess,
handleResponseError
})
);
};

const formik = useFormik({
initialValues: {
password: "",
passwordConfirm: "",
},
validationSchema: Yup.object().shape({
password: Yup.string().required().min(8),
passwordConfirm: Yup.string().oneOf([Yup.ref("password"), null]),
}),
onSubmit: handleSubmit,
validateOnBlur: true,
enableReinitialize: true,
});

return (
<ResetPasswordPageContainer>
<Logo />

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

<ResetPasswordDescription component="h1" variant="h6">
{t("resetPassword.description")}
</ResetPasswordDescription>

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

<TextField
name="password"
placeholder={t("resetPassword.passwordLabel")}
margin="normal"
type={showPassword ? "text" : "password"}
value={formik.values.password}
onChange={formik.handleChange}
error={formik.touched.password && formik.errors.password?.length > 0}
helperText={formik.touched.password && formik.errors.password}
fullWidth
InputProps={{
endAdornment: (
<IconButton onClick={handleClickShowPassword}>
{showPassword ? <VisibilityOn /> : <VisibilityOff />}
</IconButton>
),
}}
/>
<TextField
name="passwordConfirm"
placeholder={t("resetPassword.passwordConfirmLabel")}
margin="normal"
type={showPasswordConfirm ? "text" : "password"}
value={formik.values.passwordConfirm}
onChange={formik.handleChange}
error={formik.touched.passwordConfirm && formik.errors.passwordConfirm?.length > 0}
helperText={formik.touched.passwordConfirm && formik.errors.passwordConfirm}
fullWidth
InputProps={{
endAdornment: (
<IconButton onClick={handleClickShowPasswordConfirm}>
{showPasswordConfirm ? <VisibilityOn /> : <VisibilityOff />}
</IconButton>
),
}}
/>

<PrimaryButton
type="submit"
variant="contained"
height="48px"
fullWidth={true}
buttoncolor={selectedTheme.primaryPurple}
textcolor="white"
disabled={
formik.values.password.length < 8 ||
formik.values.passwordConfirm.length < 8
}
>
{t("resetPassword.buttonText")}
</PrimaryButton>
</FormContainer>

<Footer>
<FooterText>
<Trans i18nKey="forgotPassword.checkSpam" />
</FooterText>
</Footer>
</ResetPasswordPageContainer>
);
};

export default ResetPasswordPage;

+ 61
- 0
src/pages/ResetPasswordPage/ResetPasswordPage.styled.js Zobrazit soubor

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

export const ResetPasswordPageContainer = styled(Container)`
margin-top: 200px;
display: flex;
flex-direction: column;
align-items: center;
`;
export const ResetPasswordTitle = 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: 36px;
`;
export const ResetPasswordDescription = styled(Typography)`
font-family: "Open Sans";
margin-top: 9px;
width: 270px;
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 FormContainer = styled(Box)`
width: 335px;
height: 216px;
`;

export const Footer = styled(Box)`
position: absolute;
bottom: 36px;
display: flex;
width: 100%;
flex-direction: row;
justify-content: center;
`;
export const FooterText = styled(Typography)`
font-family: "Open Sans";
color: ${selectedTheme.primaryText};
padding-right: 6px;
text-align: center;
width: 340px;
line-height: 22px;
font-weight: 400;
padding: 0;
font-size: 16px;
`;

+ 5
- 3
src/request/apiEndpoints.js Zobrazit soubor

@@ -1,13 +1,15 @@
export default {
accounts: {
get: 'accounts/{accountUid}',
forgotPassword: 'forgotPassword',
resetPassword: 'resetPassword',
getCurrentUserPermissions:
'accounts/{currentAccountUid}/users/{currentUserUid}/permissions',
getAddresses: 'accounts/{accountUid}/addresses',
updateAddress: 'account/{accountUid}/addresses/{addressUid}',
deleteAddress: 'accounts/{accountUid}/addresses/{addressUid}',
getUsers: 'accounts/{accountUid}/users',
createUser: 'accounts/{accountUid}/users',
register: 'users',
updateUser: 'account/{accountUid}/users/{userUid}?actionType={actionType}',
deleteUser: 'accounts/{accountUid}/users/{userUid}',
getSettings: 'accounts/{accountUid}/settings',
@@ -17,7 +19,7 @@ export default {
},
authentications: {
getUsernames: 'authenticate/usernames',
login: 'authenticate',
login: 'auth/token',
getUserSecurityQuestion: 'users/username/securityquestion',
confirmSecurityQuestion: 'authenticate/confirm',
confirmForgotPassword: 'users/passwords/reset_token',
@@ -108,7 +110,7 @@ export default {
getRegistrationAccounts: '/users/{userUid}/accounts',
updateUser: '/users/{userUid}?updateUserActionType={actionType}',
updateUserPassword: '/users/{userUid}/passwords',
logout: '/users/{userUid}/logout',
logout: '/auth/logout',
getUsernames: '/users/email',
createUser:
'/users?fp={fp}&offer={offer}&landingPageUrl={landingPageUrl}&registrationFlowType={registrationFlowType}',

+ 8
- 0
src/request/forgotPasswordRequest.js Zobrazit soubor

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

export const forgotPasswordRequest = (payload) =>
postRequest(apiEndpoints.accounts.forgotPassword, payload);

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

+ 3
- 2
src/request/index.js Zobrazit soubor

@@ -2,11 +2,11 @@ import axios from 'axios';
import queryString from 'qs';

const request = axios.create({
baseURL: process.env.REACT_APP_BASE_API_URL,
baseURL: "http://192.168.88.175:3001/",
headers: {
'Content-Type': 'application/json',
},
withCredentials: true,
// withCredentials: true,
paramsSerializer: (params) =>
queryString.stringify(params, { arrayFormat: 'comma' }),
});
@@ -42,6 +42,7 @@ export const replaceInUrl = (url, pathVariables = {}) => {
};

export const addHeaderToken = (token) => {
console.log(`Bearer ${token.toString()}`)
request.defaults.headers.Authorization = `Bearer ${token}`;
};


+ 4
- 8
src/request/loginRequest.js Zobrazit soubor

@@ -1,5 +1,5 @@
import { getRequest, postRequest, replaceInUrl } from './index';
import apiEndpoints from './apiEndpoints';
import { getRequest, postRequest } from "./index";
import apiEndpoints from "./apiEndpoints";

export const getUsernames = (emailorusername) =>
getRequest(apiEndpoints.authentications.getUsernames, {
@@ -15,12 +15,8 @@ export const updateSecurityAnswer = (payload) =>
export const refreshTokenRequest = (payload) =>
postRequest(apiEndpoints.authentications.refreshToken, payload);

export const logoutUserRequest = (userUid) =>
postRequest(
replaceInUrl(apiEndpoints.users.logout, {
userUid,
}),
);
export const logoutUserRequest = (payload) =>
postRequest(apiEndpoints.users.logout, payload);

export const generateTokenRequest = (payload) =>
postRequest(apiEndpoints.authentications.generateToken, payload);

+ 6
- 0
src/request/registerRequest.js Zobrazit soubor

@@ -0,0 +1,6 @@
import apiEndpoints from "./apiEndpoints";

import { postRequest } from ".";

export const attemptRegister = (payload) =>
postRequest(apiEndpoints.accounts.register, payload);

+ 8
- 0
src/store/actions/filters/filtersActionConstants.js Zobrazit soubor

@@ -0,0 +1,8 @@
import { createClearType, createSetType } from "../actionHelpers"

const FILTERS_SCOPE = "FILTERS"
export const SET_FILTERS = createSetType(FILTERS_SCOPE);
export const CLEAR_FILTERS = createClearType(FILTERS_SCOPE);
export const SET_CATEGORY = "FILTERS_SET_CATEGORY";
export const SET_SUBCATEGORY = "FILTERS_SET_SUBCATEGORY";
export const SET_CITIES = "FILTERS_SET_CITIES";

+ 21
- 0
src/store/actions/filters/filtersActions.js Zobrazit soubor

@@ -0,0 +1,21 @@
import { CLEAR_FILTERS, SET_CATEGORY, SET_CITIES, SET_FILTERS, SET_SUBCATEGORY } from "./filtersActionConstants";

export const setFilters = (payload) => ({
type: SET_FILTERS,
payload,
})
export const clearFilters = () => ({
type: CLEAR_FILTERS
})
export const setCategory = (payload) => ({
type: SET_CATEGORY,
payload
})
export const setSubcategory = (payload) => ({
type: SET_SUBCATEGORY,
payload
})
export const setCities = (payload) => ({
type: SET_CITIES,
payload
})

+ 4
- 0
src/store/actions/register/registerActionConstants.js Zobrazit soubor

@@ -0,0 +1,4 @@
import { createFetchType } from "../actionHelpers";

const REGISTER_USER_SCOPE = "REGISTER_USER";
export const REGISTER_USER_FETCH = createFetchType(REGISTER_USER_SCOPE);

+ 6
- 0
src/store/actions/register/registerActions.js Zobrazit soubor

@@ -0,0 +1,6 @@
import { REGISTER_USER_FETCH } from "./registerActionConstants";

export const fetchRegisterUser = (payload) => ({
type: REGISTER_USER_FETCH,
payload
})

+ 3
- 1
src/store/actions/user/userActionConstants.js Zobrazit soubor

@@ -1,3 +1,5 @@

export const SET_USER = 'SET_USER';
export const SET_USER_ERROR = 'SET_USER_ERROR';
export const SET_USER_ERROR = 'SET_USER_ERROR';
export const FORGOT_PASSWORD = "FORGOT_PASSWORD";
export const RESET_PASSWORD = "RESET_PASSWORD";

+ 10
- 0
src/store/actions/user/userActions.js Zobrazit soubor

@@ -1,4 +1,6 @@
import {
FORGOT_PASSWORD,
RESET_PASSWORD,
SET_USER,
SET_USER_ERROR,
} from './userActionConstants';
@@ -12,3 +14,11 @@ export const setUserError = (payload) => ({
type: SET_USER_ERROR,
payload,
});
export const forgotPassword = (payload) => ({
type: FORGOT_PASSWORD,
payload
})
export const resetPassword = (payload) => ({
type: RESET_PASSWORD,
payload
})

+ 68
- 0
src/store/reducers/filters/filtersReducer.js Zobrazit soubor

@@ -0,0 +1,68 @@
import {
CLEAR_FILTERS,
SET_CATEGORY,
SET_CITIES,
SET_FILTERS,
SET_SUBCATEGORY,
} from "../../actions/filters/filtersActionConstants";
import createReducer from "../../utils/createReducer";

const initialState = {
filters: {
category: null,
subcategory: null,
cities: [],
},
};

export default createReducer(
{
[SET_FILTERS]: setFilters,
[CLEAR_FILTERS]: clearFilters,
[SET_CATEGORY]: setCategory,
[SET_SUBCATEGORY]: setSubcategory,
[SET_CITIES]: setCities,
},
initialState
);

function setFilters(state, { payload }) {
return {
...state,
filters: payload,
};
}

function clearFilters() {
return initialState;
}

function setCategory(state, { payload }) {
return {
...state,
filters: {
...state.filters,
category: payload,
},
};
}

function setSubcategory(state, { payload }) {
return {
...state,
filters: {
...state.filters,
subcategory: payload,
},
};
}

function setCities(state, { payload }) {
return {
...state,
filters: {
...state.filters,
cities: payload,
},
};
}

+ 3
- 1
src/store/reducers/index.js Zobrazit soubor

@@ -6,11 +6,12 @@ import randomDataReducer from "./randomData/randomDataReducer";
import storage from "redux-persist/lib/storage";
import createFilter from "redux-persist-transform-filter";
import persistReducer from "redux-persist/es/persistReducer";
import filtersReducer from "./filters/filtersReducer";

const loginPersistConfig = {
key: "login",
storage: storage,
transform: [createFilter("login", ["email", "token", "errorMessage"])],
transform: [createFilter("login", ["email", "token"])],
};

const userPersistConfig = {
@@ -39,5 +40,6 @@ export default combineReducers({
login: persistReducer(loginPersistConfig, loginReducer),
user: persistReducer(userPersistConfig, userReducer),
loading: loadingReducer,
filters: filtersReducer,
randomData: persistReducer(randomDataPersistConfig, randomDataReducer),
});

+ 43
- 0
src/store/saga/forgotPasswordSaga.js Zobrazit soubor

@@ -0,0 +1,43 @@
import { all, takeLatest, call } from "@redux-saga/core/effects";
import { forgotPasswordRequest, resetPasswordRequest } from "../../request/forgotPasswordRequest";
import { FORGOT_PASSWORD, RESET_PASSWORD } from "../actions/user/userActionConstants";

function* forgotPassword({payload}) {
try {
const data = yield call(forgotPasswordRequest);
if (data) {
if (payload.handleResponseSuccess) {
yield call(payload.handleResponseSuccess);
}
}
}
catch(e) {
console.log(e);
if (payload.handleResponseError) {
yield call(payload.handleResponseError);
}
}
}
function* resetPassword({payload}) {
try {
const data = yield call(resetPasswordRequest)
if (data) {
if (payload.handleResponseSuccess) {
yield call(payload.handleResponseSuccess);
}
}
}
catch(e) {
console.log(e);
if (payload.handleResponseError) {
yield call(payload.handleResponseError);
}
}
}

export default function* forgotPasswordSaga() {
yield all([
takeLatest(FORGOT_PASSWORD, forgotPassword),
takeLatest(RESET_PASSWORD, resetPassword)
])
}

+ 4
- 0
src/store/saga/index.js Zobrazit soubor

@@ -1,8 +1,12 @@
import { all } from 'redux-saga/effects';
import forgotPasswordSaga from './forgotPasswordSaga';
import loginSaga from './loginSaga';
import registerSaga from './registerSaga';

export default function* rootSaga() {
yield all([
loginSaga(),
registerSaga(),
forgotPasswordSaga()
]);
}

+ 41
- 33
src/store/saga/loginSaga.js Zobrazit soubor

@@ -1,57 +1,60 @@
import { all, call, put, takeLatest } from '@redux-saga/core/effects';
import jwt from 'jsonwebtoken';
import history from '../utils/history';
import { all, call, put, takeLatest } from "@redux-saga/core/effects";
import jwt from "jsonwebtoken";
import history from "../utils/history";
import {
AUTHENTICATE_USER,
LOGIN_USER_FETCH,
LOGOUT_USER,
REFRESH_TOKEN,
GENERATE_TOKEN,
} from '../actions/login/loginActionConstants';
} from "../actions/login/loginActionConstants";
import {
attemptLogin,
logoutUserRequest,
refreshTokenRequest,
generateTokenRequest,
} from '../../request/loginRequest';
} from "../../request/loginRequest";
import {
fetchUserError,
fetchUserSuccess,
resetLoginState,
updateUserToken,
} from '../actions/login/loginActions';
import { LOGIN_PAGE } from '../../constants/pages';
import { setUser } from '../actions/user/userActions';
import {
addHeaderToken,
removeHeaderToken,
} from '../../request';
} from "../actions/login/loginActions";
import { LOGIN_PAGE } from "../../constants/pages";
import { setUser } from "../actions/user/userActions";
import { addHeaderToken, removeHeaderToken } from "../../request";
import {
IMPERSONATE_USER_UID,
REGISTRATION_USER_UID,
} from '../../constants/sessionStorage';
} from "../../constants/sessionStorage";
import {
JWT_REFRESH_TOKEN,
JWT_TOKEN,
REFRESH_TOKEN_CONST,
} from '../../constants/localStorage';
// REFRESH_TOKEN_CONST,
} from "../../constants/localStorage";
import {
authScopeClearHelper,
authScopeStringGetHelper,
authScopeRemoveHelper,
authScopeSetHelper,
} from '../../util/helpers/authScopeHelpers';
import { rejectErrorCodeHelper } from '../../util/helpers/rejectErrorCodeHelper';
} from "../../util/helpers/authScopeHelpers";
// import { rejectErrorCodeHelper } from "../../util/helpers/rejectErrorCodeHelper";

function* fetchUser({ payload }) {
try {
const { data } = yield call(attemptLogin, payload);
if (data.JwtToken) {
const user = jwt.decode(data.JwtToken);
yield call(authScopeSetHelper, JWT_TOKEN, data.JwtToken);
yield call(authScopeSetHelper, JWT_REFRESH_TOKEN, data.JwtRefreshToken);
yield call(authScopeSetHelper, REFRESH_TOKEN_CONST, data.RefreshToken);
yield call(addHeaderToken, data.JwtToken);
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);
// yield call(authScopeSetHelper, REFRESH_TOKEN_CONST, data.RefreshToken);
yield call(addHeaderToken, token);
yield put(setUser(user));
}
yield put(fetchUserSuccess(data));
@@ -60,10 +63,14 @@ function* fetchUser({ payload }) {
}
} catch (e) {
if (e.response && e.response.data) {
if (payload.handleApiResponseSuccess) {
yield call(payload.handleApiResponseSuccess);
if (payload.handleApiResponseError) {
yield call(payload.handleApiResponseError);
}
let errorMessage = "Greska!";
if (e.response.status === 400) {
errorMessage = "Pogresan mail ili lozinka!";
}
const errorMessage = yield call(rejectErrorCodeHelper, e);
// const errorMessage = yield call(rejectErrorCodeHelper, e);
yield put(fetchUserError(errorMessage));
}
}
@@ -79,14 +86,14 @@ function* authenticateUser() {
return yield put(
fetchUserSuccess({
JwtToken,
}),
})
);
} catch (error) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
yield put(fetchUserError(errorMessage));
// const errorMessage = yield call(rejectErrorCodeHelper, error);
// yield put(fetchUserError(errorMessage));
yield call(authScopeRemoveHelper, JWT_TOKEN);
yield call(authScopeRemoveHelper, JWT_REFRESH_TOKEN);
yield call(authScopeRemoveHelper, REFRESH_TOKEN_CONST);
// yield call(authScopeRemoveHelper, JWT_REFRESH_TOKEN);
// yield call(authScopeRemoveHelper, REFRESH_TOKEN_CONST);
}
}

@@ -94,8 +101,9 @@ function* logoutUser() {
try {
const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN);
const user = jwt.decode(JwtToken);
console.log({token: JwtToken, userId: user._id})
if (user) {
yield call(logoutUserRequest, user.UserUid);
yield call(logoutUserRequest, {token: JwtToken, userId: user._id});
}
} catch (error) {
console.log(error); // eslint-disable-line
@@ -112,7 +120,7 @@ export function* refreshToken() {
const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN);
const JwtRefreshToken = yield call(
authScopeStringGetHelper,
JWT_REFRESH_TOKEN,
JWT_REFRESH_TOKEN
);

if (JwtToken && JwtRefreshToken) {

+ 32
- 0
src/store/saga/registerSaga.js Zobrazit soubor

@@ -0,0 +1,32 @@
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}) {
try {
const requestData = {
name: "Djordje Mitrovic",
email: payload.mail.toString(),
password: payload.password.toString(),
company: {
name: payload.nameOfFirm.toString(),
PIB: payload.PIB.toString(),
contacts: {
telephone: payload.phoneNumber.toString(),
location: payload.location.toString(),
web: payload.website.toString()
}
}
}
console.log("payload: ", payload)
console.log(requestData);
const data = yield call(attemptRegister, requestData);
console.log(data);
} catch (e) {
console.log(e);
}
}

export default function* registerSaga() {
yield all([takeLatest(REGISTER_USER_FETCH, fetchRegisterUser)]);
}

+ 9
- 0
src/store/selectors/filtersSelectors.js Zobrazit soubor

@@ -0,0 +1,9 @@
import { createSelector } from 'reselect';

const filtersSelector = (state) => state.filters;

export const selectFilters = createSelector(
filtersSelector,
(state) => state.filters,
);


Načítá se…
Zrušit
Uložit