Amber Shopify Project created using ReactJS+React-Redux with GraphQL API integration. Storefront Shopify API: https://github.com/Shopify/shopify-app-js/tree/main/packages/api-clients/storefront-api-client#readme
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

ProductSuggestion.jsx 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. import { useState, useEffect } from 'react';
  2. import { Box, Typography, Button } from '@mui/material';
  3. import { useSelector } from 'react-redux';
  4. import Grid from '@mui/material/Grid2';
  5. import { useNavigate } from "react-router-dom";
  6. import defaultImage from "../../assets/images/default.png"
  7. import { isProductInVisibleMenu } from '../../config/menuCollections';
  8. // const allowedSuggestionCollections = getMenuCollectionTitlesByProductType();
  9. // const isProductAllowedInSuggestion = (product) => { ... };
  10. const ProductSuggestion = () => {
  11. const [suggestProducts, setSuggestProducts] = useState([]);
  12. const products = useSelector((state) => state.products.products.data);
  13. const navigate = useNavigate();
  14. useEffect(() => {
  15. if (products.length > 0) {
  16. const getRandomProducts = (arr, num) => {
  17. const shuffled = [...arr].sort(() => 0.5 - Math.random());
  18. return shuffled.slice(0, num);
  19. };
  20. const visibleProducts = products.filter((product) => isProductInVisibleMenu(product, products));
  21. // const randomProducts = getRandomProducts(products, 4);
  22. const randomProducts = getRandomProducts(visibleProducts, 4); // Select 4 random visible products
  23. setSuggestProducts(randomProducts);
  24. }
  25. }, [products]);
  26. const renderProduct = (
  27. handle,
  28. img_url,
  29. title,
  30. collection_name,
  31. minPrice,
  32. minPriceCurrency,
  33. maxPrice,
  34. maxPriceCurrency,
  35. minDiscountPrice,
  36. minDiscountPriceCurrency,
  37. maxDiscountPrice,
  38. maxDiscountPriceCurrency,
  39. extra_desc,
  40. selected = false
  41. ) => {
  42. return (
  43. <Grid
  44. className="animate__animated animate__fadeIn"
  45. item
  46. size={{ xs: 6, sm: 6, md: 3 }}
  47. >
  48. <a href={`/products/${handle}`} style={{ textDecoration: "none", color: "#000" }}>
  49. <Box
  50. sx={{
  51. overflow: "hidden",
  52. position: "relative",
  53. cursor: "pointer",
  54. }}
  55. onClick={() => {
  56. navigate(`/products/${handle}`)
  57. }}
  58. >
  59. <img
  60. src={img_url}
  61. alt={title}
  62. style={{
  63. width: "100%",
  64. aspectRatio: "3 / 4",
  65. objectFit: "cover",
  66. objectPosition: "top center",
  67. }}
  68. />
  69. {selected && (
  70. <Button
  71. sx={{
  72. position: "absolute",
  73. top: {
  74. xs: 0,
  75. sm: 0,
  76. md: 10,
  77. lg: 20,
  78. },
  79. left: {
  80. xs: 0,
  81. sm: 0,
  82. md: 10,
  83. lg: 20,
  84. },
  85. boxShadow: 0,
  86. fontSize: 10,
  87. }}
  88. variant="contained"
  89. >
  90. NEW
  91. </Button>
  92. )}
  93. <Box sx={{ pb: 3, pt: 1, width: "90%" }}>
  94. <Typography
  95. variant="body2"
  96. sx={{
  97. fontWeight: "100",
  98. fontSize: {
  99. xs: "0.65rem",
  100. sm: "0.65rem",
  101. md: "0.75rem",
  102. },
  103. }}
  104. >
  105. {collection_name}
  106. </Typography>
  107. <Typography
  108. variant="body2"
  109. sx={{
  110. fontWeight: "400",
  111. fontSize: {
  112. xs: "0.73rem",
  113. sm: "0.73rem",
  114. md: "0.875rem",
  115. },
  116. }}
  117. >
  118. {title}
  119. </Typography>
  120. <Typography
  121. variant="body2"
  122. sx={{
  123. fontWeight: "100",
  124. fontSize: {
  125. xs: "0.73rem",
  126. sm: "0.73rem",
  127. md: "0.875rem",
  128. },
  129. textDecoration: (minDiscountPrice > 0) ? "line-through" : "none"
  130. }}
  131. >
  132. {`${minPriceCurrency} ${parseFloat(minPrice).toFixed(2)}`}
  133. </Typography>
  134. {(minDiscountPrice > 0) && <Typography
  135. variant="body2"
  136. sx={{
  137. fontWeight: "100",
  138. fontSize: {
  139. xs: "0.73rem",
  140. sm: "0.73rem",
  141. md: "0.875rem",
  142. },
  143. }}
  144. >
  145. {`${minDiscountPriceCurrency} ${parseFloat(minDiscountPrice).toFixed(2)}`}
  146. </Typography>}
  147. </Box>
  148. </Box>
  149. </a>
  150. </Grid>
  151. );
  152. };
  153. return (
  154. <Box sx={{ mb: 5 }}>
  155. <Grid container spacing={1} columns={12}>
  156. {suggestProducts.map((product, index) => {
  157. let {
  158. handle,
  159. title,
  160. images,
  161. collections,
  162. minVariantPrice,
  163. maxVariantPrice,
  164. compareAtPriceRangeMinVariantPrice,
  165. compareAtPriceRangeMaxVariantPrice,
  166. // productType and variants are not needed here because filtering already happens before rendering.
  167. // productType,
  168. // variants,
  169. selected,
  170. } = product;
  171. let minPrice = minVariantPrice.amount;
  172. let minPriceCurrency = minVariantPrice.currencyCode;
  173. let maxPrice = maxVariantPrice.amount;
  174. let maxPriceCurrency = maxVariantPrice.currencyCode;
  175. // SHOULD BE THE DISCOUNTED PRICE
  176. let minDiscountPrice = compareAtPriceRangeMinVariantPrice.amount;
  177. let minDiscountPriceCurrency = compareAtPriceRangeMinVariantPrice.currencyCode;
  178. let maxDiscountPrice = compareAtPriceRangeMaxVariantPrice.amount;
  179. let maxDiscountPriceCurrency = compareAtPriceRangeMaxVariantPrice.currencyCode;
  180. let img_url = images[0]?.url || defaultImage
  181. let collection_name = collections[0]?.title;
  182. return renderProduct(
  183. handle,
  184. img_url,
  185. title,
  186. collection_name,
  187. minPrice,
  188. minPriceCurrency,
  189. maxPrice,
  190. maxPriceCurrency,
  191. minDiscountPrice,
  192. minDiscountPriceCurrency,
  193. maxDiscountPrice,
  194. maxDiscountPriceCurrency,
  195. "",
  196. selected
  197. );
  198. })}
  199. </Grid>
  200. </Box>
  201. );
  202. };
  203. export default ProductSuggestion;