| @@ -0,0 +1,48 @@ | |||
| import React, { useCallback, useRef } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { TextField } from "../../../TextFields/TextField/TextField"; | |||
| import { EndIcon, SearchIcon } from "./HeadersMyOffers.styled"; | |||
| import { useTranslation } from "react-i18next"; | |||
| const HeadersMyOffers = (props) => { | |||
| const searchRef = useRef(null); | |||
| const {t} = useTranslation(); | |||
| let listener = useCallback((event) => { | |||
| if (event.keyCode === 13) { | |||
| event.preventDefault(); | |||
| handleSearch(); | |||
| } | |||
| }, [searchRef.current]) | |||
| const handleFocusSearch = () => { | |||
| searchRef.current.addEventListener("keyup", listener); | |||
| }; | |||
| const handleBlurSearch = () => { | |||
| searchRef.current.removeEventListener("keyup", listener); | |||
| }; | |||
| const handleSearch = () => { | |||
| props.searchMyOffers(searchRef.current.value); | |||
| }; | |||
| return ( | |||
| <TextField | |||
| fullWidth | |||
| InputProps={{ | |||
| endAdornment: ( | |||
| <EndIcon size="36px"> | |||
| <SearchIcon onClick={() => handleSearch(searchRef.current.value)} /> | |||
| </EndIcon> | |||
| ), | |||
| }} | |||
| placeholder={t("header.searchOffers")} | |||
| onFocus={handleFocusSearch} | |||
| onBlur={handleBlurSearch} | |||
| ref={searchRef} | |||
| /> | |||
| ); | |||
| }; | |||
| HeadersMyOffers.propTypes = { | |||
| children: PropTypes.node, | |||
| searchMyOffers: PropTypes.func, | |||
| }; | |||
| export default HeadersMyOffers; | |||
| @@ -0,0 +1,25 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import { Icon } from "../../../Icon/Icon"; | |||
| import { ReactComponent as Search } from "../../../../assets/images/svg/magnifying-glass.svg"; | |||
| import selectedTheme from "../../../../themes"; | |||
| export const HeadersMyOffersContainer = styled(Box)``; | |||
| export const EndIcon = styled(Icon)``; | |||
| export const SearchIcon = styled(Search)` | |||
| position: relative; | |||
| top: 11px; | |||
| left: 4px; | |||
| cursor: pointer; | |||
| color: ${selectedTheme.primaryPurple}; | |||
| & path { | |||
| width: 18px; | |||
| height: 18px; | |||
| } | |||
| @media (max-width: 600px) { | |||
| height: 14px; | |||
| width: 14px; | |||
| left: 11px; | |||
| } | |||
| `; | |||
| @@ -9,6 +9,7 @@ import { selectUserId } from "../../../store/selectors/loginSelectors"; | |||
| import { startChat } from "../../../util/helpers/chatHelper"; | |||
| import useOffers from "../../../hooks/useOffers"; | |||
| import OffersNotFound from "./OffersNotFound"; | |||
| import HeadersMyOffers from "./HeaderMyOffers.js/HeadersMyOffers"; | |||
| const Offers = (props) => { | |||
| const chats = useSelector(selectLatestChats); | |||
| @@ -20,8 +21,12 @@ const Offers = (props) => { | |||
| startChat(chats, offer, userId); | |||
| }; | |||
| console.log(offers.allOffersToShow); | |||
| return ( | |||
| <> | |||
| {props.myOffers && ( | |||
| <HeadersMyOffers searchMyOffers={offers.searchMyOffers} /> | |||
| )} | |||
| {offers.allOffersToShow.length === 0 ? ( | |||
| <OffersNotFound /> | |||
| ) : ( | |||
| @@ -52,7 +52,7 @@ const HeaderPopover = (props) => { | |||
| <PopoverNoItemsText>{t("header.noItems")}</PopoverNoItemsText> | |||
| )} | |||
| </PopoverList> | |||
| <PopoverButtonsContainer> | |||
| <PopoverButtonsContainer hideButtons={props.hideButtons}> | |||
| <PopoverButton | |||
| sx={{ | |||
| mr: 2, | |||
| @@ -92,6 +92,7 @@ HeaderPopover.propTypes = { | |||
| secondButtonIcon: PropTypes.any, | |||
| buttonOnClick: PropTypes.func, | |||
| secondButtonOnClick: PropTypes.func, | |||
| hideButtons: PropTypes.bool, | |||
| }; | |||
| export default HeaderPopover; | |||
| @@ -71,7 +71,7 @@ export const EyeIcon = styled(Eye)` | |||
| `; | |||
| export const PopoverButtonsContainer = styled(Box)` | |||
| flex-direction: column; | |||
| display: flex; | |||
| display: ${props => props.hideButtons ? 'none' : 'flex'}; | |||
| align-items: flex-end; | |||
| `; | |||
| export const PopoverNoItemsText = styled(Typography)` | |||
| @@ -2,7 +2,6 @@ import React, { useEffect, useState } from "react"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| import { useHistory } from "react-router-dom"; | |||
| import { CHAT_PAGE } from "../../../constants/pages"; | |||
| import { fetchHeaderChats } from "../../../store/actions/chat/chatActions"; | |||
| import { selectLatestChats } from "../../../store/selectors/chatSelectors"; | |||
| import { selectUserId } from "../../../store/selectors/loginSelectors"; | |||
| @@ -42,7 +41,7 @@ export const MyMessages = () => { | |||
| } | |||
| }, [chats]); | |||
| const goToMessages = () => { | |||
| history.push(CHAT_PAGE); | |||
| history.push(`messages/${chats[0].chat?._id}`); | |||
| }; | |||
| return ( | |||
| <HeaderPopover | |||
| @@ -10,6 +10,7 @@ import { | |||
| fetchOffers, | |||
| } from "../store/actions/offers/offersActions"; | |||
| import { | |||
| selectAppliedStatus, | |||
| selectSelectedCategory, | |||
| selectSelectedLocations, | |||
| selectSelectedSortOption, | |||
| @@ -34,8 +35,11 @@ const useOffers = (myOffers) => { | |||
| const selectedSubcategory = useSelector(selectSelectedSubcategory); | |||
| const selectedLocations = useSelector(selectSelectedLocations); | |||
| const selectedSortOption = useSelector(selectSelectedSortOption); | |||
| const isApplied = useSelector(selectAppliedStatus); | |||
| const total = useSelector(selectTotalOffers); | |||
| const [page, setPage] = useState(1); | |||
| const [searchQuery, setSearchQuery] = useState(""); | |||
| const [myOffersLength, setMyOffersLength] = useState(0); | |||
| //Fetching chats | |||
| useEffect(() => { | |||
| @@ -107,7 +111,7 @@ const useOffers = (myOffers) => { | |||
| const allOffersToShow = useMemo(() => { | |||
| let newOffers = [...pinnedOffersToShow, ...offersToShow]; | |||
| if (myOffers) { | |||
| // Filtering my offers based on category | |||
| // Filtering my offers based on category | |||
| if (selectedCategory && selectedCategory?._id !== 0) { | |||
| newOffers = newOffers.filter( | |||
| (item) => item.category.name === selectedCategory.name | |||
| @@ -181,18 +185,33 @@ const useOffers = (myOffers) => { | |||
| ), | |||
| ]; | |||
| } | |||
| newOffers = newOffers.filter((item) => | |||
| item?.name?.toLowerCase().includes(searchQuery.toLowerCase(), 0) | |||
| ); | |||
| setMyOffersLength(newOffers?.length); | |||
| newOffers = newOffers.slice((page - 1) * 10, page * 10); | |||
| } | |||
| return newOffers; | |||
| }, [pinnedOffersToShow, offersToShow, myOffers, page]); | |||
| }, [ | |||
| pinnedOffersToShow, | |||
| offersToShow, | |||
| myOffers, | |||
| page, | |||
| searchQuery, | |||
| isApplied, | |||
| ]); | |||
| // Total number of all offers that can be shown | |||
| const totalOffers = useMemo(() => { | |||
| if (myOffers) { | |||
| return mineOffers?.length; | |||
| return myOffersLength; | |||
| } | |||
| return total; | |||
| }, [mineOffers, total, myOffers]); | |||
| }, [total, myOffersLength]); | |||
| const searchMyOffers = (searchValue) => { | |||
| setSearchQuery(searchValue); | |||
| }; | |||
| // Changing page | |||
| const handleDifferentPage = (pageNum) => { | |||
| @@ -228,6 +247,7 @@ const useOffers = (myOffers) => { | |||
| totalOffers, | |||
| allOffersToShow, | |||
| page, | |||
| searchMyOffers, | |||
| }; | |||
| }; | |||
| export default useOffers; | |||
| @@ -27,11 +27,11 @@ const ThirdPartOfRegistration = (props) => { | |||
| }, [props.informations]) | |||
| const handleSubmit = () => { | |||
| if (!formik.values.website.matches( | |||
| if (formik.values.website?.length !== 0 && !formik.values.website.match( | |||
| /^((ftp|http|https):\/\/)?(www.)?(?!.*(ftp|http|https|www.))[a-zA-Z0-9_-]+(\.[a-zA-Z]+)+((\/)[\w#]+)*(\/\w+\?[a-zA-Z0-9_]+=\w+(&[a-zA-Z0-9_]+=\w+)*)?$/gm | |||
| )) { | |||
| formik.setFieldError("website"); | |||
| } else{ | |||
| } else { | |||
| props.handleSubmit(formik.values); | |||
| } | |||
| @@ -105,11 +105,6 @@ const ThirdPartOfRegistration = (props) => { | |||
| fullWidth | |||
| buttoncolor={selectedTheme.primaryPurple} | |||
| textcolor="white" | |||
| disabled={ | |||
| formik.values.location.length === 0 && | |||
| formik.values.phoneNumber.length === 0 && | |||
| formik.values.website.length === 0 | |||
| } | |||
| > | |||
| {t("common.continue")} | |||
| </PrimaryButton> | |||
| @@ -4,7 +4,7 @@ import { REGISTER_USER_FETCH } from "../actions/register/registerActionConstants | |||
| function* fetchRegisterUser({ payload }) { | |||
| try { | |||
| const requestData = { | |||
| let requestData = { | |||
| email: payload.values.mail.toString(), | |||
| password: payload.values.password.toString(), | |||
| image: payload.values.image | |||
| @@ -21,6 +21,12 @@ function* fetchRegisterUser({ payload }) { | |||
| }, | |||
| }, | |||
| }; | |||
| if (payload.values.phoneNumber?.length === 0) | |||
| delete requestData.company.contacts.telephone; | |||
| if (payload.values.location?.length === 0) | |||
| delete requestData.company.contacts.location; | |||
| if (payload.values.website?.length === 0) | |||
| delete requestData.company.contacts.web; | |||
| yield call(attemptRegister, requestData); | |||
| if (payload.handleResponseSuccess) { | |||
| yield call(payload.handleResponseSuccess); | |||