Guest User

Untitled

a guest
Jan 17th, 2024
242
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.49 KB | None | 0 0
  1. import React, { useEffect, useState } from 'react';
  2. import { FormattedMessage } from 'react-intl';
  3. import { Info } from 'react-feather';
  4. import { string, number, shape } from 'prop-types';
  5. import { Link } from 'react-router-dom';
  6. import Price from '../Price/price';
  7. import { UNCONSTRAINED_SIZE_KEY } from '@magento/peregrine/lib/talons/Image/useImage';
  8. import { useGalleryItem } from '../../talons/Gallery/useGalleryItem';
  9. import resourceUrl from '@magento/peregrine/lib/util/makeUrl';
  10. import VideoCallButton from './videoCallButton';
  11. import { useStyle } from '@magento/venia-ui/lib/classify';
  12. import Image from '@magento/venia-ui/lib/components/Image';
  13. import GalleryItemShimmer from '@magento/venia-ui/lib/components/Gallery/item.shimmer';
  14. import defaultClasses from './item.module.css';
  15. import WishlistGalleryButton from './addToListButton.ce.js';
  16. import Rating from '@magento/venia-ui/lib/components/Rating';
  17. import './item.module.css';
  18. import ProductTags from '../Common/productTags';
  19. import { useWindowSize } from '@magento/peregrine';
  20. import { useQuery, gql } from '@apollo/client';
  21. import Button from '@magento/venia-ui/lib/components/Button';
  22. import { BrowserPersistence } from '@magento/peregrine/lib/util';
  23. import { useSelector, useDispatch } from 'react-redux';
  24. import apiClient from '../../api';
  25.  
  26. // The placeholder image is 4:5, so we should make sure to size our product
  27. // images appropriately.
  28. const IMAGE_WIDTH = '100%';
  29. const IMAGE_HEIGHT = 375;
  30.  
  31. const storage = new BrowserPersistence();
  32.  
  33. // Gallery switches from two columns to three at 640px.
  34. const IMAGE_WIDTHS = new Map()
  35. .set(640, IMAGE_WIDTH)
  36. .set(UNCONSTRAINED_SIZE_KEY, 840);
  37.  
  38. const GET_PRODUCT_CUSTOM_ATTRIBUTES = gql`
  39. query getProducts($key: String!) {
  40. products(filter: { sku: { in: [$key] } }) {
  41. items {
  42. sku
  43. uid
  44. id
  45. categories {
  46. uid
  47. name
  48. is_anchor
  49. url_key
  50. url_path
  51. level
  52. display_mode
  53. default_sort_by
  54. description
  55. }
  56. ... on CustomizableProductInterface {
  57. options {
  58. title
  59. required
  60. sort_order
  61. option_id
  62. ... on CustomizableDropDownOption {
  63. value {
  64. option_type_id
  65. price
  66. price_type
  67. sku
  68. sort_order
  69. title
  70. }
  71. }
  72. }
  73. }
  74. custom_attributes {
  75. attribute_metadata {
  76. code
  77. }
  78. selected_attribute_options {
  79. attribute_option {
  80. label
  81. }
  82. }
  83. }
  84. }
  85. }
  86. }
  87. `;
  88.  
  89. const GalleryItem = props => {
  90. const [isItemAvailableInStore, setIsItemAvailableInStore] = useState(false);
  91.  
  92. const {
  93. handleLinkClick,
  94. item,
  95. itemRef,
  96. wishlistButtonProps,
  97. isSupportedProductType
  98. } = useGalleryItem(props);
  99.  
  100. const { storeConfig } = props;
  101.  
  102. const productUrlSuffix = storeConfig && storeConfig.product_url_suffix;
  103.  
  104. const classes = useStyle(defaultClasses, props.classes);
  105.  
  106. const customData = useSelector(state => state.custom);
  107. const { storeUserInfo } = customData;
  108.  
  109. const { isStorefrontUser: isStoreUser, outlet } = storeUserInfo;
  110.  
  111. useEffect(() => {
  112. if (outlet?.outletFilterId && item?.is_outlet_available) {
  113. if (outlet.outletFilterId == item.is_outlet_available) {
  114. setIsItemAvailableInStore(true);
  115. }
  116. }
  117. }, []);
  118.  
  119. const windowSize = useWindowSize();
  120. const isMobile = windowSize.innerWidth <= 840 ? true : false;
  121. const isTab =
  122. windowSize.innerWidth >= 841 && windowSize.innerWidth <= 1040
  123. ? true
  124. : false;
  125. const isLap =
  126. windowSize.innerWidth >= 1041 && windowSize.innerWidth <= 1240
  127. ? true
  128. : false;
  129.  
  130. const titleTextSize = isMobile
  131. ? 'text-[12px]'
  132. : isTab
  133. ? 'text-[14px]'
  134. : isLap
  135. ? 'text-[16px]'
  136. : '';
  137.  
  138. if (!item) {
  139. return <GalleryItemShimmer classes={classes} />;
  140. }
  141.  
  142. // eslint-disable-next-line no-unused-vars
  143. const { name, price_range, small_image, url_key, rating_summary } = item;
  144.  
  145. const { url } = small_image;
  146.  
  147. const [image, setImage] = useState(url ? url : '');
  148.  
  149. const [hoverImage, setProductGallery] = useState(null);
  150. const [fireWishListEvent,setFireWishListEvent] = useState(false);
  151.  
  152. const productLink = resourceUrl(`/${url_key}${productUrlSuffix || ''}`);
  153.  
  154. const productEnquiry = 'I want to enquire about ' + name + '\n\n' + url_key;
  155. const productEnquiryLink = 'https://wa.me/919943212511?text='+ encodeURIComponent(productEnquiry);
  156.  
  157. const wishlistButton = wishlistButtonProps ? (
  158. <WishlistGalleryButton
  159. fireWishListEvent={fireWishListEvent}
  160. setFireWishListEvent={setFireWishListEvent}
  161. {...wishlistButtonProps}
  162. />
  163. ) : null;
  164.  
  165. const { error, loading, data } = useQuery(GET_PRODUCT_CUSTOM_ATTRIBUTES, {
  166. fetchPolicy: 'cache-and-network',
  167. nextFetchPolicy: 'cache-first',
  168. skip: !item.sku,
  169. variables: {
  170. key: item.sku
  171. }
  172. });
  173.  
  174. const customAttributes = data?.products?.items[0]?.custom_attributes;
  175.  
  176. const customOptions = data?.products?.items[0]?.options?.filter(
  177. i => i.required
  178. );
  179.  
  180. var isVirtualTryOn = false;
  181.  
  182. if (Array.isArray(customAttributes)) {
  183. customAttributes.filter(customAttribute => {
  184. if (
  185. customAttribute.attribute_metadata.code === 'is_virtual_try_on'
  186. ) {
  187. if (
  188. customAttribute?.selected_attribute_options
  189. ?.attribute_option[0]?.label == 'Yes'
  190. ) {
  191. isVirtualTryOn = true;
  192. }
  193. }
  194. });
  195. }
  196.  
  197. const addButton =
  198. customOptions && customOptions.length > 0 ? (
  199. <a
  200.  
  201. id="productFullDetail.addItemToCart1"
  202. target={'_blank'}
  203. class="w-full text-xs tracking-[2.4px] h-[38px] text-[0.7rem]"
  204. >
  205. <button
  206.  
  207. class="tryVirtualButton-root-aqT bg-[#F8F3EC] border-2 border-[#EFEAE2] p-2 w-full rounded-sm h-[38px] product_button"
  208. type="button"
  209. >
  210. <span class="button-content-TD8 gap-1.5 grid-flow-col inline-grid items-center justify-center justify-items-center">
  211. <span class="text-[#181A1D] tracking-widest font-semibold">
  212. {isStoreUser ? 'SELECT' : 'BUY NOW'}
  213. </span>
  214. </span>
  215. </button>
  216. </a>
  217. ) : isSupportedProductType ? (
  218. <div class="w-full text-xs tracking-[2.4px] h-[38px] text-[0.7rem]">
  219. <VideoCallButton
  220. item={item}
  221. urlSuffix={productUrlSuffix}
  222. isStoreUser={isStoreUser}
  223. />
  224. </div>
  225. ) : (
  226. <div className={classes.unavailableContainer}>
  227. <Info />
  228. <p>
  229. <FormattedMessage
  230. id={'galleryItem.unavailableProduct'}
  231. defaultMessage={
  232. isStoreUser
  233. ? 'Currently unavailable to select'
  234. : 'Currently unavailable for purchase.'
  235. }
  236. />
  237. </p>
  238. </div>
  239. );
  240.  
  241. const viewDetails = (
  242. <Link
  243. to={productLink}
  244. target="_blank"
  245. class="w-full text-xs tracking-[2.4px] h-[38px] text-[0.7rem]"
  246. >
  247. <button
  248. class="tryVirtualButton-root-aqT bg-[#F8F3EC] border-2 border-[#EFEAE2] p-2 w-full rounded-sm h-[38px] product_button"
  249. type="button"
  250. >
  251. <span class="button-content-TD8 gap-1.5 grid-flow-col inline-grid items-center justify-center justify-items-center">
  252. <span class="text-[#181A1D] tracking-widest font-semibold">
  253. VIEW DETAILS4
  254. </span>
  255. </span>
  256. </button>
  257. </Link>
  258. );
  259.  
  260. // fallback to regular price when final price is unavailable
  261. const priceSource = price_range.maximum_price.final_price;
  262.  
  263. const regurlarPrice = price_range.maximum_price.regular_price;
  264.  
  265.  
  266. // Hide the Rating component until it is updated with the new look and feel (PWA-2512).
  267. // const ratingAverage = null;
  268. const ratingAverage = rating_summary ? (
  269. <Rating rating={rating_summary} />
  270. ) : null;
  271.  
  272. const virtualTryOn = isVirtualTryOn ? (
  273. <Button
  274. className={
  275. 'tracking-[1.2px] uppercase text-[10px] bg-[#774E4F] rounded-sm focus:outline-none flex justify-center items-center px-[5px] h-[25px] virtual'
  276. }
  277. onClick={() => {
  278. let script = document.createElement('script');
  279. script.onload = () => {
  280. let options = {
  281. brandId: '42241de3-5614-4e87-8e63-89103d6ea5d7'
  282. };
  283. initMirrarUI(item.sku, options);
  284. };
  285. script.src =
  286. 'https://cdn.mirrar.com/general/scripts/mirrar-ui.js';
  287. document.body.append(script);
  288. }}
  289. >
  290. <span className="text-[#FFF] text-[10px] uppercase tracking-[1.2px]">
  291. <FormattedMessage
  292. id="addToCartButton.tryBefore"
  293. defaultMessage="VIRTUAL TRY ON"
  294. />
  295. </span>
  296. </Button>
  297. ) : <div className='h-[25px]'></div>;
  298.  
  299. const itemAvailable = isItemAvailableInStore ? (
  300. <div className="flex bg-green-200 h-5 mt-2 text-xs">
  301. <p className="w-full text-center font-semibold tracking-widest m-auto">
  302. Available In Store
  303. </p>
  304. </div>
  305. ) : (
  306. <div className="flex bg-red-200 h-5 mt-2 text-xs">
  307. <p className="w-full text-center font-semibold tracking-widest m-auto">
  308. Not available at this Store
  309. </p>
  310. </div>
  311. );
  312.  
  313. return (
  314. <div
  315. data-cy="GalleryItem-root"
  316. className={classes.itemCard + ' bg-[#FFF] rounded-[10px]'}
  317. aria-live="polite"
  318. aria-busy="false"
  319. ref={itemRef}
  320. >
  321. <input type="hidden" name="productid" value={data?.products?.items[0]?.id} />
  322. <ProductTags
  323. product={item}
  324. page={'PLP'}
  325. setProductGallery={setProductGallery}
  326. />
  327.  
  328. <div className="absolute top-0 right-0 z-[9]" >{wishlistButton}</div>
  329. <Link
  330. onClick={handleLinkClick}
  331. to={productLink}
  332. className={classes.images}
  333. target="_blank"
  334. >
  335. {image ? (
  336. <Image
  337. onMouseEnter={() =>
  338. hoverImage && hoverImage.url
  339. ? setImage(hoverImage.url)
  340. : null
  341. }
  342. onMouseLeave={() => setImage(url)}
  343. style={{ backgroundColor: 'white', marginTop: 5 }}
  344. alt={name}
  345. classes={{
  346. image: classes.image,
  347. loaded: classes.imageLoaded,
  348. notLoaded: classes.imageNotLoaded,
  349. root: classes.imageContainer
  350. }}
  351. height={IMAGE_HEIGHT}
  352. resource={image}
  353. widths={IMAGE_WIDTHS}
  354. />
  355. ) : null}
  356. </Link>
  357. <div className="p-2">
  358. <div className="flex justify-between items-center mprice">
  359. <div data-cy="GalleryItem-price" className={classes.price + " !font-bold"}>
  360. <Price
  361. value={priceSource.value}
  362. currencyCode={priceSource.currency}
  363. />
  364. {regurlarPrice.value !== priceSource.value ?
  365. <s
  366. data-cy="ProductFullDetail-productPrice"
  367. className={
  368. classes.productPrice +
  369. ' text-[16px] py-1 ml-1 text-[#35383A] font-bold'
  370. }
  371. >
  372. <Price
  373. value={regurlarPrice.value}
  374. currencyCode={regurlarPrice.currency}
  375. />
  376. </s> : null}
  377.  
  378. </div>
  379. {virtualTryOn}
  380. {ratingAverage}
  381. </div>
  382. <Link
  383. onClick={handleLinkClick}
  384. to={productLink}
  385. className={classes.name + ' mt-[10px] pb-[5px]'}
  386. data-cy="GalleryItem-name"
  387. style={{ width: '100%', display: 'inline-block' }}
  388. >
  389. {isMobile ? (
  390. <span className="text-[12px]">
  391. {name && name.substring(0, 25)}
  392. {name && name.length > 25 && '...'}
  393. </span>
  394. ) : (
  395. <span className={titleTextSize}>
  396. {name &&
  397. name.substring(0, windowSize.innerWidth / 35)}
  398. {name &&
  399. name.length > windowSize.innerWidth / 35 &&
  400. '...'}
  401. </span>
  402. )}
  403. {/* {isMobile ? (
  404. <span className='text-[14px]'>
  405. {name && name.substring(0, 20)}
  406. {name && name.length > 20 && '...'}
  407. </span>
  408. ) : isTab ? (
  409. <span className='text-[14px]'>
  410. {name && name.substring(0, 20)}
  411. {name && name.length > 20 && '...'}
  412. </span>
  413. ) : isLap ? (
  414. <span className='text-[16px]'>
  415. {name && name.substring(0, 30)}
  416. {name && name.length > 30 && '...'}
  417. </span>
  418. )
  419. : (
  420. <span>
  421. {name && name.substring(0, 35)}
  422. {name && name.length > 35 && '...'}
  423. </span>
  424. )} */}
  425. </Link>
  426. <div class="flex pt-4 flex-col gap-x-2.5 gap-y-1.5 lg_flex-row">
  427. {viewDetails}
  428. {addButton}
  429. </div>
  430. {isStoreUser ? itemAvailable : null}
  431. </div>
  432. </div>
  433. );
  434. };
  435.  
  436. GalleryItem.propTypes = {
  437. classes: shape({
  438. image: string,
  439. imageLoaded: string,
  440. imageNotLoaded: string,
  441. imageContainer: string,
  442. images: string,
  443. name: string,
  444. price: string,
  445. root: string
  446. }),
  447. item: shape({
  448. id: number.isRequired,
  449. uid: string.isRequired,
  450. name: string.isRequired,
  451. small_image: shape({
  452. url: string.isRequired
  453. }),
  454. stock_status: string.isRequired,
  455. __typename: string.isRequired,
  456. url_key: string.isRequired,
  457. sku: string.isRequired,
  458. price_range: shape({
  459. maximum_price: shape({
  460. final_price: shape({
  461. value: number.isRequired,
  462. currency: string.isRequired
  463. }),
  464. regular_price: shape({
  465. value: number.isRequired,
  466. currency: string.isRequired
  467. }).isRequired,
  468. discount: shape({
  469. amount_off: number.isRequired
  470. }).isRequired
  471. }).isRequired
  472. }).isRequired
  473. }),
  474. storeConfig: shape({
  475. magento_wishlist_general_is_enabled: string.isRequired,
  476. product_url_suffix: string
  477. })
  478. };
  479.  
  480. export default GalleryItem;
  481.  
Advertisement
Add Comment
Please, Sign In to add comment