Selaa lähdekoodia

Cleaned code

feature/498
Djordje Mitrovic 3 vuotta sitten
vanhempi
commit
b183e38a81
79 muutettua tiedostoa jossa 1191 lisäystä ja 1023 poistoa
  1. 7
    6
      src/AppRoutes.js
  2. 4
    1
      src/components/Buttons/ArrowButton/ArrowButton.styled.js
  3. 1
    1
      src/components/Cards/ChatCard/ChatCommands/ChatCommands.styled.js
  4. 0
    2
      src/components/Cards/FilterCard/FilterCard.js
  5. 4
    5
      src/components/Cards/FilterCard/Skeleton/SkeletonChooserHeader/SkeletonChooserHeader.js
  6. 2
    3
      src/components/Cards/FilterCard/Skeleton/SkeletonChooserTitle/SkeletonChooserTitle.js
  7. 11
    12
      src/components/Cards/FilterCard/Skeleton/SkeletonFilterCard.js
  8. 1
    2
      src/components/Cards/FilterCard/Skeleton/SkeletonSection/SkeletonSection.js
  9. 4
    5
      src/components/Cards/FilterCard/Skeleton/SkeletonSection/SkeletonSectionOption/SkeletonSectionOption.js
  10. 0
    1
      src/components/Cards/OfferCard/SkeletonOfferCard/SkeletonOfferCard.js
  11. 25
    0
      src/components/Cards/ProfileCard/EditProfile/AppLinkField/AppLinkField.js
  12. 0
    0
      src/components/Cards/ProfileCard/EditProfile/AppLinkField/AppLinkField.styled.js
  13. 167
    0
      src/components/Cards/ProfileCard/EditProfile/EditProfile.js
  14. 4
    35
      src/components/Cards/ProfileCard/EditProfile/EditProfile.styled.js
  15. 27
    0
      src/components/Cards/ProfileCard/EditProfile/FirmNameField/FirmNameField.js
  16. 0
    0
      src/components/Cards/ProfileCard/EditProfile/FirmNameField/FirmNameField.styled.js
  17. 28
    0
      src/components/Cards/ProfileCard/EditProfile/FormikErrorMessage/FormikErrorMessage.js
  18. 11
    0
      src/components/Cards/ProfileCard/EditProfile/FormikErrorMessage/FormikErrorMessage.styled.js
  19. 42
    0
      src/components/Cards/ProfileCard/EditProfile/LocationField/LocationField.js
  20. 25
    0
      src/components/Cards/ProfileCard/EditProfile/LocationField/LocationField.styled.js
  21. 29
    0
      src/components/Cards/ProfileCard/EditProfile/PIBField/PIBField.js
  22. 0
    0
      src/components/Cards/ProfileCard/EditProfile/PIBField/PIBField.styled.js
  23. 39
    0
      src/components/Cards/ProfileCard/EditProfile/PhoneField/PhoneField.js
  24. 0
    0
      src/components/Cards/ProfileCard/EditProfile/PhoneField/PhoneField.styled.js
  25. 29
    0
      src/components/Cards/ProfileCard/EditProfile/WebsiteField/WebsiteField.js
  26. 0
    0
      src/components/Cards/ProfileCard/EditProfile/WebsiteField/WebsiteField.styled.js
  27. 7
    8
      src/components/Cards/ProfileCard/ProfileCard.js
  28. 3
    3
      src/components/Cards/ProfileCard/ProfileCard.styled.js
  29. 0
    0
      src/components/Cards/ProfileCard/ProfileContact/ProfileContact.js
  30. 4
    4
      src/components/Cards/ProfileCard/ProfileContact/ProfileContact.styled.js
  31. 2
    2
      src/components/Cards/ProfileCard/ProfileMainInfo/ProfileMainInfo.js
  32. 2
    2
      src/components/Cards/ProfileCard/ProfileMainInfo/ProfileMainInfo.styled.js
  33. 0
    0
      src/components/Cards/ProfileCard/ProfileStats/ProfileStats.js
  34. 1
    1
      src/components/Cards/ProfileCard/ProfileStats/ProfileStats.styled.js
  35. 0
    0
      src/components/Cards/ProfileCard/SkeletonProfileCard/SkeletonProfileCard.js
  36. 1
    1
      src/components/Cards/ProfileCard/SkeletonProfileCard/SkeletonProfileCard.styled.js
  37. 1
    1
      src/components/ChatColumn/ChatColumn.js
  38. 1
    1
      src/components/CreateReview/CreateReview.styled.js
  39. 32
    201
      src/components/Header/Header.js
  40. 1
    15
      src/components/Header/Header.styled.js
  41. 32
    0
      src/components/Header/LoginButton/LoginButton.js
  42. 9
    0
      src/components/Header/LoginButton/LoginButton.styled.js
  43. 43
    12
      src/components/Header/MyMessagesButton/MyMessagesButton.js
  44. 42
    10
      src/components/Header/MySwapsButton/MySwapsButton.js
  45. 32
    0
      src/components/Header/RegisterButton/RegisterButton.js
  46. 11
    0
      src/components/Header/RegisterButton/RegisterButton.styled.js
  47. 44
    12
      src/components/Header/UserButton/UserButton.js
  48. 0
    32
      src/components/IconButton/IconButton.js
  49. 1
    1
      src/components/ImagePicker/ImagePicker.js
  50. 5
    15
      src/components/Login/Fields/Password/PasswordField.js
  51. 0
    2
      src/components/MarketPlace/Header/Header.js
  52. 4
    5
      src/components/MarketPlace/Header/SkeletonHeader/SkeletonHeader.js
  53. 0
    3
      src/components/MarketPlace/MarketPlace.js
  54. 0
    2
      src/components/MarketPlace/Offers/Offers.js
  55. 1
    1
      src/components/Profile/Profile.js
  56. 26
    0
      src/components/Profile/ProfileOffers/HeaderTitle/HeaderTitle.js
  57. 32
    0
      src/components/Profile/ProfileOffers/HeaderTitle/HeaderTitle.styled.js
  58. 21
    120
      src/components/Profile/ProfileOffers/ProfileOffers.js
  59. 1
    85
      src/components/Profile/ProfileOffers/ProfileOffers.styled.js
  60. 24
    16
      src/components/Profile/ProfileOffers/ProfileOffersHeaderSkeleton/ProfileOffersHeaderSkeleton.js
  61. 1
    1
      src/components/Profile/ProfileOffers/ProfileOffersHeaderSkeleton/ProfileOffersHeaderSkeleton.styled.js
  62. 53
    0
      src/components/Profile/ProfileOffers/SearchBar/SearchBar.js
  63. 29
    0
      src/components/Profile/ProfileOffers/SearchBar/SearchBar.styled.js
  64. 76
    0
      src/components/Profile/ProfileOffers/SelectSortField/SelectSortField.js
  65. 38
    0
      src/components/Profile/ProfileOffers/SelectSortField/SelectSortField.styled.js
  66. 0
    274
      src/components/ProfileCard/EditProfile/EditProfile.js
  67. 21
    0
      src/components/Router/AuthRoute.js
  68. 14
    11
      src/i18n/resources/rs.js
  69. 9
    0
      src/initialValues/editProfileInitialValues.js
  70. 17
    16
      src/layouts/ProfileLayout/ProfileLayout.js
  71. 45
    32
      src/layouts/ProfileLayout/ProfileLayout.styled.js
  72. 0
    7
      src/pages/HomePage/HomePageMUI.js
  73. 0
    7
      src/pages/MyOffers/MyOffers.js
  74. 6
    2
      src/pages/ProfilePage/ProfilePage.js
  75. 11
    18
      src/store/reducers/login/loginReducer.js
  76. 1
    1
      src/store/saga/loginSaga.js
  77. 2
    2
      src/store/saga/registerSaga.js
  78. 4
    24
      src/store/selectors/loginSelectors.js
  79. 21
    0
      src/util/helpers/routeHelpers.js

+ 7
- 6
src/AppRoutes.js Näytä tiedosto

@@ -41,20 +41,21 @@ import ChatPage from "./pages/Chat/Chat";
import MyOffers from "./pages/MyOffers/MyOffers";
// import PricesPage from "./pages/Prices/PricesPage";
import AboutPage from "./pages/About/AboutPage";
import AuthRoute from "./components/Router/AuthRoute";
// import PrivacyPolicyPage from "./pages/PrivacyPolicy/PrivacyPolicyPage";

