| import React from 'react'; | |||||
| import PropTypes from 'prop-types'; | |||||
| import { useTranslation } from 'react-i18next'; | |||||
| const Auth = ({ children }) => { | |||||
| const { t } = useTranslation(); | |||||
| return ( | |||||
| <div className="c-auth"> | |||||
| <h1 className="c-auth__title">{t(`login.welcome`)}</h1> | |||||
| {children} | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| Auth.propTypes = { | |||||
| children: PropTypes.node, | |||||
| }; | |||||
| export default Auth; |
| import React from 'react'; | |||||
| import PropTypes from 'prop-types'; | |||||
| import SectionLoader from '../Loader/SectionLoader'; | |||||
| const AuthCard = ({ children, title, subtitle, isLoading }) => { | |||||
| return ( | |||||
| <div className="c-auth-card"> | |||||
| <SectionLoader isLoading={isLoading}> | |||||
| <h1 className="c-auth-card__title">{title}</h1> | |||||
| <h2 className="c-auth-card__subtitle">{subtitle}</h2> | |||||
| {children} | |||||
| </SectionLoader> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| AuthCard.propTypes = { | |||||
| children: PropTypes.node, | |||||
| title: PropTypes.string, | |||||
| subtitle: PropTypes.string, | |||||
| isLoading: PropTypes.bool, | |||||
| }; | |||||
| export default AuthCard; |
| import React from 'react' | |||||
| import { ArrowContainer, ArrowIcon } from "./ArrowButton.styled" | |||||
| import React from "react"; | |||||
| import { ArrowContainer, ArrowIcon } from "./ArrowButton.styled"; | |||||
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| export const ArrowButton = (props) => { | export const ArrowButton = (props) => { | ||||
| return <ArrowContainer onClick={props.onClick} className={props.className} disabled={props.disabled}> | |||||
| <ArrowIcon side={props.side} disabled={props.disabled}/> | |||||
| return ( | |||||
| <ArrowContainer | |||||
| onClick={props.onClick} | |||||
| className={props.className} | |||||
| disabled={props.disabled} | |||||
| > | |||||
| <ArrowIcon side={props.side} disabled={props.disabled} /> | |||||
| </ArrowContainer> | </ArrowContainer> | ||||
| } | |||||
| ); | |||||
| }; | |||||
| ArrowButton.propTypes = { | ArrowButton.propTypes = { | ||||
| onClick: PropTypes.func, | |||||
| className: PropTypes.string, | |||||
| side:PropTypes.string, | |||||
| disabled:PropTypes.bool, | |||||
| } | |||||
| onClick: PropTypes.func, | |||||
| className: PropTypes.string, | |||||
| side: PropTypes.string, | |||||
| disabled: PropTypes.bool, | |||||
| }; |
| import React, { useRef } from 'react'; | |||||
| import PropType from 'prop-types'; | |||||
| const Button = ({ | |||||
| variant, | |||||
| size, | |||||
| children, | |||||
| authButton, | |||||
| type, | |||||
| onClick, | |||||
| textTransform, | |||||
| className, | |||||
| disabled, | |||||
| hidden, | |||||
| minWidth, | |||||
| ...restProps | |||||
| }) => { | |||||
| const buttonRef = useRef(null); | |||||
| function styles() { | |||||
| let style = 'c-btn'; | |||||
| if (variant) { | |||||
| style += ` c-btn--${variant}`; | |||||
| } | |||||
| if (size) { | |||||
| style += ` c-btn--${size}`; | |||||
| } | |||||
| if (textTransform) { | |||||
| style += ` c-btn--${textTransform}`; | |||||
| } | |||||
| if (authButton) { | |||||
| style += ` c-btn--auth`; | |||||
| } | |||||
| if (minWidth) { | |||||
| style += ` c-btn--${minWidth}`; | |||||
| } | |||||
| if (hidden) { | |||||
| style += ` c-btn--hidden`; | |||||
| } | |||||
| if (className) { | |||||
| style += ` ${className}`; | |||||
| } | |||||
| return style; | |||||
| } | |||||
| function handleClick() { | |||||
| buttonRef.current.blur(); | |||||
| if (typeof onClick === 'function') { | |||||
| onClick(); | |||||
| } | |||||
| } | |||||
| return ( | |||||
| <button | |||||
| ref={buttonRef} | |||||
| className={styles()} | |||||
| onClick={handleClick} | |||||
| type={type} | |||||
| disabled={disabled} | |||||
| {...restProps} | |||||
| > | |||||
| {children} | |||||
| </button> | |||||
| ); | |||||
| }; | |||||
| Button.propTypes = { | |||||
| children: PropType.node, | |||||
| textTransform: PropType.oneOf(['uppercase', 'capitalize']), | |||||
| size: PropType.oneOf(['sm', 'md', 'lg', 'xl']), | |||||
| authButton: PropType.bool, | |||||
| variant: PropType.string, | |||||
| type: PropType.oneOf(['button', 'submit', 'reset']), | |||||
| onClick: PropType.func, | |||||
| className: PropType.string, | |||||
| disabled: PropType.bool, | |||||
| minWidth: PropType.oneOf(['auto']), | |||||
| hidden: PropType.bool, | |||||
| }; | |||||
| Button.defaultProps = { | |||||
| type: 'button', | |||||
| }; | |||||
| export default Button; |
| import React from 'react' | |||||
| import { IconButtonContainer, IconButtonStyled } from "./IconButton.styled" | |||||
| import React from "react"; | |||||
| import { IconButtonContainer, IconButtonStyled } from "./IconButton.styled"; | |||||
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| export const IconButton = (props) => { | export const IconButton = (props) => { | ||||
| return <IconButtonContainer style={props.containerStyle} className={props.className}> | |||||
| <IconButtonStyled disabled={props.disabled} onClick={props.onClick} sx={props.style} iconcolor={props.iconColor}> | |||||
| {props.children} | |||||
| </IconButtonStyled> | |||||
| return ( | |||||
| <IconButtonContainer | |||||
| style={props.containerStyle} | |||||
| className={props.className} | |||||
| > | |||||
| <IconButtonStyled | |||||
| disabled={props.disabled} | |||||
| onClick={props.onClick} | |||||
| sx={props.style} | |||||
| iconcolor={props.iconColor} | |||||
| > | |||||
| {props.children} | |||||
| </IconButtonStyled> | |||||
| </IconButtonContainer> | </IconButtonContainer> | ||||
| } | |||||
| ); | |||||
| }; | |||||
| IconButton.propTypes = { | IconButton.propTypes = { | ||||
| children: PropTypes.node, | |||||
| onClick: PropTypes.func, | |||||
| containerStyle: PropTypes.any, | |||||
| style: PropTypes.any, | |||||
| className: PropTypes.string, | |||||
| iconColor: PropTypes.string, | |||||
| disabled: PropTypes.bool, | |||||
| } | |||||
| children: PropTypes.node, | |||||
| onClick: PropTypes.func, | |||||
| containerStyle: PropTypes.any, | |||||
| style: PropTypes.any, | |||||
| className: PropTypes.string, | |||||
| iconColor: PropTypes.string, | |||||
| disabled: PropTypes.bool, | |||||
| }; |
| import styled from "styled-components"; | import styled from "styled-components"; | ||||
| import selectedTheme from "../../../themes"; | import selectedTheme from "../../../themes"; | ||||
| export const IconButtonContainer = styled(Box)` | |||||
| ` | |||||
| export const IconButtonContainer = styled(Box)``; | |||||
| export const IconButtonStyled = styled(IconButton)` | export const IconButtonStyled = styled(IconButton)` | ||||
| height: ${props => props.height ? props.height : "36px"}; | |||||
| width: ${props => props.width ? props.width : "36px"}; | |||||
| padding: 0; | |||||
| ${props => props.iconcolor && ` | |||||
| height: ${(props) => (props.height ? props.height : "36px")}; | |||||
| width: ${(props) => (props.width ? props.width : "36px")}; | |||||
| padding: 0; | |||||
| ${(props) => | |||||
| props.iconcolor && | |||||
| ` | |||||
| & svg path { | & svg path { | ||||
| stroke: ${props.iconcolor}; | stroke: ${props.iconcolor}; | ||||
| } | } | ||||
| `} | `} | ||||
| border: ${props => props.border ? "1px solid " + selectedTheme.backgroundSponsoredColor : "none"} | |||||
| ` | |||||
| border: ${(props) => | |||||
| props.border | |||||
| ? "1px solid " + selectedTheme.backgroundSponsoredColor | |||||
| : "none"} | |||||
| `; |
| import React from "react"; | |||||
| import { LoginButtonContainer, LoginButtonStyled } from "./LoginButton.styled"; | |||||
| import PropTypes from "prop-types"; | |||||
| //Currently not in use | |||||
| export const LoginButton = (props) => { | |||||
| return ( | |||||
| <LoginButtonContainer style={props.containerStyle}> | |||||
| <LoginButtonStyled {...props} sx={props.style} variant="contained"> | |||||
| Dugme | |||||
| </LoginButtonStyled> | |||||
| </LoginButtonContainer> | |||||
| ); | |||||
| }; | |||||
| LoginButton.propTypes = { | |||||
| children: PropTypes.node, | |||||
| type: PropTypes.string, | |||||
| variant: PropTypes.string, | |||||
| style: PropTypes.any, | |||||
| containerStyle: PropTypes.any, | |||||
| fullWidth: PropTypes.bool, | |||||
| buttonColor: PropTypes.string, | |||||
| onClick: PropTypes.func | |||||
| }; |
| import { Box, Button } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| export const LoginButtonContainer = styled(Box)` | |||||
| ` | |||||
| export const LoginButtonStyled = styled(Button)` | |||||
| background-color: ${props => props.backgroundColor}; | |||||
| color: ${props => props.textColor} | |||||
| ` |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { | |||||
| PrimaryButtonWithIconContainer, | |||||
| IconStyled, | |||||
| PrimaryButtonWithIconStyled, | |||||
| } from "./PrimaryButtonWithIcon.styled"; | |||||
| const PrimaryButtonWithIcon = (props) => { | |||||
| return ( | |||||
| <PrimaryButtonWithIconContainer | |||||
| style={props.containerStyle} | |||||
| className={props.className} | |||||
| > | |||||
| <PrimaryButtonWithIconStyled sx={props.style} {...props.buttonProps} onClick={props.onClick}> | |||||
| <IconStyled style={props.iconStyle}>{props.icon}</IconStyled> | |||||
| {props.children} | |||||
| </PrimaryButtonWithIconStyled> | |||||
| </PrimaryButtonWithIconContainer> | |||||
| ); | |||||
| }; | |||||
| PrimaryButtonWithIcon.propTypes = { | |||||
| children: PropTypes.node, | |||||
| icon: PropTypes.node, | |||||
| className: PropTypes.string, | |||||
| containerStyle: PropTypes.any, | |||||
| style: PropTypes.any, | |||||
| iconStyle: PropTypes.any, | |||||
| buttonProps: PropTypes.any, | |||||
| onClick: PropTypes.func, | |||||
| }; | |||||
| export default PrimaryButtonWithIcon; |
| import { Box } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| import { Icon } from "../../Icon/Icon"; | |||||
| import { PrimaryButton } from "../PrimaryButton/PrimaryButton"; | |||||
| export const PrimaryButtonWithIconContainer = styled(Box)``; | |||||
| export const PrimaryButtonWithIconStyled = styled(PrimaryButton)` | |||||
| position: relative; | |||||
| `; | |||||
| export const IconStyled = styled(Icon)` | |||||
| position: absolute; | |||||
| padding: 0; | |||||
| left: 10px; | |||||
| top: 0; | |||||
| bottom: 0; | |||||
| margin-top: auto; | |||||
| margin-bottom: auto; | |||||
| line-height: 21px; | |||||
| & span { | |||||
| position: absolute; | |||||
| top: 0; | |||||
| bottom: 0; | |||||
| margin-top: auto; | |||||
| margin-bottom: auto; | |||||
| } | |||||
| `; |
| import React, { useEffect, useState } from "react"; | |||||
| import React, { useMemo } from "react"; | |||||
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| import { | import { | ||||
| CheckButton, | CheckButton, | ||||
| OfferImage, | OfferImage, | ||||
| OfferTitle, | OfferTitle, | ||||
| OfferCard, | |||||
| ChatOffer, | ChatOffer, | ||||
| Commands, | Commands, | ||||
| ChatInfo, | ChatInfo, | ||||
| OfferTitleMobile, | OfferTitleMobile, | ||||
| PhoneIconContainer, | PhoneIconContainer, | ||||
| PhoneIcon, | PhoneIcon, | ||||
| LocationIconContainer, | |||||
| } from "./ChatCard.styled"; | } from "./ChatCard.styled"; | ||||
| import { ReactComponent as Location } from "../../../assets/images/svg/location.svg"; | |||||
| import selectedTheme from "../../../themes"; | import selectedTheme from "../../../themes"; | ||||
| import { useHistory } from "react-router-dom"; | import { useHistory } from "react-router-dom"; | ||||
| import useScreenDimensions from "../../../hooks/useScreenDimensions"; | import useScreenDimensions from "../../../hooks/useScreenDimensions"; | ||||
| //import { useSelector } from "react-redux"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const ChatCard = (props) => { | const ChatCard = (props) => { | ||||
| const history = useHistory(); | const history = useHistory(); | ||||
| const dimensions = useScreenDimensions(); | const dimensions = useScreenDimensions(); | ||||
| const [isMobile, setIsMobile] = useState(dimensions.width < 600); | |||||
| const chat = props.chat; | |||||
| const { t } = useTranslation(); | |||||
| useEffect(() => { | |||||
| const resize = (e) => { | |||||
| if (e.target.outerWidth < 600 && isMobile) setIsMobile(false); | |||||
| else if (e.target.outerWidth > 600 && !isMobile) setIsMobile(true); | |||||
| }; | |||||
| window.addEventListener("resize", resize); | |||||
| const chat = useMemo(() => { | |||||
| return props.chat; | |||||
| }, [props.chat]); | |||||
| return () => window.removeEventListener("resize", resize); | |||||
| }, []); | |||||
| const lastMessage = useMemo(() => { | |||||
| if (chat?.chat?.messages && chat?.chat?.messages?.length > 0) { | |||||
| return chat.chat.messages[chat.chat.messages.length - 1]?.text; | |||||
| } | |||||
| return ""; | |||||
| }, [chat]); | |||||
| const routeToItem = (userId) => { | |||||
| history.push(`/messages/${userId}`); | |||||
| const routeToItem = () => { | |||||
| history.push(`/messages/${chat?.chat?._id}`); | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <ChatCardContainer onClick={isMobile ? () => routeToItem(chat?.chat?._id) : () => {}}> | |||||
| <ChatCardContainer | |||||
| onClick={ | |||||
| dimensions.width < 600 ? () => routeToItem(chat?.chat?._id) : () => {} | |||||
| } | |||||
| > | |||||
| <Col> | <Col> | ||||
| <UserImgWrapper> | <UserImgWrapper> | ||||
| <UserImage src={chat?.interlocutorData?.image} /> | <UserImage src={chat?.interlocutorData?.image} /> | ||||
| <ChatInfo> | <ChatInfo> | ||||
| <UserName>{chat?.interlocutorData?.name}</UserName> | <UserName>{chat?.interlocutorData?.name}</UserName> | ||||
| {/* Only shows on Mobile */} | {/* Only shows on Mobile */} | ||||
| <OfferCardContainerMobile> | <OfferCardContainerMobile> | ||||
| <OfferTextMobile>Proizvod:</OfferTextMobile> | |||||
| <OfferTextMobile>{t("messages.cardProduct")}</OfferTextMobile> | |||||
| <OfferTitleMobile>{chat?.offerData?.name}</OfferTitleMobile> | <OfferTitleMobile>{chat?.offerData?.name}</OfferTitleMobile> | ||||
| </OfferCardContainerMobile> | </OfferCardContainerMobile> | ||||
| {/* ^^^^^ */} | {/* ^^^^^ */} | ||||
| <LastMessage> | |||||
| {chat?.chat?.messages | |||||
| ? chat?.chat?.messages[chat?.chat?.messages?.length - 1]?.text | |||||
| : ""} | |||||
| </LastMessage> | |||||
| <LastMessage>{lastMessage}</LastMessage> | |||||
| <LocationContainer> | <LocationContainer> | ||||
| <LocationIcon> | |||||
| <Location height="12px" width="12px" /> | |||||
| </LocationIcon> | |||||
| <LocationIconContainer> | |||||
| <LocationIcon /> | |||||
| </LocationIconContainer> | |||||
| <XSText>{chat?.interlocutorData?.location}</XSText> | <XSText>{chat?.interlocutorData?.location}</XSText> | ||||
| </LocationContainer> | </LocationContainer> | ||||
| </ChatInfo> | </ChatInfo> | ||||
| </Col> | </Col> | ||||
| <Line /> | <Line /> | ||||
| {/* Only shows on Desktop */} | |||||
| <Col mobileDisappear> | <Col mobileDisappear> | ||||
| <ChatOffer> | <ChatOffer> | ||||
| <OfferImgWrapper> | <OfferImgWrapper> | ||||
| <OfferImage src={chat?.offerData?.firstImage} /> | <OfferImage src={chat?.offerData?.firstImage} /> | ||||
| </OfferImgWrapper> | </OfferImgWrapper> | ||||
| <OfferCardContainer> | <OfferCardContainer> | ||||
| <OfferText>Proizvod:</OfferText> | |||||
| <OfferText>{t("messages.cardProduct")}</OfferText> | |||||
| <OfferTitle>{chat?.offerData?.name}</OfferTitle> | <OfferTitle>{chat?.offerData?.name}</OfferTitle> | ||||
| </OfferCardContainer> | </OfferCardContainer> | ||||
| </ChatOffer> | </ChatOffer> | ||||
| </Col> | </Col> | ||||
| {/* ^^^^^^^ */} | |||||
| <Commands> | <Commands> | ||||
| <PhoneIconContainer> | <PhoneIconContainer> | ||||
| <PhoneIcon /> | <PhoneIcon /> | ||||
| textcolor={selectedTheme.primaryPurple} | textcolor={selectedTheme.primaryPurple} | ||||
| variant={"outlined"} | variant={"outlined"} | ||||
| style={{ fontWeight: "600" }} | style={{ fontWeight: "600" }} | ||||
| onClick={() => routeToItem(chat?.chat?._id)} | |||||
| onClick={routeToItem} | |||||
| > | > | ||||
| Pogledaj caskanje | |||||
| {t("messages.seeChats")} | |||||
| </CheckButton> | </CheckButton> | ||||
| </Commands> | </Commands> | ||||
| </ChatCardContainer> | </ChatCardContainer> | ||||
| vertical: PropTypes.bool, | vertical: PropTypes.bool, | ||||
| chat: PropTypes.any, | chat: PropTypes.any, | ||||
| }; | }; | ||||
| OfferCard.defaultProps = { | |||||
| ChatCard.defaultProps = { | |||||
| halfwidth: false, | halfwidth: false, | ||||
| sponsored: false, | sponsored: false, | ||||
| }; | }; |
| import selectedTheme from "../../../themes"; | import selectedTheme from "../../../themes"; | ||||
| 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 { ReactComponent as Eye } from "../../../assets/images/svg/eye-striked.svg"; | |||||
| import { ReactComponent as Phone } from "../../../assets/images/svg/phone.svg"; | import { ReactComponent as Phone } from "../../../assets/images/svg/phone.svg"; | ||||
| import { ReactComponent as Location } from "../../../assets/images/svg/location.svg"; | |||||
| export const ChatCardContainer = styled(Container)` | export const ChatCardContainer = styled(Container)` | ||||
| display: flex; | display: flex; | ||||
| min-width: 72px; | min-width: 72px; | ||||
| max-width: 72px; | max-width: 72px; | ||||
| `; | `; | ||||
| export const OfferFlexContainer = styled(Container)` | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| margin: 0; | |||||
| padding: 0; | |||||
| max-height: 184px; | |||||
| @media (max-width: 600px) { | |||||
| ${(props) => | |||||
| props.vertical && | |||||
| ` | |||||
| flex-direction: column; | |||||
| `} | |||||
| } | |||||
| export const LocationIcon = styled(Location)` | |||||
| height: 12px; | |||||
| width: 12px; | |||||
| `; | `; | ||||
| export const OfferCardContainer = styled(Container)` | export const OfferCardContainer = styled(Container)` | ||||
| } | } | ||||
| `; | `; | ||||
| export const OfferInfo = styled(Box)` | |||||
| display: flex; | |||||
| flex: 2; | |||||
| flex-direction: column; | |||||
| justify-content: space-between; | |||||
| margin-left: 18px; | |||||
| ${(props) => | |||||
| props.vertical && | |||||
| ` | |||||
| margin-left: 0; | |||||
| margin-top: 5px; | |||||
| `} | |||||
| `; | |||||
| export const OfferTitle = styled(Typography)` | export const OfferTitle = styled(Typography)` | ||||
| font-family: "Open Sans"; | font-family: "Open Sans"; | ||||
| flex: 1; | flex: 1; | ||||
| } | } | ||||
| `; | `; | ||||
| export const OfferAuthor = styled(Box)` | |||||
| display: flex; | |||||
| flex: 1; | |||||
| flex-direction: column; | |||||
| `; | |||||
| export const OfferAuthorName = styled(Typography)` | |||||
| font-family: "Open Sans"; | |||||
| line-height: 22px; | |||||
| font-size: 16px; | |||||
| color: ${selectedTheme.primaryText}; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 14px; | |||||
| ${(props) => | |||||
| props.vertical && | |||||
| ` | |||||
| line-height: 19px; | |||||
| font-size: 14px; | |||||
| position: absolute; | |||||
| bottom: 80px; | |||||
| `} | |||||
| } | |||||
| `; | |||||
| export const OfferLocation = styled(Typography)` | |||||
| font-family: "Open Sans"; | |||||
| color: ${selectedTheme.primaryDarkText}; | |||||
| line-height: 16px; | |||||
| font-size: 12px; | |||||
| ${(props) => | |||||
| props.vertical && | |||||
| ` | |||||
| font-size: 12px; | |||||
| margin-top: 5px; | |||||
| position: absolute; | |||||
| bottom: 61px; | |||||
| `} | |||||
| `; | |||||
| export const OfferDetails = styled(Box)` | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| flex-wrap: ${(props) => (!props.halfwidth ? "no-wrap" : "wrap")}; | |||||
| justify-content: start; | |||||
| gap: 1rem; | |||||
| @media (max-width: 650px) { | |||||
| flex-direction: column; | |||||
| justify-content: center; | |||||
| gap: 0; | |||||
| } | |||||
| `; | |||||
| export const OfferCategory = styled(Box)` | |||||
| font-family: "Open Sans"; | |||||
| color: ${selectedTheme.primaryText}; | |||||
| line-height: 16px; | |||||
| font-size: 12px; | |||||
| ${(props) => | |||||
| props.vertical && | |||||
| ` | |||||
| position: absolute; | |||||
| bottom: 15px; | |||||
| `} | |||||
| `; | |||||
| export const OfferPackage = styled(Box)` | |||||
| font-family: "Open Sans"; | |||||
| color: ${selectedTheme.primaryText}; | |||||
| line-height: 16px; | |||||
| font-size: 12px; | |||||
| `; | |||||
| export const OfferViews = styled(Box)` | |||||
| font-family: "Open Sans"; | |||||
| color: ${selectedTheme.primaryText}; | |||||
| line-height: 16px; | |||||
| font-size: 12px; | |||||
| ${(props) => | |||||
| props.vertical && | |||||
| ` | |||||
| display: none; | |||||
| `} | |||||
| `; | |||||
| export const OfferDescriptionTitle = styled(Box)` | |||||
| font-family: "Open Sans"; | |||||
| font-size: 12px; | |||||
| color: ${selectedTheme.primaryDarkText}; | |||||
| line-height: 16px; | |||||
| `; | |||||
| export const OfferDescriptionText = styled(Box)` | |||||
| font-family: "Open Sans"; | |||||
| font-size: 16px; | |||||
| color: ${selectedTheme.primaryDarkText}; | |||||
| line-height: 22px; | |||||
| max-width: calc(100% - 230px); | |||||
| max-height: 120px; | |||||
| overflow: hidden; | |||||
| display: -webkit-box; | |||||
| -webkit-line-clamp: 5; | |||||
| -webkit-box-orient: vertical; | |||||
| @media (max-width: 1500px) { | |||||
| display: none; | |||||
| } | |||||
| `; | |||||
| export const OfferDescription = styled(Box)` | |||||
| flex: 3; | |||||
| margin: auto 0; | |||||
| padding-left: 35px; | |||||
| @media (max-width: 1500px) { | |||||
| display: none; | |||||
| } | |||||
| `; | |||||
| export const DetailIcon = styled(Icon)` | |||||
| & svg { | |||||
| width: 14px; | |||||
| position: relative; | |||||
| top: -1px; | |||||
| } | |||||
| `; | |||||
| export const DetailText = styled(Typography)` | |||||
| font-family: "Open Sans"; | |||||
| color: ${selectedTheme.primaryText}; | |||||
| line-height: 16px; | |||||
| font-size: 12px; | |||||
| position: relative; | |||||
| top: -2px; | |||||
| left: 3px; | |||||
| `; | |||||
| export const CheckButton = styled(PrimaryButton)` | export const CheckButton = styled(PrimaryButton)` | ||||
| width: 180px; | width: 180px; | ||||
| height: 48px; | height: 48px; | ||||
| } | } | ||||
| } | } | ||||
| `; | `; | ||||
| export const OfferImageContainer = styled(Box)` | |||||
| min-width: 144px; | |||||
| min-height: 144px; | |||||
| width: 144px; | |||||
| height: 144px; | |||||
| @media (max-width: 600px) { | |||||
| ${(props) => | |||||
| !props.vertical | |||||
| ? ` | |||||
| min-width: 108px; | |||||
| min-height: 108px; | |||||
| width: 108px; | |||||
| height: 108px; | |||||
| ` | |||||
| : `margin-top: 4px;`} | |||||
| border-radius: 4px; | |||||
| overflow: hidden; | |||||
| box-shadow: 4px 4px 9px rgba(0, 0, 0, 0.12); | |||||
| } | |||||
| `; | |||||
| export const OfferTitleAboveImage = styled(OfferTitle)` | |||||
| padding-bottom: 12px; | |||||
| padding-top: 5px; | |||||
| padding-left: 1px; | |||||
| display: block; | |||||
| ${(props) => props.vertical && `display: none;`} | |||||
| @media (min-width: 551px) { | |||||
| display: none; | |||||
| } | |||||
| `; | |||||
| export const EyeIcon = styled(Eye)` | |||||
| width: 12px; | |||||
| height: 11px; | |||||
| @media (max-width: 600px) { | |||||
| position: relative; | |||||
| top: 1px !important; | |||||
| } | |||||
| `; | |||||
| export const ChatOffer = styled(Box)` | export const ChatOffer = styled(Box)` | ||||
| display: flex; | display: flex; | ||||
| } | } | ||||
| `; | `; | ||||
| export const OfferCard = styled(Box)``; | |||||
| export const ChatInfo = styled(Box)` | export const ChatInfo = styled(Box)` | ||||
| height: 100%; | height: 100%; | ||||
| display: flex; | display: flex; | ||||
| } | } | ||||
| `; | `; | ||||
| export const LocationIcon = styled(Box)` | |||||
| export const LocationIconContainer = styled(Box)` | |||||
| height: 12px; | height: 12px; | ||||
| width: auto; | width: auto; | ||||
| position: relative; | position: relative; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import FilterRadioDropdown from "../../FilterDropdown/Radio/FilterRadioDropdown"; | |||||
| import { CategoryChosenIcon, CategoryIcon } from "./CategoryChoser.styled"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const firstCategoryOption = { | |||||
| label: "SVE KATEGORIJE", | |||||
| value: { _id: 0 }, | |||||
| }; | |||||
| const CategoryChoser = (props) => { | |||||
| const filters = props.filters; | |||||
| const { t } = useTranslation(); | |||||
| const handleSelectCategory = (category) => { | |||||
| filters.setSelectedCategory(category); | |||||
| filters.clearSelectedSubcategory(); | |||||
| }; | |||||
| return ( | |||||
| <FilterRadioDropdown | |||||
| data={[...filters?.categories]} | |||||
| icon={ | |||||
| filters.selectedCategory?.name ? ( | |||||
| <CategoryChosenIcon /> | |||||
| ) : ( | |||||
| <CategoryIcon /> | |||||
| ) | |||||
| } | |||||
| title={ | |||||
| filters.selectedCategory?.name | |||||
| ? filters.selectedCategory?.name | |||||
| : t("filters.categories.title") | |||||
| } | |||||
| searchPlaceholder={t("filters.categories.placeholder")} | |||||
| setSelected={handleSelectCategory} | |||||
| selected={filters.selectedCategory} | |||||
| firstOption={firstCategoryOption} | |||||
| /> | |||||
| ); | |||||
| }; | |||||
| CategoryChoser.propTypes = { | |||||
| filters: PropTypes.any, | |||||
| }; | |||||
| export default CategoryChoser; |
| import { ReactComponent as Category } from "../../../../../assets/images/svg/category.svg"; | |||||
| import { ReactComponent as CategoryChosen } from "../../../../../assets/images/svg/category-chosen.svg"; | |||||
| import styled from "styled-components" | |||||
| export const CategoryChosenIcon = styled(CategoryChosen)` | |||||
| ` | |||||
| export const CategoryIcon = styled(Category)` | |||||
| ` |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import FilterCheckboxDropdown from "../../FilterDropdown/Checkbox/FilterCheckboxDropdown"; | |||||
| import { LocationIcon } from "./LocationChoser.styled"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const LocationChoser = (props) => { | |||||
| const { t } = useTranslation(); | |||||
| const filters = props.filters; | |||||
| return ( | |||||
| <FilterCheckboxDropdown | |||||
| searchPlaceholder={t("filters.location.placeholder")} | |||||
| data={[...filters.locations]} | |||||
| filters={ | |||||
| filters?.selectedLocations?.length > 0 | |||||
| ? [...filters.selectedLocations] | |||||
| : [] | |||||
| } | |||||
| icon={<LocationIcon />} | |||||
| title={t("filters.location.title")} | |||||
| setItemsSelected={filters.setSelectedLocations} | |||||
| /> | |||||
| ); | |||||
| }; | |||||
| LocationChoser.propTypes = { | |||||
| filters: PropTypes.any, | |||||
| }; | |||||
| export default LocationChoser; |
| import styled from "styled-components"; | |||||
| import { ReactComponent as Location } from "../../../../../assets/images/svg/location.svg"; | |||||
| export const LocationIcon = styled(Location)` | |||||
| ` |
| import React, { useEffect, useMemo, useState } from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { SubcategoryIcon } from "./SubcategoryChoser.styled"; | |||||
| import FilterRadioDropdown from "../../FilterDropdown/Radio/FilterRadioDropdown"; | |||||
| import _ from "lodash"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const firstSubcategoryOption = { | |||||
| label: "SVE PODKATEGORIJE", | |||||
| value: { _id: 0 }, | |||||
| }; | |||||
| const SubcategoryChoser = (props) => { | |||||
| const filters = props.filters; | |||||
| const { t } = useTranslation(); | |||||
| const [isOpened, setIsOpened] = useState(false); | |||||
| const [isDisabled, setIsDisabled] = useState(true); | |||||
| const setInitialOpen = useMemo(() => { | |||||
| return _.once(() => { | |||||
| setIsOpened(true); | |||||
| }); | |||||
| }, []); | |||||
| useEffect(() => { | |||||
| if (!filters.selectedCategory || filters.selectedCategory?._id === 0) { | |||||
| setIsOpened(false); | |||||
| setIsDisabled(true); | |||||
| } else { | |||||
| setIsDisabled(false); | |||||
| setInitialOpen(); | |||||
| } | |||||
| }, [filters.selectedCategory]); | |||||
| const handleOpen = () => { | |||||
| setIsOpened((prevState) => !prevState); | |||||
| }; | |||||
| return ( | |||||
| <FilterRadioDropdown | |||||
| data={filters.subcategories ? [...filters.subcategories] : []} | |||||
| icon={<SubcategoryIcon />} | |||||
| title={ | |||||
| filters.selectedSubcategory?.name | |||||
| ? filters.selectedSubcategory?.name | |||||
| : t("filters.subcategories.title") | |||||
| } | |||||
| searchPlaceholder={t("filters.subcategories.placeholder")} | |||||
| setSelected={filters.setSelectedSubcategory} | |||||
| selected={filters.selectedSubcategory} | |||||
| open={isOpened} | |||||
| disabled={isDisabled} | |||||
| handleOpen={handleOpen} | |||||
| firstOption={firstSubcategoryOption} | |||||
| /> | |||||
| ); | |||||
| }; | |||||
| SubcategoryChoser.propTypes = { | |||||
| filters: PropTypes.any, | |||||
| }; | |||||
| export default SubcategoryChoser; |
| import styled from "styled-components"; | |||||
| import { ReactComponent as Subcategory } from "../../../../../assets/images/svg/subcategory.svg"; | |||||
| export const SubcategoryIcon = styled(Subcategory)``; |
| import React, { useEffect, useState } from "react"; | |||||
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| import { | |||||
| ContentContainer, | |||||
| FilterCardContainer, | |||||
| Footer, | |||||
| Header, | |||||
| Title, | |||||
| } from "./FilterCard.styled"; | |||||
| import { ReactComponent as Subcategory } from "../../../assets/images/svg/subcategory.svg"; | |||||
| import { ReactComponent as Category } from "../../../assets/images/svg/category.svg"; | |||||
| import { ReactComponent as CategoryChosen } from "../../../assets/images/svg/category-chosen.svg"; | |||||
| import { ReactComponent as Location } from "../../../assets/images/svg/location.svg"; | |||||
| import Link from "../../Link/Link"; | |||||
| import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton"; | |||||
| import FilterCheckboxDropdown from "./FilterDropdown/Checkbox/FilterCheckboxDropdown"; | |||||
| import FilterRadioDropdown from "./FilterDropdown/Radio/FilterRadioDropdown"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| import selectedTheme from "../../../themes"; | |||||
| import { ContentContainer, FilterCardContainer } from "./FilterCard.styled"; | |||||
| import useFilters from "../../../hooks/useFilters"; | import useFilters from "../../../hooks/useFilters"; | ||||
| import HeaderBack from "../../ItemDetails/Header/Header"; | import HeaderBack from "../../ItemDetails/Header/Header"; | ||||
| import FilterHeader from "./FilterHeader/FilterHeader"; | |||||
| import FilterFooter from "./FilterFooter/FilterFooter"; | |||||
| import CategoryChoser from "./Choser/CategoryChoser/CategoryChoser"; | |||||
| import SubcategoryChoser from "./Choser/SubcategoryChoser/SubcategoryChoser"; | |||||
| import LocationChoser from "./Choser/LocationChoser/LocationChoser"; | |||||
| const FilterCard = (props) => { | const FilterCard = (props) => { | ||||
| const { t } = useTranslation(); | |||||
| const [isOpened, setIsOpened] = useState(false); | |||||
| const [isDisabled, setIsDisabled] = useState(true); | |||||
| const filters = useFilters(props.myOffers); | const filters = useFilters(props.myOffers); | ||||
| useEffect(() => { | |||||
| if (!filters.selectedCategory || filters.selectedCategory?._id === 0) { | |||||
| setIsOpened(false); | |||||
| setIsDisabled(true); | |||||
| } else { | |||||
| setIsDisabled(false); | |||||
| } | |||||
| }, [filters.selectedCategory]); | |||||
| const handleSelectCategory = (category) => { | |||||
| filters.setSelectedCategory(category); | |||||
| filters.setSelectedSubcategory(); | |||||
| }; | |||||
| const handleOpen = () => { | |||||
| setIsOpened((prevState) => !prevState); | |||||
| }; | |||||
| const handleFilters = () => { | |||||
| filters.applyFilters(); | |||||
| if (props.closeResponsive) props.closeResponsive(); | |||||
| }; | |||||
| const clearFilters = () => { | |||||
| filters.clearFilters(); | |||||
| }; | |||||
| return ( | return ( | ||||
| <FilterCardContainer | <FilterCardContainer | ||||
| responsiveOpen={props.responsiveOpen} | responsiveOpen={props.responsiveOpen} | ||||
| responsive={props.responsive} | responsive={props.responsive} | ||||
| myOffers={props.myOffers} | myOffers={props.myOffers} | ||||
| > | > | ||||
| {/* Header title for my offers */} | |||||
| {props.myOffers && <HeaderBack />} | {props.myOffers && <HeaderBack />} | ||||
| <Header> | |||||
| <Title>{t("filters.title")}</Title> | |||||
| <Link | |||||
| to="#" | |||||
| textsize={"12px"} | |||||
| font={"Open Sans"} | |||||
| onClick={clearFilters} | |||||
| > | |||||
| {t("filters.cancel")} | |||||
| </Link> | |||||
| </Header> | |||||
| <FilterHeader /> | |||||
| <ContentContainer> | <ContentContainer> | ||||
| {/* Categories */} | {/* Categories */} | ||||
| <FilterRadioDropdown | |||||
| data={[...filters?.categories]} | |||||
| icon={ | |||||
| filters.selectedCategory?.name ? <CategoryChosen /> : <Category /> | |||||
| } | |||||
| title={ | |||||
| filters.selectedCategory?.name | |||||
| ? filters.selectedCategory?.name | |||||
| : t("filters.categories.title") | |||||
| } | |||||
| searchPlaceholder={t("filters.categories.placeholder")} | |||||
| setSelected={handleSelectCategory} | |||||
| selected={filters.selectedCategory} | |||||
| firstOption={{ | |||||
| label: "SVE KATEGORIJE", | |||||
| value: { _id: 0 }, | |||||
| }} | |||||
| /> | |||||
| <CategoryChoser filters={filters} /> | |||||
| {/* Subcategories */} | {/* Subcategories */} | ||||
| <FilterRadioDropdown | |||||
| data={filters.subcategories ? [...filters.subcategories] : []} | |||||
| icon={<Subcategory />} | |||||
| title={ | |||||
| filters.selectedSubcategory?.name | |||||
| ? filters.selectedSubcategory?.name | |||||
| : t("filters.subcategories.title") | |||||
| } | |||||
| searchPlaceholder={t("filters.subcategories.placeholder")} | |||||
| setSelected={filters.setSelectedSubcategory} | |||||
| selected={filters.selectedSubcategory} | |||||
| open={isOpened} | |||||
| disabled={isDisabled} | |||||
| handleOpen={handleOpen} | |||||
| firstOption={{ | |||||
| label: "SVE PODKATEGORIJE", | |||||
| value: { _id: 0 }, | |||||
| }} | |||||
| /> | |||||
| <SubcategoryChoser filters={filters} /> | |||||
| {/* Locations */} | {/* Locations */} | ||||
| <FilterCheckboxDropdown | |||||
| searchPlaceholder={t("filters.location.placeholder")} | |||||
| data={[...filters.locations]} | |||||
| filters={ | |||||
| filters?.selectedLocations?.length > 0 | |||||
| ? [...filters.selectedLocations] | |||||
| : [] | |||||
| } | |||||
| icon={<Location />} | |||||
| title={t("filters.location.title")} | |||||
| setItemsSelected={filters.setSelectedLocations} | |||||
| /> | |||||
| <LocationChoser filters={filters} /> | |||||
| </ContentContainer> | </ContentContainer> | ||||
| <Footer responsiveOpen={props.responsiveOpen}> | |||||
| {props.responsiveOpen && ( | |||||
| <PrimaryButton | |||||
| variant="outlined" | |||||
| fullWidth | |||||
| onClick={props.closeResponsive} | |||||
| textcolor={selectedTheme.primaryPurple} | |||||
| font="Open Sans" | |||||
| style={{ | |||||
| fontWeight: "600", | |||||
| fontSize: "12px", | |||||
| border: "0", | |||||
| textAlign: "center", | |||||
| }} | |||||
| > | |||||
| ZATVORI | |||||
| </PrimaryButton> | |||||
| )} | |||||
| <PrimaryButton | |||||
| variant="outlined" | |||||
| fullWidth | |||||
| onClick={handleFilters} | |||||
| textcolor={selectedTheme.primaryPurple} | |||||
| font="Open Sans" | |||||
| style={{ | |||||
| fontWeight: "600", | |||||
| fontSize: "12px", | |||||
| borderColor: selectedTheme.primaryPurple, | |||||
| }} | |||||
| > | |||||
| {t("filters.usefilters")} | |||||
| </PrimaryButton> | |||||
| </Footer> | |||||
| <FilterFooter /> | |||||
| </FilterCardContainer> | </FilterCardContainer> | ||||
| ); | ); | ||||
| }; | }; |
| import { Box, Typography } from "@mui/material"; | |||||
| import { Box } from "@mui/material"; | |||||
| import styled from "styled-components"; | import styled from "styled-components"; | ||||
| import selectedTheme from "../../../themes"; | |||||
| export const FilterCardContainer = styled(Box)` | export const FilterCardContainer = styled(Box)` | ||||
| position: fixed; | position: fixed; | ||||
| margin-top: -14px; | margin-top: -14px; | ||||
| } | } | ||||
| `; | `; | ||||
| export const Title = styled(Typography)` | |||||
| font-size: 24px; | |||||
| line-height: 33px; | |||||
| font-weight: 700; | |||||
| font-family: "Open Sans"; | |||||
| color: ${selectedTheme.primaryText}; | |||||
| position: relative; | |||||
| `; | |||||
| export const Header = styled(Box)` | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: space-between; | |||||
| align-items: center; | |||||
| margin-bottom: 1rem; | |||||
| `; | |||||
| export const Footer = styled(Box)` | |||||
| position: "sticky"; | |||||
| ${(props) => | |||||
| props.responsiveOpen && | |||||
| ` | |||||
| flex-direction: row; | |||||
| display: flex; | |||||
| justify-content: space-around;`} | |||||
| bottom: 0; | |||||
| & div button { | |||||
| height: 48px; | |||||
| padding-top: 7px; | |||||
| } | |||||
| & div button:hover { | |||||
| background-color: ${selectedTheme.primaryPurple} !important; | |||||
| color: ${selectedTheme.primaryBackgroundColor} !important; | |||||
| } | |||||
| `; | |||||
| export const ContentContainer = styled(Box)` | export const ContentContainer = styled(Box)` | ||||
| overflow-y: auto; | overflow-y: auto; | ||||
| height: 100%; | height: 100%; | ||||
| scrollbar-color: #ddd; | scrollbar-color: #ddd; | ||||
| ${() => window.scrollbars.visible && `padding-right: 15px`}; | ${() => window.scrollbars.visible && `padding-right: 15px`}; | ||||
| `; | `; | ||||
| }, [toSearch]); | }, [toSearch]); | ||||
| useEffect(() => { | useEffect(() => { | ||||
| if (props.selected?._id !== 0 && props.selected !== null && props.selected !== undefined) { | |||||
| if ( | |||||
| props.selected?._id !== 0 && | |||||
| props.selected !== null && | |||||
| props.selected !== undefined | |||||
| ) { | |||||
| setIsOpened(true); | setIsOpened(true); | ||||
| } | } | ||||
| }, [props.selected]) | |||||
| }, [props.selected]); | |||||
| const handleClear = () => { | const handleClear = () => { | ||||
| setToSearch(""); | setToSearch(""); | ||||
| toggleIconClosed={<DropdownDown />} | toggleIconClosed={<DropdownDown />} | ||||
| toggleIconOpened={<DropdownUp />} | toggleIconOpened={<DropdownUp />} | ||||
| fullWidth | fullWidth | ||||
| open={isOpened} | |||||
| open={ props?.open !== undefined ? props.open : isOpened} | |||||
| disabled={props.disabled} | disabled={props.disabled} | ||||
| setIsOpened={handleOpen} | setIsOpened={handleOpen} | ||||
| toggleIconStyles={{ | toggleIconStyles={{ |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { FilterFooterContainer } from "./FilterFooter.styled"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| import useFilters from "../../../../hooks/useFilters"; | |||||
| const FilterFooter = (props) => { | |||||
| const { t } = useTranslation(); | |||||
| const filters = useFilters(); | |||||
| const handleFilters = () => { | |||||
| filters.applyFilters(); | |||||
| if (props.closeResponsive) props.closeResponsive(); | |||||
| }; | |||||
| return ( | |||||
| <FilterFooterContainer> | |||||
| {props.responsiveOpen && ( | |||||
| <PrimaryButton | |||||
| variant="outlined" | |||||
| fullWidth | |||||
| onClick={props.closeResponsive} | |||||
| textcolor={selectedTheme.primaryPurple} | |||||
| font="Open Sans" | |||||
| style={{ | |||||
| fontWeight: "600", | |||||
| fontSize: "12px", | |||||
| border: "0", | |||||
| textAlign: "center", | |||||
| }} | |||||
| > | |||||
| {t("common.close")} | |||||
| </PrimaryButton> | |||||
| )} | |||||
| <PrimaryButton | |||||
| variant="outlined" | |||||
| fullWidth | |||||
| onClick={handleFilters} | |||||
| textcolor={selectedTheme.primaryPurple} | |||||
| font="Open Sans" | |||||
| style={{ | |||||
| fontWeight: "600", | |||||
| fontSize: "12px", | |||||
| borderColor: selectedTheme.primaryPurple, | |||||
| }} | |||||
| > | |||||
| {t("filters.usefilters")} | |||||
| </PrimaryButton> | |||||
| </FilterFooterContainer> | |||||
| ); | |||||
| }; | |||||
| (FilterFooter.propTypes = { | |||||
| responsiveOpen: PropTypes.bool, | |||||
| closeResponsive: PropTypes.func, | |||||
| }), | |||||
| (FilterFooter.defaultProps = { | |||||
| responsiveOpen: false, | |||||
| }); | |||||
| export default FilterFooter; |
| import { Box } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| export const FilterFooterContainer = styled(Box)` | |||||
| position: "sticky"; | |||||
| ${(props) => | |||||
| props.responsiveOpen && | |||||
| ` | |||||
| flex-direction: row; | |||||
| display: flex; | |||||
| justify-content: space-around;`} | |||||
| bottom: 0; | |||||
| & div button { | |||||
| height: 48px; | |||||
| padding-top: 7px; | |||||
| } | |||||
| & div button:hover { | |||||
| background-color: ${selectedTheme.primaryPurple} !important; | |||||
| color: ${selectedTheme.primaryBackgroundColor} !important; | |||||
| } | |||||
| `; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { FilterHeaderContainer, Title } from "./FilterHeader.styled"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| import useFilters from "../../../../hooks/useFilters"; | |||||
| import Link from "../../../Link/Link"; | |||||
| const FilterHeader = () => { | |||||
| const filters = useFilters(); | |||||
| const { t } = useTranslation(); | |||||
| const clearFilters = () => { | |||||
| filters.clearFilters(); | |||||
| }; | |||||
| return ( | |||||
| <FilterHeaderContainer> | |||||
| <Title>{t("filters.title")}</Title> | |||||
| <Link to="#" textsize={"12px"} font={"Open Sans"} onClick={clearFilters}> | |||||
| {t("filters.cancel")} | |||||
| </Link> | |||||
| </FilterHeaderContainer> | |||||
| ); | |||||
| }; | |||||
| FilterHeader.propTypes = { | |||||
| children: PropTypes.node, | |||||
| }; | |||||
| export default FilterHeader; |
| import { Box, Typography } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| export const FilterHeaderContainer = styled(Box)` | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: space-between; | |||||
| align-items: center; | |||||
| margin-bottom: 1rem; | |||||
| `; | |||||
| export const Title = styled(Typography)` | |||||
| font-size: 24px; | |||||
| line-height: 33px; | |||||
| font-weight: 700; | |||||
| font-family: "Open Sans"; | |||||
| color: ${selectedTheme.primaryText}; | |||||
| position: relative; | |||||
| `; |
| import React from 'react'; | |||||
| //import PropTypes from 'prop-types'; | |||||
| //import SectionLoader from '../Loader/SectionLoader'; | |||||
| import { Box } from '@mui/system'; | |||||
| const HomeListCard = () => { | |||||
| return ( | |||||
| <Box> Title </Box> | |||||
| ); | |||||
| }; | |||||
| // AuthCard.propTypes = { | |||||
| // children: PropTypes.node, | |||||
| // title: PropTypes.string, | |||||
| // subtitle: PropTypes.string, | |||||
| // isLoading: PropTypes.bool, | |||||
| // }; | |||||
| export default HomeListCard; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| import { InfoGroup, InfoIcon, InfoText } from "./Information.styled"; | |||||
| const Information = (props) => { | |||||
| return ( | |||||
| <InfoGroup hide={props.hide}> | |||||
| <InfoIcon | |||||
| color={selectedTheme.iconStrokeColor} | |||||
| component="span" | |||||
| size="16px" | |||||
| > | |||||
| {/* <CategoryIcon width={"14px"} /> */} | |||||
| {props.icon} | |||||
| </InfoIcon> | |||||
| {/* <InfoText>{offer?.offer?.category?.name}</InfoText> */} | |||||
| <InfoText>{props.value}</InfoText> | |||||
| </InfoGroup> | |||||
| ); | |||||
| }; | |||||
| Information.propTypes = { | |||||
| icon: PropTypes.node, | |||||
| value: PropTypes.string, | |||||
| hide: PropTypes.bool, | |||||
| }; | |||||
| export default Information; |
| import { Box, Typography } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| export const InfoGroup = styled(Box)` | |||||
| display: ${props => props.hide ? 'none' : 'flex'}; | |||||
| flex-direction: row; | |||||
| align-items: center; | |||||
| gap: 4px; | |||||
| `; | |||||
| export const InfoIcon = styled(Box)` | |||||
| display: flex; | |||||
| align-items: center; | |||||
| `; | |||||
| export const InfoText = styled(Typography)` | |||||
| font-family: "Open Sans"; | |||||
| text-transform: capitalize; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 12px; | |||||
| } | |||||
| `; |
| import React, { useEffect } from "react"; | |||||
| import React, { useEffect, useMemo } from "react"; | |||||
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| import { | import { | ||||
| CheckButton, | CheckButton, | ||||
| OfferInfo, | OfferInfo, | ||||
| Info, | Info, | ||||
| PostDate, | PostDate, | ||||
| InfoIcon, | |||||
| InfoText, | |||||
| InfoGroup, | |||||
| OfferTitle, | OfferTitle, | ||||
| OfferDescriptionText, | OfferDescriptionText, | ||||
| OfferDescriptionTitle, | OfferDescriptionTitle, | ||||
| OfferDetails, | OfferDetails, | ||||
| OfferImage, | OfferImage, | ||||
| Scroller, | Scroller, | ||||
| CategoryIcon, | |||||
| SubcategoryIcon, | |||||
| QuantityIcon, | |||||
| EyeIcon, | |||||
| } from "./ItemDetailsCard.styled"; | } from "./ItemDetailsCard.styled"; | ||||
| import { ReactComponent as Category } from "../../../assets/images/svg/category.svg"; | |||||
| import { ReactComponent as Subcategory } from "../../../assets/images/svg/subcategory.svg"; | |||||
| import { ReactComponent as Quantity } from "../../../assets/images/svg/quantity.svg"; | |||||
| import { ReactComponent as Eye } from "../../../assets/images/svg/eye-striked.svg"; | |||||
| import selectedTheme from "../../../themes"; | import selectedTheme from "../../../themes"; | ||||
| import { useDispatch, useSelector } from "react-redux"; | import { useDispatch, useSelector } from "react-redux"; | ||||
| import { selectLatestChats } from "../../../store/selectors/chatSelectors"; | import { selectLatestChats } from "../../../store/selectors/chatSelectors"; | ||||
| import { useHistory } from "react-router-dom"; | |||||
| import { increaseCounter } from "../../../store/actions/counter/counterActions"; | import { increaseCounter } from "../../../store/actions/counter/counterActions"; | ||||
| import _ from "lodash"; | import _ from "lodash"; | ||||
| import { selectUserId } from "../../../store/selectors/loginSelectors"; | import { selectUserId } from "../../../store/selectors/loginSelectors"; | ||||
| import { formatDateLocale } from "../../../util/helpers/dateHelpers"; | |||||
| import { startChat } from "../../../util/helpers/chatHelper"; | |||||
| import Information from "./Information/Information"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const ItemDetailsCard = (props) => { | const ItemDetailsCard = (props) => { | ||||
| const offer = props.offer; | const offer = props.offer; | ||||
| const history = useHistory(); | |||||
| const chats = useSelector(selectLatestChats); | const chats = useSelector(selectLatestChats); | ||||
| const userId = useSelector(selectUserId); | const userId = useSelector(selectUserId); | ||||
| const { t } = useTranslation(); | |||||
| const dispatch = useDispatch(); | const dispatch = useDispatch(); | ||||
| const dateCreated = new Date(offer?.offer?._created); | |||||
| const increaseOfferCounter = useMemo(() => { | |||||
| return _.once(function (id) { | |||||
| dispatch(increaseCounter(id)); | |||||
| }); | |||||
| }, []); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| if (offer?.offer?._id) { | if (offer?.offer?._id) { | ||||
| _.once(function () { | |||||
| dispatch(increaseCounter(offer?.offer?._id)); | |||||
| })(); | |||||
| increaseOfferCounter(offer?.offer?._id); | |||||
| } | } | ||||
| }, [offer]); | }, [offer]); | ||||
| const dayCreated = | |||||
| dateCreated.getDate() < 10 | |||||
| ? "0" + dateCreated.getDate() | |||||
| : dateCreated.getDate(); | |||||
| const monthCreated = | |||||
| dateCreated.getMonth() < 10 | |||||
| ? "0" + (dateCreated.getMonth() + 1) | |||||
| : dateCreated.getMonth() + 1; | |||||
| const yearCreated = dateCreated.getFullYear(); | |||||
| const date = formatDateLocale(new Date(offer?.offer?._created)); | |||||
| const startExchange = () => { | const startExchange = () => { | ||||
| const chatItem = chats.find( | |||||
| (item) => item.chat.offerId === offer?.offer?._id | |||||
| ); | |||||
| if (chatItem !== undefined) { | |||||
| history.push(`/messages/${chatItem.chat._id}`); | |||||
| } else { | |||||
| if (offer?.offer?.userId !== userId) { | |||||
| history.push(`/messages/newMessage`, { | |||||
| offerId: offer?.offer?._id, | |||||
| }); | |||||
| } | |||||
| } | |||||
| startChat(chats, offer, userId); | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <ItemDetailsCardContainer | <ItemDetailsCardContainer | ||||
| > | > | ||||
| <OfferInfo> | <OfferInfo> | ||||
| <Info> | <Info> | ||||
| <InfoGroup> | |||||
| <InfoIcon | |||||
| color={selectedTheme.iconStrokeColor} | |||||
| component="span" | |||||
| size="16px" | |||||
| > | |||||
| <Category width={"14px"} /> | |||||
| </InfoIcon> | |||||
| <InfoText>{offer?.offer?.category?.name}</InfoText> | |||||
| </InfoGroup> | |||||
| <InfoGroup> | |||||
| <InfoIcon | |||||
| color={selectedTheme.iconStrokeColor} | |||||
| component="span" | |||||
| size="16px" | |||||
| > | |||||
| <Subcategory width={"14px"} /> | |||||
| </InfoIcon> | |||||
| <InfoText>{offer?.offer?.subcategory}</InfoText> | |||||
| </InfoGroup> | |||||
| <InfoGroup> | |||||
| <InfoIcon | |||||
| color={selectedTheme.iconStrokeColor} | |||||
| component="span" | |||||
| size="16px" | |||||
| > | |||||
| <Quantity width={"22px"} height={"16px"} /> | |||||
| </InfoIcon> | |||||
| <InfoText>{offer?.offer?.condition}</InfoText> | |||||
| </InfoGroup> | |||||
| {!props.hideViews && ( | |||||
| <InfoGroup views> | |||||
| <InfoIcon color={"black"} component="span" size="12px" last> | |||||
| <Eye width={"18px"} height={"20px"} /> | |||||
| </InfoIcon> | |||||
| <InfoText>{offer?.offer?.views?.count}</InfoText> | |||||
| </InfoGroup> | |||||
| )} | |||||
| <Information | |||||
| icon={<CategoryIcon />} | |||||
| value={offer?.offer?.category?.name} | |||||
| /> | |||||
| <Information | |||||
| icon={<SubcategoryIcon />} | |||||
| value={offer?.offer?.subcategory} | |||||
| /> | |||||
| <Information | |||||
| icon={<QuantityIcon />} | |||||
| value={offer?.offer?.condition} | |||||
| /> | |||||
| <Information icon={<EyeIcon />} value={offer?.offer?.views?.count} /> | |||||
| </Info> | </Info> | ||||
| <PostDate> | |||||
| {dayCreated}.{monthCreated}.{yearCreated} | |||||
| </PostDate> | |||||
| <PostDate>{date}</PostDate> | |||||
| </OfferInfo> | </OfferInfo> | ||||
| <Details | <Details | ||||
| hasScrollBar={!props.showPublishButton} | hasScrollBar={!props.showPublishButton} | ||||
| })} | })} | ||||
| </Scroller> | </Scroller> | ||||
| <OfferDetails> | <OfferDetails> | ||||
| <OfferDescriptionTitle>Opis:</OfferDescriptionTitle> | |||||
| <OfferDescriptionTitle> | |||||
| {t("itemDetailsCard.description")} | |||||
| </OfferDescriptionTitle> | |||||
| <OfferDescriptionText showBarterButton={props.showExchangeButton}> | <OfferDescriptionText showBarterButton={props.showExchangeButton}> | ||||
| {offer?.offer?.description} | {offer?.offer?.description} | ||||
| </OfferDescriptionText> | </OfferDescriptionText> | ||||
| </OfferDetails> | </OfferDetails> | ||||
| </Details> | </Details> | ||||
| {!props.halfwidth && props.showExchangeButton ? ( | |||||
| <React.Fragment> | |||||
| {!props.halfwidth && props.showExchangeButton && ( | |||||
| <CheckButton | <CheckButton | ||||
| variant={props.sponsored ? "contained" : "outlined"} | variant={props.sponsored ? "contained" : "outlined"} | ||||
| buttoncolor={selectedTheme.primaryPurple} | buttoncolor={selectedTheme.primaryPurple} | ||||
| textcolor={props.sponsored ? "white" : selectedTheme.primaryPurple} | textcolor={props.sponsored ? "white" : selectedTheme.primaryPurple} | ||||
| style={{ fontWeight: "600" }} | |||||
| onClick={startExchange} | onClick={startExchange} | ||||
| > | > | ||||
| Trampi | |||||
| {t("itemDetailsCard.startExchangeButton")} | |||||
| </CheckButton> | </CheckButton> | ||||
| </React.Fragment> | |||||
| ) : ( | |||||
| <></> | |||||
| )} | )} | ||||
| </ItemDetailsCardContainer> | </ItemDetailsCardContainer> | ||||
| ); | ); | ||||
| }; | }; | ||||
| ItemDetailsCard.propTypes = { | ItemDetailsCard.propTypes = { | ||||
| children: PropTypes.node, | |||||
| id: PropTypes.number, | |||||
| title: PropTypes.string, | |||||
| description: PropTypes.string, | |||||
| category: PropTypes.string, | |||||
| subcategory: PropTypes.string, | |||||
| condition: PropTypes.string, | |||||
| showNumberOfViews: PropTypes.bool, | |||||
| author: PropTypes.string, | |||||
| location: PropTypes.string, | |||||
| images: PropTypes.node, | |||||
| quantity: PropTypes.number, | |||||
| package: PropTypes.string, | |||||
| numberOfViews: PropTypes.number, | |||||
| halfwidth: PropTypes.bool, | halfwidth: PropTypes.bool, | ||||
| sponsored: PropTypes.bool, | sponsored: PropTypes.bool, | ||||
| offer: PropTypes.any, | offer: PropTypes.any, | ||||
| hideViews: PropTypes.bool, | hideViews: PropTypes.bool, | ||||
| showExchangeButton: PropTypes.bool, | showExchangeButton: PropTypes.bool, | ||||
| // offer: PropTypes.shape({ | |||||
| // images: PropTypes.any, | |||||
| // name:PropTypes.string, | |||||
| // description:PropTypes.string, | |||||
| // condition:PropTypes.string, | |||||
| // category:PropTypes.shape({ | |||||
| // name:PropTypes.string | |||||
| // }), | |||||
| // location:PropTypes.shape({ | |||||
| // city:PropTypes.string | |||||
| // }) | |||||
| // }) | |||||
| showBarterButton: PropTypes.bool, | showBarterButton: PropTypes.bool, | ||||
| showPublishButton: PropTypes.bool, | showPublishButton: PropTypes.bool, | ||||
| className: PropTypes.string, | className: PropTypes.string, |
| import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton"; | import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton"; | ||||
| import { Icon } from "../../Icon/Icon"; | import { Icon } from "../../Icon/Icon"; | ||||
| import HorizontalScroller from "../../Scroller/HorizontalScroller"; | import HorizontalScroller from "../../Scroller/HorizontalScroller"; | ||||
| import { ReactComponent as Category } from "../../../assets/images/svg/category.svg"; | |||||
| import { ReactComponent as Subcategory } from "../../../assets/images/svg/subcategory.svg"; | |||||
| import { ReactComponent as Quantity } from "../../../assets/images/svg/quantity.svg"; | |||||
| import { ReactComponent as Eye } from "../../../assets/images/svg/eye-striked.svg"; | |||||
| export const ItemDetailsCardContainer = styled(Container)` | export const ItemDetailsCardContainer = styled(Container)` | ||||
| display: flex; | display: flex; | ||||
| margin: 0; | margin: 0; | ||||
| } | } | ||||
| `; | `; | ||||
| export const InfoGroup = styled(Box)` | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| align-items: center; | |||||
| gap: 4px; | |||||
| `; | |||||
| export const PostDate = styled(Typography)` | export const PostDate = styled(Typography)` | ||||
| font-family: "Open Sans"; | font-family: "Open Sans"; | ||||
| font-size: 12px; | font-size: 12px; | ||||
| left: 5px; | left: 5px; | ||||
| } | } | ||||
| `; | `; | ||||
| export const InfoIcon = styled(Box)` | |||||
| display: flex; | |||||
| align-items: center; | |||||
| `; | |||||
| export const InfoText = styled(Typography)` | |||||
| font-family: "Open Sans"; | |||||
| text-transform: capitalize; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 12px; | |||||
| } | |||||
| `; | |||||
| export const OfferTitle = styled(Typography)` | export const OfferTitle = styled(Typography)` | ||||
| font-family: "Open Sans"; | font-family: "Open Sans"; | ||||
| flex: 1; | flex: 1; | ||||
| position: absolute; | position: absolute; | ||||
| bottom: 9px; | bottom: 9px; | ||||
| right: 12px; | right: 12px; | ||||
| font-weight: 600; | |||||
| &:hover button { | &:hover button { | ||||
| background-color: ${selectedTheme.primaryPurple} !important; | background-color: ${selectedTheme.primaryPurple} !important; | ||||
| color: white !important; | color: white !important; | ||||
| justify-content: center; | justify-content: center; | ||||
| margin-bottom: 30px; | margin-bottom: 30px; | ||||
| `; | `; | ||||
| export const CategoryIcon = styled(Category)` | |||||
| width: 14px; | |||||
| ` | |||||
| export const SubcategoryIcon = styled(Subcategory)` | |||||
| width: 14px; | |||||
| ` | |||||
| export const QuantityIcon = styled(Quantity)` | |||||
| width: 22px; | |||||
| height: 16px; | |||||
| ` | |||||
| export const EyeIcon = styled(Eye)` | |||||
| width: 18px; | |||||
| height: 20px; | |||||
| ` |
| import React from 'react' | |||||
| import PropTypes from 'prop-types' | |||||
| const OfferDetails = () => { | |||||
| return ( | |||||
| <div>OfferDetails</div> | |||||
| ) | |||||
| } | |||||
| OfferDetails.propTypes = { | |||||
| offer: PropTypes.any, | |||||
| } | |||||
| export default OfferDetails |
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const history = useHistory(); | const history = useHistory(); | ||||
| const changeChat = () => { | const changeChat = () => { | ||||
| // if (!props.selected) { | |||||
| history.push(`/messages/${props?.chat?.chat?._id}`) | |||||
| // } | |||||
| } | |||||
| history.push(`/messages/${props?.chat?.chat?._id}`); | |||||
| }; | |||||
| return ( | return ( | ||||
| <MiniChatCardContainer selected={props.selected} onClick={changeChat}> | <MiniChatCardContainer selected={props.selected} onClick={changeChat}> | ||||
| <ProfileImage src={props?.chat?.interlocutorData?.image} /> | <ProfileImage src={props?.chat?.interlocutorData?.image} /> |
| // Setters | // Setters | ||||
| const setSelectedCategory = (payload) => { | const setSelectedCategory = (payload) => { | ||||
| console.log('payl: ', payload); | |||||
| if (isApplied !== false) { | if (isApplied !== false) { | ||||
| dispatch(setIsAppliedStatus(false)); | dispatch(setIsAppliedStatus(false)); | ||||
| } | } | ||||
| dispatch(setFilteredSubcategory(payload)); | dispatch(setFilteredSubcategory(payload)); | ||||
| } | } | ||||
| }; | }; | ||||
| const clearSelectedSubcategory = () => { | |||||
| setSelectedSubcategory(); | |||||
| } | |||||
| const setSelectedLocations = (payload) => { | const setSelectedLocations = (payload) => { | ||||
| if (isApplied !== false) { | if (isApplied !== false) { | ||||
| dispatch(setIsAppliedStatus(false)); | dispatch(setIsAppliedStatus(false)); | ||||
| setSelectedCategory, | setSelectedCategory, | ||||
| selectedSubcategory, | selectedSubcategory, | ||||
| setSelectedSubcategory, | setSelectedSubcategory, | ||||
| clearSelectedSubcategory, | |||||
| selectedLocations, | selectedLocations, | ||||
| setSelectedLocations, | setSelectedLocations, | ||||
| categories, | categories, |
| miniChatHeaderTitle: "Moje Poruke", | miniChatHeaderTitle: "Moje Poruke", | ||||
| send: "Pošalji", | send: "Pošalji", | ||||
| sendPlaceholder: "Poruka...", | sendPlaceholder: "Poruka...", | ||||
| seeChats: "Pogledaj ćaskanje" | |||||
| }, | }, | ||||
| editProfile: { | editProfile: { | ||||
| website: "Web Sajt*", | website: "Web Sajt*", | ||||
| cancel: "Otkaži", | cancel: "Otkaži", | ||||
| delete: "Obriši", | delete: "Obriši", | ||||
| }, | }, | ||||
| itemDetailsCard: { | |||||
| description: "Opis: ", | |||||
| startExchangeButton: "Trampi", | |||||
| } | |||||
| }; | }; |
| import React from 'react'; | import React from 'react'; | ||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||
| import Button from '../../components/Buttons/Button'; | |||||
| import Section from '../../components/Section/Section'; | import Section from '../../components/Section/Section'; | ||||
| const NotFoundPage = () => { | const NotFoundPage = () => { | ||||
| <div className="c-error-page__content"> | <div className="c-error-page__content"> | ||||
| <h1 className="c-error-page__title">404</h1> | <h1 className="c-error-page__title">404</h1> | ||||
| <p className="c-error-page__text">{t('notFound.text')}</p> | <p className="c-error-page__text">{t('notFound.text')}</p> | ||||
| <Button | |||||
| className="c-error-page__button" | |||||
| variant="primary-outlined" | |||||
| > | |||||
| {t('notFound.goBack')} | |||||
| </Button> | |||||
| </div> | </div> | ||||
| </Section> | </Section> | ||||
| </div> | </div> |
| getUserSecurityQuestion: "users/username/securityquestion", | getUserSecurityQuestion: "users/username/securityquestion", | ||||
| confirmSecurityQuestion: "authenticate/confirm", | confirmSecurityQuestion: "authenticate/confirm", | ||||
| confirmForgotPassword: "users/passwords/reset_token", | confirmForgotPassword: "users/passwords/reset_token", | ||||
| resetPassword: "reset-password", | |||||
| forgotPassword: "forgot-password", | |||||
| resetPassword: "auth/reset-password", | |||||
| forgotPassword: "auth/forgot-password", | |||||
| refreshToken: "/auth/refresh", | refreshToken: "/auth/refresh", | ||||
| generateToken: "/authenticate/generate", | generateToken: "/authenticate/generate", | ||||
| authenticate: | authenticate: |
| return getRequest(apiEndpoints.offers.getOffers); | return getRequest(apiEndpoints.offers.getOffers); | ||||
| }; | }; | ||||
| export const attemptFetchOneOffer = (payload) => { | export const attemptFetchOneOffer = (payload) => { | ||||
| const url = `${apiEndpoints.offers.getOneOffer}/${payload}/frontend`; | |||||
| const url = `${apiEndpoints.offers.getOneOffer}/${payload}`; | |||||
| return getRequest(url); | return getRequest(url); | ||||
| } | } | ||||
| export const attemptFetchMoreOffers = (page, payload) => { | export const attemptFetchMoreOffers = (page, payload) => { |
| import history from "../../store/utils/history"; | |||||
| export const startChat = (chats, offer, userId) => { | |||||
| const chatItem = chats.find( | |||||
| (item) => item.chat.offerId === offer?.offer?._id | |||||
| ); | |||||
| if (chatItem !== undefined) { | |||||
| history.push(`/messages/${chatItem.chat._id}`); | |||||
| } else { | |||||
| if (offer?.offer?.userId !== userId) { | |||||
| history.push(`/messages/newMessage`, { | |||||
| offerId: offer?.offer?._id, | |||||
| }); | |||||
| } | |||||
| } | |||||
| } |
| const end = formatDate(dates.end); | const end = formatDate(dates.end); | ||||
| return i18next.t('common.date.range', { start, end }); | return i18next.t('common.date.range', { start, end }); | ||||
| } | } | ||||
| export function formatDateLocale(date) { | |||||
| const dayCreated = | |||||
| date.getDate() < 10 | |||||
| ? "0" + date.getDate() | |||||
| : date.getDate(); | |||||
| const monthCreated = | |||||
| date.getMonth() < 10 | |||||
| ? "0" + (date.getMonth() + 1) | |||||
| : date.getMonth() + 1; | |||||
| const yearCreated = date.getFullYear(); | |||||
| return `${dayCreated}.${monthCreated}.${yearCreated}`; | |||||
| } |