Переглянути джерело

Fixed all bugs assigned to djordje

feature/587
Djordje Mitrovic 3 роки тому
джерело
коміт
782c77da1d
50 змінених файлів з 560 додано та 192 видалено
  1. 5
    0
      package-lock.json
  2. 2
    1
      package.json
  3. 5
    0
      src/assets/images/svg/category-header.svg
  4. 4
    0
      src/assets/images/svg/half-logo.svg
  5. 3
    0
      src/assets/images/svg/like.svg
  6. 1
    10
      src/assets/images/svg/phone.svg
  7. 10
    0
      src/assets/images/svg/pin.svg
  8. 6
    0
      src/assets/images/svg/swaps.svg
  9. 3
    5
      src/components/Cards/ChatCard/ChatCard.js
  10. 22
    2
      src/components/Cards/ChatCard/ChatCommands/ChatCommands.js
  11. 5
    1
      src/components/Cards/ChatCard/ChatCommands/ChatCommands.styled.js
  12. 3
    3
      src/components/Cards/CreateOfferCard/FirstPart/FirstPartCreateOffer.js
  13. 2
    1
      src/components/Cards/FilterCard/Choser/SubcategoryChoser/SubcategoryChoser.js
  14. 16
    8
      src/components/Cards/FilterCard/FilterCard.js
  15. 10
    4
      src/components/Cards/FilterCard/FilterFooter/FilterFooter.js
  16. 8
    1
      src/components/Cards/FilterCard/FilterHeader/FilterHeader.js
  17. 13
    11
      src/components/Cards/OfferCard/OfferCard.js
  18. 43
    9
      src/components/Cards/OfferCard/OfferCard.styled.js
  19. 4
    3
      src/components/CreateReview/FirstStep/FirstStepCreateReview.js
  20. 1
    0
      src/components/CreateReview/FirstStep/FirstStepCreateReview.styled.js
  21. 24
    2
      src/components/DirectChat/DirectChatContent/DirectChatContentHeader/DirectChatContentHeader.js
  22. 2
    2
      src/components/Header/Header.js
  23. 5
    1
      src/components/Header/Header.styled.js
  24. 2
    2
      src/components/IconButton/IconButton.js
  25. 25
    15
      src/components/MarketPlace/Header/Header.js
  26. 7
    2
      src/components/MarketPlace/Header/Header.styled.js
  27. 2
    0
      src/components/MarketPlace/Offers/Offers.js
  28. 2
    2
      src/components/MarketPlace/Offers/Offers.styled.js
  29. 0
    1
      src/components/Popovers/HeaderPopover/HeaderPopover.styled.js
  30. 24
    0
      src/components/Popovers/PhonePopover/PhonePopover.js
  31. 44
    0
      src/components/Popovers/PhonePopover/PhonePopover.styled.js
  32. 19
    2
      src/components/Popovers/PopoverComponent.js
  33. 21
    0
      src/components/Profile/ProfileOffers/NoProfileOffers.js/NoProfileOffers.js
  34. 35
    0
      src/components/Profile/ProfileOffers/NoProfileOffers.js/NoProfileOffers.styled.js
  35. 70
    45
      src/components/Profile/ProfileOffers/ProfileOffers.js
  36. 10
    10
      src/components/ProfileCard/EditProfile/EditProfile.js
  37. 16
    12
      src/components/ProfileCard/ProfileContact/ProfileContact.js
  38. 3
    3
      src/components/UserReviews/NoReviews/NoReviews.js
  39. 1
    1
      src/components/UserReviews/UserReviews.styled.js
  40. 19
    0
      src/hooks/useIsMobile.js
  41. 6
    0
      src/hooks/useOffers/useMyOffers.js
  42. 4
    0
      src/i18n/resources/rs.js
  43. 1
    1
      src/pages/HomePage/HomePage.styled.js
  44. 20
    10
      src/pages/RegisterPages/Register/FirstPart/FirstPartOfRegistration.js
  45. 2
    1
      src/pages/RegisterPages/Register/Register.js
  46. 16
    14
      src/pages/RegisterPages/Register/Register.styled.js
  47. 0
    1
      src/request/index.js
  48. 8
    2
      src/store/saga/profileSaga.js
  49. 1
    0
      src/util/helpers/queryHelpers.js
  50. 5
    4
      src/validations/registerValidations/firstPartValidation.js

+ 5
- 0
package-lock.json Переглянути файл

} }
} }
} }
},
"yup-password": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/yup-password/-/yup-password-0.2.2.tgz",
"integrity": "sha512-2PHfqGWtbXg4OfDV7VKFIb3hyEaYgTYpEORnFqgGAYqzENWmGzWMoeGvJg2Ohmq6maTRxhJzLZpNTITrqlZTrA=="
} }
} }
} }

+ 2
- 1
package.json Переглянути файл

"socket.io-client": "^4.5.1", "socket.io-client": "^4.5.1",
"styled-components": "^5.3.5", "styled-components": "^5.3.5",
"web-vitals": "^1.1.2", "web-vitals": "^1.1.2",
"yup": "^0.32.9"
"yup": "^0.32.9",
"yup-password": "^0.2.2"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",

+ 5
- 0
src/assets/images/svg/category-header.svg Переглянути файл

<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.99984 1.66675L1.6665 5.83341L9.99984 10.0001L18.3332 5.83341L9.99984 1.66675Z" stroke="#4D4D4D" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M1.6665 14.1667L9.99984 18.3334L18.3332 14.1667" stroke="#4D4D4D" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M1.6665 10L9.99984 14.1667L18.3332 10" stroke="#4D4D4D" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

+ 4
- 0
src/assets/images/svg/half-logo.svg Переглянути файл

<svg width="85" height="84" viewBox="0 0 85 84" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="34.8508" cy="19.0459" r="10.5693" transform="rotate(45 34.8508 19.0459)" fill="#FEB005"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M51.5556 12.6063C48.8541 9.9048 44.4742 9.90481 41.7728 12.6063L27.6188 26.7602C27.6189 26.7604 27.6191 26.7605 27.6192 26.7606C31.7468 30.8882 31.7468 37.5803 27.6192 41.7079C23.5128 45.8143 16.8681 45.8354 12.7356 41.7711C10.7896 44.4744 11.0325 48.266 13.4642 50.6977L41.7727 79.0063C44.4742 81.7077 48.8541 81.7077 51.5556 79.0063L79.8642 50.6977C82.5656 47.9962 82.5656 43.6163 79.8642 40.9149L51.5556 12.6063Z" fill="#FEB005"/>
</svg>

+ 3
- 0
src/assets/images/svg/like.svg Переглянути файл

<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.25 16.5H3C2.60218 16.5 2.22064 16.342 1.93934 16.0607C1.65804 15.7794 1.5 15.3978 1.5 15V9.75C1.5 9.35218 1.65804 8.97064 1.93934 8.68934C2.22064 8.40804 2.60218 8.25 3 8.25H5.25M10.5 6.75V3.75C10.5 3.15326 10.2629 2.58097 9.84099 2.15901C9.41903 1.73705 8.84674 1.5 8.25 1.5L5.25 8.25V16.5H13.71C14.0717 16.5041 14.4228 16.3773 14.6984 16.143C14.9741 15.9087 15.1558 15.5827 15.21 15.225L16.245 8.475C16.2776 8.26002 16.2631 8.04051 16.2025 7.83169C16.1419 7.62287 16.0366 7.42972 15.8939 7.26564C15.7512 7.10155 15.5746 6.97045 15.3762 6.88141C15.1778 6.79238 14.9624 6.74754 14.745 6.75H10.5Z" stroke="#5A3984" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

+ 1
- 10
src/assets/images/svg/phone.svg Переглянути файл