const AppRoutes = () => {
return (
<Switch>
<Route exact path={BASE_PAGE} component={HomePage} />
<Route exact path={LOGIN_PAGE} component={LoginPage} />
<AuthRoute exact path={LOGIN_PAGE} component={LoginPage} />
<Route path={NOT_FOUND_PAGE} component={NotFoundPage} />
<Route path={REGISTER_SUCCESSFUL_PAGE} component={RegisterSuccessful} />
<Route path={REGISTER_PAGE} component={Register} />
<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} />
<AuthRoute path={REGISTER_SUCCESSFUL_PAGE} component={RegisterSuccessful} />
<AuthRoute path={REGISTER_PAGE} component={Register} />
<AuthRoute path={FORGOT_PASSWORD_MAIL_SENT} component={MailSent} />
<AuthRoute path={FORGOT_PASSWORD_PAGE} component={ForgotPasswordPage} />
<AuthRoute path={RESET_PASSWORD_PAGE} component={ResetPasswordPage} />
<Route path={CREATE_OFFER_PAGE} component={CreateOffer} />
<Route path={ITEM_DETAILS_PAGE} component={ItemDetailsPage} />
<Route path={PROFILE_PAGE} component={ProfilePage} />

+ 4
- 1
src/components/Buttons/ArrowButton/ArrowButton.styled.js Näytä tiedosto

@@ -1,7 +1,7 @@
import IconButton from "../../IconButton/IconButton";
import { ReactComponent as DownArrow } from "../../../assets/images/svg/arrow-down.svg";
import styled from "styled-components";
import selectedTheme from "../../../themes";
import { IconButton } from "../IconButton/IconButton";

export const ArrowIcon = styled(DownArrow)`
${(props) =>
@@ -11,6 +11,9 @@ export const ArrowIcon = styled(DownArrow)`
`}
width: 18px;
height: 18px;
position: relative;
top: 1px;
left: 1px;
& path {
${(props) =>
props.disabled &&

+ 1
- 1
src/components/Cards/ChatCard/ChatCommands/ChatCommands.styled.js Näytä tiedosto

@@ -2,8 +2,8 @@ import { Box } from "@mui/material";
import styled from "styled-components";
import { ReactComponent as Phone } from "../../../../assets/images/svg/phone.svg";
import selectedTheme from "../../../../themes";
import { IconButton } from "../../../Buttons/IconButton/IconButton";
import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton";
import IconButton from "../../../IconButton/IconButton";
import PopoverComponent from "../../../Popovers/PopoverComponent";



+ 0
- 2
src/components/Cards/FilterCard/FilterCard.js Näytä tiedosto

@@ -27,7 +27,6 @@ const FilterCard = (props) => {
skeleton={props.skeleton}
>
<SkeletonFilterCard
animationStage={props.animationStage}
skeleton={props.skeleton}
/>
{/* Header title for my offers */}
@@ -75,7 +74,6 @@ FilterCard.propTypes = {
closeResponsive: PropTypes.func,
myOffers: PropTypes.bool,
skeleton: PropTypes.bool,
animationStage: PropTypes.number,
filtersOpened: PropTypes.bool,
toggleFilters: PropTypes.func,
};

+ 4
- 5
src/components/Cards/FilterCard/Skeleton/SkeletonChooserHeader/SkeletonChooserHeader.js Näytä tiedosto

@@ -8,21 +8,20 @@ import {
SkeletonChooserContainer,
} from "./SkeletonChooserHeader.styled";

const SkeletonChooserHeader = (props) => {
const SkeletonChooserHeader = () => {
return (
<SkeletonChooserContainer>
<LeftContainer>
<CircleOne animationStage={props.animationStage}/>
<Line animationStage={props.animationStage}/>
<CircleOne/>
<Line/>
</LeftContainer>
<CircleSecond animationStage={props.animationStage}/>
<CircleSecond/>
</SkeletonChooserContainer>
);
};

SkeletonChooserHeader.propTypes = {
children: PropTypes.node,
animationStage: PropTypes.any,
};

export default SkeletonChooserHeader;

+ 2
- 3
src/components/Cards/FilterCard/Skeleton/SkeletonChooserTitle/SkeletonChooserTitle.js Näytä tiedosto

@@ -4,8 +4,8 @@ import { SkeletonChooserTitleContainer, SkeletonChooserTitleLine } from './Skele

const SkeletonChooserTitle = (props) => {
return (
<SkeletonChooserTitleContainer center={props.center} animationStage={props.animationStage} >
<SkeletonChooserTitleLine center={props.center} animationStage={props.animationStage}/>
<SkeletonChooserTitleContainer center={props.center} >
<SkeletonChooserTitleLine center={props.center} />
</SkeletonChooserTitleContainer>
)
}
@@ -13,7 +13,6 @@ const SkeletonChooserTitle = (props) => {
SkeletonChooserTitle.propTypes = {
children: PropTypes.any,
center: PropTypes.bool,
animationStage: PropTypes.number,
}

export default SkeletonChooserTitle

+ 11
- 12
src/components/Cards/FilterCard/Skeleton/SkeletonFilterCard.js Näytä tiedosto

@@ -13,26 +13,25 @@ import SkeletonSection from "./SkeletonSection/SkeletonSection";
const SkeletonFilterCard = (props) => {

return (
<SkeletonFilterCardContainer animationStage={props.animationStage} skeleton={props.skeleton}>
<SkeletonFilterCardContainer skeleton={props.skeleton}>
<SkeletonHeader>
<SkeletonHeaderLineOne animationStage={props.animationStage} />
<SkeletonHeaderLineSecond animationStage={props.animationStage} />
<SkeletonHeaderLineOne />
<SkeletonHeaderLineSecond />
</SkeletonHeader>
<SkeletonChooserHeader animationStage={props.animationStage}/>
<SkeletonChooserTitle animationStage={props.animationStage} />
<SkeletonSection numberOfOptions={14} animationStage={props.animationStage} />
<SkeletonChooserHeader animationStage={props.animationStage} />
<SkeletonChooserHeader animationStage={props.animationStage} />
<SkeletonChooserTitle animationStage={props.animationStage} />
<SkeletonSection numberOfOptions={3} animationStage={props.animationStage} />
<SkeletonChooserTitle center animationStage={props.animationStage} />
<SkeletonChooserHeader/>
<SkeletonChooserTitle />
<SkeletonSection numberOfOptions={14} />
<SkeletonChooserHeader />
<SkeletonChooserHeader />
<SkeletonChooserTitle />
<SkeletonSection numberOfOptions={3} />
<SkeletonChooserTitle center />
</SkeletonFilterCardContainer>
);
};

SkeletonFilterCard.propTypes = {
children: PropTypes.any,
animationStage: PropTypes.number,
skeleton: PropTypes.bool,
};


+ 1
- 2
src/components/Cards/FilterCard/Skeleton/SkeletonSection/SkeletonSection.js Näytä tiedosto

@@ -10,7 +10,7 @@ const SkeletonSection = (props) => {
return (
<SkeletonSectionContainer>
{arrayForMapping.map((item, index) => (
<SkeletonSectionOption key={index} animationStage={props.animationStage} />
<SkeletonSectionOption key={index} />
))}
</SkeletonSectionContainer>
);
@@ -19,7 +19,6 @@ const SkeletonSection = (props) => {
SkeletonSection.propTypes = {
children: PropTypes.node,
numberOfOptions: PropTypes.number,
animationStage: PropTypes.number,
};

export default SkeletonSection;

+ 4
- 5
src/components/Cards/FilterCard/Skeleton/SkeletonSection/SkeletonSectionOption/SkeletonSectionOption.js Näytä tiedosto

@@ -2,21 +2,20 @@ import React from 'react'
import PropTypes from 'prop-types'
import { Circle, EndLine, Line, OptionLeftContainer, SkeletonSectionOptionContainer } from './SkeletonSectionOption.styled'

const SkeletonSectionOption = (props) => {
const SkeletonSectionOption = () => {
return (
<SkeletonSectionOptionContainer>
<OptionLeftContainer>
<Circle animationStage={props.animationStage} />
<Line animationStage={props.animationStage} />
<Circle/>
<Line/>
</OptionLeftContainer>
<EndLine animationStage={props.animationStage} />
<EndLine/>
</SkeletonSectionOptionContainer>
)
}

SkeletonSectionOption.propTypes = {
children: PropTypes.any,
animationStage: PropTypes.number,
}

export default SkeletonSectionOption

+ 0
- 1
src/components/Cards/OfferCard/SkeletonOfferCard/SkeletonOfferCard.js Näytä tiedosto

@@ -57,7 +57,6 @@ const SkeletonOfferCard = (props) => {
SkeletonOfferCard.propTypes = {
children: PropTypes.node,
skeleton: PropTypes.bool,
animationStage: PropTypes.number,
};

export default SkeletonOfferCard;

+ 25
- 0
src/components/Cards/ProfileCard/EditProfile/AppLinkField/AppLinkField.js Näytä tiedosto

@@ -0,0 +1,25 @@
import React from "react";
import PropTypes from "prop-types";
import { InputField, InputFieldLabel } from "../EditProfile.styled";
import { useTranslation } from "react-i18next";

const AppLinkField = (props) => {
const { t } = useTranslation();
return (
<>
<InputFieldLabel leftText={t("editProfile.applink").toUpperCase()} />
<InputField
name="firmApplink"
values={props.formik.values.firmApplink}
margin="normal"
fullWidth
/>
</>
);
};

AppLinkField.propTypes = {
formik: PropTypes.any,
};

export default AppLinkField;

+ 0
- 0
src/components/Cards/ProfileCard/EditProfile/AppLinkField/AppLinkField.styled.js Näytä tiedosto


+ 167
- 0
src/components/Cards/ProfileCard/EditProfile/EditProfile.js Näytä tiedosto

@@ -0,0 +1,167 @@
import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import BackdropComponent from "../../../MUI/BackdropComponent";
import {
EditProfileContainer,
ProfileImageContainer,
BackButton,
CloseButton,
SaveButton,
ProfileHeader,
BasicInfo,
DetailsInfo,
ButtonsContainer,
ProfileImagePicker,
} from "./EditProfile.styled";
import selectedTheme from "../../../../themes";
import { useFormik } from "formik";
import { ReactComponent as ArrowBack } from "../../../../assets/images/svg/arrow-back.svg";
import { ReactComponent as CloseIcon } from "../../../../assets/images/svg/close-modal.svg";
import { useTranslation } from "react-i18next";
import {
editMineProfile,
fetchMineProfile,
} from "../../../../store/actions/profile/profileActions";
import { useDispatch, useSelector } from "react-redux";
import { selectUserId } from "../../../../store/selectors/loginSelectors";
import editProfileValidation from "../../../../validations/editProfileValidation";
import useIsMobile from "../../../../hooks/useIsMobile";
import { useMemo } from "react";
import editProfileInitialValues from "../../../../initialValues/editProfileInitialValues";
import FirmNameField from "./FirmNameField/FirmNameField";
import PIBField from "./PIBField/PIBField";
import LocationField from "./LocationField/LocationField";
import WebsiteField from "./WebsiteField/WebsiteField";
import AppLinkField from "./AppLinkField/AppLinkField";
import PhoneField from "./PhoneField/PhoneField";
import FormikErrorMessage from "./FormikErrorMessage/FormikErrorMessage";

const EditProfile = (props) => {
const [profileImage, setProfileImage] = useState(props.profile.image);
const [showBasic, setShowBasic] = useState(true);
const [showDetails, setShowDetails] = useState(true);
const { t } = useTranslation();
const dispatch = useDispatch();
const { isMobile } = useIsMobile();
const userId = useSelector(selectUserId);

useEffect(() => {
setShowDetails(!isMobile);
}, [isMobile]);

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

const handleSubmit = (values) => {
dispatch(editMineProfile({ ...values, handleApiResponseSuccess }));
props.closeModalHandler();
};
const initialValues = useMemo(
() => editProfileInitialValues(props?.profile),
[props?.profile]
);

const formik = useFormik({
initialValues,
validationSchema: editProfileValidation,
onSubmit: handleSubmit,
validateOnBlur: true,
enableReinitialize: true,
});

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

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

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

return (
<>
<BackdropComponent
handleClose={closeEditModalHandler}
isLoading
position="fixed"
/>
<EditProfileContainer component="form" onSubmit={formik.handleSubmit}>
{!showBasic && (
<BackButton onClick={showDetailsHandler}>
<ArrowBack />
</BackButton>
)}
<ProfileImageContainer>
<ProfileImagePicker
image={profileImage}
setImage={setImage}
></ProfileImagePicker>
<ProfileHeader>{props.profile.company.name}</ProfileHeader>
</ProfileImageContainer>
<CloseButton onClick={closeEditModalHandler}>
<CloseIcon />
</CloseButton>
{showBasic && (
<BasicInfo>
<FirmNameField formik={formik} />
<PIBField formik={formik} />
<LocationField formik={formik} />
</BasicInfo>
)}
{showDetails && (
<DetailsInfo>
<WebsiteField formik={formik} />
<AppLinkField formik={formik} />
<PhoneField formik={formik} />
</DetailsInfo>
)}

<FormikErrorMessage formik={formik} />

<ButtonsContainer>
{isMobile && (
<>
<SaveButton
height="44px"
width="155px"
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor={selectedTheme.colors.primaryPurple}
onClick={showDetailsHandler}
>
{showDetails
? t("editProfile.showBasic")
: t("editProfile.showDetails")}
</SaveButton>
</>
)}
<SaveButton
type="submit"
variant="contained"
height={isMobile ? "44px" : "48px"}
width={isMobile ? "155px" : "335px"}
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor="white"
>
{t("common.save")}
</SaveButton>
</ButtonsContainer>
</EditProfileContainer>
</>
);
};

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

export default EditProfile;

src/components/ProfileCard/EditProfile/EditProfile.styled.js → src/components/Cards/ProfileCard/EditProfile/EditProfile.styled.js Näytä tiedosto

@@ -1,9 +1,9 @@
import styled from "styled-components";
import { Box, TextField, Typography } from "@mui/material";
import ImagePicker from "../../ImagePicker/ImagePicker";
import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton";
import { Label } from "../../CheckBox/Label";
import selectedTheme from "../../../themes";
import ImagePicker from "../../../ImagePicker/ImagePicker";
import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton";
import { Label } from "../../../CheckBox/Label";
import selectedTheme from "../../../../themes";

export const EditProfileContainer = styled(Box)`
background-color: #fff;
@@ -120,29 +120,6 @@ export const InputField = styled(TextField)`
}
`;

export const InputFieldLabelLocation = styled(Label)`
position: relative;
bottom: -8px;
margin: 10px 0;
& label {
font-size: 12px;
font-weight: 600;
line-height: 20px;
color: #808080;
cursor: auto;
letter-spacing: 0.2px;
}

@media screen and (max-width: 600px) {
bottom: -12px;
margin: 5px 0 17px 0;
& label {
font-size: 9px;
margin-top: 0;
}
}
`;

export const SaveButton = styled(PrimaryButton)`
font-size: 12px;
letter-spacing: 1.5px;
@@ -158,14 +135,6 @@ export const ButtonsContainer = styled(Box)`
}
`;

export const ErrorMessage = styled(Typography)`
color: red;
font-family: ${selectedTheme.fonts.textFont};
position: relative;
top: 20px;
font-size: 14px;
`;

export const BasicInfo = styled(Box)``;

export const DetailsInfo = styled(Box)``;

+ 27
- 0
src/components/Cards/ProfileCard/EditProfile/FirmNameField/FirmNameField.js Näytä tiedosto

@@ -0,0 +1,27 @@
import React from "react";
import PropTypes from "prop-types";
import { InputField, InputFieldLabel } from "../EditProfile.styled";
import { useTranslation } from "react-i18next";

const FirmNameField = (props) => {
const { t } = useTranslation();
return (
<>
<InputFieldLabel leftText={t("common.labelFirm").toUpperCase()} />
<InputField
name="firmName"
value={props.formik.values.firmName}
onChange={props.formik.handleChange}
error={props.formik.touched.firmName && props.formik.errors.firmName}
margin="normal"
fullWidth
/>
</>
);
};

FirmNameField.propTypes = {
formik: PropTypes.any,
};

export default FirmNameField;

+ 0
- 0
src/components/Cards/ProfileCard/EditProfile/FirmNameField/FirmNameField.styled.js Näytä tiedosto


+ 28
- 0
src/components/Cards/ProfileCard/EditProfile/FormikErrorMessage/FormikErrorMessage.js Näytä tiedosto

@@ -0,0 +1,28 @@
import React from "react";
import PropTypes from "prop-types";
import { ErrorMessage } from "./FormikErrorMessage.styled";

const FormikErrorMessage = (props) => {
return (
<>
{props.formik.errors.firmName && props.formik.touched.firmName ? (
<ErrorMessage>{props.formik.errors.firmName}</ErrorMessage>
) : props.formik.errors.firmPIB && props.formik.touched.firmPIB ? (
<ErrorMessage>{props.formik.errors.firmPIB}</ErrorMessage>
) : props.formik.errors.firmLocation &&
props.formik.touched.firmLocation ? (
<ErrorMessage>{props.formik.errors.firmLocation}</ErrorMessage>
) : props.formik.errors.firmPhone && props.formik.touched.firmPhone ? (
<ErrorMessage>{props.formik.errors.firmPhone}</ErrorMessage>
) : (
<></>
)}
</>
);
};

FormikErrorMessage.propTypes = {
formik: PropTypes.any,
};

export default FormikErrorMessage;

+ 11
- 0
src/components/Cards/ProfileCard/EditProfile/FormikErrorMessage/FormikErrorMessage.styled.js Näytä tiedosto

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

export const ErrorMessage = styled(Typography)`
color: red;
font-family: ${selectedTheme.fonts.textFont};
position: relative;
top: 20px;
font-size: 14px;
`;

+ 42
- 0
src/components/Cards/ProfileCard/EditProfile/LocationField/LocationField.js Näytä tiedosto

@@ -0,0 +1,42 @@
import React from "react";
import PropTypes from "prop-types";
import AutoSuggestTextField from "../../../../TextFields/AutoSuggestTextField/AutoSuggestTextField";
import { InputFieldLabelLocation } from "./LocationField.styled";
import { useDispatch, useSelector } from "react-redux";
import { selectLocations } from "../../../../../store/selectors/locationsSelectors";
import { useEffect } from "react";
import { fetchLocations } from "../../../../../store/actions/locations/locationsActions";
import { useTranslation } from "react-i18next";

const LocationField = (props) => {
const { t } = useTranslation();
const locations = useSelector(selectLocations);
const dispatch = useDispatch();
useEffect(() => {
if (locations?.length === 0) {
dispatch(fetchLocations());
}
}, [locations]);

return (
<>
<InputFieldLabelLocation
leftText={t("common.labelLocation").toUpperCase()}
/>
<AutoSuggestTextField
editLocation
data={locations.map((item) => ({ name: item.city }))}
value={props.formik.values.firmLocation}
onChange={(event, { newValue }) =>
props.formik.setFieldValue("firmLocation", newValue)
}
/>
</>
);
};

LocationField.propTypes = {
formik: PropTypes.any,
};

export default LocationField;

+ 25
- 0
src/components/Cards/ProfileCard/EditProfile/LocationField/LocationField.styled.js Näytä tiedosto

@@ -0,0 +1,25 @@
import styled from "styled-components";
import { Label } from "../../../../CheckBox/Label";

export const InputFieldLabelLocation = styled(Label)`
position: relative;
bottom: -8px;
margin: 10px 0;
& label {
font-size: 12px;
font-weight: 600;
line-height: 20px;
color: #808080;
cursor: auto;
letter-spacing: 0.2px;
}

