You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. import React, { useMemo } from "react";
  2. import PropTypes from "prop-types";
  3. import {
  4. DetailIcon,
  5. DetailText,
  6. EditIcon,
  7. EditIconContainer,
  8. EyeIcon,
  9. Line,
  10. MessageIcon,
  11. OfferAuthor,
  12. OfferAuthorName,
  13. OfferCardContainer,
  14. OfferCategory,
  15. OfferDetails,
  16. OfferFlexContainer,
  17. OfferImage,
  18. OfferImageContainer,
  19. OfferInfo,
  20. OfferLocation,
  21. OfferTitle,
  22. OfferTitleAboveImage,
  23. OfferViews,
  24. OfferDate,
  25. // PinIcon,
  26. RemoveIcon,
  27. RemoveIconContainer,
  28. LikeIcon,
  29. LikeIconContainer,
  30. CategoryIcon,
  31. CalendarIcon,
  32. PinIconContainer,
  33. PinOutlinedIcon,
  34. ButtonsContainer,
  35. TooltipInnerContainer,
  36. UnpinOutlinedIcon,
  37. AcceptIconContainer,
  38. AcceptIcon,
  39. } from "./OfferCard.styled";
  40. import { ReactComponent as Message } from "../../../assets/images/svg/mail.svg";
  41. import { useHistory } from "react-router-dom";
  42. import { useDispatch, useSelector } from "react-redux";
  43. import { selectUserId } from "../../../store/selectors/loginSelectors";
  44. import useIsMobile from "../../../hooks/useIsMobile";
  45. import { getImageUrl, variants } from "../../../util/helpers/imageUrlGetter";
  46. import OfferDescription from "./OfferDescription/OfferDescription";
  47. import CheckButton from "./CheckButton/CheckButton";
  48. import { formatDateLocale } from "../../../util/helpers/dateHelpers";
  49. import {
  50. toggleDeleteOfferModal,
  51. toggleEditOfferModal,
  52. } from "../../../store/actions/modal/modalActions";
  53. import { Tooltip } from "@mui/material";
  54. import { useTranslation } from "react-i18next";
  55. import { replaceInRoute } from "../../../util/helpers/routeHelpers";
  56. import {
  57. ADMIN_ITEM_DETAILS_PAGE,
  58. ITEM_DETAILS_PAGE,
  59. } from "../../../constants/pages";
  60. import exchangeStatus from "../../../constants/exchangeStatus";
  61. const OfferCard = (props) => {
  62. const dispatch = useDispatch();
  63. const history = useHistory();
  64. const userId = useSelector(selectUserId);
  65. const { isMobile } = useIsMobile();
  66. const date = formatDateLocale(new Date(props.offer?._created));
  67. const { t } = useTranslation();
  68. const pinOffer = (event) => {
  69. event.stopPropagation();
  70. dispatch(
  71. toggleDeleteOfferModal({
  72. offer: props.offer,
  73. pin: true,
  74. pinnedOffer: props.offer.pinned,
  75. deleteOffer: false,
  76. })
  77. );
  78. };
  79. const routeToItem = (itemId) => {
  80. if (!props.disabledCheckButton) {
  81. if (props.isAdmin) {
  82. history.push(
  83. replaceInRoute(ADMIN_ITEM_DETAILS_PAGE, {
  84. offerId: itemId,
  85. })
  86. );
  87. } else {
  88. history.push({
  89. pathname: replaceInRoute(ITEM_DETAILS_PAGE, {
  90. offerId: itemId,
  91. }),
  92. state: {
  93. view: true,
  94. },
  95. });
  96. }
  97. }
  98. };
  99. const messageUser = (event) => {
  100. event.stopPropagation();
  101. props.messageUser(props.offer);
  102. };
  103. const makeReview = (event) => {
  104. event.stopPropagation();
  105. if (!props.disabledReviews) {
  106. props.makeReview(props.offer);
  107. }
  108. };
  109. const openEditOfferModal = (event) => {
  110. event.stopPropagation();
  111. dispatch(
  112. toggleEditOfferModal({
  113. editOffer: true,
  114. offer: props.offer,
  115. isAdmin: props.isAdmin,
  116. customUserId: props?.offer?.userId,
  117. })
  118. );
  119. };
  120. const openRemoveModal = (event) => {
  121. event.stopPropagation();
  122. dispatch(
  123. toggleDeleteOfferModal({
  124. offer: props.offer,
  125. isAdmin: props.isAdmin,
  126. })
  127. );
  128. };
  129. const acceptExchange = (event) => {
  130. event.stopPropagation();
  131. props.acceptExchange();
  132. };
  133. const showMessageIcon = useMemo(() => {
  134. if (userId === props.offer?.userId) {
  135. return false;
  136. }
  137. return true;
  138. }, [userId, props.offer]);
  139. return (
  140. <React.Fragment>
  141. <OfferCardContainer
  142. vertical={props.vertical}
  143. sponsored={
  144. props?.pinned !== undefined
  145. ? props?.pinned?.toString()
  146. : props?.offer?.pinned?.toString()
  147. }
  148. halfwidth={props.halfwidth ? 1 : 0}
  149. onClick={() => routeToItem(props?.offer?._id)}
  150. >
  151. {/* This only shows on vertical offer card */}
  152. <OfferTitleAboveImage
  153. vertical={props.vertical}
  154. noOfButtons={
  155. props.isAdmin
  156. ? 3
  157. : props.isMyOffer
  158. ? props?.offer?.pinned
  159. ? 3
  160. : 2
  161. : props?.offer?.pinned
  162. ? 2
  163. : 1
  164. }
  165. onClick={() => routeToItem(props?.offer?._id)}
  166. >
  167. {props?.offer?.name}
  168. </OfferTitleAboveImage>
  169. {/* ^^^^^^^ */}
  170. <OfferFlexContainer vertical={props.vertical}>
  171. <OfferImageContainer vertical={props.vertical}>
  172. <OfferImage
  173. src={
  174. props?.offer?.images
  175. ? getImageUrl(
  176. props?.offer?.images[0],
  177. variants.offerCard,
  178. isMobile
  179. )
  180. : ""
  181. }
  182. alt={t("offer.imageAlt")}
  183. vertical={props.vertical}
  184. ></OfferImage>
  185. </OfferImageContainer>
  186. <OfferInfo vertical={props.vertical}>
  187. <OfferTitle
  188. vertical={props.vertical}
  189. onClick={() => routeToItem(props?.offer?._id)}
  190. >
  191. {props?.offer?.name}
  192. </OfferTitle>
  193. <OfferAuthor vertical={props.vertical}>
  194. <OfferAuthorName vertical={props.vertical}>
  195. {props?.offer?.user?.company?.name}
  196. </OfferAuthorName>
  197. <OfferLocation vertical={props.vertical}>
  198. {props?.offer?.location?.city}
  199. </OfferLocation>
  200. </OfferAuthor>
  201. <OfferDetails>
  202. <OfferCategory vertical={props.vertical}>
  203. <DetailIcon color="black" component="span" size="16px">
  204. <CategoryIcon />
  205. </DetailIcon>
  206. <DetailText>{props?.offer?.category?.name}</DetailText>
  207. </OfferCategory>
  208. {props.dontShowViews ? (
  209. <></>
  210. ) : (
  211. <OfferViews vertical={props.vertical}>
  212. <DetailIcon color="black" component="span" size="16px">
  213. <EyeIcon />
  214. </DetailIcon>
  215. <DetailText>{props?.offer?.views?.count}</DetailText>
  216. </OfferViews>
  217. )}
  218. <OfferDate vertical={props.vertical}>
  219. <DetailIcon component="span" size="16px">
  220. <CalendarIcon />
  221. </DetailIcon>
  222. <DetailText>{date}</DetailText>
  223. </OfferDate>
  224. </OfferDetails>
  225. </OfferInfo>
  226. {!props.halfwidth ? (
  227. <React.Fragment>
  228. <Line />
  229. <OfferDescription description={props?.offer?.description} />
  230. <CheckButton
  231. disabled={props.disabledCheckButton}
  232. offerId={props?.offer?._id}
  233. sponsored={props.sponsored}
  234. />
  235. </React.Fragment>
  236. ) : (
  237. <></>
  238. )}
  239. <ButtonsContainer vertical={props.vertical}>
  240. {/* {props?.offer?.pinned && (
  241. <PinIcon vertical={props.vertical} isMyOffer={props.isMyOffer} />
  242. )} */}
  243. {props.isMyOffer ? (
  244. <>
  245. <Tooltip title={t("deleteOffer.tooltip")}>
  246. <TooltipInnerContainer>
  247. <RemoveIconContainer
  248. vertical={props.vertical}
  249. onClick={openRemoveModal}
  250. >
  251. <RemoveIcon />
  252. </RemoveIconContainer>
  253. </TooltipInnerContainer>
  254. </Tooltip>
  255. <Tooltip title={t("offer.tooltip")}>
  256. <TooltipInnerContainer>
  257. <EditIconContainer
  258. vertical={props.vertical}
  259. onClick={openEditOfferModal}
  260. >
  261. <EditIcon />
  262. </EditIconContainer>
  263. </TooltipInnerContainer>
  264. </Tooltip>
  265. </>
  266. ) : props.aboveChat ? (
  267. props.exchangeState === exchangeStatus.ACCEPTED ||
  268. props.exchangeState === exchangeStatus.REVIEWED ? (
  269. <LikeIconContainer
  270. customDisabled={props.disabledReviews}
  271. disabled={props.disabledReviews}
  272. onClick={makeReview}
  273. >
  274. <LikeIcon disabled={props.disabledReviews} />
  275. </LikeIconContainer>
  276. ) : (
  277. <AcceptIconContainer // MENJATI
  278. // customDisabled={
  279. // props.exchangeState === exchangeStatus.I_OFFERED ||
  280. // props.disabledReviews
  281. // }
  282. disabled={
  283. props.exchangeState === exchangeStatus.I_OFFERED ||
  284. props.disabledReviews
  285. }
  286. onClick={acceptExchange}
  287. >
  288. <AcceptIcon
  289. disabled={
  290. props.disabledReviews ||
  291. props.exchangeState === exchangeStatus.I_OFFERED
  292. }
  293. />
  294. </AcceptIconContainer>
  295. )
  296. ) : (
  297. <Tooltip title={t("messages.tooltip")}>
  298. <TooltipInnerContainer>
  299. <MessageIcon
  300. aria-label={t("labels.messageUser")}
  301. showMessageIcon={showMessageIcon}
  302. vertical={props.vertical}
  303. onClick={messageUser}
  304. >
  305. <Message />
  306. </MessageIcon>
  307. </TooltipInnerContainer>
  308. </Tooltip>
  309. )}
  310. {props.isAdmin &&
  311. (!props?.offer?.pinned ? (
  312. <Tooltip title={t("admin.pin.tooltip")}>
  313. <TooltipInnerContainer>
  314. <PinIconContainer
  315. showMessageIcon
  316. onClick={pinOffer}
  317. vertical={props.vertical}
  318. >
  319. <PinOutlinedIcon />
  320. </PinIconContainer>
  321. </TooltipInnerContainer>
  322. </Tooltip>
  323. ) : (
  324. <Tooltip title={t("admin.unpin.tooltip")}>
  325. <TooltipInnerContainer>
  326. <PinIconContainer
  327. showMessageIcon
  328. onClick={pinOffer}
  329. vertical={props.vertical}
  330. >
  331. <UnpinOutlinedIcon />
  332. </PinIconContainer>
  333. </TooltipInnerContainer>
  334. </Tooltip>
  335. ))}
  336. </ButtonsContainer>
  337. </OfferFlexContainer>
  338. </OfferCardContainer>
  339. </React.Fragment>
  340. );
  341. };
  342. OfferCard.propTypes = {
  343. children: PropTypes.node,
  344. _id: PropTypes.string,
  345. title: PropTypes.string,
  346. description: PropTypes.string,
  347. category: PropTypes.string,
  348. author: PropTypes.string,
  349. location: PropTypes.string,
  350. image: PropTypes.node,
  351. quantity: PropTypes.number,
  352. package: PropTypes.string,
  353. numberOfViews: PropTypes.number,
  354. halfwidth: PropTypes.bool,
  355. sponsored: PropTypes.bool,
  356. offer: PropTypes.any,
  357. pinned: PropTypes.bool,
  358. vertical: PropTypes.bool,
  359. isMyOffer: PropTypes.bool,
  360. aboveChat: PropTypes.bool,
  361. disabledReviews: PropTypes.bool,
  362. messageUser: PropTypes.func,
  363. makeReview: PropTypes.func,
  364. dontShowViews: PropTypes.bool,
  365. skeleton: PropTypes.bool,
  366. disabledCheckButton: PropTypes.bool,
  367. isAdmin: PropTypes.bool,
  368. exchangeState: PropTypes.any,
  369. acceptExchange: PropTypes.func,
  370. };
  371. OfferCard.defaultProps = {
  372. halfwidth: false,
  373. sponsored: false,
  374. messageUser: () => {},
  375. makeReview: () => {},
  376. };
  377. export default OfferCard;