<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_789_9087)">
<path d="M14.25 0.75L17.25 3.75L14.25 6.75" stroke="#5A3984" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.25 3.75H17.25" stroke="#5A3984" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16.5001 12.6901V14.9401C16.5009 15.1489 16.4581 15.3557 16.3745 15.5471C16.2908 15.7385 16.168 15.9103 16.0141 16.0515C15.8602 16.1927 15.6785 16.3002 15.4806 16.3671C15.2828 16.434 15.0731 16.4589 14.8651 16.4401C12.5572 16.1893 10.3403 15.4007 8.39257 14.1376C6.58044 12.9861 5.04407 11.4497 3.89257 9.63757C2.62506 7.68098 1.83625 5.45332 1.59007 3.13507C1.57133 2.92767 1.59598 2.71864 1.66245 2.52129C1.72892 2.32394 1.83575 2.14259 1.97615 1.98879C2.11654 1.83499 2.28743 1.7121 2.47792 1.62796C2.6684 1.54382 2.87433 1.50027 3.08257 1.50007H5.33257C5.69655 1.49649 6.04942 1.62538 6.32539 1.86272C6.60137 2.10006 6.78163 2.42966 6.83257 2.79007C6.92754 3.51012 7.10366 4.21712 7.35757 4.89757C7.45848 5.16602 7.48032 5.45776 7.4205 5.73823C7.36069 6.01871 7.22172 6.27616 7.02007 6.48007L6.06757 7.43257C7.13524 9.31023 8.68991 10.8649 10.5676 11.9326L11.5201 10.9801C11.724 10.7784 11.9814 10.6395 12.2619 10.5796C12.5424 10.5198 12.8341 10.5417 13.1026 10.6426C13.783 10.8965 14.49 11.0726 15.2101 11.1676C15.5744 11.219 15.9071 11.4025 16.145 11.6832C16.3828 11.9639 16.5092 12.3223 16.5001 12.6901Z" stroke="#5A3984" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_789_9087">
<rect width="18" height="18" fill="white"/>
</clipPath>
</defs>
<path d="M16.4999 12.6901V14.9401C16.5008 15.1489 16.458 15.3557 16.3743 15.5471C16.2907 15.7385 16.1679 15.9103 16.014 16.0515C15.8601 16.1927 15.6784 16.3002 15.4805 16.3671C15.2826 16.434 15.073 16.4589 14.8649 16.4401C12.5571 16.1893 10.3402 15.4007 8.39245 14.1376C6.58032 12.9861 5.04395 11.4497 3.89245 9.63757C2.62493 7.68098 1.83613 5.45332 1.58995 3.13507C1.57121 2.92767 1.59586 2.71864 1.66233 2.52129C1.72879 2.32394 1.83563 2.14259 1.97602 1.98879C2.11642 1.83499 2.2873 1.7121 2.47779 1.62796C2.66828 1.54382 2.87421 1.50027 3.08245 1.50007H5.33245C5.69643 1.49649 6.04929 1.62538 6.32527 1.86272C6.60125 2.10006 6.78151 2.42966 6.83245 2.79007C6.92742 3.51012 7.10354 4.21712 7.35745 4.89757C7.45836 5.16602 7.4802 5.45776 7.42038 5.73823C7.36056 6.01871 7.2216 6.27616 7.01995 6.48007L6.06745 7.43257C7.13512 9.31023 8.68979 10.8649 10.5675 11.9326L11.5199 10.9801C11.7239 10.7784 11.9813 10.6395 12.2618 10.5796C12.5423 10.5198 12.834 10.5417 13.1024 10.6426C13.7829 10.8965 14.4899 11.0726 15.21 11.1676C15.5743 11.219 15.907 11.4025 16.1448 11.6832C16.3827 11.9639 16.5091 12.3223 16.4999 12.6901Z" stroke="#5A3984" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>

+ 10
- 0
src/assets/images/svg/pin.svg Переглянути файл

<svg width="22" height="23" viewBox="0 0 22 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1316_10558)">
<path d="M9.81609 1.53679C10.1267 0.998802 10.8149 0.814402 11.3529 1.12501L19.1471 5.62501C19.686 5.93614 19.8695 6.6238 19.5589 7.16179C19.2483 7.69977 18.561 7.8847 18.0221 7.57356L17.1239 7.05501L14.8659 11.7675C15.6335 13.0185 15.9281 14.5404 15.6218 16.0482L15.5995 16.1572C15.5264 16.5087 15.2604 16.7936 14.9319 16.9408C14.6259 17.1052 14.2475 17.0856 13.9339 16.9046L4.19109 11.2796C3.8778 11.0987 3.66982 10.7797 3.63449 10.4183C3.59729 10.0599 3.73729 9.7023 4.00684 9.46415L4.09008 9.39042C5.24052 8.36994 6.70729 7.86497 8.17508 7.90456L11.1272 3.59282L10.2279 3.07356C9.68988 2.76296 9.50548 2.07477 9.81609 1.53679ZM9.47426 15.6289L7.78676 18.5517C7.47563 19.0906 6.78888 19.2746 6.24998 18.9635C5.71108 18.6523 5.52707 17.9656 5.8382 17.4267L7.5257 14.5039L9.47426 15.6289Z" fill="#FEB005"/>
</g>
<defs>
<clipPath id="clip0_1316_10558">
<rect width="13.5" height="18" fill="white" transform="translate(9.4043) rotate(30)"/>
</clipPath>
</defs>
</svg>

+ 6
- 0
src/assets/images/svg/swaps.svg Переглянути файл

<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.66754 1.08737L15.6675 4.08737C15.9174 4.21155 16.1278 4.40299 16.2748 4.64015C16.4219 4.87732 16.4999 5.1508 16.5 5.42987V12.5774C16.4999 12.8564 16.4219 13.1299 16.2748 13.3671C16.1278 13.6043 15.9174 13.7957 15.6675 13.9199L9.66754 16.9199C9.45914 17.0241 9.22932 17.0784 8.99629 17.0784C8.76326 17.0784 8.53343 17.0241 8.32504 16.9199L2.32504 13.9199C2.07538 13.7941 1.86585 13.601 1.72008 13.3625C1.5743 13.1239 1.49809 12.8494 1.50004 12.5699V5.42987C1.50018 5.1508 1.57818 4.87732 1.72525 4.64015C1.87231 4.40299 2.08263 4.21155 2.33254 4.08737L8.33254 1.08737C8.53995 0.9843 8.76842 0.930664 9.00004 0.930664C9.23165 0.930664 9.46012 0.9843 9.66754 1.08737V1.08737Z" stroke="#5A3984" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M1.74023 4.62012L9.00023 8.25012L16.2602 4.62012" stroke="#5A3984" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9 17.07V8.25" stroke="#5A3984" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.25 2.625L12.75 6.375" stroke="#5A3984" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

+ 3
- 5
src/components/Cards/ChatCard/ChatCard.js Переглянути файл

Line, Line,
} from "./ChatCard.styled"; } from "./ChatCard.styled";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import useScreenDimensions from "../../../hooks/useScreenDimensions";
import LittleOfferDetails from "./LittleOfferDetails/LittleOfferDetails"; import LittleOfferDetails from "./LittleOfferDetails/LittleOfferDetails";
import MobileOfferDetails from "./MobileOfferDetails/MobileOfferDetails"; import MobileOfferDetails from "./MobileOfferDetails/MobileOfferDetails";
import OfferLocation from "./OfferLocation/OfferLocation"; import OfferLocation from "./OfferLocation/OfferLocation";
import ChatCommands from "./ChatCommands/ChatCommands"; import ChatCommands from "./ChatCommands/ChatCommands";
import useIsMobile from "../../../hooks/useIsMobile";