@media screen and (max-width: 600px) {
bottom: -12px;
margin: 5px 0 17px 0;
& label {
font-size: 9px;
margin-top: 0;
}
}
`;

+ 29
- 0
src/components/Cards/ProfileCard/EditProfile/PIBField/PIBField.js Näytä tiedosto

@@ -0,0 +1,29 @@
import React from "react";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
import { InputField, InputFieldLabel } from "../EditProfile.styled";

const PIBField = (props) => {
const { t } = useTranslation();
return (
<>
<InputFieldLabel leftText={t("common.labelPIB")} />
<InputField
name="firmPIB"
type="number"
value={props.formik.values.firmPIB}
onChange={props.formik.handleChange}
error={props.formik.touched.firmPIB && props.formik.errors.firmPIB}
margin="normal"
fullWidth
disabled
/>
</>
);
};

PIBField.propTypes = {
formik: PropTypes.any,
};

export default PIBField;

+ 0
- 0
src/components/Cards/ProfileCard/EditProfile/PIBField/PIBField.styled.js Näytä tiedosto


+ 39
- 0
src/components/Cards/ProfileCard/EditProfile/PhoneField/PhoneField.js Näytä tiedosto

@@ -0,0 +1,39 @@
import React from "react";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
import { InputField, InputFieldLabel } from "../EditProfile.styled";

const PhoneField = (props) => {
const { t } = useTranslation();
return (
<>
<InputFieldLabel leftText={t("editProfile.phoneNumber").toUpperCase()} />
<InputField
type="number"
name="firmPhone"
value={props.formik.values.firmPhone}
onChange={(event) => {
props.formik.setFieldValue("firmPhone", event.target.value);
}}
error={props.formik.touched.firmPhone && props.formik.errors.firmPhone}
margin="normal"
fullWidth
onInput={(e) => {
e.target.value =
e.target.value[0] === "0" && e.target.value.length > 1
? "0" +
String(
Math.max(0, parseInt(e.target.value)).toString().slice(0, 14)
)
: Math.max(0, parseInt(e.target.value)).toString().slice(0, 14);
}}
/>
</>
);
};

PhoneField.propTypes = {
formik: PropTypes.any,
};

export default PhoneField;

+ 0
- 0
src/components/Cards/ProfileCard/EditProfile/PhoneField/PhoneField.styled.js Näytä tiedosto


+ 29
- 0
src/components/Cards/ProfileCard/EditProfile/WebsiteField/WebsiteField.js Näytä tiedosto

@@ -0,0 +1,29 @@
import React from "react";
import PropTypes from "prop-types";
import { InputField, InputFieldLabel } from "../EditProfile.styled";
import { useTranslation } from "react-i18next";

const WebsiteField = (props) => {
const { t } = useTranslation();
return (
<>
<InputFieldLabel
leftText={t("editProfile.website").toUpperCase()}
labelWebsite
/>
<InputField
name="firmWebsite"
value={props.formik.values.firmWebsite}
onChange={props.formik.handleChange}
margin="normal"
fullWidth
/>
</>
);
};

WebsiteField.propTypes = {
formik: PropTypes.any,
};

export default WebsiteField;

+ 0
- 0
src/components/Cards/ProfileCard/EditProfile/WebsiteField/WebsiteField.styled.js Näytä tiedosto


src/components/ProfileCard/ProfileCard.js → src/components/Cards/ProfileCard/ProfileCard.js Näytä tiedosto

@@ -13,23 +13,23 @@ import {
} from "./ProfileCard.styled";
import PersonOutlineIcon from "@mui/icons-material/PersonOutline";
import { useRouteMatch } from "react-router-dom";
import { fetchProfile } from "../../store/actions/profile/profileActions";
import { fetchProfile } from "../../../store/actions/profile/profileActions";
import { useDispatch, useSelector } from "react-redux";
import { useEffect } from "react";
import { selectProfile } from "../../store/selectors/profileSelectors";
import { selectUserId } from "../../store/selectors/loginSelectors";
import { selectProfile } from "../../../store/selectors/profileSelectors";
import { selectUserId } from "../../../store/selectors/loginSelectors";
import { useState } from "react";
import { fetchProfileOffers } from "../../store/actions/offers/offersActions";
import { fetchProfileOffers } from "../../../store/actions/offers/offersActions";
import EditProfile from "./EditProfile/EditProfile";
import ProfileMainInfo from "./ProfileMainInfo/ProfileMainInfo";
import ProfileContact from "./ProfileContact/ProfileContact";
import ProfileStats from "./ProfileStats/ProfileStats";
import { useTranslation } from "react-i18next";
import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors";
import { PROFILE_SCOPE } from "../../store/actions/profile/profileActionConstants";
import { selectIsLoadingByActionType } from "../../../store/selectors/loadingSelectors";
import { PROFILE_SCOPE } from "../../../store/actions/profile/profileActionConstants";
import SkeletonProfileCard from "./SkeletonProfileCard/SkeletonProfileCard";
import { useMemo } from "react";
import companyData from "../../notFoundData/companyData";
import companyData from "../../../notFoundData/companyData";

const ProfileCard = () => {
const [isMyProfile, setIsMyProfile] = useState(false);
@@ -51,7 +51,6 @@ const ProfileCard = () => {
return companyData;
}, [profileFromRedux]);

console.log("profile", profile);

useEffect(() => {
if (idProfile?.length > 0) {

src/components/ProfileCard/ProfileCard.styled.js → src/components/Cards/ProfileCard/ProfileCard.styled.js Näytä tiedosto

@@ -1,10 +1,10 @@
import styled from "styled-components";
import { Card, Typography, Grid, Box } from "@mui/material";
import selectedTheme from "../../themes";
import { ReactComponent as Edit } from "../../assets/images/svg/edit.svg";
import selectedTheme from "../../../themes";
import { ReactComponent as Edit } from "../../../assets/images/svg/edit.svg";
// import { ReactComponent as Pocket } from "../../assets/images/svg/pocket.svg";
// import { ReactComponent as Globe } from "../../assets/images/svg/globe.svg";
import { ReactComponent as Mail } from "../../assets/images/svg/mail.svg";
import { ReactComponent as Mail } from "../../../assets/images/svg/mail.svg";
// import { ReactComponent as Location } from "../../assets/images/svg/location.svg";
// import { PRIMARY_PURPLE_COLOR, PRIMARY_YELLOW_COLOR } from '../../constants/stylesConstants';


src/components/ProfileCard/ProfileContact/ProfileContact.js → src/components/Cards/ProfileCard/ProfileContact/ProfileContact.js Näytä tiedosto


src/components/ProfileCard/ProfileContact/ProfileContact.styled.js → src/components/Cards/ProfileCard/ProfileContact/ProfileContact.styled.js Näytä tiedosto

@@ -1,9 +1,9 @@
import styled from "styled-components";
import { Grid, Typography } from "@mui/material";
import { ReactComponent as Location } from "../../../assets/images/svg/location.svg";
import { ReactComponent as Mail } from "../../../assets/images/svg/mail.svg";
import { ReactComponent as Globe } from "../../../assets/images/svg/globe.svg";
import selectedTheme from "../../../themes";
import { ReactComponent as Location } from "../../../../assets/images/svg/location.svg";
import { ReactComponent as Mail } from "../../../../assets/images/svg/mail.svg";
import { ReactComponent as Globe } from "../../../../assets/images/svg/globe.svg";
import selectedTheme from "../../../../themes";

export const ProfileContactContainer = styled(Grid)`
padding-top: 2rem;

src/components/ProfileCard/ProfileMainInfo/ProfileMainInfo.js → src/components/Cards/ProfileCard/ProfileMainInfo/ProfileMainInfo.js Näytä tiedosto

@@ -11,8 +11,8 @@ import {
ProfilePIB,
} from "./ProfileMainInfo.styled";
import { useTranslation } from "react-i18next";
import { getImageUrl, variants } from "../../../util/helpers/imageUrlGetter";
import useIsMobile from "../../../hooks/useIsMobile";
import { getImageUrl, variants } from "../../../../util/helpers/imageUrlGetter";
import useIsMobile from "../../../../hooks/useIsMobile";

