| "redux-persist-transform-filter": "0.0.20", | "redux-persist-transform-filter": "0.0.20", | ||||
| "redux-saga": "^1.1.3", | "redux-saga": "^1.1.3", | ||||
| "sass": "^1.34.1", | "sass": "^1.34.1", | ||||
| "socket.io": "^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" |
| import React from "react"; | import React from "react"; | ||||
| // import io from 'socket.io-client'; | |||||
| import { Router } from "react-router-dom"; | import { Router } from "react-router-dom"; | ||||
| import { Helmet } from "react-helmet-async"; | import { Helmet } from "react-helmet-async"; | ||||
| import i18next from "i18next"; | import i18next from "i18next"; | ||||
| import { StyledEngineProvider } from "@mui/material"; | import { StyledEngineProvider } from "@mui/material"; | ||||
| import GlobalStyle from "./components/Styles/globalStyles"; | import GlobalStyle from "./components/Styles/globalStyles"; | ||||
| // const URL = "http://192.168.88.143:3001"; | |||||
| // const socket = io(URL, {autoConnect: true, transports: ['websocket']}); | |||||
| const App = () => { | const App = () => { | ||||
| // console.log(io) | |||||
| // const [isConnected, setIsConnected] = useState(socket.connected); | |||||
| // const [lastPong, setLastPong] = useState(null); | |||||
| // console.log(); | |||||
| // useEffect(() => { | |||||
| // socket.on("connect", (client) => { | |||||
| // console.log(client); | |||||
| // setIsConnected(true); | |||||
| // }); | |||||
| // // socket.on("connect_error", (err) => { | |||||
| // // console.log(err); | |||||
| // // }); | |||||
| // socket.on("connection", (client) => { | |||||
| // console.log(client); | |||||
| // }); | |||||
| // socket.on("disconnect", () => { | |||||
| // setIsConnected(false); | |||||
| // }); | |||||
| // // socket.on('emit', (client) => { | |||||
| // // console.log(client); | |||||
| // // }) | |||||
| // socket.on("sokkk", (clg) => { | |||||
| // console.log(clg); | |||||
| // }) | |||||
| // // socket.onAny((event, ...args) => { | |||||
| // // console.log(event, args); | |||||
| // // }); | |||||
| // socket.on('povratna', (data) => { | |||||
| // console.log(data) | |||||
| // }) | |||||
| // // socket.open; | |||||
| // socket.on("pong", () => { | |||||
| // setLastPong(new Date().toISOString()); | |||||
| // }); | |||||
| // // socket.connect(); | |||||
| // return () => { | |||||
| // socket.off("connect"); | |||||
| // socket.off("disconnect"); | |||||
| // socket.off("pong"); | |||||
| // }; | |||||
| // }, []); | |||||
| // const handleClick = () => { | |||||
| // // socket.connect(); | |||||
| // // socket.emit("sokkk 2", "sock"); | |||||
| // // socket.emit("sock") | |||||
| // }; | |||||
| // const sendPing = () => { | |||||
| // socket.emit("sokkk", { | |||||
| // poruka: "Za Duleta" | |||||
| // }); | |||||
| // }; | |||||
| return ( | return ( | ||||
| <Router history={history}> | <Router history={history}> | ||||
| <Helmet> | <Helmet> | ||||
| <title>{i18next.t("app.title")}</title> | <title>{i18next.t("app.title")}</title> | ||||
| </Helmet> | </Helmet> | ||||
| <StyledEngineProvider injectFirst> | <StyledEngineProvider injectFirst> | ||||
| {/* <button onClick={handleClick}>Kik</button> */} | |||||
| <Header /> | <Header /> | ||||
| <GlobalStyle /> | <GlobalStyle /> | ||||
| {/* <div> | |||||
| <p>Connected: {"" + isConnected}</p> | |||||
| <br /> | |||||
| <p>Last pong: {lastPong || "-"}</p> | |||||
| <br /> | |||||
| <button onClick={sendPing}>Send ping</button> | |||||
| </div> */} | |||||
| <AppRoutes /> | <AppRoutes /> | ||||
| </StyledEngineProvider> | </StyledEngineProvider> | ||||
| {/* </main> */} | {/* </main> */} |
| padding: 18px; | padding: 18px; | ||||
| max-width: 2000px; | max-width: 2000px; | ||||
| position: relative; | position: relative; | ||||
| @media (max-width: 600px) { | |||||
| padding-bottom: 50px; | |||||
| } | |||||
| padding-bottom: 80px; | |||||
| `; | `; | ||||
| export const OfferImage = styled.img` | export const OfferImage = styled.img` | ||||
| width: 144px; | width: 144px; | ||||
| gap: 4px; | gap: 4px; | ||||
| @media (max-width: 600px) { | @media (max-width: 600px) { | ||||
| /* flex: 1; */ | /* flex: 1; */ | ||||
| ${props => props.last && `flex: none;`} | |||||
| ${(props) => props.last && `flex: none;`} | |||||
| } | } | ||||
| `; | `; | ||||
| export const PostDate = styled(Typography)` | export const PostDate = styled(Typography)` | ||||
| font-size: 9px; | font-size: 9px; | ||||
| line-height: 13px; | line-height: 13px; | ||||
| } | } | ||||
| `; | `; | ||||
| export const OfferDescriptionText = styled(Box)` | export const OfferDescriptionText = styled(Box)` | ||||
| font-family: "Open Sans"; | font-family: "Open Sans"; | ||||
| font-size: 16px; | font-size: 16px; | ||||
| color: ${selectedTheme.primaryDarkText}; | color: ${selectedTheme.primaryDarkText}; | ||||
| line-height: 22px; | line-height: 22px; | ||||
| max-width: calc(100% - 230px); | |||||
| max-height: 120px; | |||||
| overflow: hidden; | |||||
| display: -webkit-box; | |||||
| -webkit-line-clamp: 5; | |||||
| -webkit-box-orient: vertical; | |||||
| max-width: calc(100% - 30px); | |||||
| @media (max-width: 600px) { | @media (max-width: 600px) { | ||||
| font-size: 14px; | font-size: 14px; | ||||
| } | } | ||||
| // export const OfferImage = styled.img` | // export const OfferImage = styled.img` | ||||
| // ` | // ` | ||||
| export const Scroller = styled(HorizontalScroller)` | export const Scroller = styled(HorizontalScroller)` | ||||
| & div { | |||||
| margin: 0 9px; | |||||
| } | |||||
| ` | |||||
| & div { | |||||
| margin: 0 9px; | |||||
| } | |||||
| `; |
| CheckButton, | CheckButton, | ||||
| DetailIcon, | DetailIcon, | ||||
| DetailText, | DetailText, | ||||
| EditIcon, | |||||
| EditIconContainer, | |||||
| EyeIcon, | EyeIcon, | ||||
| Line, | Line, | ||||
| MessageIcon, | MessageIcon, | ||||
| OfferTitle, | OfferTitle, | ||||
| OfferTitleAboveImage, | OfferTitleAboveImage, | ||||
| OfferViews, | OfferViews, | ||||
| RemoveIcon, | |||||
| RemoveIconContainer, | |||||
| } from "./OfferCard.styled"; | } from "./OfferCard.styled"; | ||||
| import { ReactComponent as Category } from "../../../assets/images/svg/category.svg"; | import { ReactComponent as Category } from "../../../assets/images/svg/category.svg"; | ||||
| import { ReactComponent as Message } from "../../../assets/images/svg/mail.svg"; | import { ReactComponent as Message } from "../../../assets/images/svg/mail.svg"; | ||||
| } | } | ||||
| halfwidth={props.halfwidth ? 1 : 0} | halfwidth={props.halfwidth ? 1 : 0} | ||||
| > | > | ||||
| <OfferTitleAboveImage vertical={props.vertical} onClick={() => routeToItem(props?.offer?._id)}>{props?.offer?.name}</OfferTitleAboveImage> | |||||
| <OfferTitleAboveImage | |||||
| vertical={props.vertical} | |||||
| onClick={() => routeToItem(props?.offer?._id)} | |||||
| > | |||||
| {props?.offer?.name} | |||||
| </OfferTitleAboveImage> | |||||
| <OfferFlexContainer vertical={props.vertical}> | <OfferFlexContainer vertical={props.vertical}> | ||||
| <OfferImageContainer vertical={props.vertical}> | <OfferImageContainer vertical={props.vertical}> | ||||
| <OfferImage src={props?.offer?.images[0]} vertical={props.vertical}></OfferImage> | |||||
| <OfferImage | |||||
| src={props?.offer?.images[0]} | |||||
| vertical={props.vertical} | |||||
| ></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}>{props?.offer?.user?.company?.name}</OfferAuthorName> | |||||
| <OfferLocation vertical={props.vertical}>{props?.offer?.location?.city}</OfferLocation> | |||||
| <OfferAuthorName vertical={props.vertical}> | |||||
| {props?.offer?.user?.company?.name} | |||||
| </OfferAuthorName> | |||||
| <OfferLocation vertical={props.vertical}> | |||||
| {props?.offer?.location?.city} | |||||
| </OfferLocation> | |||||
| </OfferAuthor> | </OfferAuthor> | ||||
| <OfferDetails> | <OfferDetails> | ||||
| <OfferCategory vertical={props.vertical}> | <OfferCategory vertical={props.vertical}> | ||||
| <></> | <></> | ||||
| )} | )} | ||||
| <MessageIcon vertical={props.vertical}> | |||||
| <Message /> | |||||
| </MessageIcon> | |||||
| {/* {props.image} | |||||
| {props.title} | |||||
| {props.description} | |||||
| {props.category} | |||||
| {props.author} | |||||
| {props.location} | |||||
| {props.quantity} | |||||
| {props.package} | |||||
| {props.numberOfViews} */} | |||||
| {props.isMyOffer ? ( | |||||
| <> | |||||
| <RemoveIconContainer vertical={props.vertical}> | |||||
| <RemoveIcon /> | |||||
| </RemoveIconContainer> | |||||
| <EditIconContainer vertical={props.vertical}> | |||||
| <EditIcon /> | |||||
| </EditIconContainer> | |||||
| </> | |||||
| ) : ( | |||||
| <MessageIcon vertical={props.vertical}> | |||||
| <Message /> | |||||
| </MessageIcon> | |||||
| )} | |||||
| </OfferFlexContainer> | </OfferFlexContainer> | ||||
| </OfferCardContainer> | </OfferCardContainer> | ||||
| </React.Fragment> | </React.Fragment> | ||||
| offer: PropTypes.any, | offer: PropTypes.any, | ||||
| pinned: PropTypes.bool, | pinned: PropTypes.bool, | ||||
| vertical: PropTypes.bool, | vertical: PropTypes.bool, | ||||
| isMyOffer: PropTypes.bool, | |||||
| }; | }; | ||||
| OfferCard.defaultProps = { | OfferCard.defaultProps = { | ||||
| halfwidth: false, | halfwidth: false, |
| import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton"; | import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton"; | ||||
| import { Icon } from "../../Icon/Icon"; | import { Icon } from "../../Icon/Icon"; | ||||
| 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 Edit } from "../../../assets/images/svg/edit.svg"; | |||||
| export const OfferCardContainer = styled(Container)` | export const OfferCardContainer = styled(Container)` | ||||
| display: flex; | display: flex; | ||||
| top: 1px !important; | top: 1px !important; | ||||
| } | } | ||||
| `; | `; | ||||
| export const RemoveIconContainer = styled(MessageIcon)` | |||||
| ` | |||||
| export const RemoveIcon = styled(Remove)` | |||||
| ` | |||||
| export const EditIconContainer = styled(MessageIcon)` | |||||
| right: 70px; | |||||
| ` | |||||
| export const EditIcon = styled(Edit)` | |||||
| ` |
| }; | }; | ||||
| const handleLogoClick = () => { | const handleLogoClick = () => { | ||||
| history.push(HOME_PAGE); | |||||
| history.push({ | |||||
| pathname: HOME_PAGE, | |||||
| state: { | |||||
| logo: true | |||||
| } | |||||
| }); | |||||
| } | } | ||||
| return ( | return ( |
| import React from 'react'; | |||||
| import React, { useMemo } from 'react'; | |||||
| import Header from "./Header/Header"; | import Header from "./Header/Header"; | ||||
| import { useSelector } from 'react-redux'; | import { useSelector } from 'react-redux'; | ||||
| import { ItemDetailsContainer } from './ItemDetails.styled'; | import { ItemDetailsContainer } from './ItemDetails.styled'; | ||||
| import ItemDetailsCard from "../Cards/ItemDetailsCard/ItemDetailsCard"; | import ItemDetailsCard from "../Cards/ItemDetailsCard/ItemDetailsCard"; | ||||
| import ItemDetailsHeaderCard from "./ItemDetailsHeaderCard/ItemDetailsHeaderCard"; | import ItemDetailsHeaderCard from "./ItemDetailsHeaderCard/ItemDetailsHeaderCard"; | ||||
| import { selectOffer } from '../../store/selectors/offersSelectors'; | import { selectOffer } from '../../store/selectors/offersSelectors'; | ||||
| import { selectUserId } from '../../store/selectors/loginSelectors'; | |||||
| // import { useHistory } from 'react-router-dom'; | // import { useHistory } from 'react-router-dom'; | ||||
| const ItemDetails = () => { | const ItemDetails = () => { | ||||
| const offer = useSelector(selectOffer); | const offer = useSelector(selectOffer); | ||||
| const userId = useSelector(selectUserId); | |||||
| let isMyProfile = useMemo(() => { | |||||
| if (offer?.offer?.userId?.toString() === userId.toString()) { | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| }, [offer, userId]) | |||||
| console.log(isMyProfile) | |||||
| return ( | return ( | ||||
| <ItemDetailsContainer> | <ItemDetailsContainer> | ||||
| <Header/> | <Header/> | ||||
| <ItemDetailsHeaderCard offer={offer} /> | |||||
| <ItemDetailsCard offer={offer}/> | |||||
| <ItemDetailsHeaderCard offer={offer} isMyProfile={isMyProfile} /> | |||||
| <ItemDetailsCard offer={offer} isMyOffer={isMyProfile}/> | |||||
| </ItemDetailsContainer> | </ItemDetailsContainer> | ||||
| ) | ) | ||||
| } | } |
| BottomDetails, | BottomDetails, | ||||
| StatusText, | StatusText, | ||||
| PIBIcon, | PIBIcon, | ||||
| UserIcon, | |||||
| UserIconContainer, | |||||
| } from "./ItemDetailsHeaderCard.styled"; | } from "./ItemDetailsHeaderCard.styled"; | ||||
| import { ItemDetailsHeaderContainer } from "./ItemDetailsHeaderCard.styled"; | import { ItemDetailsHeaderContainer } from "./ItemDetailsHeaderCard.styled"; | ||||
| import { ReactComponent as Category } from "../../../assets/images/svg/category.svg"; | import { ReactComponent as Category } from "../../../assets/images/svg/category.svg"; | ||||
| console.log("header offer: ", props.offer); | console.log("header offer: ", props.offer); | ||||
| const offer = props.offer; | const offer = props.offer; | ||||
| if (!props.offer) { | if (!props.offer) { | ||||
| return ( | |||||
| <div> | |||||
| Loading... | |||||
| </div> | |||||
| ) | |||||
| return <div>Loading...</div>; | |||||
| } | } | ||||
| let percentOfSucceededExchanges; | let percentOfSucceededExchanges; | ||||
| if (offer?.companyData?.statistics?.exchanges?.succeeded === 0) { | if (offer?.companyData?.statistics?.exchanges?.succeeded === 0) { | ||||
| } | } | ||||
| const handleGoProfile = () => { | const handleGoProfile = () => { | ||||
| history.push(`/profile/${offer?.offer?.userId}`); | history.push(`/profile/${offer?.offer?.userId}`); | ||||
| } | |||||
| }; | |||||
| return ( | return ( | ||||
| <ItemDetailsHeaderContainer | <ItemDetailsHeaderContainer | ||||
| sponsored={offer?.offer?.pinned?.toString()} | |||||
| isMyProfile={props.isMyProfile} | |||||
| halfwidth={props.halfwidth ? 1 : 0} | halfwidth={props.halfwidth ? 1 : 0} | ||||
| > | > | ||||
| <HeaderTop> | <HeaderTop> | ||||
| <OfferImage src={offer?.companyData?.image}/> | |||||
| <OfferImage src={offer?.companyData?.image} /> | |||||
| <OfferDetails> | <OfferDetails> | ||||
| <OfferTitle onClick={handleGoProfile}>{offer?.companyData?.company?.name}</OfferTitle> | |||||
| <OfferTitle isMyProfile={props.isMyProfile} onClick={handleGoProfile}> | |||||
| {offer?.companyData?.company?.name} | |||||
| </OfferTitle> | |||||
| <DetailContainer> | <DetailContainer> | ||||
| <PIBIcon | |||||
| color={selectedTheme.iconStrokeColor} | |||||
| component="span" | |||||
| > | |||||
| <PIBIcon color={selectedTheme.iconStrokeColor} component="span"> | |||||
| <PIB /> | <PIB /> | ||||
| </PIBIcon> | </PIBIcon> | ||||
| <DetailText>PIB - {offer?.companyData?.company?.PIB}</DetailText> | |||||
| <DetailText isMyProfile={props.isMyProfile}> | |||||
| PIB - {offer?.companyData?.company?.PIB} | |||||
| </DetailText> | |||||
| </DetailContainer> | </DetailContainer> | ||||
| <DetailContainer shouldHideResponsive> | <DetailContainer shouldHideResponsive> | ||||
| <DetailIcon | <DetailIcon | ||||
| > | > | ||||
| <Category width={"22px"} /> | <Category width={"22px"} /> | ||||
| </DetailIcon> | </DetailIcon> | ||||
| <DetailText > | |||||
| <DetailText isMyProfile={props.isMyProfile}> | |||||
| {offer?.companyData?.company?.contacts?.location} | {offer?.companyData?.company?.contacts?.location} | ||||
| </DetailText> | </DetailText> | ||||
| </DetailContainer> | </DetailContainer> | ||||
| </OfferDetails> | </OfferDetails> | ||||
| <MessageIcon> | |||||
| <MessageColor /> | |||||
| </MessageIcon> | |||||
| {props.isMyProfile ? ( | |||||
| <UserIconContainer onClick={handleGoProfile}> | |||||
| <UserIcon /> | |||||
| </UserIconContainer> | |||||
| ) : ( | |||||
| <MessageIcon> | |||||
| <MessageColor /> | |||||
| </MessageIcon> | |||||
| )} | |||||
| </HeaderTop> | </HeaderTop> | ||||
| <HeaderDetails> | <HeaderDetails> | ||||
| <BottomDetails> | <BottomDetails> | ||||
| <b>{offer?.companyData?.statistics?.publishes?.count}</b> objava | <b>{offer?.companyData?.statistics?.publishes?.count}</b> objava | ||||
| </StatusText> | </StatusText> | ||||
| <StatusText> | <StatusText> | ||||
| <b>{offer?.companyData?.statistics?.views?.count}</b> ukupnih pregleda | |||||
| <b>{offer?.companyData?.statistics?.views?.count}</b> ukupnih | |||||
| pregleda | |||||
| </StatusText> | </StatusText> | ||||
| <StatusText> | <StatusText> | ||||
| <b>{percentOfSucceededExchanges}</b> % uspesnih trampi | <b>{percentOfSucceededExchanges}</b> % uspesnih trampi | ||||
| halfwidth: PropTypes.bool, | halfwidth: PropTypes.bool, | ||||
| sponsored: PropTypes.bool, | sponsored: PropTypes.bool, | ||||
| offer: PropTypes.any, | offer: PropTypes.any, | ||||
| isMyProfile: PropTypes.bool, | |||||
| // offer: PropTypes.shape({ | // offer: PropTypes.shape({ | ||||
| // images: PropTypes.any, | // images: PropTypes.any, | ||||
| // name:PropTypes.string, | // name:PropTypes.string, |
| import { IconButton } from "../../Buttons/IconButton/IconButton"; | import { IconButton } from "../../Buttons/IconButton/IconButton"; | ||||
| import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton"; | import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton"; | ||||
| import { Icon } from "../../Icon/Icon"; | import { Icon } from "../../Icon/Icon"; | ||||
| import { ReactComponent as User} from "../../../assets/images/svg/user.svg"; | |||||
| export const ItemDetailsHeaderContainer = styled(Box)` | export const ItemDetailsHeaderContainer = styled(Box)` | ||||
| display: flex; | display: flex; | ||||
| box-sizing: border-box; | box-sizing: border-box; | ||||
| margin: 10px 0; | margin: 10px 0; | ||||
| background-color: ${(props) => | background-color: ${(props) => | ||||
| props.sponsored === "true" | |||||
| ? selectedTheme.backgroundSponsoredColor | |||||
| props.isMyProfile | |||||
| ? selectedTheme.primaryPurple | |||||
| : "white"}; | : "white"}; | ||||
| border-radius: 4px; | border-radius: 4px; | ||||
| border: 1px solid ${selectedTheme.borderNormal}; | |||||
| border: 1px solid ${selectedTheme.primaryPurple}; | |||||
| max-width: 2000px; | max-width: 2000px; | ||||
| position: relative; | position: relative; | ||||
| `; | `; | ||||
| export const OfferTitle = styled(Typography)` | export const OfferTitle = styled(Typography)` | ||||
| margin-bottom: 12px; | margin-bottom: 12px; | ||||
| font-family: "Open Sans"; | font-family: "Open Sans"; | ||||
| color: ${selectedTheme.primaryPurple}; | |||||
| color: ${props => props.isMyProfile ? selectedTheme.primaryYellow : selectedTheme.primaryPurple}; | |||||
| font-weight: 700; | font-weight: 700; | ||||
| font-size: 24px; | font-size: 24px; | ||||
| cursor: pointer; | cursor: pointer; | ||||
| `; | `; | ||||
| export const OfferPIB = styled(Box)` | export const OfferPIB = styled(Box)` | ||||
| font-family: "Open Sans"; | font-family: "Open Sans"; | ||||
| color: ${selectedTheme.primaryText}; | |||||
| color: ${props => props.isMyProfile ? selectedTheme.primaryDarkTextThird : selectedTheme.primaryText}; | |||||
| line-height: 16px; | line-height: 16px; | ||||
| font-size: 12px; | font-size: 12px; | ||||
| `; | `; | ||||
| flex-direction: column; | flex-direction: column; | ||||
| flex-wrap: ${(props) => (!props.halfwidth ? "no-wrap" : "wrap")}; | flex-wrap: ${(props) => (!props.halfwidth ? "no-wrap" : "wrap")}; | ||||
| justify-content: start; | justify-content: start; | ||||
| `; | `; | ||||
| export const StatusText = styled(Grid)` | export const StatusText = styled(Grid)` | ||||
| `; | `; | ||||
| export const DetailText = styled(Typography)` | export const DetailText = styled(Typography)` | ||||
| font-family: "Open Sans"; | font-family: "Open Sans"; | ||||
| color: ${selectedTheme.primaryText}; | |||||
| color: ${props => props.isMyProfile ? "white" : selectedTheme.primaryText}; | |||||
| line-height: 16px; | line-height: 16px; | ||||
| font-size: 16px; | font-size: 16px; | ||||
| position: relative; | position: relative; | ||||
| } | } | ||||
| } | } | ||||
| `; | `; | ||||
| export const UserIconContainer = styled(MessageIcon)` | |||||
| background-color: ${selectedTheme.primaryIconBackgroundColor}; | |||||
| ` | |||||
| export const UserIcon = styled(User)` | |||||
| ` |
| selectPinnedOffers, | selectPinnedOffers, | ||||
| selectTotalOffers, | selectTotalOffers, | ||||
| } from "../../../store/selectors/offersSelectors"; | } from "../../../store/selectors/offersSelectors"; | ||||
| // import useFilters from "../../../hooks/useFilters"; | |||||
| import Paging from "../../Paging/Paging"; | import Paging from "../../Paging/Paging"; | ||||
| // import { convertQueryString } from "../../../util/helpers/queryHelpers"; | |||||
| import { HOME_PAGE } from "../../../constants/pages"; | import { HOME_PAGE } from "../../../constants/pages"; | ||||
| import { useHistory } from "react-router-dom"; | import { useHistory } from "react-router-dom"; | ||||
| // import qs from "query-string"; | |||||
| // import useSorting from "../../../hooks/useSorting"; | |||||
| import { useQueryString } from "../../../hooks/useQueryString"; | import { useQueryString } from "../../../hooks/useQueryString"; | ||||
| const Offers = (props) => { | const Offers = (props) => { | ||||
| // const filters = useFilters(); | |||||
| const [page, setPage] = useState(1); | const [page, setPage] = useState(1); | ||||
| // const [initialLoad, setInitialLoad] = useState(true); | |||||
| const pinnedOffers = useSelector(selectPinnedOffers); | const pinnedOffers = useSelector(selectPinnedOffers); | ||||
| const offers = useSelector(selectOffers); | const offers = useSelector(selectOffers); | ||||
| const total = useSelector(selectTotalOffers); | const total = useSelector(selectTotalOffers); | ||||
| const history = useHistory(); | const history = useHistory(); | ||||
| // const sorting = useSorting(); | |||||
| const dispatch = useDispatch(); | const dispatch = useDispatch(); | ||||
| const offersRef = useRef(null); | const offersRef = useRef(null); | ||||
| const queryStringHook = useQueryString(); | const queryStringHook = useQueryString(); | ||||
| // const queryString = history.location.search.substring(1); | |||||
| // const queryObject = qs.parse(queryString); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| let queryObject = queryStringHook.getQueryObject(); | let queryObject = queryStringHook.getQueryObject(); | ||||
| if (queryObject.page && queryObject.page !== 1) { | if (queryObject.page && queryObject.page !== 1) { | ||||
| }, [history.location.search]); | }, [history.location.search]); | ||||
| useEffect(() => { | useEffect(() => { | ||||
| // console.log("sorting.loadedQS", sorting.loadedQS); | |||||
| // console.log("queryString", queryString) | |||||
| if (history?.location?.state?.logo) { | |||||
| dispatch(fetchOffers({queryString: ""})); | |||||
| history.location.state = undefined; | |||||
| } | |||||
| }, [history.location.state]) | |||||
| useEffect(() => { | |||||
| if (queryStringHook.loadedFromURL) { | if (queryStringHook.loadedFromURL) { | ||||
| dispatch(fetchOffers({ queryString: "?" + queryStringHook.queryString })); | dispatch(fetchOffers({ queryString: "?" + queryStringHook.queryString })); | ||||
| history.push({ | history.push({ | ||||
| { key: "size", value: "10" }, | { key: "size", value: "10" }, | ||||
| { key: "page", value: "1" }, | { key: "page", value: "1" }, | ||||
| ]); | ]); | ||||
| // queryStringHook.appendToQueryString("page", 1); | |||||
| } | } | ||||
| }, [queryStringHook.loadedFromURL, queryStringHook.queryString]); | }, [queryStringHook.loadedFromURL, queryStringHook.queryString]); | ||||
| import React from 'react' | |||||
| import React, { useEffect, useMemo } from 'react' | |||||
| import PropTypes from 'prop-types' | import PropTypes from 'prop-types' | ||||
| import { ProfileContainer } from './Profile.styled' | import { ProfileContainer } from './Profile.styled' | ||||
| import ProfileCard from '../ProfileCard/ProfileCard' | import ProfileCard from '../ProfileCard/ProfileCard' | ||||
| import ProfileOffers from './ProfileOffers/ProfileOffers' | import ProfileOffers from './ProfileOffers/ProfileOffers' | ||||
| import { useDispatch, useSelector } from 'react-redux' | |||||
| import { selectUserId } from '../../store/selectors/loginSelectors' | |||||
| import { useRouteMatch } from 'react-router-dom' | |||||
| import { fetchProfile } from '../../store/actions/profile/profileActions' | |||||
| import { fetchProfileOffers } from '../../store/actions/offers/offersActions' | |||||
| const Profile = () => { | const Profile = () => { | ||||
| const userId = useSelector(selectUserId); | |||||
| const dispatch = useDispatch(); | |||||
| const routeMatch = useRouteMatch(); | |||||
| const idProfile = routeMatch.params.idProfile; | |||||
| useEffect(() => { | |||||
| if (idProfile?.length > 0) { | |||||
| dispatch(fetchProfile(idProfile)); | |||||
| dispatch(fetchProfileOffers(idProfile)) | |||||
| } | |||||
| }, [idProfile]); | |||||
| const isMyProfile = useMemo(() => { | |||||
| if (userId === idProfile) { | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| }, [userId, idProfile]) | |||||
| return ( | return ( | ||||
| <ProfileContainer> | <ProfileContainer> | ||||
| <ProfileCard /> | |||||
| <ProfileOffers /> | |||||
| <ProfileCard isMyProfile={isMyProfile}/> | |||||
| <ProfileOffers isMyProfile={isMyProfile}/> | |||||
| </ProfileContainer> | </ProfileContainer> | ||||
| ) | ) | ||||
| } | } |
| import { selectProfileOffers } from "../../../store/selectors/offersSelectors"; | import { selectProfileOffers } from "../../../store/selectors/offersSelectors"; | ||||
| import useScreenDimensions from "../../../hooks/useScreenDimensions"; | import useScreenDimensions from "../../../hooks/useScreenDimensions"; | ||||
| const ProfileOffers = () => { | |||||
| const ProfileOffers = (props) => { | |||||
| const [sortOption, setSortOption] = useState(sortEnum.INITIAL); | const [sortOption, setSortOption] = useState(sortEnum.INITIAL); | ||||
| const [offersToShow, setOffersToShow] = useState([]); | |||||
| const searchRef = useRef(null); | const searchRef = useRef(null); | ||||
| // const [toSearch, setToSearch] = useState(""); | |||||
| const profileOffers = useSelector(selectProfileOffers); | const profileOffers = useSelector(selectProfileOffers); | ||||
| const dimensions = useScreenDimensions(); | const dimensions = useScreenDimensions(); | ||||
| console.log(profileOffers); | |||||
| const [offersToShow, setOffersToShow] = useState([]); | |||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| useEffect(() => { | useEffect(() => { | ||||
| let newOffersToShow = [...offersToShow]; | let newOffersToShow = [...offersToShow]; | ||||
| if (sortOption.value === sortEnum.OLD.value) { | if (sortOption.value === sortEnum.OLD.value) { | ||||
| } | } | ||||
| setOffersToShow([...newOffersToShow]); | setOffersToShow([...newOffersToShow]); | ||||
| }, [sortOption]); | }, [sortOption]); | ||||
| useEffect(() => { | useEffect(() => { | ||||
| if (profileOffers?.length > 0) setOffersToShow(profileOffers); | if (profileOffers?.length > 0) setOffersToShow(profileOffers); | ||||
| }, [profileOffers]); | }, [profileOffers]); | ||||
| const handleSearch = () => { | const handleSearch = () => { | ||||
| const valueToSearch = searchRef?.current?.value; | const valueToSearch = searchRef?.current?.value; | ||||
| console.log(valueToSearch); | |||||
| console.log(offersToShow); | |||||
| let newOffersToShow = profileOffers.filter((item) => | let newOffersToShow = profileOffers.filter((item) => | ||||
| item.name.toLowerCase().includes(valueToSearch.toLowerCase()) | item.name.toLowerCase().includes(valueToSearch.toLowerCase()) | ||||
| ); | ); | ||||
| setOffersToShow([...newOffersToShow]); | setOffersToShow([...newOffersToShow]); | ||||
| }; | }; | ||||
| const handleChangeSelect = (event) => { | const handleChangeSelect = (event) => { | ||||
| let chosenOption; | let chosenOption; | ||||
| for (const sortOption in sortEnum) { | for (const sortOption in sortEnum) { | ||||
| } | } | ||||
| } | } | ||||
| }; | }; | ||||
| let listener; | let listener; | ||||
| const handleFocusSearch = () => { | const handleFocusSearch = () => { | ||||
| listener = (event) => { | listener = (event) => { | ||||
| }; | }; | ||||
| searchRef.current.addEventListener("keyup", listener); | searchRef.current.addEventListener("keyup", listener); | ||||
| }; | }; | ||||
| const handleBlurSearch = () => { | const handleBlurSearch = () => { | ||||
| searchRef.current.removeEventListener("keyup", listener); | searchRef.current.removeEventListener("keyup", listener); | ||||
| }; | }; | ||||
| return ( | return ( | ||||
| <ProfileOffersContainer> | <ProfileOffersContainer> | ||||
| <HeaderSelect | <HeaderSelect | ||||
| sx={{ mb: 1.4 }} | sx={{ mb: 1.4 }} | ||||
| > | > | ||||
| <OffersIcon /> | <OffersIcon /> | ||||
| <HeaderTitle>Moje objave</HeaderTitle> | |||||
| <HeaderTitle>{props.isMyProfile ? "Moje objave" : "Objave kompanije"}</HeaderTitle> | |||||
| </Grid> | </Grid> | ||||
| <SearchInput | <SearchInput | ||||
| fullWidth | fullWidth | ||||
| <OffersContainer> | <OffersContainer> | ||||
| {dimensions.width > 600 ? ( | {dimensions.width > 600 ? ( | ||||
| offersToShow.map((item) => ( | offersToShow.map((item) => ( | ||||
| <OfferCard offer={item} key={JSON.stringify(item)} pinned /> | |||||
| <OfferCard isMyOffer={props.isMyProfile} offer={item} key={JSON.stringify(item)} pinned /> | |||||
| )) | )) | ||||
| ) : ( | ) : ( | ||||
| <OffersScroller hideArrows> | <OffersScroller hideArrows> | ||||
| {offersToShow.map((item) => ( | {offersToShow.map((item) => ( | ||||
| <OfferCard vertical offer={item} key={JSON.stringify(item)} pinned />))} | |||||
| <OfferCard vertical isMyOffer={props.isMyProfile} offer={item} key={JSON.stringify(item)} pinned />))} | |||||
| </OffersScroller> | </OffersScroller> | ||||
| )} | )} | ||||
| </OffersContainer> | </OffersContainer> | ||||
| ProfileOffers.propTypes = { | ProfileOffers.propTypes = { | ||||
| children: PropTypes.node, | children: PropTypes.node, | ||||
| isMyProfile: PropTypes.bool, | |||||
| }; | }; | ||||
| export default ProfileOffers; | export default ProfileOffers; |
| import { Grid, Stack } from "@mui/material"; | import { Grid, Stack } from "@mui/material"; | ||||
| import PersonOutlineIcon from "@mui/icons-material/PersonOutline"; | import PersonOutlineIcon from "@mui/icons-material/PersonOutline"; | ||||
| import { useRouteMatch } from "react-router-dom"; | |||||
| import { fetchProfile } from "../../store/actions/profile/profileActions"; | |||||
| import { useDispatch, useSelector } from "react-redux"; | |||||
| import { useEffect } from "react"; | |||||
| import { useSelector } from "react-redux"; | |||||
| import { selectProfile } from "../../store/selectors/profileSelectors"; | import { selectProfile } from "../../store/selectors/profileSelectors"; | ||||
| import { selectUserId } from "../../store/selectors/loginSelectors"; | |||||
| import { useState } from "react"; | |||||
| import { fetchProfileOffers } from "../../store/actions/offers/offersActions"; | |||||
| const ProfileCard = () => { | |||||
| const [isMyProfile, setIsMyProfile] = useState(false); | |||||
| const routeMatch = useRouteMatch(); | |||||
| const dispatch = useDispatch(); | |||||
| const ProfileCard = (props) => { | |||||
| const profile = useSelector(selectProfile); | const profile = useSelector(selectProfile); | ||||
| const userId = useSelector(selectUserId); | |||||
| const idProfile = routeMatch.params.idProfile; | |||||
| console.log(idProfile); | |||||
| useEffect(() => { | |||||
| if (idProfile?.length > 0) { | |||||
| dispatch(fetchProfile(idProfile)); | |||||
| dispatch(fetchProfileOffers(idProfile)) | |||||
| if (userId === idProfile) setIsMyProfile(true); | |||||
| } | |||||
| }, [idProfile]); | |||||
| let percentOfSucceededExchanges; | let percentOfSucceededExchanges; | ||||
| if (profile?.statistics?.exchanges?.succeeded === 0) { | if (profile?.statistics?.exchanges?.succeeded === 0) { | ||||
| sx={{ mb: 1.4 }} | sx={{ mb: 1.4 }} | ||||
| > | > | ||||
| <PersonOutlineIcon color="action" sx={{ mr: 0.9 }} /> | <PersonOutlineIcon color="action" sx={{ mr: 0.9 }} /> | ||||
| <HeaderTitle>Moj Profil</HeaderTitle> | |||||
| <HeaderTitle>{props.isMyProfile ? "Moj profil" : "Profil kompanije"}</HeaderTitle> | |||||
| </Grid> | </Grid> | ||||
| <ProfileCardWrapper variant="outlined" isMyProfile={isMyProfile}> | |||||
| {isMyProfile ? (<EditButton> | |||||
| <ProfileCardWrapper variant="outlined" isMyProfile={props.isMyProfile}> | |||||
| {props.isMyProfile ? (<EditButton> | |||||
| <EditIcon /> | <EditIcon /> | ||||
| </EditButton>) : ( | </EditButton>) : ( | ||||
| <MessageButton> | <MessageButton> | ||||
| alignItems="start" | alignItems="start" | ||||
| sx={{ ml: 2 }} | sx={{ ml: 2 }} | ||||
| > | > | ||||
| <ProfileName isMyProfile={isMyProfile} variant="h5"> | |||||
| <ProfileName isMyProfile={props.isMyProfile} variant="h5"> | |||||
| {profile?.company?.name} | {profile?.company?.name} | ||||
| </ProfileName> | </ProfileName> | ||||
| <ProfilePIBContainer | <ProfilePIBContainer | ||||
| alignItems="center" | alignItems="center" | ||||
| > | > | ||||
| <PocketIcon /> | <PocketIcon /> | ||||
| <ProfilePIB isMyProfile={isMyProfile} variant="subtitle2"> | |||||
| <ProfilePIB isMyProfile={props.isMyProfile} variant="subtitle2"> | |||||
| PIB: {profile?.company?.PIB} | PIB: {profile?.company?.PIB} | ||||
| </ProfilePIB> | </ProfilePIB> | ||||
| </ProfilePIBContainer> | </ProfilePIBContainer> | ||||
| alignItems={{ xs: "start", sm: "center" }} | alignItems={{ xs: "start", sm: "center" }} | ||||
| > | > | ||||
| <Stack direction="row"> | <Stack direction="row"> | ||||
| <LocationIcon isMyProfile={isMyProfile} /> | |||||
| <ContactItem isMyProfile={isMyProfile} variant="subtitle2"> | |||||
| <LocationIcon isMyProfile={props.isMyProfile} /> | |||||
| <ContactItem isMyProfile={props.isMyProfile} variant="subtitle2"> | |||||
| {profile?.company?.contacts?.location} | {profile?.company?.contacts?.location} | ||||
| </ContactItem> | </ContactItem> | ||||
| </Stack> | </Stack> | ||||
| <Stack direction="row"> | <Stack direction="row"> | ||||
| <MailIcon isMyProfile={isMyProfile} /> | |||||
| <ContactItem isMyProfile={isMyProfile} variant="subtitle2"> | |||||
| <MailIcon isMyProfile={props.isMyProfile} /> | |||||
| <ContactItem isMyProfile={props.isMyProfile} variant="subtitle2"> | |||||
| {profile?.email} | {profile?.email} | ||||
| </ContactItem> | </ContactItem> | ||||
| </Stack> | </Stack> | ||||
| <Stack direction="row"> | <Stack direction="row"> | ||||
| <GlobeIcon isMyProfile={isMyProfile} /> | |||||
| <ContactItem isMyProfile={isMyProfile} variant="subtitle2"> | |||||
| <GlobeIcon isMyProfile={props.isMyProfile} /> | |||||
| <ContactItem isMyProfile={props.isMyProfile} variant="subtitle2"> | |||||
| {profile?.company?.contacts?.web} | {profile?.company?.contacts?.web} | ||||
| </ContactItem> | </ContactItem> | ||||
| </Stack> | </Stack> | ||||
| ProfileCard.propTypes = { | ProfileCard.propTypes = { | ||||
| children: PropTypes.node, | children: PropTypes.node, | ||||
| isMyProfile: PropTypes.bool, | |||||
| }; | }; | ||||
| export default ProfileCard; | export default ProfileCard; |
| export const MessageButton = styled(EditButton)` | export const MessageButton = styled(EditButton)` | ||||
| background: ${selectedTheme.primaryPurple}; | background: ${selectedTheme.primaryPurple}; | ||||
| width: 40px; | |||||
| height: 40px; | |||||
| `; | `; | ||||
| export const ProfileCardWrapper = styled(Card)` | export const ProfileCardWrapper = styled(Card)` | ||||
| width: 19.5px; | width: 19.5px; | ||||
| height: 19.5px; | height: 19.5px; | ||||
| position: relative; | position: relative; | ||||
| right: 0.7px; | |||||
| left: 2.5px; | |||||
| top: 3.5px; | |||||
| & path { | & path { | ||||
| stroke: ${selectedTheme.primaryYellow}; | stroke: ${selectedTheme.primaryYellow}; | ||||
| } | } |