const ChatCard = (props) => { const ChatCard = (props) => {
const history = useHistory(); const history = useHistory();
const dimensions = useScreenDimensions();
const { isMobile } = useIsMobile();


const chat = useMemo(() => { const chat = useMemo(() => {
return props.chat; return props.chat;
}; };
return ( return (
<ChatCardContainer <ChatCardContainer
onClick={
dimensions.width < 600 ? () => routeToItem(chat?.chat?._id) : () => {}
}
onClick={isMobile ? () => routeToItem(chat?.chat?._id) : () => {}}
> >
<Col> <Col>
<UserImgWrapper> <UserImgWrapper>

+ 22
- 2
src/components/Cards/ChatCard/ChatCommands/ChatCommands.js Переглянути файл

import React from "react";
import React, { useState } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { import {
CheckButton, CheckButton,
Commands, Commands,
PhoneIcon, PhoneIcon,
PhoneIconContainer, PhoneIconContainer,
Popover,
} from "./ChatCommands.styled"; } from "./ChatCommands.styled";
import selectedTheme from "../../../../themes"; import selectedTheme from "../../../../themes";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import PhonePopover from "../../../Popovers/PhonePopover/PhonePopover";


const ChatCommands = (props) => { const ChatCommands = (props) => {
const { t } = useTranslation(); const { t } = useTranslation();
const [showPhonePopover, setShowPhonePopover] = useState(false);
const [phonePopoverAnchorEl, setPhonePopoverAnchorEl] = useState(null);


return ( return (
<Commands> <Commands>
<PhoneIconContainer>
<PhoneIconContainer
onClick={(event) => {
console.log(event);
setShowPhonePopover(true);
setPhonePopoverAnchorEl(event.currentTarget);
}}
>
<PhoneIcon /> <PhoneIcon />
</PhoneIconContainer> </PhoneIconContainer>
<CheckButton <CheckButton
> >
{t("messages.seeChats")} {t("messages.seeChats")}
</CheckButton> </CheckButton>
<Popover
anchorEl={phonePopoverAnchorEl}
open={showPhonePopover}
anchorRight
onClose={() => {
setShowPhonePopover(false);
setPhonePopoverAnchorEl(null);
}}
content={<PhonePopover />}
/>
</Commands> </Commands>
); );
}; };

+ 5
- 1
src/components/Cards/ChatCard/ChatCommands/ChatCommands.styled.js Переглянути файл

import selectedTheme from "../../../../themes"; import selectedTheme from "../../../../themes";
import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton"; import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton";
import IconButton from "../../../IconButton/IconButton"; import IconButton from "../../../IconButton/IconButton";
import PopoverComponent from "../../../Popovers/PopoverComponent";




export const Commands = styled(Box)` export const Commands = styled(Box)`
display: none; display: none;
} }
transition: 0.2s all; transition: 0.2s all;
`;
`;
export const Popover = styled(PopoverComponent)`
`

+ 3
- 3
src/components/Cards/CreateOfferCard/FirstPart/FirstPartCreateOffer.js Переглянути файл

import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { SelectField } from "../CreateOffer.styled"; import { SelectField } from "../CreateOffer.styled";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import useScreenDimensions from "../../../../hooks/useScreenDimensions";
import useIsMobile from "../../../../hooks/useIsMobile";


const FirstPartCreateOffer = (props) => { const FirstPartCreateOffer = (props) => {
const [subcat, setSubcat] = useState([]); const [subcat, setSubcat] = useState([]);
const locations = useSelector((state) => state.locations.locations); const locations = useSelector((state) => state.locations.locations);
const categories = useSelector((state) => state.categories.categories); const categories = useSelector((state) => state.categories.categories);
const dimensions = useScreenDimensions();
const { isMobile } = useIsMobile();


const { t } = useTranslation(); const { t } = useTranslation();


/> />


<FieldLabel leftText={t("offer.productDescription")} /> <FieldLabel leftText={t("offer.productDescription")} />
{dimensions.width > 600 ? (
{!isMobile ? (
<DescriptionField <DescriptionField
name="description" name="description"
placeholder={t("offer.description")} placeholder={t("offer.description")}

+ 2
- 1
src/components/Cards/FilterCard/Choser/SubcategoryChoser/SubcategoryChoser.js Переглянути файл

})); }));


useEffect(() => { useEffect(() => {
if (props.queryStringHook.isInitiallyLoaded) {
if (props?.queryStringHook?.isInitiallyLoaded || props.isMyOffers) {
if ( if (
!filters.category.selectedCategoryLocally || !filters.category.selectedCategoryLocally ||
filters.category.selectedCategoryLocally?._id === 0 filters.category.selectedCategoryLocally?._id === 0
filters: PropTypes.any, filters: PropTypes.any,
categoryOpened: PropTypes.bool, categoryOpened: PropTypes.bool,
queryStringHook: PropTypes.any, queryStringHook: PropTypes.any,
isMyOffers: PropTypes.bool,
}; };


export default SubcategoryChoser; export default SubcategoryChoser;

+ 16
- 8
src/components/Cards/FilterCard/FilterCard.js Переглянути файл

categoryRef.current.closeSection(); categoryRef.current.closeSection();
subcategoryRef.current.closeSection(); subcategoryRef.current.closeSection();
locationRef.current.closeSection(); locationRef.current.closeSection();
}
};
return ( return (
<FilterCardContainer <FilterCardContainer
filtersOpened={props.filtersOpened} filtersOpened={props.filtersOpened}
{/* Header title for my offers */} {/* Header title for my offers */}
{props.myOffers && <HeaderBack />} {props.myOffers && <HeaderBack />}


<FilterHeader filters={offers} closeAllSections={closeAllSections} />
<FilterHeader
filters={offers}
closeAllSections={closeAllSections}
isMyOffers={props.myOffers}
toggleFilters={props.toggleFilters}
/>


<ContentContainer> <ContentContainer>
{/* Categories */} {/* Categories */}
<CategoryChoser filters={filters} ref={categoryRef} /> <CategoryChoser filters={filters} ref={categoryRef} />


{/* Subcategories */} {/* Subcategories */}
<SubcategoryChoser filters={filters} queryStringHook={offers.queryStringHook} ref={subcategoryRef} categoryOpened={categoryRef.current?.isOpened} />
<SubcategoryChoser
filters={filters}
queryStringHook={offers.queryStringHook}
ref={subcategoryRef}
categoryOpened={categoryRef.current?.isOpened}
isMyOffers={props.myOffers}
/>


{/* Locations */} {/* Locations */}
<LocationChoser filters={filters} ref={locationRef}/>
<LocationChoser filters={filters} ref={locationRef} />
</ContentContainer> </ContentContainer>


<FilterFooter
toggleFilters={props.toggleFilters}
filters={offers}
/>
<FilterFooter toggleFilters={props.toggleFilters} filters={offers} />
</FilterCardContainer> </FilterCardContainer>
); );
}; };

+ 10
- 4
src/components/Cards/FilterCard/FilterFooter/FilterFooter.js Переглянути файл

import selectedTheme from "../../../../themes"; import selectedTheme from "../../../../themes";
import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton"; import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import useScreenDimensions from "../../../../hooks/useScreenDimensions";
import useSearch from "../../../../hooks/useOffers/useSearch";
import useIsMobile from "../../../../hooks/useIsMobile";


const FilterFooter = (props) => { const FilterFooter = (props) => {
const { t } = useTranslation(); const { t } = useTranslation();
console.log(useIsMobile);
console.log(useSearch);
console.log(useTranslation);
const isMobile = useIsMobile;
console.log(isMobile);
const filters = props.filters; const filters = props.filters;
const screenDimensions = useScreenDimensions();
const handleFilters = () => { const handleFilters = () => {
filters.apply(); filters.apply();
props.toggleFilters();
}; };
return ( return (
<FilterFooterContainer responsiveOpen={screenDimensions.width < 600}>
{screenDimensions.width < 600 && (
<FilterFooterContainer responsiveOpen={isMobile}>
{isMobile && (
<PrimaryButton <PrimaryButton
variant="outlined" variant="outlined"
fullWidth fullWidth

+ 8
- 1
src/components/Cards/FilterCard/FilterHeader/FilterHeader.js Переглянути файл

const filters = props.filters; const filters = props.filters;
const { t } = useTranslation(); const { t } = useTranslation();
const clearFilters = () => { const clearFilters = () => {
filters.clearFiltersAndApply();
if (props.isMyOffers) {
filters.clear();
} else {
filters.clearFiltersAndApply();
}
props.toggleFilters();
props.closeAllSections(); props.closeAllSections();
}; };
return ( return (
children: PropTypes.node, children: PropTypes.node,
filters: PropTypes.any, filters: PropTypes.any,
closeAllSections: PropTypes.func, closeAllSections: PropTypes.func,
isMyOffers: PropTypes.bool,
toggleFilters: PropTypes.func,
}; };


export default FilterHeader; export default FilterHeader;

+ 13
- 11
src/components/Cards/OfferCard/OfferCard.js Переглянути файл

OfferTitle, OfferTitle,
OfferTitleAboveImage, OfferTitleAboveImage,
OfferViews, OfferViews,
PinIcon,
RemoveIcon, RemoveIcon,
RemoveIconContainer, RemoveIconContainer,
StarIcon,
StarIconContainer,
LikeIcon,
LikeIconContainer,
} from "./OfferCard.styled"; } from "./OfferCard.styled";
import DeleteOffer from "./DeleteOffer/DeleteOffer"; import DeleteOffer from "./DeleteOffer/DeleteOffer";
import { ReactComponent as Category } from "../../../assets/images/svg/category.svg"; import { ReactComponent as Category } from "../../../assets/images/svg/category.svg";
></OfferImage> ></OfferImage>
</OfferImageContainer> </OfferImageContainer>
<OfferInfo vertical={props.vertical}> <OfferInfo vertical={props.vertical}>
<OfferTitle
vertical={props.vertical}
onClick={() => routeToItem(props?.offer?._id)}
>
{props?.offer?.name}
</OfferTitle>
<OfferTitle
vertical={props.vertical}
onClick={() => routeToItem(props?.offer?._id)}
>
{props?.offer?.name}
</OfferTitle>
<OfferAuthor> <OfferAuthor>
<OfferAuthorName vertical={props.vertical}> <OfferAuthorName vertical={props.vertical}>
{props?.offer?.user?.company?.name} {props?.offer?.user?.company?.name}
</EditIconContainer> </EditIconContainer>
</> </>
) : props.aboveChat ? ( ) : props.aboveChat ? (
<StarIconContainer
<LikeIconContainer
disabled={props.disabledReviews} disabled={props.disabledReviews}
onClick={makeReview} onClick={makeReview}
> >
<StarIcon disabled={props.disabledReviews} />
</StarIconContainer>
<LikeIcon disabled={props.disabledReviews} />
</LikeIconContainer>
) : ( ) : (
<MessageIcon <MessageIcon
showMessageIcon={showMessageIcon} showMessageIcon={showMessageIcon}
<Message /> <Message />
</MessageIcon> </MessageIcon>
)} )}
{props?.offer?.pinned && <PinIcon isMyOffer={props.isMyOffer} />}
</OfferFlexContainer> </OfferFlexContainer>
</OfferCardContainer> </OfferCardContainer>
{deleteOfferModal && ( {deleteOfferModal && (

+ 43
- 9
src/components/Cards/OfferCard/OfferCard.styled.js Переглянути файл

import { ReactComponent as Eye } from "../../../assets/images/svg/eye-striked.svg"; import { ReactComponent as Eye } from "../../../assets/images/svg/eye-striked.svg";
import { ReactComponent as Remove } from "../../../assets/images/svg/trash.svg"; import { ReactComponent as Remove } from "../../../assets/images/svg/trash.svg";
import { ReactComponent as Edit } from "../../../assets/images/svg/edit.svg"; import { ReactComponent as Edit } from "../../../assets/images/svg/edit.svg";
import { ReactComponent as Star } from "../../../assets/images/svg/star.svg";
import { ReactComponent as Like } from "../../../assets/images/svg/like.svg";
import { ReactComponent as Pin } from "../../../assets/images/svg/pin.svg";


export const OfferCardContainer = styled(Container)` export const OfferCardContainer = styled(Container)`
display: ${(props) => (props.skeleton ? "none" : "flex")}; display: ${(props) => (props.skeleton ? "none" : "flex")};
height: 180px; height: 180px;
position: relative; position: relative;
@media (max-width: 550px) { @media (max-width: 550px) {
height: 184px;
height: 194px;
padding: 18px; padding: 18px;
padding-top: 12px; padding-top: 12px;
${(props) => ${(props) =>
font-size: 24px; font-size: 24px;
width: calc(100% - 120px); width: calc(100% - 120px);
cursor: pointer; cursor: pointer;
overflow: hidden;
line-height: 33px;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
max-height: 33px;
margin-bottom: 28px;
@media (max-width: 550px) { @media (max-width: 550px) {
width: 100%; width: 100%;
font-size: 18px; font-size: 18px;
} }
`; `;
export const OfferTitleAboveImage = styled(OfferTitle)` export const OfferTitleAboveImage = styled(OfferTitle)`
padding-bottom: 12px;
padding-bottom: 18px;
padding-top: 5px; padding-top: 5px;
padding-left: 1px; padding-left: 1px;
display: block; display: block;
width: 60%;
max-width: 60%;
height: 40px;
line-height: 20px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
${(props) => props.vertical && `display: none;`} ${(props) => props.vertical && `display: none;`}
@media (min-width: 551px) { @media (min-width: 551px) {
display: none; display: none;
@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
position: absolute; position: absolute;
display: block; display: block;
right: 20px;
top: 75%;
right: 16px;
top: 16px;
} }
`; `;
export const RemoveIcon = styled(Remove)``; export const RemoveIcon = styled(Remove)``;
@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
position: absolute; position: absolute;
display: block; display: block;
right: 20px;
top: 60%;
right: 55px;
top: 16px;
} }
`; `;
export const EditIcon = styled(Edit)``; export const EditIcon = styled(Edit)``;
export const StarIconContainer = styled(MessageIcon)`
export const LikeIconContainer = styled(MessageIcon)`
display: block; display: block;
opacity: ${(props) => (props.disabled ? "0.4" : "1")}; opacity: ${(props) => (props.disabled ? "0.4" : "1")};
${(props) => ${(props) =>
} }
`} `}
`; `;
export const StarIcon = styled(Star)`
export const LikeIcon = styled(Like)`
& path { & path {
stroke: ${(props) => stroke: ${(props) =>
props.disabled props.disabled
: selectedTheme.primaryPurple}; : selectedTheme.primaryPurple};
} }
`; `;
export const PinIcon = styled(Pin)`
position: absolute;
top: 20px;
right: 68px;
@media (max-width: 600px) {
top: 20px;
right: 55px;
}
${(props) =>
props.isMyOffer &&
`
right: 134px;
top: 26px;
@media (max-width: 600px) {
top: 20px;
right: 94px;
}
`}
`;

+ 4
- 3
src/components/CreateReview/FirstStep/FirstStepCreateReview.js Переглянути файл

import selectedTheme from "../../../themes"; import selectedTheme from "../../../themes";
import { useFormik } from "formik"; import { useFormik } from "formik";
import * as Yup from "yup"; import * as Yup from "yup";
import useScreenDimensions from "../../../hooks/useScreenDimensions";
import useIsMobile from "../../../hooks/useIsMobile";


const FirstStepCreateReview = (props) => { const FirstStepCreateReview = (props) => {
const offer = props.offer; const offer = props.offer;
const interlocutor = props.interlocutor; const interlocutor = props.interlocutor;
const dimensions = useScreenDimensions();
const { isMobile } = useIsMobile();
const { t } = useTranslation(); const { t } = useTranslation();
const handleSubmit = (values) => { const handleSubmit = (values) => {
props.goToNextStep(values); props.goToNextStep(values);
<FieldLabel leftText={t("reviews.hasExchangeSucceed").toUpperCase()} /> <FieldLabel leftText={t("reviews.hasExchangeSucceed").toUpperCase()} />
<SelectField <SelectField
defaultValue={formik.values.exchangeSucceed} defaultValue={formik.values.exchangeSucceed}
exchange
onChange={(event) => onChange={(event) =>
formik.setFieldValue("exchangeSucceed", event.target.value) formik.setFieldValue("exchangeSucceed", event.target.value)
} }
value={formik.values.comment} value={formik.values.comment}
name="comment" name="comment"
onChange={formik.handleChange} onChange={formik.handleChange}
height={dimensions.width < 600 ? "64px" : "100px"}
height={isMobile ? "64px" : "100px"}
/> />


<NextButton <NextButton

+ 1
- 0
src/components/CreateReview/FirstStep/FirstStepCreateReview.styled.js Переглянути файл

margin-bottom: 18px; margin-bottom: 18px;
height: 48px; height: 48px;
text-align: left; text-align: left;
${props => props.exchange && `background-color: ${selectedTheme.backgroundSponsoredColor};`}
@media (max-width: 600px) { @media (max-width: 600px) {
height: 33px; height: 33px;
font-size: 14px; font-size: 14px;

+ 24
- 2
src/components/DirectChat/DirectChatContent/DirectChatContentHeader/DirectChatContentHeader.js Переглянути файл

import React from "react";
import React, { useState } from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { import {
DirectChatContentHeaderContainer, DirectChatContentHeaderContainer,
ProfileLocationText, ProfileLocationText,
ProfileName, ProfileName,
} from "./DirectChatContentHeader.styled"; } from "./DirectChatContentHeader.styled";
import PopoverComponent from "../../../Popovers/PopoverComponent";
import PhonePopover from "../../../Popovers/PhonePopover/PhonePopover";


const DirectChatContentHeader = (props) => { const DirectChatContentHeader = (props) => {
const [showPhonePopover, setShowPhonePopover] = useState(false);
const [phonePopoverAnchorEl, setPhonePopoverAnchorEl] = useState(null);

const togglePhonePopover = (event) => {
console.log(event);
setShowPhonePopover(true);
setPhonePopoverAnchorEl(event.currentTarget);
}

return ( return (
<DirectChatContentHeaderContainer> <DirectChatContentHeaderContainer>
<DirectChatContentHeaderFlexContainer> <DirectChatContentHeaderFlexContainer>
</ProfileDetails> </ProfileDetails>
</DirectChatContentHeaderFlexContainer> </DirectChatContentHeaderFlexContainer>
<DirectChatContentHeaderFlexContainer> <DirectChatContentHeaderFlexContainer>
<PhoneIconContainer>
<PhoneIconContainer onClick={togglePhonePopover}>
<PhoneIcon /> <PhoneIcon />
</PhoneIconContainer> </PhoneIconContainer>
</DirectChatContentHeaderFlexContainer> </DirectChatContentHeaderFlexContainer>
<PopoverComponent
anchorEl={phonePopoverAnchorEl}
open={showPhonePopover}
anchorRight
onClose={() => {
setShowPhonePopover(false);
setPhonePopoverAnchorEl(null);
}}
content={<PhonePopover />}
/>
</DirectChatContentHeaderContainer> </DirectChatContentHeaderContainer>
); );
}; };

+ 2
- 2
src/components/Header/Header.js Переглянути файл

SearchIcon, SearchIcon,
SearchInput, SearchInput,
SearchInputMobile, SearchInputMobile,
SwapsIcon,
ToggleDrawerButton, ToggleDrawerButton,
ToolsButtonsContainer, ToolsButtonsContainer,
ToolsContainer, ToolsContainer,
import { useTheme } from "@mui/system"; import { useTheme } from "@mui/system";
import MenuOutlinedIcon from "@mui/icons-material/MenuOutlined"; import MenuOutlinedIcon from "@mui/icons-material/MenuOutlined";
import MailIcon from "@mui/icons-material/EmailOutlined"; import MailIcon from "@mui/icons-material/EmailOutlined";
import Autorenew from "@mui/icons-material/Autorenew";
import AccountCircle from "@mui/icons-material/PersonOutlineOutlined"; import AccountCircle from "@mui/icons-material/PersonOutlineOutlined";
import Drawer from "../MUI/DrawerComponent"; import Drawer from "../MUI/DrawerComponent";
import PopoverComponent from "../Popovers/PopoverComponent"; import PopoverComponent from "../Popovers/PopoverComponent";
color: selectedTheme.primaryPurple, color: selectedTheme.primaryPurple,
}} }}
> >
<Autorenew />
<SwapsIcon />
</IconButton> </IconButton>
<IconButton <IconButton
onClick={(e) => { onClick={(e) => {

+ 5
- 1
src/components/Header/Header.styled.js Переглянути файл

import { PrimaryButton } from "../Buttons/PrimaryButton/PrimaryButton"; import { PrimaryButton } from "../Buttons/PrimaryButton/PrimaryButton";
import { TextField } from "../TextFields/TextField/TextField"; import { TextField } from "../TextFields/TextField/TextField";
import { ReactComponent as Search } from "../../assets/images/svg/magnifying-glass.svg"; import { ReactComponent as Search } from "../../assets/images/svg/magnifying-glass.svg";
import { ReactComponent as Swaps } from "../../assets/images/svg/swaps.svg";
import selectedTheme from "../../themes"; import selectedTheme from "../../themes";
import { Icon } from "../Icon/Icon"; import { Icon } from "../Icon/Icon";


export const SearchInput = styled(TextField)` export const SearchInput = styled(TextField)`
background-color: #f4f4f4;
background-color: ${selectedTheme.primaryBackgroundColor};
width: 45%; width: 45%;
flex: 3; flex: 3;
max-width: 520px; max-width: 520px;
} }
`; `;
export const HeaderContainer = styled(Box)``; export const HeaderContainer = styled(Box)``;
export const SwapsIcon = styled(Swaps)`

`

+ 2
- 2
src/components/IconButton/IconButton.js Переглянути файл

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


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



+ 25
- 15
src/components/MarketPlace/Header/Header.js Переглянути файл

import React from "react"; import React from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { import {
CategoryHeaderIcon,
HeaderAltLocation, HeaderAltLocation,
HeaderButton, HeaderButton,
HeaderButtons, HeaderButtons,
<HeaderContainer skeleton={props.skeleton}> <HeaderContainer skeleton={props.skeleton}>
{/* Setting appropriate header title if page is market place or my offers */} {/* Setting appropriate header title if page is market place or my offers */}
<Tooltip title={headerString}> <Tooltip title={headerString}>
{!props.myOffers ? (
headerString === "Sve kategorije" &&
(sorting.selectedSortOption === sortEnum.INITIAL ||
sorting.selectedSortOption === sortEnum.NEW) ? (
<React.Fragment>
<HeaderLocation initial>{headerString}</HeaderLocation>
<HeaderAltLocation>{t("header.newOffers")}</HeaderAltLocation>
</React.Fragment>
<>
{!props.myOffers ? (
<>
<CategoryHeaderIcon />
{headerString === "Sve kategorije" &&
(sorting.selectedSortOption === sortEnum.INITIAL ||
sorting.selectedSortOption === sortEnum.NEW) ? (
<React.Fragment>
<HeaderLocation initial>{headerString}</HeaderLocation>
<HeaderAltLocation>
{t("header.newOffers")}
</HeaderAltLocation>
</React.Fragment>
) : (
<>
<HeaderLocation>{headerString}</HeaderLocation>
</>
)}
</>
) : ( ) : (
<HeaderLocation>{headerString}</HeaderLocation>
)
) : (
<MySwapsTitle>
<RefreshIcon /> {t("header.myOffers")}
</MySwapsTitle>
)}
<MySwapsTitle>
<RefreshIcon /> {t("header.myOffers")}
</MySwapsTitle>
)}
</>
</Tooltip> </Tooltip>
{/* ^^^^^^ */} {/* ^^^^^^ */}



+ 7
- 2
src/components/MarketPlace/Header/Header.styled.js Переглянути файл

import { IconButton } from "../../Buttons/IconButton/IconButton"; import { IconButton } from "../../Buttons/IconButton/IconButton";
import Option from "../../Select/Option/Option"; import Option from "../../Select/Option/Option";
import Select from "../../Select/Select"; import Select from "../../Select/Select";
import { ReactComponent as Refresh } from "../../../assets/images/svg/refresh.svg";
import { ReactComponent as Swaps } from "../../../assets/images/svg/swaps.svg";
import { ReactComponent as CategoryHeader } from "../../../assets/images/svg/category-header.svg";


export const HeaderContainer = styled(Box)` export const HeaderContainer = styled(Box)`
margin-top: 20px; margin-top: 20px;
line-height: 22px; line-height: 22px;
font-size: 16px; font-size: 16px;
flex: 2; flex: 2;
margin-left: 9px;
max-width: ${(props) => (props.initial ? "fit-content" : "50%")}; max-width: ${(props) => (props.initial ? "fit-content" : "50%")};
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
font-weight: 400; font-weight: 400;
position: relative; position: relative;
left: -5px; left: -5px;
background-color: white;
& div:first-child { & div:first-child {
padding-left: 8px; padding-left: 8px;
} }
display: none; display: none;
} }
`; `;
export const RefreshIcon = styled(Refresh)`
export const RefreshIcon = styled(Swaps)`
width: 18px; width: 18px;
height: 18px; height: 18px;
position: relative; position: relative;
position: relative; position: relative;
left: 9px; left: 9px;
`; `;
export const CategoryHeaderIcon = styled(CategoryHeader)`
`

+ 2
- 0
src/components/MarketPlace/Offers/Offers.js Переглянути файл

) : ( ) : (
<OffersContainer ref={offersRef}> <OffersContainer ref={offersRef}>
{offers.allOffersToShow.map((item) => { {offers.allOffersToShow.map((item) => {
console.log(item);
return ( return (
<OfferCard <OfferCard
key={item._id} key={item._id}
offer={item} offer={item}
halfwidth={props.isGrid} halfwidth={props.isGrid}
messageUser={messageOneUser} messageUser={messageOneUser}
isMyOffer={item?.userId === userId}
/> />
); );
})} })}

+ 2
- 2
src/components/MarketPlace/Offers/Offers.styled.js Переглянути файл

top: ${props => props.myOffers ? "126px" : "93px"}; top: ${props => props.myOffers ? "126px" : "93px"};
right: 18px; right: 18px;
cursor: pointer; cursor: pointer;
background-color: ${selectedTheme.offerBackgroundColor} !important;
background-color: ${selectedTheme.primaryBackgroundColor} !important;
& div { & div {
width: 16px; width: 16px;
height: 16px; height: 16px;
} }
`; `;
export const FilterIcon = styled(Filter)` export const FilterIcon = styled(Filter)`
background-color: ${selectedTheme.offerBackgroundColor};
background-color: ${selectedTheme.primaryBackgroundColor};
`; `;

+ 0
- 1
src/components/Popovers/HeaderPopover/HeaderPopover.styled.js Переглянути файл

`; `;
export const PopoverListItemAvatarContainer = styled(ListItemAvatar)``; export const PopoverListItemAvatarContainer = styled(ListItemAvatar)``;
export const PopoverButton = styled(Button)` export const PopoverButton = styled(Button)`
text-decoration: underline;
color: ${selectedTheme.primaryPurple}; color: ${selectedTheme.primaryPurple};
font-weight: 500; font-weight: 500;
text-align: right; text-align: right;

+ 24
- 0
src/components/Popovers/PhonePopover/PhonePopover.js Переглянути файл

import React from "react";
import PropTypes from "prop-types";
import {
Arrow,
PhoneLabel,
PhoneNumber,
PhonePopoverContainer,
} from "./PhonePopover.styled";

const PhonePopover = () => {
return (
<PhonePopoverContainer>
<Arrow />
<PhoneLabel>Broj telefona</PhoneLabel>
<PhoneNumber>065/000-018</PhoneNumber>
</PhonePopoverContainer>
);
};

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

export default PhonePopover;

+ 44
- 0
src/components/Popovers/PhonePopover/PhonePopover.styled.js Переглянути файл

import { Box } from "@mui/material";
import styled from "styled-components";
import selectedTheme from "../../../themes";

export const PhonePopoverContainer = styled(Box)`
width: 138px;
height: 49px;
filter: drop-shadow(4px 4px 9px rgba(0, 0, 0, 0.04));
position: relative;
overflow: visible !important;
`;
export const Arrow = styled(Box)`
position: absolute;
width: 13px;
height: 13px;
right: -6px;
top: 18px;
background: white;
border-radius: 0.72px;
transform: rotate(45deg);
`;
export const PhoneLabel = styled(Box)`
color: ${selectedTheme.primaryDarkText};
font-size: 12px;
line-height: 16px;
text-align: center;
align-items: center;
display: flex;
font-family: "Open Sans";
position: relative;
left: 18px;
top: 5px;
`;
export const PhoneNumber = styled(Box)`
position: relative;
left: 18px;
top: 5px;
font-family: "Open Sans";
font-weight: 600;
font-size: 16px;
line-height: 22px;
align-items: center;
color: ${selectedTheme.primaryPurple};
`;

+ 19
- 2
src/components/Popovers/PopoverComponent.js Переглянути файл

import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { Popover } from "@mui/material"; import { Popover } from "@mui/material";


const PopoverComponent = ({ open, anchorEl, onClose, content }) => {
const PopoverComponent = ({ open, anchorEl, onClose, content, className, anchorRight }) => {
const handleClose = () => { const handleClose = () => {
onClose(); onClose();
}; };


return ( return (
<Popover <Popover
className={className}
open={open} open={open}
anchorEl={anchorEl} anchorEl={anchorEl}
onClose={handleClose} onClose={handleClose}
anchorOrigin={{ anchorOrigin={{
vertical: "bottom",
vertical: anchorRight ? "top" : "bottom",
horizontal: "left", horizontal: "left",
}} }}
PaperProps={{
style: {
overflow: "visible",
overflowX: "visible",
overflowY: "visible",
}
}}
transformOrigin={{
vertical: "top",
horizontal: anchorRight ? "right" : "center"
}}
> >
{content} {content}
</Popover> </Popover>
open: PropTypes.bool.isRequired, open: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
content: PropTypes.any, content: PropTypes.any,
className: PropTypes.string,
anchorRight: PropTypes.bool,
}; };
PopoverComponent.defaultProps = {
anchorRight: false,
}


export default PopoverComponent; export default PopoverComponent;

+ 21
- 0
src/components/Profile/ProfileOffers/NoProfileOffers.js/NoProfileOffers.js Переглянути файл

import React from 'react'
import PropTypes from 'prop-types'
import { NoProfileOffersAltText, NoProfileOffersContainer, NoProfileOffersIcon, NoProfileOffersMainText } from './NoProfileOffers.styled'
import { useTranslation } from 'react-i18next'

const NoProfileOffers = () => {
const {t} = useTranslation();
return (
<NoProfileOffersContainer>
<NoProfileOffersIcon />
<NoProfileOffersMainText>{t("profile.noOffers.mainText")}</NoProfileOffersMainText>
<NoProfileOffersAltText>{t("profile.noOffers.altText")}</NoProfileOffersAltText>
</NoProfileOffersContainer>
)
}

NoProfileOffers.propTypes = {
children: PropTypes.node,
}

export default NoProfileOffers

+ 35
- 0
src/components/Profile/ProfileOffers/NoProfileOffers.js/NoProfileOffers.styled.js Переглянути файл

import { Box, Typography } from "@mui/material";
import styled from "styled-components";
import {ReactComponent as HalfLogo} from "../../../../assets/images/svg/half-logo.svg"
import selectedTheme from "../../../../themes";

export const NoProfileOffersContainer = styled(Box)`
text-align: center;
background-color: white;
height: 340px;
display: flex;
flex-direction: column;
border-radius: 4px;
`
export const NoProfileOffersIcon = styled(HalfLogo)`
margin-top: 85px;
text-align: center;
width: 100%;
`
export const NoProfileOffersMainText = styled(Typography)`
font-family: "Open Sans";
font-weight: 700;
font-size: 24px;
text-align: center;
color: ${selectedTheme.primaryPurple};
margin-top: 10px;
line-height: 33px;
`
export const NoProfileOffersAltText = styled(Typography)`
font-family: "Open Sans";
font-size: 16px;
color: ${selectedTheme.primaryGrayText};
text-align: center;
margin-top: 9px;
line-height: 22px;
`

+ 70
- 45
src/components/Profile/ProfileOffers/ProfileOffers.js Переглянути файл

import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useRef } from "react"; import { useRef } from "react";
import { selectProfileOffers } from "../../../store/selectors/offersSelectors"; import { selectProfileOffers } from "../../../store/selectors/offersSelectors";
import useScreenDimensions from "../../../hooks/useScreenDimensions";
import { selectLatestChats } from "../../../store/selectors/chatSelectors"; import { selectLatestChats } from "../../../store/selectors/chatSelectors";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { selectUserId } from "../../../store/selectors/loginSelectors"; import { selectUserId } from "../../../store/selectors/loginSelectors";
import NoProfileOffers from "./NoProfileOffers.js/NoProfileOffers";
import { selectIsLoadingByActionType } from "../../../store/selectors/loadingSelectors";
import { OFFERS_PROFILE_SCOPE } from "../../../store/actions/offers/offersActionConstants";
import SkeletonOfferCard from "../../Cards/OfferCard/SkeletonOfferCard/SkeletonOfferCard";
import useIsMobile from "../../../hooks/useIsMobile";


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


const messageUser = (offer) => { const messageUser = (offer) => {
const chatItem = chats.find( const chatItem = chats.find(
}, [sortOption]); }, [sortOption]);


useEffect(() => { useEffect(() => {
if (profileOffers?.length > 0) setOffersToShow(profileOffers);
if (profileOffers) setOffersToShow(profileOffers);
}, [profileOffers]); }, [profileOffers]);


const handleSearch = () => { const handleSearch = () => {


return ( return (
<ProfileOffersContainer> <ProfileOffersContainer>
<HeaderSelect
value={sortOption?.value ? sortOption.value : sortEnum.INITIAL.value}
IconComponent={DownArrow}
onChange={handleChangeSelect}
>
{Object.keys(sortEnum).map((property) => {
return (
<SelectOption
value={sortEnum[property].value}
key={sortEnum[property].value}
>
{sortEnum[property].mainText}
</SelectOption>
);
})}
</HeaderSelect>
{offersToShow.length !== 0 ? (
<HeaderSelect
value={sortOption?.value ? sortOption.value : sortEnum.INITIAL.value}
IconComponent={DownArrow}
onChange={handleChangeSelect}
>
{Object.keys(sortEnum).map((property) => {
return (
<SelectOption
value={sortEnum[property].value}
key={sortEnum[property].value}
>
{sortEnum[property].mainText}
</SelectOption>
);
})}
</HeaderSelect>
) : (
<></>
)}
<Grid <Grid
container container
direction="row" direction="row"
{props.isMyProfile ? "Moje objave" : "Objave kompanije"} {props.isMyProfile ? "Moje objave" : "Objave kompanije"}
</HeaderTitle> </HeaderTitle>
</Grid> </Grid>
<SearchInput
fullWidth
ref={searchRef}
onFocus={handleFocusSearch}
onBlur={handleBlurSearch}
// ref={searchRef}
placeholder={t("header.searchOffers")}
italicPlaceholder
InputProps={{
endAdornment: (
<IconContainer onClick={handleSearch}>
<SearchIcon />
</IconContainer>
),
}}
/>
{offersToShow.length !== 0 ? (
<SearchInput
fullWidth
ref={searchRef}
onFocus={handleFocusSearch}
onBlur={handleBlurSearch}
// ref={searchRef}
placeholder={t("header.searchOffers")}
italicPlaceholder
InputProps={{
endAdornment: (
<IconContainer onClick={handleSearch}>
<SearchIcon />
</IconContainer>
),
}}
/>
) : (
<></>
)}
<OffersContainer> <OffersContainer>
{dimensions.width > 600 ? (
offersToShow.map((item) => (
<OfferCard
isMyOffer={props.isMyProfile}
offer={item}
key={JSON.stringify(item)}
pinned
messageUser={messageUser}
/>
))
{!isMobile ? (
isLoadingMineOffers || isLoadingMineOffers === undefined ? (
arrayForMapping.map((item, index) => (
<SkeletonOfferCard key={index} />
))
) : offersToShow.length !== 0 ? (
offersToShow.map((item) => (
<OfferCard
isMyOffer={props.isMyProfile}
offer={item}
key={JSON.stringify(item)}
pinned
messageUser={messageUser}
/>
))
) : (
<NoProfileOffers />
)
) : ( ) : (
<OffersScroller hideArrows> <OffersScroller hideArrows>
{offersToShow.map((item) => ( {offersToShow.map((item) => (

+ 10
- 10
src/components/ProfileCard/EditProfile/EditProfile.js Переглянути файл

} from "../../../store/actions/profile/profileActions"; } from "../../../store/actions/profile/profileActions";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { selectUserId } from "../../../store/selectors/loginSelectors"; import { selectUserId } from "../../../store/selectors/loginSelectors";
import useScreenDimensions from "../../../hooks/useScreenDimensions";
import editProfileValidation from "../../../validations/editProfileValidation"; import editProfileValidation from "../../../validations/editProfileValidation";
import useIsMobile from "../../../hooks/useIsMobile";


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


useEffect(() => { useEffect(() => {
if (dimensions.width < 600) {
if (isMobile) {
setShowDetails(false); setShowDetails(false);
} else { } else {
setShowDetails(true); setShowDetails(true);
} }
}, [dimensions.width]);
}, [isMobile]);


const handleApiResponseSuccess = () => { const handleApiResponseSuccess = () => {
dispatch(fetchMineProfile(userId)); dispatch(fetchMineProfile(userId));


const formik = useFormik({ const formik = useFormik({
initialValues: { initialValues: {
firmName: `${props.profile.company.name}`,
firmPIB: `${props.profile.company.PIB}`,
firmLocation: `${props.profile.company.contacts.location}`,
firmWebsite: `${props.profile.company.contacts.web}`,
firmName: `${props?.profile?.company?.name}`,
firmPIB: `${props?.profile?.company?.PIB}`,
firmLocation: `${props?.profile?.company?.contacts?.location ?? ""}`,
firmWebsite: `${props?.profile?.company?.contacts?.web ?? ""}`,
firmApplink: "", firmApplink: "",
firmPhone: `${props.profile.company.contacts.telephone}`,
firmPhone: `${props?.profile?.company?.contacts?.telephone ?? ""}`,
firmLogo: profileImage, firmLogo: profileImage,
}, },
validationSchema: editProfileValidation, validationSchema: editProfileValidation,
<></> <></>
)} )}


{dimensions.width > 600 ? (
{!isMobile ? (
<ButtonsContainer> <ButtonsContainer>
<SaveButton <SaveButton
type="submit" type="submit"

+ 16
- 12
src/components/ProfileCard/ProfileContact/ProfileContact.js Переглянути файл

justifyContent={{ xs: "center", sm: "start" }} justifyContent={{ xs: "center", sm: "start" }}
alignItems={{ xs: "start", sm: "center" }} alignItems={{ xs: "start", sm: "center" }}
> >
<Stack direction="row">
<LocationIcon isMyProfile={props.isMyProfile} />
<ContactItem isMyProfile={props.isMyProfile} variant="subtitle2">
{props.profile?.company?.contacts?.location}
</ContactItem>
</Stack>
{props.profile?.company?.contacts?.location && (
<Stack direction="row">
<LocationIcon isMyProfile={props.isMyProfile} />
<ContactItem isMyProfile={props.isMyProfile} variant="subtitle2">
{props.profile?.company?.contacts?.location}
</ContactItem>
</Stack>
)}
<Stack direction="row"> <Stack direction="row">
<MailIcon isMyProfile={props.isMyProfile} /> <MailIcon isMyProfile={props.isMyProfile} />
<ContactItem isMyProfile={props.isMyProfile} variant="subtitle2"> <ContactItem isMyProfile={props.isMyProfile} variant="subtitle2">
{props.profile?.email} {props.profile?.email}
</ContactItem> </ContactItem>
</Stack> </Stack>
<Stack direction="row">
<GlobeIcon isMyProfile={props.isMyProfile} />
<ContactItem isMyProfile={props.isMyProfile} variant="subtitle2">
{props.profile?.company?.contacts?.web}
</ContactItem>
</Stack>
{props.profile?.company?.contacts?.web && (
<Stack direction="row">
<GlobeIcon isMyProfile={props.isMyProfile} />
<ContactItem isMyProfile={props.isMyProfile} variant="subtitle2">
{props.profile?.company?.contacts?.web}
</ContactItem>
</Stack>
)}
</ProfileContactContainer> </ProfileContactContainer>
); );
}; };

+ 3
- 3
src/components/UserReviews/NoReviews/NoReviews.js Переглянути файл

import React from "react"; import React from "react";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import useScreenDimensions from "../../../hooks/useScreenDimensions";
import { import {
NoReviewsAltText, NoReviewsAltText,
NoReviewsContainer, NoReviewsContainer,
} from "./NoReviews.styled"; } from "./NoReviews.styled";
import UserReviewsSkeleton from "./UserReviewsSkeleton/UserReviewsSkeleton"; import UserReviewsSkeleton from "./UserReviewsSkeleton/UserReviewsSkeleton";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import useIsMobile from "../../../hooks/useIsMobile";
const NoReviews = () => { const NoReviews = () => {
const { width } = useScreenDimensions();
const { isMobile } = useIsMobile();
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<NoReviewsContainer> <NoReviewsContainer>
<NoReviewsText>{t("reviews.title")}</NoReviewsText> <NoReviewsText>{t("reviews.title")}</NoReviewsText>
<NoReviewsAltText>{t("reviews.altTitle")}</NoReviewsAltText> <NoReviewsAltText>{t("reviews.altTitle")}</NoReviewsAltText>
<UserReviewsSkeleton numOfElements={width < 600 ? 1 : 2} />
<UserReviewsSkeleton numOfElements={isMobile ? 1 : 2} />
</NoReviewsContainer> </NoReviewsContainer>
); );
}; };

+ 1
- 1
src/components/UserReviews/UserReviews.styled.js Переглянути файл

/* height: ${props => props.numOfReviews > 0 ? props.numOfReviews * 185 + 82 + 'px' : `calc(100% - 90px)`}; */ /* height: ${props => props.numOfReviews > 0 ? props.numOfReviews * 185 + 82 + 'px' : `calc(100% - 90px)`}; */
/* max-height: 100vh; */ /* max-height: 100vh; */
@media (max-width: 1200px) { @media (max-width: 1200px) {
padding: 0;
padding: 0 50px;
} }
@media (max-width: 600px) { @media (max-width: 600px) {
position: relative; position: relative;

+ 19
- 0
src/hooks/useIsMobile.js Переглянути файл

import { useEffect, useState } from "react";

const useIsMobile = () => {
const [isMobile, setIsMobile] = useState(false);
useEffect(() => {
const resize = () => {
if (window.innerWidth < 600) {
if (!isMobile) setIsMobile(true);
} else {
if (isMobile) setIsMobile(false);
}
};
window.addEventListener("resize", resize);
resize();
return () => window.removeEventListener("resize", resize);
}, []);
return { isMobile };
};
export default useIsMobile;

+ 6
- 0
src/hooks/useOffers/useMyOffers.js Переглянути файл

dispatch(fetchMineOffers()); dispatch(fetchMineOffers());
}, []); }, []);


const clear = () => {
filters.clear();
setAppliedFilters(false);
}

const apply = () => { const apply = () => {
paging.changePage(1); paging.changePage(1);
setAppliedFilters(false); setAppliedFilters(false);
allOffersToShow, allOffersToShow,
totalOffers, totalOffers,
apply, apply,
clear,
}; };
}; };
export default useMyOffers; export default useMyOffers;

+ 4
- 0
src/i18n/resources/rs.js Переглянути файл

numberOfViews: " ukupnih pregleda", numberOfViews: " ukupnih pregleda",
successComunication: " korektna komunikacija", successComunication: " korektna komunikacija",
back: "Nazad na objave", back: "Nazad na objave",
noOffers: {
mainText: "Objave nisu pronađene",
altText: "Nažalost nemate ni jednu objavu"
}
}, },
}; };

+ 1
- 1
src/pages/HomePage/HomePage.styled.js Переглянути файл

flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-color: ${selectedTheme.offerBackgroundColor};
background-color: ${selectedTheme.primaryBackgroundColor};
`; `;
export const GridStyled = styled(Grid)` export const GridStyled = styled(Grid)`

+ 20
- 10
src/pages/RegisterPages/Register/FirstPart/FirstPartOfRegistration.js Переглянути файл

const [emailTakenStatus, setEmailTakenStatus] = useState(false); const [emailTakenStatus, setEmailTakenStatus] = useState(false);
const { t } = useTranslation(); const { t } = useTranslation();


useEffect(() => {
if (props.informations?.mail) {
formik.setFieldValue("mail", props.informations.mail);
formik.setFieldValue("password", props.informations.password)
}
}, [props.informations])

useEffect(() => { useEffect(() => {
if (props.error.length > 0) { if (props.error.length > 0) {
setEmailTakenStatus(true); setEmailTakenStatus(true);


const formik = useFormik({ const formik = useFormik({
initialValues: { initialValues: {
mail: "",
password: "",
mail: props.informations?.mail ?? "",
password: props.informations?.password ?? "",
}, },
validationSchema: firstPartValidation, validationSchema: firstPartValidation,
onSubmit: props.handleSubmit, onSubmit: props.handleSubmit,
enableReinitialize: true, enableReinitialize: true,
}); });


const handleSubmitForm = (event) => {
event.preventDefault();
console.log(formik);
if (!formik.isValid) {
if (formik.errors.mail) {
formik.setFieldValue("mail", "");
formik.setFieldTouched("mail", true);
}
if (formik.errors.password) {
formik.setFieldValue("password", "");
formik.setFieldTouched("password", true);
}
} else {
formik.handleSubmit(event)
}
}

const handleClickShowPassword = () => { const handleClickShowPassword = () => {
setShowPassword((prevState) => !prevState); setShowPassword((prevState) => !prevState);
}; };
return ( return (
<FormContainer component="form" onSubmit={formik.handleSubmit}>
<FormContainer component="form" onSubmit={handleSubmitForm}>
<RegisterDescription component="p" variant="p"> <RegisterDescription component="p" variant="p">
{t("register.descriptionFirst")} {t("register.descriptionFirst")}
</RegisterDescription> </RegisterDescription>

+ 2
- 1
src/pages/RegisterPages/Register/Register.js Переглянути файл

} }
}; };



const registerUser = (values) => { const registerUser = (values) => {
dispatch( dispatch(
fetchRegisterUser({ values, handleResponseSuccess, handleResponseError }) fetchRegisterUser({ values, handleResponseSuccess, handleResponseError })
</LoginTextContainer> </LoginTextContainer>
</RegisterPageContent> </RegisterPageContent>


<Footer>
<Footer currentStep={currentStep}>
<FooterText> <FooterText>
<Trans i18nKey="register.acceptTerms" />{" "} <Trans i18nKey="register.acceptTerms" />{" "}
<NavLink <NavLink

+ 16
- 14
src/pages/RegisterPages/Register/Register.styled.js Переглянути файл

width: 335px; width: 335px;
padding: 0; padding: 0;
flex: 1; flex: 1;
position: relative;
/* position: relative; */ /* position: relative; */
transition: 1s all; transition: 1s all;
${props => props.currentstep === 3 && `margin-top: 40px`};
margin-bottom: 60px;
${(props) => props.currentstep === 3 && `margin-top: 40px;`};
@media (max-height: 900px) { @media (max-height: 900px) {
margin-top: 60px; margin-top: 60px;
} }
@media (max-height: 800px) { @media (max-height: 800px) {
margin-top: 30px; margin-top: 30px;
flex: none;
height: 95vh;
${(props) => props.currentstep === 3 && `height: 105vh`};
${(props) => props.currentstep === 2 && `height: 100vh`};
/* flex: none; */
/* height: 95vh; */
/* ${(props) => props.currentstep === 3 && `height: 105vh`};
${(props) => props.currentstep === 2 && `height: 100vh`}; */
}
@media (max-width: 600px) {
margin-bottom: 60px;
} }
`; `;
export const RegisterTitle = styled(Typography)` export const RegisterTitle = styled(Typography)`
padding: 0; padding: 0;
`; `;
export const Footer = styled(Box)` export const Footer = styled(Box)`
position: relative;
bottom: 36px;
position: absolute;
bottom: -48px;
display: flex; display: flex;
width: 100%; width: 100%;
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
@media (max-height: 800px) {
bottom: 10px;
}
`; `;
export const FooterText = styled(Typography)` export const FooterText = styled(Typography)`
font-family: "Open Sans"; font-family: "Open Sans";
padding: 0; padding: 0;
flex: 1; flex: 1;
position: relative; position: relative;
margin-bottom: 100px;
@media (max-height: 800px) {
/* margin-bottom: 100px; */
/* @media (max-height: 800px) {
flex: none; flex: none;
height: 95vh; height: 95vh;
${(props) => props.currentstep === 3 && `height: 105vh`}; ${(props) => props.currentstep === 3 && `height: 105vh`};
${(props) => props.currentstep === 2 && `height: 100vh`}; ${(props) => props.currentstep === 2 && `height: 100vh`};
}
} */
`; `;
export const ErrorMessage = styled(Box)` export const ErrorMessage = styled(Box)`
color: red; color: red;
text-align: left; text-align: left;
font-size: 14px; font-size: 14px;
width: 100%; width: 100%;
`
`;

+ 0
- 1
src/request/index.js Переглянути файл

// baseURL: "http://192.168.88.150:3001/", // baseURL: "http://192.168.88.150:3001/",
// baseURL: "http://192.168.88.175:3005/", // baseURL: "http://192.168.88.175:3005/",
baseURL: "https://trampa-api-test.dilig.net/", baseURL: "https://trampa-api-test.dilig.net/",

headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },

+ 8
- 2
src/store/saga/profileSaga.js Переглянути файл

name: payload.payload.firmName, name: payload.payload.firmName,
PIB: payload.payload.firmPIB, PIB: payload.payload.firmPIB,
contacts: { contacts: {
telephone: payload.payload.firmPhone,
location: payload.payload.firmLocation,
telephone: payload.payload.firmPhone.toString(),
location: payload.payload.firmLocation ?? "",
web: payload.payload.firmWebsite, web: payload.payload.firmWebsite,
}, },
}, },
}; };


if (payload.payload.firmLogo.includes("https")) delete reqData.image; if (payload.payload.firmLogo.includes("https")) delete reqData.image;
if (reqData.company.contacts.telephone.length === 0)
delete reqData.company.contacts.telephone;
if (reqData.company.contacts.location.length === 0)
delete reqData.company.contacts.location;
if (reqData.company.contacts.web.length === 0)
delete reqData.company.contacts.web;


const userId = yield select(selectUserId); const userId = yield select(selectUserId);
const data = yield call(attemptEditProfile, userId, reqData); const data = yield call(attemptEditProfile, userId, reqData);

+ 1
- 0
src/util/helpers/queryHelpers.js Переглянути файл

VALUE_SORTBY_POPULAR, VALUE_SORTBY_POPULAR,
} from "../../constants/queryStringConstants"; } from "../../constants/queryStringConstants";
import { sortEnum } from "../../enums/sortEnum"; import { sortEnum } from "../../enums/sortEnum";
// import { ReactComponent as CategoryHeader } from "../../assets/images/svg/category-header.svg"
// import qs from "query-string"; // import qs from "query-string";


export const convertQueryStringForFrontend = (queryURL) => { export const convertQueryStringForFrontend = (queryURL) => {

+ 5
- 4
src/validations/registerValidations/firstPartValidation.js Переглянути файл

import * as Yup from "yup"; import * as Yup from "yup";
import YupPassword from 'yup-password';
YupPassword(Yup);
import i18n from "../../i18n"; import i18n from "../../i18n";
export default Yup.object().shape({ export default Yup.object().shape({
mail: Yup.string() mail: Yup.string()
password: Yup.string() password: Yup.string()
.required(i18n.t("login.passwordRequired")) .required(i18n.t("login.passwordRequired"))
.min(8, i18n.t("login.passwordLength")) .min(8, i18n.t("login.passwordLength"))
.matches(
/^(?=.*[a-z])(?=.*[A-Z])(?=.*[#$^+=!*()@%&]).{8,25}$/g,
i18n.t("password.strongPassword")
),
.minLowercase(1, i18n.t("password.strongPassword"))
.minUppercase(1, i18n.t("password.strongPassword"))
.minSymbols(1, i18n.t("password.strongPassword")),
}); });

Завантаження…
Відмінити
Зберегти