const ProfileMainInfo = (props) => {
const { t } = useTranslation();

src/components/ProfileCard/ProfileMainInfo/ProfileMainInfo.styled.js → src/components/Cards/ProfileCard/ProfileMainInfo/ProfileMainInfo.styled.js Näytä tiedosto

@@ -1,7 +1,7 @@
import styled from "styled-components";
import { Grid, Typography } from "@mui/material";
import selectedTheme from "../../../themes";
import { ReactComponent as Pocket } from "../../../assets/images/svg/pocket.svg";
import selectedTheme from "../../../../themes";
import { ReactComponent as Pocket } from "../../../../assets/images/svg/pocket.svg";

export const ProfileMainInfoContainer = styled(Grid)`
display: flex;

src/components/ProfileCard/ProfileStats/ProfileStats.js → src/components/Cards/ProfileCard/ProfileStats/ProfileStats.js Näytä tiedosto


src/components/ProfileCard/ProfileStats/ProfileStats.styled.js → src/components/Cards/ProfileCard/ProfileStats/ProfileStats.styled.js Näytä tiedosto

@@ -1,6 +1,6 @@
import styled from "styled-components";
import { Grid, Typography } from "@mui/material";
import selectedTheme from "../../../themes";
import selectedTheme from "../../../../themes";

export const ProfileStatsContainer = styled(Grid)`
display: flex;

src/components/ProfileCard/SkeletonProfileCard/SkeletonProfileCard.js → src/components/Cards/ProfileCard/SkeletonProfileCard/SkeletonProfileCard.js Näytä tiedosto


src/components/ProfileCard/SkeletonProfileCard/SkeletonProfileCard.styled.js → src/components/Cards/ProfileCard/SkeletonProfileCard/SkeletonProfileCard.styled.js Näytä tiedosto

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

const skeletonAnimation = keyframes`
0% {

+ 1
- 1
src/components/ChatColumn/ChatColumn.js Näytä tiedosto

@@ -14,7 +14,7 @@ import { ReactComponent as Down } from "../../assets/images/svg/down-arrow.svg";
import { IconStyled } from "../Icon/Icon.styled";
import { Grid } from "@mui/material";
import MailOutlineIcon from "@mui/icons-material/MailOutline";
import { HeaderTitle } from "../ProfileCard/ProfileCard.styled";
import { HeaderTitle } from "../Cards/ProfileCard/ProfileCard.styled";
import { useTranslation } from "react-i18next";
import { useDispatch, useSelector } from "react-redux";
import { selectLatestChats } from "../../store/selectors/chatSelectors";

+ 1
- 1
src/components/CreateReview/CreateReview.styled.js Näytä tiedosto

@@ -1,10 +1,10 @@
import { Box, Typography } from "@mui/material";
import styled from "styled-components";
import { PrimaryButton } from "../Buttons/PrimaryButton/PrimaryButton";
import IconButton from "../IconButton/IconButton";
import { ReactComponent as Close } from "../../assets/images/svg/close-modal.svg";
import { ReactComponent as ArrowBack } from "../../assets/images/svg/arrow-back.svg";
import selectedTheme from "../../themes";
import { IconButton } from "../Buttons/IconButton/IconButton";

export const CreateReviewContainer = styled(Box)`
background-color: #fff;

+ 32
- 201
src/components/Header/Header.js Näytä tiedosto

@@ -1,50 +1,25 @@
import React, { useState, useEffect, useRef } from "react";
import {
AuthButtonsContainer,
// EndIcon,
// FilterContainer,
// FilterIcon,
HeaderContainer,
LoginButton,
LogoContainer,
RegisterButton,
// SearchIcon,
// SearchInput,
// SearchInputMobile,
ToolsButtonsContainer,
ToolsContainer,
} from "./Header.styled";
import PropTypes from "prop-types";
import { AppBar, Toolbar, useMediaQuery } from "@mui/material";
import { useTheme } from "@mui/system";
import PopoverComponent from "../Popovers/PopoverComponent";
import { MyPosts } from "../Popovers/MyPosts/MyPosts";
import { MyMessages } from "../Popovers/MyMessages/MyMessages";
import { MyProfile } from "../Popovers/MyProfile/MyProfile";
import { ReactComponent as LogoHorizontal } from "../../assets/images/svg/logo-horizontal.svg";
import selectedTheme from "../../themes";
import { useTranslation } from "react-i18next";
import { useDispatch, useSelector } from "react-redux";
import { selectUserId } from "../../store/selectors/loginSelectors";
import { selectProfileName } from "../../store/selectors/profileSelectors";
import { useHistory, useRouteMatch } from "react-router-dom";
import {
ABOUT_PAGE,
BASE_PAGE,
FORGOT_PASSWORD_MAIL_SENT,
FORGOT_PASSWORD_PAGE,
HOME_PAGE,
LOGIN_PAGE,
REGISTER_PAGE,
REGISTER_SUCCESSFUL_PAGE,
RESET_PASSWORD_PAGE,
} from "../../constants/pages";
import { ABOUT_PAGE, BASE_PAGE, HOME_PAGE } from "../../constants/pages";
import { fetchMineProfile } from "../../store/actions/profile/profileActions";
import CreateOffer from "../Cards/CreateOfferCard/CreateOffer";
import useSearch from "../../hooks/useOffers/useSearch";
import { routeMatches } from "../../util/helpers/routeHelpers";
import { isAuthRoute, routeMatches } from "../../util/helpers/routeHelpers";
import AboutHeader from "./AboutHeader/AboutHeader";
// import { useCallback } from "react";
import SearchInput from "./SearchInput/SearchInput";
import DrawerContainer from "./DrawerContainer/DrawerContainer";
import OpenDrawerButton from "./OpenDrawerButton/OpenDrawerButton";
@@ -52,11 +27,11 @@ import AddOfferButton from "./AddOfferButton/AddOfferButton";
import MySwapsButton from "./MySwapsButton/MySwapsButton";
import MyMessagesButton from "./MyMessagesButton/MyMessagesButton";
import UserButton from "./UserButton/UserButton";
import LoginButton from "./LoginButton/LoginButton";
import RegisterButton from "./RegisterButton/RegisterButton";

const Header = () => {
const setShowSearchBar = useState(true)[1];
const [showCreateOfferModal, setShowCreateOfferModal] = useState(false);
const { t } = useTranslation();
const theme = useTheme();
const searchRef = useRef(null);
const matches = useMediaQuery(theme.breakpoints.down("md"));
@@ -65,85 +40,37 @@ const Header = () => {
const dispatch = useDispatch();
const name = useSelector(selectProfileName);
const history = useHistory();
const routeMatch = useRouteMatch();
const drawerRef = useRef(null);
const [shouldShow, setShouldShow] = useState(true);
const routeMatch = useRouteMatch();

// Dont show header on auth routes(login, register, etc.)
useEffect(() => {
if (isAuthRoute()) setShouldShow(false);
else setShouldShow(true);
}, [routeMatch]);

// Fetch mine profile on loading home page
useEffect(() => {
if (user && user?.length > 0) {
dispatch(fetchMineProfile());
}
}, []);
useEffect(() => {
setUserPopoverOpen(false);
setUserAnchorEl(null);
return () => {
setUserPopoverOpen(false);
setUserAnchorEl(null);
};
}, []);

// Sets value into search input based on query string
useEffect(() => {
if (searchRef.current) {
searchRef.current.value = search.searchString ?? "";
}
}, [search.searchString]);
useEffect(() => {
if (history.location.pathname !== "/home") {
setShowSearchBar(false);
} else {
setShowSearchBar(true);
}
}, [history.location.pathname]);

const closeCreateOfferModal = () => {
setShowCreateOfferModal(false);
};
}, [search.searchString, searchRef.current]);

// Removes scroll when modal is open
if (showCreateOfferModal) {
document.body.style.overflow = "hidden";
} else {
document.body.style.overflow = "auto";
}

const [postsPopoverOpen, setPostsPopoverOpen] = useState(false);
const [postsAnchorEl, setPostsAnchorEl] = useState(null);

const [msgPopoverOpen, setMsgPopoverOpen] = useState(false);
const [msgAnchorEl, setMsgAnchorEl] = useState(null);

const [userPopoverOpen, setUserPopoverOpen] = useState(false);
const [userAnchorEl, setUserAnchorEl] = useState(null);

const [shouldShow, setShouldShow] = useState(true);

useEffect(() => {
let shouldShowHeader = true;
if (
routeMatches(LOGIN_PAGE) ||
routeMatches(REGISTER_PAGE) ||
routeMatches(REGISTER_SUCCESSFUL_PAGE) ||
routeMatches(FORGOT_PASSWORD_PAGE) ||
routeMatches(FORGOT_PASSWORD_MAIL_SENT) ||
routeMatches(RESET_PASSWORD_PAGE)
) {
shouldShowHeader = false;
}
setShouldShow(shouldShowHeader);
}, [location.pathname, user, routeMatch]);

useEffect(() => {
setUserPopoverOpen(false);
setMsgPopoverOpen(false);
setPostsPopoverOpen(false);
}, [location.pathname]);
const handleNavigateLogin = () => {
setShouldShow(false);
history.push(LOGIN_PAGE);
};
const handleNavigateRegister = () => {
setShouldShow(false);
history.push(REGISTER_PAGE);
};

// Handling search when user is on marketplace and when he is not
const handleSearch = (value) => {
if (!routeMatches(HOME_PAGE) && !routeMatches(BASE_PAGE)) {
const newQueryString = new URLSearchParams({ search: value });
@@ -155,10 +82,8 @@ const Header = () => {
search.searchOffers(value);
}
};
// const toggleFilters = () => {
// setOpenFilters((prevState) => !prevState);
// };

// When user clicks logo, he sends specific state so filters can be removed
const handleLogoClick = () => {
history.push({
pathname: HOME_PAGE,
@@ -167,34 +92,12 @@ const Header = () => {
},
});
};

const handleAddOfferClick = () => {
setUserPopoverOpen(false);
setUserAnchorEl(null);
setShowCreateOfferModal(true);
};
const openPostsPopover = (event) => {
setPostsPopoverOpen(true);
setPostsAnchorEl(event.currentTarget);
};
const openMesgPopover = (event) => {
setMsgPopoverOpen(true);
setMsgAnchorEl(event.currentTarget);
};
const openUserPopover = (event) => {
setUserPopoverOpen(true);
setUserAnchorEl(event.currentTarget);
};
const closePostsPopover = () => {
setPostsPopoverOpen(false);
setPostsAnchorEl(null);
};
const closeMsgPopover = () => {
setMsgPopoverOpen(false);
setMsgAnchorEl(null);
};
const closeUserPopover = () => {
setUserPopoverOpen(false);
setUserAnchorEl(null);
const closeCreateOfferModal = () => {
setShowCreateOfferModal(false);
};

return (
@@ -210,11 +113,6 @@ const Header = () => {
<LogoHorizontal />
</LogoContainer>

<DrawerContainer
ref={drawerRef}
showCreateOfferModal={setShowCreateOfferModal}
/>

<SearchInput ref={searchRef} handleSearch={handleSearch} />
{routeMatches(ABOUT_PAGE) && <AboutHeader />}

@@ -232,11 +130,11 @@ const Header = () => {
{!routeMatches(ABOUT_PAGE) && (
<>
<AddOfferButton onClick={handleAddOfferClick} />
<MySwapsButton onClick={openPostsPopover} />
<MyMessagesButton onClick={openMesgPopover} />
<MySwapsButton />
<MyMessagesButton />
</>
)}
<UserButton onClick={openUserPopover} name={name}/>
<UserButton name={name} />
</React.Fragment>
)}
</ToolsButtonsContainer>
@@ -248,87 +146,20 @@ const Header = () => {
/>
) : (
<React.Fragment>
<LoginButton
type="submit"
variant="contained"
fullWidth
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor="white"
onClick={handleNavigateLogin}
>
{t("login.headerTitle")}
</LoginButton>
<RegisterButton
type="submit"
variant="contained"
fullWidth
buttoncolor={selectedTheme.colors.primaryYellow}
textcolor={selectedTheme.colors.yellowButtonTextColor}
onClick={handleNavigateRegister}
>
{t("register.headerTitle")}
</RegisterButton>
<LoginButton />
<RegisterButton />
</React.Fragment>
)}
</AuthButtonsContainer>
)}
</ToolsContainer>
</Toolbar>
{user && (
<React.Fragment>
<PopoverComponent
anchorEl={postsAnchorEl}
open={postsPopoverOpen}
onClose={() => {
setPostsPopoverOpen(false);
setPostsAnchorEl(null);
}}
content={<MyPosts closePopover={closePostsPopover} />}
/>
<PopoverComponent
anchorEl={msgAnchorEl}
open={msgPopoverOpen}
onClose={() => {
setMsgPopoverOpen(false);
setMsgAnchorEl(null);
}}
content={<MyMessages closePopover={closeMsgPopover} />}
/>
<PopoverComponent
anchorEl={userAnchorEl}
open={userPopoverOpen}
onClose={() => {
setUserPopoverOpen(false);
setUserAnchorEl(null);
}}
content={<MyProfile closePopover={closeUserPopover} />}
/>
</React.Fragment>
)}
</AppBar>
{/* <SearchInputMobile
fullWidth
shouldShow={showSearchBar}
ref={searchMobileRef}
placeholder={t("header.searchOffers")}
InputProps={{
endAdornment: (
<EndIcon size="36px">
<SearchIcon
onClick={() => handleSearch(searchMobileRef.current.value)}
/>
</EndIcon>
),
}}
italicPlaceholder
onFocus={handleFocusSearch}
onBlur={handleBlurSearch}
/> */}
{/* <FilterCard
responsive={true}
responsiveOpen={openFilters}
closeResponsive={toggleFilters}
/> */}

<DrawerContainer
ref={drawerRef}
showCreateOfferModal={setShowCreateOfferModal}
/>
{showCreateOfferModal && (
<CreateOffer closeCreateOfferModal={closeCreateOfferModal} />
)}

+ 1
- 15
src/components/Header/Header.styled.js Näytä tiedosto

@@ -1,6 +1,5 @@
import { Box } from "@mui/material";
import styled from "styled-components";
import { PrimaryButton } from "../Buttons/PrimaryButton/PrimaryButton";


export const DrawerContainer = styled(Box)`
@@ -57,20 +56,7 @@ export const ToolsContainer = styled(Box)`
${(props) => props.mobile && `width: auto;`}
}
`;
export const RegisterButton = styled(PrimaryButton)`
height: 49px;
width: 180px;
font-weight: 600;
@media (max-width: 550px) {
margin-bottom: 20px;
}
`;
export const LoginButton = styled(PrimaryButton)`
height: 49px;
width: 180px;
font-weight: 600;
margin-right: 10px;
`;

export const AuthButtonsContainer = styled(Box)`
display: flex;
justify-content: flex-start;

+ 32
- 0
src/components/Header/LoginButton/LoginButton.js Näytä tiedosto

@@ -0,0 +1,32 @@
import React from "react";
import PropTypes from "prop-types";
import { LoginButtonContainer } from "./LoginButton.styled";
import selectedTheme from "../../../themes";
import { useTranslation } from "react-i18next";
import { LOGIN_PAGE } from "../../../constants/pages";
import history from "../../../store/utils/history";

const LoginButton = () => {
const { t } = useTranslation();
const handleNavigateLogin = () => {
history.push(LOGIN_PAGE);
};
return (
<LoginButtonContainer
type="submit"
variant="contained"
fullWidth
buttoncolor={selectedTheme.colors.primaryPurple}
textcolor="white"
onClick={handleNavigateLogin}
>
{t("login.headerTitle")}
</LoginButtonContainer>
);
};

LoginButton.propTypes = {
children: PropTypes.node,
};

export default LoginButton;

+ 9
- 0
src/components/Header/LoginButton/LoginButton.styled.js Näytä tiedosto

@@ -0,0 +1,9 @@
import styled from "styled-components";
import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton";

export const LoginButtonContainer = styled(PrimaryButton)`
height: 49px;
width: 180px;
font-weight: 600;
margin-right: 10px;
`;

+ 43
- 12
src/components/Header/MyMessagesButton/MyMessagesButton.js Näytä tiedosto

@@ -4,20 +4,51 @@ import selectedTheme from "../../../themes";
import { IconButton } from "../../Buttons/IconButton/IconButton";
import MailIcon from "@mui/icons-material/EmailOutlined";
import { Badge } from "@mui/material";
import { useState } from "react";
import PopoverComponent from "../../Popovers/PopoverComponent";
import { MyMessages } from "../../Popovers/MyMessages/MyMessages";
import { useLocation } from "react-router-dom";
import { useEffect } from "react";

const MyMessagesButton = (props) => {
const MyMessagesButton = () => {
const location = useLocation();
const [msgPopoverOpen, setMsgPopoverOpen] = useState(false);
const [msgAnchorEl, setMsgAnchorEl] = useState(null);
useEffect(() => {
setMsgPopoverOpen(false);
}, [location.pathname]);
const openMsgPopover = (event) => {
setMsgPopoverOpen(true);
setMsgAnchorEl(event.currentTarget);
};

const closeMsgPopover = () => {
setMsgPopoverOpen(false);
setMsgAnchorEl(null);
};
return (
<IconButton
onClick={props.onClick}
style={{
background: selectedTheme.colors.primaryIconBackgroundColor,
color: selectedTheme.colors.primaryPurple,
}}
>
<Badge color="primary">
<MailIcon />
</Badge>
</IconButton>
<>
<IconButton
onClick={openMsgPopover}
style={{
background: selectedTheme.colors.primaryIconBackgroundColor,
color: selectedTheme.colors.primaryPurple,
}}
>
<Badge color="primary">
<MailIcon />
</Badge>
</IconButton>
<PopoverComponent
anchorEl={msgAnchorEl}
open={msgPopoverOpen}
onClose={() => {
setMsgPopoverOpen(false);
setMsgAnchorEl(null);
}}
content={<MyMessages closePopover={closeMsgPopover} />}
/>
</>
);
};


+ 42
- 10
src/components/Header/MySwapsButton/MySwapsButton.js Näytä tiedosto

@@ -3,18 +3,50 @@ import PropTypes from "prop-types";
import selectedTheme from "../../../themes";
import { IconButton } from "../../Buttons/IconButton/IconButton";
import { SwapsIcon } from "./MySwapsButton.styled";
import PopoverComponent from "../../Popovers/PopoverComponent";
import { MyPosts } from "../../Popovers/MyPosts/MyPosts";
import { useState } from "react";
import { useEffect } from "react";
import { useLocation } from "react-router-dom";

const MySwapsButton = (props) => {
const MySwapsButton = () => {
const location = useLocation();
const [postsPopoverOpen, setPostsPopoverOpen] = useState(false);
const [postsAnchorEl, setPostsAnchorEl] = useState(null);

useEffect(() => {
setPostsPopoverOpen(false);
}, [location.pathname]);

const openPostsPopover = (event) => {
setPostsPopoverOpen(true);
setPostsAnchorEl(event.currentTarget);
};
const closePostsPopover = () => {
setPostsPopoverOpen(false);
setPostsAnchorEl(null);
};
return (
<IconButton
onClick={props.onClick}
style={{
background: selectedTheme.colors.primaryIconBackgroundColor,
color: selectedTheme.colors.primaryPurple,
}}
>
<SwapsIcon />
</IconButton>
<>
<IconButton
onClick={openPostsPopover}
style={{
background: selectedTheme.colors.primaryIconBackgroundColor,
color: selectedTheme.colors.primaryPurple,
}}
>
<SwapsIcon />
</IconButton>
<PopoverComponent
anchorEl={postsAnchorEl}
open={postsPopoverOpen}
onClose={() => {
setPostsPopoverOpen(false);
setPostsAnchorEl(null);
}}
content={<MyPosts closePopover={closePostsPopover} />}
/>
</>
);
};


+ 32
- 0
src/components/Header/RegisterButton/RegisterButton.js Näytä tiedosto

@@ -0,0 +1,32 @@
import React from "react";
import PropTypes from "prop-types";
import selectedTheme from "../../../themes";
import { RegisterButtonContainer } from "./RegisterButton.styled";
import { useTranslation } from "react-i18next";
import { REGISTER_PAGE } from "../../../constants/pages";
import history from "../../../store/utils/history";

const RegisterButton = () => {
const { t } = useTranslation();
const handleNavigateRegister = () => {
history.push(REGISTER_PAGE);
};
return (
<RegisterButtonContainer
type="submit"
variant="contained"
fullWidth
buttoncolor={selectedTheme.colors.primaryYellow}
textcolor={selectedTheme.colors.yellowButtonTextColor}
onClick={handleNavigateRegister}
>
{t("register.headerTitle")}
</RegisterButtonContainer>
);
};

RegisterButton.propTypes = {
children: PropTypes.node,
};

export default RegisterButton;

+ 11
- 0
src/components/Header/RegisterButton/RegisterButton.styled.js Näytä tiedosto

@@ -0,0 +1,11 @@
import styled from "styled-components";
import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton";

export const RegisterButtonContainer = styled(PrimaryButton)`
height: 49px;
width: 180px;
font-weight: 600;
@media (max-width: 550px) {
margin-bottom: 20px;
}
`;

+ 44
- 12
src/components/Header/UserButton/UserButton.js Näytä tiedosto

@@ -4,26 +4,58 @@ import selectedTheme from "../../../themes";
import { AccountCircle } from "@mui/icons-material";
import { IconButton } from "../../Buttons/IconButton/IconButton";
import { UserButtonContainer, UserName } from "./UserButton.styled";
import PopoverComponent from "../../Popovers/PopoverComponent";
import { MyProfile } from "../../Popovers/MyProfile/MyProfile";
import { useState } from "react";
import { useEffect } from "react";
import { useLocation } from "react-router-dom";

const UserButton = (props) => {
const location = useLocation();
const [userPopoverOpen, setUserPopoverOpen] = useState(false);
const [userAnchorEl, setUserAnchorEl] = useState(null);

useEffect(() => {
setUserPopoverOpen(false);
}, [location.pathname]);

const openUserPopover = (event) => {
setUserPopoverOpen(true);
setUserAnchorEl(event.currentTarget);
};
const closeUserPopover = () => {
setUserPopoverOpen(false);
setUserAnchorEl(null);
};
return (
<UserButtonContainer onClick={props.onClick}>
<UserName>{props.name}</UserName>
<IconButton
style={{
background: selectedTheme.colors.primaryIconBackgroundColor,
color: selectedTheme.colors.primaryPurple,
<>
<UserButtonContainer onClick={openUserPopover}>
<UserName>{props.name}</UserName>
<IconButton
style={{
background: selectedTheme.colors.primaryIconBackgroundColor,
color: selectedTheme.colors.primaryPurple,
}}
>
<AccountCircle />
</IconButton>
</UserButtonContainer>
<PopoverComponent
anchorEl={userAnchorEl}
open={userPopoverOpen}
onClose={() => {
setUserPopoverOpen(false);
setUserAnchorEl(null);
}}
>
<AccountCircle />
</IconButton>
</UserButtonContainer>
content={<MyProfile closePopover={closeUserPopover} />}
/>
</>
);
};

UserButton.propTypes = {
onClick: PropTypes.func,
name: PropTypes.string,
onClick: PropTypes.func,
name: PropTypes.string,
};

export default UserButton;

+ 0
- 32
src/components/IconButton/IconButton.js Näytä tiedosto

@@ -1,32 +0,0 @@
import React, { useRef } from 'react';
import PropType from 'prop-types';

const IconButton = ({ children, onClick, className }) => {
const buttonRef = useRef(null);

function handleClick(event) {
buttonRef.current.blur();
if (typeof onClick === 'function') {
onClick(event);
}
}

return (
<button
type="button"
ref={buttonRef}
onClick={handleClick}
className={`c-icon-button ${className && className}`}
>
{children}
</button>
);
};

IconButton.propTypes = {
children: PropType.node,
onClick: PropType.func,
className: PropType.string,
};

export default IconButton;

+ 1
- 1
src/components/ImagePicker/ImagePicker.js Näytä tiedosto

@@ -30,7 +30,7 @@ const ImagePicker = (props) => {
}
}, [props.image]);

let listener = useCallback(
const listener = useCallback(
(event) => {
if (imageRef.current) {
if (imageRef.current.contains(event.target)) {

+ 5
- 15
src/components/Login/Fields/Password/PasswordField.js Näytä tiedosto

@@ -1,12 +1,12 @@
import React, { forwardRef, useEffect, useState } from "react";
import PropTypes from "prop-types";
import IconButton from "../../../IconButton/IconButton";
import { ReactComponent as VisibilityOn } from "../../../../assets/images/svg/eye-striked.svg";
import { ReactComponent as VisibilityOff } from "../../../../assets/images/svg/eye.svg";
import { useSelector } from "react-redux";
import { selectLoginError } from "../../../../store/selectors/loginSelectors";
import { TextField } from "../../../TextFields/TextField/TextField";
import { useTranslation } from "react-i18next";
import { IconButton } from "../../../Buttons/IconButton/IconButton";

const PasswordField = forwardRef((props, ref) => {
const formik = props.formik;
@@ -14,22 +14,11 @@ const PasswordField = forwardRef((props, ref) => {
const handleClickShowPassword = () => setShowPassword(!showPassword);
const handleMouseDownPassword = () => setShowPassword(!showPassword);
const error = useSelector(selectLoginError);
const {t} = useTranslation();
// useEffect(() => {
// console.log("error", error);
// console.log("formik errors password", formik.errors.password);
// console.log("formik touched", formik.touched);
// console.log("formik.isVaid", formik);
// if (!formik.isValid) formik.setFieldValue("password", "");
// // if (error?.length > 0 || formik.errors.password) {
// // formik.setFieldValue("password", "");
// // console.log(formik.errors.password)
// // }
// }, [formik.isValid])
const { t } = useTranslation();

useEffect(() => {
console.dir(error);
}, [error])
}, [error]);

return (
<TextField
@@ -41,7 +30,8 @@ const PasswordField = forwardRef((props, ref) => {
value={formik.values.password}
onChange={formik.handleChange}
error={
(formik.touched.password && formik.errors.password?.length > 0) || error.length > 0
(formik.touched.password && formik.errors.password?.length > 0) ||
error.length > 0
}
helperText={formik.touched.password && formik.errors.password}
fullWidth

+ 0
- 2
src/components/MarketPlace/Header/Header.js Näytä tiedosto

@@ -60,7 +60,6 @@ const Header = (props) => {
<>
<SkeletonHeader
skeleton={props.skeleton}
animationStage={props.animationStage}
/>
<HeaderContainer skeleton={props.skeleton}>
{/* Setting appropriate header title if page is market place or my offers */}
@@ -154,7 +153,6 @@ Header.propTypes = {
category: PropTypes.string,
myOffers: PropTypes.bool,
skeleton: PropTypes.bool,
animationStage: PropTypes.number,
sorting: PropTypes.any,
};
Header.defaultProps = {

+ 4
- 5
src/components/MarketPlace/Header/SkeletonHeader/SkeletonHeader.js Näytä tiedosto

@@ -5,13 +5,13 @@ import { CircleGroup, SkeletonHeaderCircle, SkeletonHeaderContainer, SkeletonHea
const SkeletonHeader = (props) => {
return (
<SkeletonHeaderContainer skeleton={props.skeleton}>
<SkeletonHeaderLine animationStage={props.animationStage} />
<SkeletonHeaderLine />
<SkeletonRowGroup>
<CircleGroup>
<SkeletonHeaderCircle animationStage={props.animationStage} />
<SkeletonHeaderCircle animationStage={props.animationStage} />
<SkeletonHeaderCircle />
<SkeletonHeaderCircle />
</CircleGroup>
<SkeletonHeaderRightLine animationStage={props.animationStage} />
<SkeletonHeaderRightLine />
</SkeletonRowGroup>
</SkeletonHeaderContainer>
)
@@ -19,7 +19,6 @@ const SkeletonHeader = (props) => {

SkeletonHeader.propTypes = {
skeleton: PropTypes.bool,
animationStage: PropTypes.number,
}

export default SkeletonHeader

+ 0
- 3
src/components/MarketPlace/MarketPlace.js Näytä tiedosto

@@ -16,12 +16,10 @@ const MarketPlace = (props) => {
myOffers={props.myOffers}
sorting={props.offers.sorting}
skeleton={props.skeleton}
animationStage={props.animationStage}
/>
<Offers
isGrid={isGrid}
myOffers={props.myOffers}
animationStage={props.animationStage}
skeleton={props.skeleton}
offers={offers}
toggleFilters={props.toggleFilters}
@@ -33,7 +31,6 @@ const MarketPlace = (props) => {
MarketPlace.propTypes = {
children: PropTypes.node,
myOffers: PropTypes.bool,
animationStage: PropTypes.number,
skeleton: PropTypes.bool,
offers: PropTypes.any,
toggleFilters: PropTypes.func

+ 0
- 2
src/components/MarketPlace/Offers/Offers.js Näytä tiedosto

@@ -73,7 +73,6 @@ const Offers = (props) => {
<SkeletonOfferCard
key={index}
skeleton
animationStage={props.animationStage}
/>
))}
</>
@@ -87,7 +86,6 @@ Offers.propTypes = {
isGrid: PropTypes.bool,
myOffers: PropTypes.bool,
skeleton: PropTypes.bool,
animationStage: PropTypes.number,
offers: PropTypes.any,
toggleFilters: PropTypes.func,
};

+ 1
- 1
src/components/Profile/Profile.js Näytä tiedosto

@@ -1,7 +1,7 @@
import React, { useEffect, useMemo } from "react";
import PropTypes from "prop-types";
import { ProfileContainer } from "./Profile.styled";
import ProfileCard from "../ProfileCard/ProfileCard";
import ProfileCard from "../Cards/ProfileCard/ProfileCard";
import ProfileOffers from "./ProfileOffers/ProfileOffers";
import { useDispatch, useSelector } from "react-redux";
import { selectUserId } from "../../store/selectors/loginSelectors";

+ 26
- 0
src/components/Profile/ProfileOffers/HeaderTitle/HeaderTitle.js Näytä tiedosto

@@ -0,0 +1,26 @@
import React from "react";
import PropTypes from "prop-types";
import {
HeaderTitleContainer,
HeaderTitleText,
OffersIcon,
} from "./HeaderTitle.styled";
import { useTranslation } from "react-i18next";

const HeaderTitle = (props) => {
const { t } = useTranslation();
return (
<HeaderTitleContainer container>
<OffersIcon />
<HeaderTitleText>
{props.isMyProfile ? t("profile.myOffers") : t("profile.profileOffers")}
</HeaderTitleText>
</HeaderTitleContainer>
);
};

HeaderTitle.propTypes = {
isMyProfile: PropTypes.bool,
};

export default HeaderTitle;

+ 32
- 0
src/components/Profile/ProfileOffers/HeaderTitle/HeaderTitle.styled.js Näytä tiedosto

@@ -0,0 +1,32 @@
import { Grid, Typography } from "@mui/material";
import styled from "styled-components";
import { ReactComponent as Package } from "../../../../assets/images/svg/package-gray.svg";
import selectedTheme from "../../../../themes";

export const HeaderTitleText = styled(Typography)`
font-size: 16px;
font-family: ${selectedTheme.fonts.textFont};
color: ${selectedTheme.colors.primaryDarkTextThird};
position: relative;
margin-left: 10px;
@media (max-width: 600px) {
font-size: 12px;
}
`;
export const OffersIcon = styled(Package)`
width: 18px;
height: 18px;
& path {
stroke: ${selectedTheme.colors.primaryDarkTextThird};
}
@media (max-width: 600px) {
width: 12px;
height: 12px;
}
`;
export const HeaderTitleContainer = styled(Grid)`
flex-direction: row;
justify-content: start;
align-items: center;
margin-bottom: 8px;
`

+ 21
- 120
src/components/Profile/ProfileOffers/ProfileOffers.js Näytä tiedosto

@@ -1,26 +1,14 @@
import React from "react";
import PropTypes from "prop-types";
import {
DownArrow,
HeaderSelect,
HeaderTitle,
IconContainer,
OffersContainer,
OffersIcon,
OffersScroller,
ProfileOffersContainer,
SearchIcon,
SearchInput,
SelectOption,
} from "./ProfileOffers.styled";
import { Grid } from "@mui/material";
import { useState } from "react";
import { sortEnum } from "../../../enums/sortEnum";
import { useEffect } from "react";
import { useSelector } from "react-redux";
import OfferCard from "../../Cards/OfferCard/OfferCard";
import { useTranslation } from "react-i18next";
import { useRef } from "react";
import { selectProfileOffers } from "../../../store/selectors/offersSelectors";
import { selectLatestChats } from "../../../store/selectors/chatSelectors";
import { useHistory } from "react-router-dom";
@@ -31,19 +19,21 @@ import { OFFERS_PROFILE_SCOPE } from "../../../store/actions/offers/offersAction
import SkeletonOfferCard from "../../Cards/OfferCard/SkeletonOfferCard/SkeletonOfferCard";
import useIsMobile from "../../../hooks/useIsMobile";
import ProfileOffersHeaderSkeleton from "./ProfileOffersHeaderSkeleton/ProfileOffersHeaderSkeleton";
import SelectSortField from "./SelectSortField/SelectSortField";
import HeaderTitle from "./HeaderTitle/HeaderTitle";
import SearchBar from "./SearchBar/SearchBar";
import { replaceInRoute } from "../../../util/helpers/routeHelpers";
import { CHAT_MESSAGE_PAGE } from "../../../constants/pages";

const ProfileOffers = (props) => {
const [sortOption, setSortOption] = useState(sortEnum.INITIAL);
const [offersToShow, setOffersToShow] = useState([]);
const isLoadingMineOffers = useSelector(
selectIsLoadingByActionType(OFFERS_PROFILE_SCOPE)
);
const searchRef = useRef(null);
const chats = useSelector(selectLatestChats);
const profileOffers = useSelector(selectProfileOffers);
const { isMobile } = useIsMobile();
const history = useHistory();
const { t } = useTranslation();
const userId = useSelector(selectUserId);
const arrayForMapping = Array.apply(null, Array(4)).map(() => {});

@@ -52,133 +42,44 @@ const ProfileOffers = (props) => {
(item) => item.chat.offerId === offer?.offer?._id
);
if (chatItem !== undefined) {
history.push(`/messages/${chatItem.chat._id}`);
history.push(
replaceInRoute(CHAT_MESSAGE_PAGE, { idChat: chatItem.chat._id })
);
} else {
if (offer?.offer?.userId !== userId) {
history.push(`/messages/newMessage`, {
offerId: offer?.offer?._id,
});
history.push(
replaceInRoute(CHAT_MESSAGE_PAGE, { idChat: "newMessage" }),
{
offerId: offer?.offer?._id,
}
);
}
}
};

useEffect(() => {
let newOffersToShow = [...offersToShow];
if (sortOption.value === sortEnum.OLD.value) {
newOffersToShow.sort(
(a, b) => new Date(a._created) - new Date(b._created)
);
}
if (sortOption.value === sortEnum.NEW.value) {
newOffersToShow.sort(
(a, b) => new Date(b._created) - new Date(a._created)
);
}
if (sortOption.value === sortEnum.POPULAR.value) {
newOffersToShow.sort(
(a, b) => a.views.viewers.length - b.views.viewers.length
);
}
setOffersToShow([...newOffersToShow]);
}, [sortOption]);

useEffect(() => {
if (profileOffers) setOffersToShow(profileOffers);
}, [profileOffers]);

const handleSearch = () => {
const valueToSearch = searchRef?.current?.value;
const handleSearch = (value) => {
let newOffersToShow = profileOffers.filter((item) =>
item.name.toLowerCase().includes(valueToSearch.toLowerCase())
item.name.toLowerCase().includes(value.toLowerCase())
);
setOffersToShow([...newOffersToShow]);
};

const handleChangeSelect = (event) => {
let chosenOption;
for (const sortOption in sortEnum) {
if (sortEnum[sortOption].value === event.target.value) {
chosenOption = sortEnum[sortOption];
setSortOption(chosenOption);
}
}
};

let listener;
const handleFocusSearch = () => {
listener = (event) => {
if (event.keyCode === 13) {
event.preventDefault();
handleSearch();
}
};
searchRef.current.addEventListener("keyup", listener);
};

const handleBlurSearch = () => {
searchRef.current.removeEventListener("keyup", listener);
};

return (
<ProfileOffersContainer>
{isLoadingMineOffers || isLoadingMineOffers === undefined ? (
<ProfileOffersHeaderSkeleton />
) : (
<>
<HeaderSelect
value={
sortOption?.value ? sortOption.value : sortEnum.INITIAL.value
}
IconComponent={DownArrow}
onChange={handleChangeSelect}
>
<SelectOption
value={sortEnum.INITIAL.value}
key={sortEnum.INITIAL.value}
style={{ display: "none" }}
>
{sortEnum.INITIAL.mainText}
</SelectOption>
{Object.keys(sortEnum).map((property) => {
if (sortEnum[property].value === sortEnum.INITIAL.value) return;
return (
<SelectOption
value={sortEnum[property].value}
key={sortEnum[property].value}
>
{sortEnum[property].mainText}
</SelectOption>
);
})}
</HeaderSelect>
<Grid
container
direction="row"
justifyContent="start"
alignItems="center"
sx={{ mb: 1.4 }}
>
<OffersIcon />
<HeaderTitle>
{props.isMyProfile ? "Moje objave" : "Objave kompanije"}
</HeaderTitle>
</Grid>
<SearchInput
fullWidth
ref={searchRef}
onFocus={handleFocusSearch}
onBlur={handleBlurSearch}
// ref={searchRef}
placeholder={t("header.searchOffers")}
italicPlaceholder
InputProps={{
endAdornment: (
<IconContainer onClick={handleSearch}>
<SearchIcon />
</IconContainer>
),
}}
<SelectSortField
offersToShow={offersToShow}
setOffersToShow={setOffersToShow}
/>
<HeaderTitle isMyProfile={props.isMyProfile} />
<SearchBar handleSearch={handleSearch} />
</>
)}
<OffersContainer>

+ 1
- 85
src/components/Profile/ProfileOffers/ProfileOffers.styled.js Näytä tiedosto

@@ -1,13 +1,5 @@
import { Box, Typography } from "@mui/material";
import { Box } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../themes";
import { ReactComponent as Search } from "../../../assets/images/svg/magnifying-glass.svg";
import { ReactComponent as Package } from "../../../assets/images/svg/package-gray.svg";
import { TextField } from "../../TextFields/TextField/TextField";
import { Icon } from "../../Icon/Icon";
import Select from "../../Select/Select";
import Option from "../../Select/Option/Option";
import { ReactComponent as Down } from "../../../assets/images/svg/down-arrow.svg";
import HorizontalScroller from "../../Scroller/HorizontalScroller";

export const ProfileOffersContainer = styled(Box)`
@@ -23,82 +15,6 @@ export const ProfileOffersContainer = styled(Box)`
padding: 0;
}
`;
export const HeaderTitle = styled(Typography)`
font-size: 16px;
font-family: ${selectedTheme.fonts.textFont};
color: ${selectedTheme.colors.primaryDarkTextThird};
position: relative;
margin-left: 10px;
@media (max-width: 600px) {
font-size: 12px;
}
`;
export const OffersIcon = styled(Package)`
width: 18px;
height: 18px;
& path {
stroke: ${selectedTheme.colors.primaryDarkTextThird};
}
@media (max-width: 600px) {
width: 12px;
height: 12px;
}
`;
export const SearchInput = styled(TextField)`
position: relative;
top: 15px;
& div fieldset {
border-color: ${selectedTheme.colors.primaryPurple} !important;
}
@media (max-width: 600px) {
top: 5px;
height: 46px;
& div {
background-color: white;
}
}
`;
export const SearchIcon = styled(Search)`
width: 18px;
height: 18px;
`;
export const IconContainer = styled(Icon)`
cursor: pointer;
position: relative;
top: 4px;
`;
export const HeaderSelect = styled(Select)`
width: 210px;
height: 35px;
font-family: ${selectedTheme.fonts.textFont};
margin-top: 3px;
font-weight: 400;
position: absolute;
top: -8px;
right: 50px;
& div:first-child {
padding-left: 8px;
}

@media (max-width: 1200px) {
right: 36px;
}

@media (max-width: 650px) {
width: 144px;
height: 30px;
font-size: 14px;
right: 1px;
}
`;
export const SelectOption = styled(Option)`
@media (max-width: 600px) {
height: 20px !important;
min-height: 35px;
margin: 2px;
}
`;
export const DownArrow = styled(Down)``;
export const OffersContainer = styled(Box)`
margin-top: 30px;
`;

+ 24
- 16
src/components/Profile/ProfileOffers/ProfileOffersHeaderSkeleton/ProfileOffersHeaderSkeleton.js Näytä tiedosto

@@ -1,24 +1,32 @@
import React from 'react'
import PropTypes from 'prop-types'
import { ProfileOffersHeaderSkeletonContainer, ProfileOffersHeaderSkeletonGroupOne, ProfileOffersHeaderSkeletonGroupSecond, ProfileOffersHeaderSkeletonLineForth, ProfileOffersHeaderSkeletonLineOne, ProfileOffersHeaderSkeletonLineSecond, ProfileOffersHeaderSkeletonLineThird } from './ProfileOffersHeaderSkeleton.styled'
import React from "react";
import PropTypes from "prop-types";
import {
ProfileOffersHeaderSkeletonContainer,
ProfileOffersHeaderSkeletonGroupOne,
ProfileOffersHeaderSkeletonGroupSecond,
ProfileOffersHeaderSkeletonLineForth,
ProfileOffersHeaderSkeletonLineOne,
ProfileOffersHeaderSkeletonLineSecond,
ProfileOffersHeaderSkeletonLineThird,
} from "./ProfileOffersHeaderSkeleton.styled";

const ProfileOffersHeaderSkeleton = () => {
return (
<ProfileOffersHeaderSkeletonContainer>
<ProfileOffersHeaderSkeletonGroupOne>
<ProfileOffersHeaderSkeletonLineOne />
<ProfileOffersHeaderSkeletonLineSecond />
</ProfileOffersHeaderSkeletonGroupOne>
<ProfileOffersHeaderSkeletonGroupSecond>
<ProfileOffersHeaderSkeletonLineThird />
<ProfileOffersHeaderSkeletonLineForth />
</ProfileOffersHeaderSkeletonGroupSecond>
<ProfileOffersHeaderSkeletonGroupOne>
<ProfileOffersHeaderSkeletonLineOne />
<ProfileOffersHeaderSkeletonLineSecond />
</ProfileOffersHeaderSkeletonGroupOne>
<ProfileOffersHeaderSkeletonGroupSecond>
<ProfileOffersHeaderSkeletonLineThird />
<ProfileOffersHeaderSkeletonLineForth />
</ProfileOffersHeaderSkeletonGroupSecond>
</ProfileOffersHeaderSkeletonContainer>
)
}
);
};

ProfileOffersHeaderSkeleton.propTypes = {
children: PropTypes.node,
}
children: PropTypes.node,
};

export default ProfileOffersHeaderSkeleton
export default ProfileOffersHeaderSkeleton;

+ 1
- 1
src/components/Profile/ProfileOffers/ProfileOffersHeaderSkeleton/ProfileOffersHeaderSkeleton.styled.js Näytä tiedosto

@@ -3,7 +3,7 @@ import styled from "styled-components";
import {
SkeletonBackgroundColor,
SkeletonItemBackgroundColor,
} from "../../../ProfileCard/SkeletonProfileCard/SkeletonProfileCard.styled";
} from "../../../Cards/ProfileCard/SkeletonProfileCard/SkeletonProfileCard.styled";

export const ProfileOffersHeaderSkeletonContainer = styled(Box)`
display: flex;

+ 53
- 0
src/components/Profile/ProfileOffers/SearchBar/SearchBar.js Näytä tiedosto

@@ -0,0 +1,53 @@
import React from "react";
import PropTypes from "prop-types";
import { IconContainer, SearchIcon, SearchInput } from "./SearchBar.styled";
import { useCallback } from "react";
import { useRef } from "react";
import { useTranslation } from "react-i18next";

const SearchBar = (props) => {
const searchRef = useRef(null);
const { t } = useTranslation();
let listener = useCallback(
(event) => {
if (event.keyCode === 13) {
event.preventDefault();
props.handleSearch(searchRef.current?.value);
}
},
[searchRef]
);

const handleFocusSearch = () => {
searchRef.current.addEventListener("keyup", listener);
};
const handleBlurSearch = () => {
searchRef.current.removeEventListener("keyup", listener);
};

return (
<SearchInput
fullWidth
ref={searchRef}
onFocus={handleFocusSearch}
onBlur={handleBlurSearch}
placeholder={t("header.searchOffers")}
italicPlaceholder
InputProps={{
endAdornment: (
<IconContainer
onClick={() => props.handleSearch(searchRef.current?.value)}
>
<SearchIcon />
</IconContainer>
),
}}
/>
);
};

SearchBar.propTypes = {
handleSearch: PropTypes.func,
};

export default SearchBar;

+ 29
- 0
src/components/Profile/ProfileOffers/SearchBar/SearchBar.styled.js Näytä tiedosto

@@ -0,0 +1,29 @@
import styled from "styled-components";
import selectedTheme from "../../../../themes";
import { TextField } from "../../../TextFields/TextField/TextField";
import { ReactComponent as Search } from "../../../../assets/images/svg/magnifying-glass.svg";
import { Icon } from "../../../Icon/Icon";

export const SearchInput = styled(TextField)`
position: relative;
top: 15px;
& div fieldset {
border-color: ${selectedTheme.colors.primaryPurple} !important;
}
@media (max-width: 600px) {
top: 5px;
height: 46px;
& div {
background-color: white;
}
}
`;
export const SearchIcon = styled(Search)`
width: 18px;
height: 18px;
`;
export const IconContainer = styled(Icon)`
cursor: pointer;
position: relative;
top: 4px;
`;

+ 76
- 0
src/components/Profile/ProfileOffers/SelectSortField/SelectSortField.js Näytä tiedosto

@@ -0,0 +1,76 @@
import React from "react";
import PropTypes from "prop-types";
import {
DownArrow,
HeaderSelect,
SelectOption,
} from "./SelectSortField.styled";
import { sortEnum } from "../../../../enums/sortEnum";
import { useState } from "react";
import { useEffect } from "react";

const SelectSortField = (props) => {
const [sortOption, setSortOption] = useState(sortEnum.INITIAL);

useEffect(() => {
let newOffersToShow = [...props.offersToShow];
if (sortOption.value === sortEnum.OLD.value) {
newOffersToShow.sort(
(a, b) => new Date(a._created) - new Date(b._created)
);
}
if (sortOption.value === sortEnum.NEW.value) {
newOffersToShow.sort(
(a, b) => new Date(b._created) - new Date(a._created)
);
}
if (sortOption.value === sortEnum.POPULAR.value) {
newOffersToShow.sort((a, b) => b.views.count - a.views.count);
}
props.setOffersToShow([...newOffersToShow]);
}, [sortOption]);
const handleChangeSelect = (event) => {
let chosenOption;
console.log(sortOption);
for (const sortOption in sortEnum) {
if (sortEnum[sortOption].value === event.target.value) {
chosenOption = sortEnum[sortOption];
console.log(chosenOption);
setSortOption(chosenOption);
}
}
};
return (
<HeaderSelect
value={sortOption?.value ? sortOption.value : sortEnum.INITIAL.value}
IconComponent={DownArrow}
onChange={handleChangeSelect}
>
<SelectOption
value={sortEnum.INITIAL.value}
key={sortEnum.INITIAL.value}
style={{ display: "none" }}
>
{sortEnum.INITIAL.mainText}
</SelectOption>
{Object.keys(sortEnum).map((property) => {
if (sortEnum[property].value === sortEnum.INITIAL.value) return;
return (
<SelectOption
value={sortEnum[property].value}
key={sortEnum[property].value}
>
{sortEnum[property].mainText}
</SelectOption>
);
})}
</HeaderSelect>
);
};

SelectSortField.propTypes = {
offersToShow: PropTypes.array,
setOffersToShow: PropTypes.func,
};

export default SelectSortField;

+ 38
- 0
src/components/Profile/ProfileOffers/SelectSortField/SelectSortField.styled.js Näytä tiedosto

@@ -0,0 +1,38 @@
import styled from "styled-components";
import Select from "../../../Select/Select";
import Option from "../../../Select/Option/Option";
import { ReactComponent as Down } from "../../../../assets/images/svg/down-arrow.svg";
import selectedTheme from "../../../../themes";

export const HeaderSelect = styled(Select)`
width: 210px;
height: 35px;
font-family: ${selectedTheme.fonts.textFont};
margin-top: 3px;
font-weight: 400;
position: absolute;
top: -8px;
right: 50px;
& div:first-child {
padding-left: 8px;
}

@media (max-width: 1200px) {
right: 36px;
}

@media (max-width: 650px) {
width: 144px;
height: 30px;
font-size: 14px;
right: 1px;
}
`;
export const SelectOption = styled(Option)`
@media (max-width: 600px) {
height: 20px !important;
min-height: 35px;
margin: 2px;
}
`;
export const DownArrow = styled(Down)``;

+ 0
- 274
src/components/ProfileCard/EditProfile/EditProfile.js Näytä tiedosto

@@ -1,274 +0,0 @@
import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import BackdropComponent from "../../MUI/BackdropComponent";
import {
EditProfileContainer,
ProfileImageContainer,
InputFieldLabel,
InputField,
BackButton,
CloseButton,
SaveButton,
ProfileHeader,
BasicInfo,
DetailsInfo,
ButtonsContainer,
ErrorMessage,
ProfileImagePicker,
InputFieldLabelLocation,
} from "./EditProfile.styled";
import selectedTheme from "../../../themes";
import { useFormik } from "formik";
import { ReactComponent as ArrowBack } from "../../../assets/images/svg/arrow-back.svg";
import { ReactComponent as CloseIcon } from "../../../assets/images/svg/close-modal.svg";
import { useTranslation } from "react-i18next";
import {
editMineProfile,
fetchMineProfile,
} from "../../../store/actions/profile/profileActions";
import { useDispatch, useSelector } from "react-redux";
import { selectUserId } from "../../../store/selectors/loginSelectors";
import editProfileValidation from "../../../validations/editProfileValidation";
import useIsMobile from "../../../hooks/useIsMobile";
import AutoSuggestTextField from "../../TextFields/AutoSuggestTextField/AutoSuggestTextField";
import { selectLocations } from "../../../store/selectors/locationsSelectors";

const EditProfile = (props) => {
const [profileImage, setProfileImage] = useState(props.profile.image);
const [showBasic, setShowBasic] = useState(true);
const [showDetails, setShowDetails] = useState(true);
const { t } = useTranslation();
const dispatch = useDispatch();
const { isMobile } = useIsMobile();
const userId = useSelector(selectUserId);
const locations = useSelector(selectLocations);

useEffect(() => {
if (isMobile) {
setShowDetails(false);
} else {
setShowDetails(true);
}
}, [isMobile]);

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

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

const formik = useFormik({
initialValues: {
firmName: `${props?.profile?.company?.name}`,
firmPIB: `${props?.profile?.company?.PIB}`,
firmLocation: `${props?.profile?.company?.contacts?.location ?? ""}`,
firmWebsite: `${props?.profile?.company?.contacts?.web ?? ""}`,
firmApplink: "",
firmPhone: `${props?.profile?.company?.contacts?.telephone ?? ""}`,
firmLogo: profileImage,
},
validationSchema: editProfileValidation,
onSubmit: handleSubmit,
validateOnBlur: true,
enableReinitialize: true,
});

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

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

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

return (
<>
<BackdropComponent
handleClose={closeEditModalHandler}
isLoading
position="fixed"
/>
<EditProfileContainer component="form" onSubmit={formik.handleSubmit}>
{!showBasic && (
<BackButton onClick={showDetailsHandler}>
<ArrowBack />
</BackButton>
)}
<ProfileImageContainer>
<ProfileImagePicker
image={profileImage}
setImage={setImage}
></ProfileImagePicker>
<ProfileHeader>{props.profile.company.name}</ProfileHeader>
</ProfileImageContainer>
<CloseButton onClick={closeEditModalHandler}>
<CloseIcon />
</CloseButton>
{showBasic && (
<BasicInfo>
<InputFieldLabel leftText={t("common.labelFirm").toUpperCase()} />
<InputField
name="firmName"
value={formik.values.firmName}
onChange={formik.handleChange}
error={formik.touched.firmName && formik.errors.firmName}
margin="normal"
fullWidth
/>
<InputFieldLabel leftText={t("common.labelPIB")} />
<InputField
name="firmPIB"
type="number"
value={formik.values.firmPIB}
onChange={formik.handleChange}
error={formik.touched.firmPIB && formik.errors.firmPIB}
margin="normal"
fullWidth
disabled
/>
<InputFieldLabelLocation
leftText={t("common.labelLocation").toUpperCase()}
/>
<AutoSuggestTextField
editLocation
data={locations.map((item) => ({ name: item.city }))}
value={formik.values.firmLocation}
onChange={(event, { newValue }) =>
formik.setFieldValue("firmLocation", newValue)
}
/>
{/* <InputField
name="firmLocation"
value={formik.values.firmLocation}
onChange={formik.handleChange}
error={formik.touched.firmLocation && formik.errors.firmLocation}
margin="normal"
fullWidth
/> */}
</BasicInfo>
)}
{showDetails && (
<DetailsInfo>
<InputFieldLabel
leftText={t("editProfile.website").toUpperCase()}
labelWebsite
/>
<InputField
name="firmWebsite"
value={formik.values.firmWebsite}
onChange={formik.handleChange}
margin="normal"
fullWidth
/>
<InputFieldLabel
leftText={t("editProfile.applink").toUpperCase()}
/>
<InputField
name="firmApplink"
values={formik.values.firmApplink}
margin="normal"
fullWidth
/>
<InputFieldLabel
leftText={t("editProfile.phoneNumber").toUpperCase()}
/>
<InputField
type="number"
name="firmPhone"
value={formik.values.firmPhone}
onChange={(event) => {
formik.setFieldValue("firmPhone", event.target.value);
}}
error={formik.touched.firmPhone && formik.errors.firmPhone}
margin="normal"
fullWidth
onInput={(e) => {
e.target.value =
e.target.value[0] === "0" && e.target.value.length > 1
? "0" +
String(
Math.max(0, parseInt(e.target.value))
.toString()
.slice(0, 14)
)
: Math.max(0, parseInt(e.target.value))
.toString()
.slice(0, 14);
}}
/>
</DetailsInfo>
)}

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

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

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

export default EditProfile;

+ 21
- 0
src/components/Router/AuthRoute.js Näytä tiedosto

@@ -0,0 +1,21 @@
import React, { useMemo } from "react";
import { Redirect, Route } from "react-router";
import { useSelector } from "react-redux";
import { BASE_PAGE } from "../../constants/pages";
import { selectUserId } from "../../store/selectors/loginSelectors";

const AuthRoute = ({ ...props }) => {
const userId = useSelector(selectUserId);
const isUserAuthenticated = useMemo(() => {
if (userId?.length === 0) return false;
return true;
}, [userId]);

return !isUserAuthenticated ? (
<Route {...props} />
) : (
<Redirect to={BASE_PAGE} />
);
};

export default AuthRoute;

+ 14
- 11
src/i18n/resources/rs.js Näytä tiedosto

@@ -100,9 +100,10 @@ export default {
welcome: "Dobro došli na trampu, želimo vam uspešno trampovanje!",
imageError: "Slika je obavezna!",
serverError: "Greška sa serverom!",
phoneNumberNoOfCharacters: "Broj telefona mora imati izmedju 6 i 15 karaktera!",
phoneNumberNoOfCharacters:
"Broj telefona mora imati izmedju 6 i 15 karaktera!",
locationError: "Odaberite ispravnu lokaciju!",
websiteError: "Unesite ispravnu adresu svog website!"
websiteError: "Unesite ispravnu adresu svog website!",
},
forgotPassword: {
title: "Povrati lozinku",
@@ -171,11 +172,11 @@ export default {
newOffer: "Nova Objava",
product: "Proizvod",
descriptionLabel: "Opis:",
checkButtonLabel: "Pogledaj proizvod"
checkButtonLabel: "Pogledaj proizvod",
},
apiErrors: {
somethingWentWrong: "Greška sa serverom!",
offerNotFound: "Ponuda nije pronađena!"
offerNotFound: "Ponuda nije pronađena!",
},
header: {
addOffer: "Dodaj proizvod",
@@ -205,7 +206,7 @@ export default {
leaveComment: "Ostavi komentar",
rates: "Ocene kompanije",
finishedReviewTitle: "Hvala vam",
finishedReviewAltTitle: "na izdvojenom vremenu i datoj oceni!"
finishedReviewAltTitle: "na izdvojenom vremenu i datoj oceni!",
},
messages: {
headerTitle: "Moje Ćaskanje",
@@ -214,7 +215,7 @@ export default {
send: "Pošalji",
sendPlaceholder: "Poruka...",
seeChats: "Pogledaj ćaskanje",
noMessagesToast: "Nemate ni jednu poruku!"
noMessagesToast: "Nemate ni jednu poruku!",
},
editProfile: {
website: "Web Sajt*",
@@ -270,11 +271,13 @@ export default {
altText: "Nažalost nemate ni jednu objavu",
},
backToHome: "Nazad na sve objave",
myOffers: "Moje objave",
profileOffers: "Objave kompanije",
},
about: {
header: {
title: "O Trampi",
navigation: 'O nama',
navigation: "O nama",
paragraph:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ac augue tortor. Nulla facilisi. Cras vestibulum risus eget tincidunt egestas. Duis blandit enim sit amet dui vehicula luctus. Suspendisse id blandit arcu, vitae consequat nisi. Duis ut vestibulum tellus. Curabitur eu fringilla nisi.",
},
@@ -315,7 +318,7 @@ export default {
prices: {
header: {
title: "Cenovnik",
navigation: 'Cenovnik',
navigation: "Cenovnik",
link: "Pročitajte opširnije o našim ponudama",
},
altText:
@@ -369,7 +372,7 @@ export default {
},
aboutFooter: {
goStart: "Početak stranice",
middleText: "Diligent Software © 2022 | Sva prava zadržana"
middleText: "Diligent Software © 2022 | Sva prava zadržana",
},
notFoundData: {
PIB: "PIB broj",
@@ -380,6 +383,6 @@ export default {
offerName: "Naslov ponude",
condition: "Stanje",
description: "Opis",
email: "Mejl kompanije"
}
email: "Mejl kompanije",
},
};

+ 9
- 0
src/initialValues/editProfileInitialValues.js Näytä tiedosto

@@ -0,0 +1,9 @@
export default (profile) => ({
firmName: profile?.company?.name,
firmPIB: profile?.company?.PIB,
firmLocation: profile?.company?.contacts?.location ?? "",
firmWebsite: profile?.company?.contacts?.web ?? "",
firmApplink: "",
firmPhone: profile?.company?.contacts?.telephone ?? "",
firmLogo: profile?.image,
})

+ 17
- 16
src/layouts/ProfileLayout/ProfileLayout.js Näytä tiedosto

@@ -1,25 +1,25 @@
import React from "react";
import PropTypes from "prop-types";
import { Content, RightCard, ProfileLayoutContainer, HeaderCard, MiddleCard } from "./ProfileLayout.styled";
import { Grid } from "@mui/material";
import {
ContentRightCardContainer,
Content,
RightCard,
ProfileLayoutContainer,
} from "./ProfileLayout.styled";

const ProfileLayout = (props) => {
return (
<ProfileLayoutContainer>
<ProfileLayoutContainer
singleOffer={props.singleOffer}
profile={props.profile}
>
{props.children}
<Grid container maxHeight maxWidth={1900}>
<MiddleCard item xs={9.5} lg={6.5} xl={6.6} md={6}>
<HeaderCard>
{props.headerCard}
</HeaderCard>
<Content>
{props.content}
</Content>
</MiddleCard>
<RightCard item xs={2.5} lg={3} xl={3} md={3}>
{props.rightCard}
<ContentRightCardContainer>
<Content item>{props.content}</Content>
<RightCard item singleOffer={props.singleOffer} profile={props.profile}>
{props.rightCard}
</RightCard>
</Grid>
</ContentRightCardContainer>
</ProfileLayoutContainer>
);
};
@@ -29,7 +29,8 @@ ProfileLayout.propTypes = {
leftCard: PropTypes.node,
content: PropTypes.node,
rightCard: PropTypes.node,
headerCard: PropTypes.node,
singleOffer: PropTypes.bool,
profile: PropTypes.bool,
};

export default ProfileLayout;

+ 45
- 32
src/layouts/ProfileLayout/ProfileLayout.styled.js Näytä tiedosto

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

export const ProfileLayoutContainer = styled(Container)`
padding-left: 0;
padding-right: 0;
margin: 0;
width: 100%;
display: flex;
max-width: none;
flex: 1;
height: 100%;
margin-top: 80px;
@media (max-width: 600px) {
margin-top: 40px;
}
`
padding-left: 36px;
padding-right: ${(props) => (props.singleOffer ? "76px" : 0)};
margin: 0;
width: 100%;
max-width: none;
/* display: flex; */
position: relative;
/* flex: 1; */
height: 100%;
@media (max-width: 1200px) {
padding-right: ${(props) => (props.profile ? 0 : "36px")};
}
@media (max-width: 600px) {
padding-left: 18px;
padding-right: ${(props) => (props.profile ? 0 : "18px")};
}
`;

export const LeftCard = styled(Grid)`
margin-top: 30px;
export const ContentRightCardContainer = styled(Box)`
display: flex;

@media screen and (max-width: 600px) {
flex-direction: column;
}
`;

export const RightCard = styled(Grid)`
margin-top: 0;
margin-left: 0;
padding-left: 0;
${(props) => props.profile && `min-width: 350px;`}

@media screen and (min-width: 600px) {
margin-top: 34px;
margin-left: ${(props) => (props.profile ? "0" : "36px")};
padding-left: ${(props) => (props.singleOffer ? "36px" : 0)};
border-top-right-radius: 4px;
background-color: green;
`
${(props) => props.singleOffer && `width: 100%`}
}

@media screen and (max-width: 1200px) {
margin-left: 0;
}
`;
export const Content = styled(Grid)`
background-color: yellow;
height: 100%;
`
export const RightCard = styled(Grid)`
margin-top: 30px;
border-top-left-radius: 4px;
background-color: blue;
`
export const MiddleCard = styled(Grid)`
`
export const HeaderCard = styled(Box)`
height: 450px;
background-color: orange;
`
width: 100%;
`;

+ 0
- 7
src/pages/HomePage/HomePageMUI.js Näytä tiedosto

@@ -7,7 +7,6 @@ import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelect
import { useSelector } from "react-redux";
import { OFFERS_SCOPE } from "../../store/actions/offers/offersActionConstants";
import useOffers from "../../hooks/useOffers/useOffers";
import useSkeleton from "../../hooks/useSkeleton";

const HomePage = () => {
const isLoadingOffers = useSelector(
@@ -15,10 +14,6 @@ const HomePage = () => {
);
const [filtersOpened, setFiltersOpened] = useState(false);
const offers = useOffers();
const { transitionStage } = useSkeleton({
timeoutInterval: 900,
isLoadingIndicator: isLoadingOffers,
});
const toggleFilters = () => {
setFiltersOpened((prevFiltersOpened) => !prevFiltersOpened);
};
@@ -31,7 +26,6 @@ const HomePage = () => {
offers={offers}
filtersOpened={filtersOpened}
skeleton={isLoadingOffers}
animationStage={transitionStage}
toggleFilters={toggleFilters}
/>
}
@@ -39,7 +33,6 @@ const HomePage = () => {
<MarketPlace
offers={offers}
skeleton={isLoadingOffers}
animationStage={transitionStage}
toggleFilters={toggleFilters}
/>
}

+ 0
- 7
src/pages/MyOffers/MyOffers.js Näytä tiedosto

@@ -5,7 +5,6 @@ import MainLayout from "../../layouts/MainLayout/MainLayout";
import FilterCard from "../../components/Cards/FilterCard/FilterCard";
import MarketPlace from "../../components/MarketPlace/MarketPlace";
import useMyOffers from "../../hooks/useOffers/useMyOffers";
import useSkeleton from "../../hooks/useSkeleton";
import { useSelector } from "react-redux";
import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors";
import { OFFERS_MINE_SCOPE } from "../../store/actions/offers/offersActionConstants";
@@ -17,10 +16,6 @@ const MyOffers = () => {
);
const [filtersOpened, setFiltersOpened] = useState(false);

const { transitionStage } = useSkeleton({
timeoutInterval: 900,
isLoadingIndicator: isLoadingMineOffers,
});
const toggleFilters = () => {
setFiltersOpened((prevFiltersOpened) => !prevFiltersOpened);
};
@@ -31,7 +26,6 @@ const MyOffers = () => {
<FilterCard
myOffers
offers={offers}
animationStage={transitionStage}
filtersOpened={filtersOpened}
toggleFilters={toggleFilters}
skeleton={isLoadingMineOffers}
@@ -41,7 +35,6 @@ const MyOffers = () => {
<MarketPlace
myOffers={true}
offers={offers}
animationStage={transitionStage}
skeleton={isLoadingMineOffers}
toggleFilters={toggleFilters}
/>

+ 6
- 2
src/pages/ProfilePage/ProfilePage.js Näytä tiedosto

@@ -1,5 +1,5 @@
import React from "react";
import ItemDetailsLayout from "../../layouts/ItemDetailsLayout/ItemDetailsLayout";
import ProfileLayout from "../../layouts/ProfileLayout/ProfileLayout";
import { ProfilePageContainer } from "./ProfilePage.styled";
import Profile from "../../components/Profile/Profile";
import UserReviews from "../../components/UserReviews/UserReviews";
@@ -7,7 +7,11 @@ import UserReviews from "../../components/UserReviews/UserReviews";
const ProfilePage = () => {
return (
<ProfilePageContainer>
<ItemDetailsLayout content={<Profile/>} rightCard={<UserReviews isProfileReviews/>} profile />
<ProfileLayout
content={<Profile />}
rightCard={<UserReviews isProfileReviews />}
profile
/>
</ProfilePageContainer>
);
};

+ 11
- 18
src/store/reducers/login/loginReducer.js Näytä tiedosto

@@ -1,4 +1,4 @@
import createReducer from '../../utils/createReducer';
import createReducer from "../../utils/createReducer";
import {
CLEAR_LOGIN_USER_ERROR,
LOGIN_USER_ERROR,
@@ -7,21 +7,18 @@ import {
UPDATE_USER_JWT_TOKEN,
GENERATE_TOKEN_SUCCESS,
GENERATE_TOKEN_ERROR,
} from '../../actions/login/loginActionConstants';
} from "../../actions/login/loginActionConstants";

const initialState = {
email: '',
token: {
RefreshToken: '',
JwtToken: '',
userId: ''
},
errorMessage: '',
email: "",
jwtToken: {},
refreshToken: {},
userId: "",
errorMessage: "",
};

export default createReducer(
{

[LOGIN_USER_SUCCESS]: setUser,
[UPDATE_USER_JWT_TOKEN]: setUserJwtToken,
[RESET_LOGIN_STATE]: resetLoginState,
@@ -30,24 +27,20 @@ export default createReducer(
[GENERATE_TOKEN_SUCCESS]: generateToken,
[GENERATE_TOKEN_ERROR]: generateTokenError,
},
initialState,
initialState
);


function setUser(state, action) {
return {
...state,
token: action.payload,
...action.payload,
};
}

function setUserJwtToken(state, action) {
return {
...state,
token: {
...state.token,
JwtToken: action.payload,
},
jwtToken: action.payload,
};
}

@@ -65,7 +58,7 @@ function resetLoginState() {
function clearLoginErrors(state) {
return {
...state,
errorMessage: '',
errorMessage: "",
};
}


+ 1
- 1
src/store/saga/loginSaga.js Näytä tiedosto

@@ -59,7 +59,7 @@ function* fetchLogin({ payload }) {
yield call(addHeaderToken, token);
const profileData = yield call(attemptFetchProfile, userId);
if (profileData) yield put(setMineProfile(profileData.data));
yield put(fetchUserSuccess({JwtToken: accessToken, RefreshToken: refreshToken, userId}));
yield put(fetchUserSuccess({jwtToken: accessToken, refreshToken: refreshToken, userId}));
if (payload.handleApiResponseSuccess) {
yield call(payload.handleApiResponseSuccess);
}

+ 2
- 2
src/store/saga/registerSaga.js Näytä tiedosto

@@ -60,8 +60,8 @@ function* fetchRegisterUser({ payload }) {
if (profileData) yield put(setMineProfile(profileData.data));
yield put(
fetchUserSuccess({
JwtToken: accessToken,
RefreshToken: refreshToken,
jwtToken: accessToken,
refreshToken: refreshToken,
userId,
})
);

+ 4
- 24
src/store/selectors/loginSelectors.js Näytä tiedosto

@@ -1,31 +1,11 @@
import { createSelector } from 'reselect';
import { createSelector } from "reselect";

const loginSelector = (state) => state.login;

export const selectLoginEmail = createSelector(
loginSelector,
(state) => state.email,
);

export const selectUsernames = createSelector(
loginSelector,
(state) => state.usernames,
);

export const selectTokens = createSelector(
loginSelector,
(state) => state.token,
);

export const selectJWTToken = createSelector(
loginSelector,
(state) => state.token,
);
export const selectUserId = createSelector(
loginSelector,
(state) => state.token.userId
)
(state) => state.userId
);
export const selectLoginError = createSelector(
loginSelector,
(state) => state.errorMessage,
(state) => state.errorMessage
);

+ 21
- 0
src/util/helpers/routeHelpers.js Näytä tiedosto

@@ -1,3 +1,11 @@
import {
FORGOT_PASSWORD_MAIL_SENT,
FORGOT_PASSWORD_PAGE,
LOGIN_PAGE,
REGISTER_PAGE,
REGISTER_SUCCESSFUL_PAGE,
RESET_PASSWORD_PAGE,
} from "../../constants/pages";
import history from "../../store/utils/history";

export const routeMatches = (route) => {
@@ -18,3 +26,16 @@ export const replaceInRoute = (route, pathVariables = {}) => {
route
);
};
export const isAuthRoute = () => {
if (
routeMatches(LOGIN_PAGE) ||
routeMatches(REGISTER_PAGE) ||
routeMatches(REGISTER_SUCCESSFUL_PAGE) ||
routeMatches(FORGOT_PASSWORD_PAGE) ||
routeMatches(FORGOT_PASSWORD_MAIL_SENT) ||
routeMatches(RESET_PASSWORD_PAGE)
) {
return true;
}
return false;
};

Loading…
Peruuta
Tallenna