memo and lazy load
This commit is contained in:
parent
36c2dd98a2
commit
bd6c90ab9d
5 changed files with 268 additions and 206 deletions
|
|
@ -1,184 +1,236 @@
|
||||||
project/
|
/ (root)
|
||||||
├── frontend/
|
├── .env
|
||||||
│ ├── node_modules/
|
├── .gitignore
|
||||||
│ ├── src/
|
├── Dockerfile
|
||||||
│ │ ├── pages/
|
├── README.md
|
||||||
│ │ │ ├── Admin/
|
├── config.js
|
||||||
│ │ │ │ ├── BrandingPage.jsx
|
├── docker-compose.yml
|
||||||
│ │ │ │ ├── ReportsPage.jsx
|
├── fileStructure.txt
|
||||||
│ │ │ │ ├── ProductEditPage.jsx
|
├── index.html
|
||||||
│ │ │ │ ├── OrdersPage.jsx
|
├── main.jsx
|
||||||
│ │ │ │ ├── EmailTemplatesPage.jsx
|
├── nginx.conf
|
||||||
│ │ │ │ ├── SettingsPage.jsx
|
├── package.json
|
||||||
│ │ │ │ ├── BlogEditPage.jsx
|
├── setup-frontend.sh
|
||||||
│ │ │ │ ├── CategoriesPage.jsx
|
├── start.sh
|
||||||
│ │ │ │ ├── CustomersPage.jsx
|
├── vite.config.js
|
||||||
│ │ │ │ ├── CouponsPage.jsx
|
│
|
||||||
│ │ │ │ ├── ProductReviewsPage.jsx
|
|
||||||
│ │ │ │ ├── BlogPage.jsx
|
|
||||||
│ │ │ │ ├── BlogCommentsPage.jsx
|
|
||||||
│ │ │ │ ├── DashboardPage.jsx
|
|
||||||
│ │ │ │ └── ProductsPage.jsx
|
|
||||||
│ │ │ ├── CheckoutPage.jsx
|
|
||||||
│ │ │ ├── CouponEditPage.jsx
|
|
||||||
│ │ │ ├── ProductsPage.jsx
|
|
||||||
│ │ │ ├── UserOrdersPage.jsx
|
|
||||||
│ │ │ ├── CartPage.jsx
|
|
||||||
│ │ │ ├── ProductDetailPage.jsx
|
|
||||||
│ │ │ ├── BlogDetailPage.jsx
|
|
||||||
│ │ │ ├── BlogPage.jsx
|
|
||||||
│ │ │ ├── CouponRedemptionsPage.jsx
|
|
||||||
│ │ │ ├── HomePage.jsx
|
|
||||||
│ │ │ ├── LoginPage.jsx
|
|
||||||
│ │ │ ├── PaymentSuccessPage.jsx
|
|
||||||
│ │ │ ├── RegisterPage.jsx
|
|
||||||
│ │ │ ├── VerifyPage.jsx
|
|
||||||
│ │ │ ├── NotFoundPage.jsx
|
|
||||||
│ │ │ └── PaymentCancelPage.jsx
|
|
||||||
│ │ ├── services/
|
|
||||||
│ │ │ ├── emailTemplateService.js
|
|
||||||
│ │ │ ├── blogAdminService.js
|
|
||||||
│ │ │ ├── adminService.js
|
|
||||||
│ │ │ ├── couponService.js
|
|
||||||
│ │ │ ├── productService.js
|
|
||||||
│ │ │ ├── productReviewService.js
|
|
||||||
│ │ │ ├── consentService.js (NEW)
|
|
||||||
│ │ │ ├── settingsAdminService.js
|
|
||||||
│ │ │ ├── imageService.js
|
|
||||||
│ │ │ ├── cartService.js
|
|
||||||
│ │ │ ├── categoryAdminService.js
|
|
||||||
│ │ │ ├── authService.js
|
|
||||||
│ │ │ ├── blogService.js
|
|
||||||
│ │ │ └── api.js
|
|
||||||
│ │ ├── components/
|
|
||||||
│ │ │ ├── ProductReviews.jsx
|
|
||||||
│ │ │ ├── OrderStatusDialog.jsx
|
|
||||||
│ │ │ ├── ImageUploader.jsx
|
|
||||||
│ │ │ ├── CookieConsentPopup.jsx
|
|
||||||
│ │ │ ├── CookieSettingsButton.jsx
|
|
||||||
│ │ │ ├── Footer.jsx
|
|
||||||
│ │ │ ├── CouponInput.jsx
|
|
||||||
│ │ │ ├── EmailDialog.jsx
|
|
||||||
│ │ │ ├── StripePaymentForm.jsx
|
|
||||||
│ │ │ ├── ProductImage.jsx
|
|
||||||
│ │ │ ├── ProtectedRoute.jsx
|
|
||||||
│ │ │ ├── Notifications.jsx
|
|
||||||
│ │ │ └── ProductRatingDisplay.jsx
|
|
||||||
│ │ ├── hooks/
|
|
||||||
│ │ │ ├── apiHooks.js
|
|
||||||
│ │ │ ├── blogHooks.js
|
|
||||||
│ │ │ ├── emailTemplateHooks.js
|
|
||||||
│ │ │ ├── adminHooks.js
|
|
||||||
│ │ │ ├── productReviewHooks.js
|
|
||||||
│ │ │ ├── reduxHooks.js
|
|
||||||
│ │ │ ├── couponAdminHooks.js
|
|
||||||
│ │ │ ├── settingsAdminHooks.js
|
|
||||||
│ │ │ ├── categoryAdminHooks.js
|
|
||||||
│ │ │ └── brandingHooks.js
|
|
||||||
│ │ ├── layouts/
|
|
||||||
│ │ │ ├── MainLayout.jsx
|
|
||||||
│ │ │ ├── AdminLayout.jsx
|
|
||||||
│ │ │ └── AuthLayout.jsx
|
|
||||||
│ │ ├── features/
|
|
||||||
│ │ │ ├── ui/
|
|
||||||
│ │ │ │ └── uiSlice.js
|
|
||||||
│ │ │ ├── cart/
|
|
||||||
│ │ │ │ └── cartSlice.js
|
|
||||||
│ │ │ ├── auth/
|
|
||||||
│ │ │ │ └── authSlice.js
|
|
||||||
│ │ │ └── theme/
|
|
||||||
│ │ │ ├── ThemeProvider.jsx
|
|
||||||
│ │ │ └── index.js
|
|
||||||
│ │ ├── utils/
|
|
||||||
│ │ │ └── imageUtils.js
|
|
||||||
│ │ ├── store/
|
|
||||||
│ │ │ └── index.js
|
|
||||||
│ │ ├── context/
|
|
||||||
│ │ │ └── StripeContext.jsx
|
|
||||||
│ │ └── assets/
|
|
||||||
│ │ ├── App.jsx
|
|
||||||
│ │ ├── main.jsx
|
|
||||||
│ │ └── config.js
|
|
||||||
│ └── public/
|
|
||||||
│ ├── favicon.svg
|
|
||||||
│ ├── vite.config.js
|
|
||||||
│ ├── README.md
|
|
||||||
│ ├── Dockerfile
|
|
||||||
│ ├── nginx.conf
|
|
||||||
│ ├── setup-frontend.sh
|
|
||||||
│ ├── index.html
|
|
||||||
│ └── .env
|
|
||||||
├── backend/
|
├── backend/
|
||||||
│ ├── node_modules/
|
│ ├── node_modules/
|
||||||
│ ├── src/
|
│ ├── public/
|
||||||
│ │ ├── routes/
|
│ │ ├── seo-files/
|
||||||
│ │ │ ├── cart.js
|
│ │ ├── uploads/
|
||||||
│ │ │ ├── couponAdmin.js
|
│ │ ├── robots.txt
|
||||||
│ │ │ ├── emailTemplatesAdmin.js
|
│ │ └── sitemap.xml
|
||||||
│ │ │ ├── productAdmin.js
|
│ │
|
||||||
│ │ │ ├── blogAdmin.js
|
│ └── src/
|
||||||
│ │ │ ├── orderAdmin.js
|
│ ├── db/
|
||||||
│ │ │ ├── settingsAdmin.js
|
│ │ └── index.js
|
||||||
│ │ │ ├── blog.js
|
│ │
|
||||||
│ │ │ ├── auth.js
|
│ ├── middleware/
|
||||||
│ │ │ ├── productReviews.js
|
│ │ ├── adminAuth.js
|
||||||
│ │ │ ├── stripePayment.js
|
│ │ ├── auth.js
|
||||||
│ │ │ ├── products.js
|
│ │ ├── seoMiddleware.js
|
||||||
│ │ │ ├── productReviewsAdmin.js
|
│ │ └── upload.js
|
||||||
│ │ │ ├── blogCommentsAdmin.js
|
│ │
|
||||||
│ │ │ ├── userAdmin.js
|
│ ├── models/
|
||||||
│ │ │ ├── categoryAdmin.js
|
│ │ └── SystemSettings.js
|
||||||
│ │ │ ├── shipping.js
|
│ │
|
||||||
│ │ │ ├── images.js
|
│ ├── routes/
|
||||||
│ │ │ ├── userOrders.js
|
│ │ ├── auth.js
|
||||||
│ │ │ ├── publicSettings.js
|
│ │ ├── blog.js
|
||||||
│ │ │ └── productAdminImages.js
|
│ │ ├── blogAdmin.js
|
||||||
│ │ ├── middleware/
|
│ │ ├── blogCommentsAdmin.js
|
||||||
│ │ │ ├── upload.js
|
│ │ ├── cart.js
|
||||||
│ │ │ ├── adminAuth.js
|
│ │ ├── categoryAdmin.js
|
||||||
│ │ │ └── auth.js
|
│ │ ├── couponAdmin.js
|
||||||
│ │ ├── services/
|
│ │ ├── emailCampaignsAdmin.js
|
||||||
│ │ │ ├── shippingService.js
|
│ │ ├── emailTemplatesAdmin.js
|
||||||
│ │ │ ├── emailService.js
|
│ │ ├── emailTracking.js
|
||||||
│ │ │ └── notificationService.js
|
│ │ ├── images.js
|
||||||
│ │ ├── models/
|
│ │ ├── mailingListAdmin.js
|
||||||
│ │ │ └── SystemSettings.js
|
│ │ ├── orderAdmin.js
|
||||||
│ │ └── db/
|
│ │ ├── productAdmin.js
|
||||||
│ │ ├── index.js
|
│ │ ├── productAdminImages.js
|
||||||
│ │ ├── index.js
|
│ │ ├── productReviews.js
|
||||||
│ │ └── config.js
|
│ │ ├── productReviewsAdmin.js
|
||||||
│ └── public/
|
│ │ ├── products.js
|
||||||
│ ├── uploads/
|
│ │ ├── publicSettings.js
|
||||||
│ │ ├── products/
|
│ │ ├── settingsAdmin.js
|
||||||
│ │ └── blog/
|
│ │ ├── shipping.js
|
||||||
│ ├── package-lock.json
|
│ │ ├── stripePayment.js
|
||||||
│ ├── README.md
|
│ │ ├── subscribers.js
|
||||||
│ ├── .env
|
│ │ ├── subscribersAdmin.js
|
||||||
│ ├── package.json
|
│ │ ├── userAdmin.js
|
||||||
│ ├── Dockerfile
|
│ │ └── userOrders.js
|
||||||
│ └── .gitignore
|
│ │
|
||||||
└── db/
|
│ ├── services/
|
||||||
├── init/
|
│ │ ├── cacheService.js
|
||||||
│ ├── 18-email-templates.sql
|
│ │ ├── emailService.js
|
||||||
│ ├── 01-schema.sql
|
│ │ ├── notificationService.js
|
||||||
│ ├── 02-seed.sql
|
│ │ ├── queueService.js
|
||||||
│ ├── 16-blog-schema.sql
|
│ │ ├── shippingService.js
|
||||||
│ ├── 15-coupon.sql
|
│ │ ├── sitemapService.js
|
||||||
│ ├── 17-product-reviews.sql
|
│ │ └── storageService.js
|
||||||
│ ├── 19-branding-settings.sql (NEW)
|
│ │
|
||||||
│ ├── 04-product-images.sql
|
│ └── uploads/
|
||||||
│ ├── 09-system-settings.sql
|
│ ├── temp/
|
||||||
│ ├── 14-product-notifications.sql
|
│ ├── config.js
|
||||||
│ ├── 10-payment.sql
|
│ ├── index.js
|
||||||
│ ├── 11-notifications.sql
|
│ └── worker.js
|
||||||
│ ├── 12-shipping-orders.sql
|
│
|
||||||
│ ├── 08-create-email.sql
|
├── db/
|
||||||
│ ├── 05-admin-role.sql
|
│ ├── init/
|
||||||
│ ├── 03-api-key.sql
|
│ │ ├── 01-schema.sql
|
||||||
│ ├── 07-user-keys.sql
|
│ │ ├── 02-seed.sql
|
||||||
│ ├── 13-cart-metadata.sql
|
│ │ ├── 03-api-key.sql
|
||||||
│ └── 06-product-categories.sql
|
│ │ ├── 04-product-images.sql
|
||||||
└── test/
|
│ │ ├── 05-admin-role.sql
|
||||||
├── fileStructure.txt
|
│ │ ├── 06-product-categories.sql
|
||||||
├── docker-compose.yml
|
│ │ ├── 07-user-keys.sql
|
||||||
└── .gitignore
|
│ │ ├── 08-create-email.sql
|
||||||
|
│ │ ├── 09-system-settings.sql
|
||||||
|
│ │ ├── 10-payment.sql
|
||||||
|
│ │ ├── 11-notifications.sql
|
||||||
|
│ │ ├── 12-shipping-orders.sql
|
||||||
|
│ │ ├── 13-cart-metadata.sql
|
||||||
|
│ │ ├── 14-product-notifications.sql
|
||||||
|
│ │ ├── 15-coupon.sql
|
||||||
|
│ │ ├── 16-blog-schema.sql
|
||||||
|
│ │ ├── 17-product-reviews.sql
|
||||||
|
│ │ ├── 18-email-templates.sql
|
||||||
|
│ │ ├── 19-branding-settings.sql
|
||||||
|
│ │ ├── 20-mailinglist.sql
|
||||||
|
│ │ ├── 21-order-refund.sql
|
||||||
|
│ │ └── 22-blog-json.sql
|
||||||
|
│ │
|
||||||
|
│ └── test/
|
||||||
|
│
|
||||||
|
└── frontend/
|
||||||
|
├── node_modules/
|
||||||
|
├── public/
|
||||||
|
│ ├── seo-files/
|
||||||
|
│ └── favicon.svg
|
||||||
|
│
|
||||||
|
└── src/
|
||||||
|
├── assets/
|
||||||
|
├── components/
|
||||||
|
│ ├── CookieConsentPopup.jsx
|
||||||
|
│ ├── CookieSettingsButton.jsx
|
||||||
|
│ ├── CouponInput.jsx
|
||||||
|
│ ├── EmailDialog.jsx
|
||||||
|
│ ├── Footer.jsx
|
||||||
|
│ ├── ImageUploader.jsx
|
||||||
|
│ ├── Notifications.jsx
|
||||||
|
│ ├── OrderStatusDialog.jsx
|
||||||
|
│ ├── ProductImage.jsx
|
||||||
|
│ ├── ProductRatingDisplay.jsx
|
||||||
|
│ ├── ProductReviews.jsx
|
||||||
|
│ ├── ProtectedRoute.jsx
|
||||||
|
│ ├── SEOMetaTags.jsx
|
||||||
|
│ ├── StripePaymentForm.jsx
|
||||||
|
│ └── SubscriptionForm.jsx
|
||||||
|
│
|
||||||
|
├── context/
|
||||||
|
│ └── StripeContext.jsx
|
||||||
|
│
|
||||||
|
├── features/
|
||||||
|
│ ├── auth/
|
||||||
|
│ │ └── authSlice.js
|
||||||
|
│ ├── cart/
|
||||||
|
│ │ └── cartSlice.js
|
||||||
|
│ └── ui/
|
||||||
|
│ └── uiSlice.js
|
||||||
|
│
|
||||||
|
├── hooks/
|
||||||
|
│ ├── adminHooks.js
|
||||||
|
│ ├── apiHooks.js
|
||||||
|
│ ├── blogHooks.js
|
||||||
|
│ ├── brandingHooks.js
|
||||||
|
│ ├── categoryAdminHooks.js
|
||||||
|
│ ├── couponAdminHooks.js
|
||||||
|
│ ├── emailCampaignHooks.js
|
||||||
|
│ ├── emailTemplateHooks.js
|
||||||
|
│ ├── productAdminHooks.js
|
||||||
|
│ ├── productReviewHooks.js
|
||||||
|
│ ├── reduxHooks.js
|
||||||
|
│ ├── settingsAdminHooks.js
|
||||||
|
│ ├── useProductSeo.js
|
||||||
|
│ ├── useSeoMeta.js
|
||||||
|
│ └── useSeoUrl.js
|
||||||
|
│
|
||||||
|
├── layouts/
|
||||||
|
│ ├── AdminLayout.jsx
|
||||||
|
│ ├── AuthLayout.jsx
|
||||||
|
│ └── MainLayout.jsx
|
||||||
|
│
|
||||||
|
├── pages/
|
||||||
|
│ ├── Admin/
|
||||||
|
│ │ ├── BlogCommentsPage.jsx
|
||||||
|
│ │ ├── BlogEditPage.jsx
|
||||||
|
│ │ ├── BlogPage.jsx
|
||||||
|
│ │ ├── BlogPreviewPage.jsx
|
||||||
|
│ │ ├── BrandingPage.jsx
|
||||||
|
│ │ ├── CampaignAnalyticsPage.jsx
|
||||||
|
│ │ ├── CampaignSendPage.jsx
|
||||||
|
│ │ ├── CategoriesPage.jsx
|
||||||
|
│ │ ├── CouponsPage.jsx
|
||||||
|
│ │ ├── CustomersPage.jsx
|
||||||
|
│ │ ├── DashboardPage.jsx
|
||||||
|
│ │ ├── EmailCampaignEditorPage.jsx
|
||||||
|
│ │ ├── EmailCampaignsPage.jsx
|
||||||
|
│ │ ├── EmailTemplatesPage.jsx
|
||||||
|
│ │ ├── MailingListsPage.jsx
|
||||||
|
│ │ ├── OrdersPage.jsx
|
||||||
|
│ │ ├── ProductEditPage.jsx
|
||||||
|
│ │ ├── ProductReviewsPage.jsx
|
||||||
|
│ │ ├── ProductsPage.jsx
|
||||||
|
│ │ ├── ReportsPage.jsx
|
||||||
|
│ │ ├── SettingsPage.jsx
|
||||||
|
│ │ └── SubscribersPage.jsx
|
||||||
|
│ │
|
||||||
|
│ ├── BlogDetailPage.jsx
|
||||||
|
│ ├── BlogPage.jsx
|
||||||
|
│ ├── CartPage.jsx
|
||||||
|
│ ├── CheckoutPage.jsx
|
||||||
|
│ ├── CouponEditPage.jsx
|
||||||
|
│ ├── CouponRedemptionsPage.jsx
|
||||||
|
│ ├── HomePage.jsx
|
||||||
|
│ ├── LoginPage.jsx
|
||||||
|
│ ├── NotFoundPage.jsx
|
||||||
|
│ ├── PaymentCancelPage.jsx
|
||||||
|
│ ├── PaymentSuccessPage.jsx
|
||||||
|
│ ├── ProductDetailPage.jsx
|
||||||
|
│ ├── ProductsPage.jsx
|
||||||
|
│ ├── RegisterPage.jsx
|
||||||
|
│ ├── SubscriptionConfirmPage.jsx
|
||||||
|
│ ├── SubscriptionPreferencesPage.jsx
|
||||||
|
│ ├── UnsubscribePage.jsx
|
||||||
|
│ ├── UserOrdersPage.jsx
|
||||||
|
│ └── VerifyPage.jsx
|
||||||
|
│
|
||||||
|
├── services/
|
||||||
|
│ ├── adminService.js
|
||||||
|
│ ├── api.js
|
||||||
|
│ ├── authService.js
|
||||||
|
│ ├── blogAdminService.js
|
||||||
|
│ ├── blogService.js
|
||||||
|
│ ├── cartService.js
|
||||||
|
│ ├── categoryAdminService.js
|
||||||
|
│ ├── consentService.js
|
||||||
|
│ ├── couponService.js
|
||||||
|
│ ├── emailTemplateService.js
|
||||||
|
│ ├── imageService.js
|
||||||
|
│ ├── productReviewsService.js
|
||||||
|
│ ├── productService.js
|
||||||
|
│ └── settingsAdminService.js
|
||||||
|
│
|
||||||
|
├── store/
|
||||||
|
│ └── index.js
|
||||||
|
│
|
||||||
|
├── theme/
|
||||||
|
│ ├── index.js
|
||||||
|
│ └── ThemeProvider.jsx
|
||||||
|
│
|
||||||
|
└── utils/
|
||||||
|
├── imageUtils.js
|
||||||
|
└── App.jsx
|
||||||
|
|
@ -140,8 +140,16 @@ function App() {
|
||||||
<UserOrdersPage />
|
<UserOrdersPage />
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
} />
|
} />
|
||||||
<Route index element={<HomePage />} />
|
<Route index element={
|
||||||
<Route path="products" element={<ProductsPage />} />
|
<Suspense fallback={<LoadingComponent />}>
|
||||||
|
<HomePage />
|
||||||
|
</Suspense>
|
||||||
|
} />
|
||||||
|
<Route path="products" element={
|
||||||
|
<Suspense fallback={<LoadingComponent />}>
|
||||||
|
<ProductsPage />
|
||||||
|
</Suspense>
|
||||||
|
} />
|
||||||
<Route path="products/:id" element={<ProductDetailPage />} />
|
<Route path="products/:id" element={<ProductDetailPage />} />
|
||||||
<Route path="confirm-subscription" element={<SubscriptionConfirmPage />} />
|
<Route path="confirm-subscription" element={<SubscriptionConfirmPage />} />
|
||||||
<Route path="unsubscribe" element={<UnsubscribePage />} />
|
<Route path="unsubscribe" element={<UnsubscribePage />} />
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState, memo } from 'react';
|
||||||
import { Box } from '@mui/material';
|
import { Box } from '@mui/material';
|
||||||
import imageUtils from '@utils/imageUtils';
|
import imageUtils from '@utils/imageUtils';
|
||||||
|
|
||||||
|
|
@ -11,7 +11,7 @@ import imageUtils from '@utils/imageUtils';
|
||||||
* @param {string} props.placeholderImage - Placeholder image to use when no image is available
|
* @param {string} props.placeholderImage - Placeholder image to use when no image is available
|
||||||
* @returns {JSX.Element} - ProductImage component
|
* @returns {JSX.Element} - ProductImage component
|
||||||
*/
|
*/
|
||||||
const ProductImage = ({
|
const ProductImage = memo(({
|
||||||
images,
|
images,
|
||||||
alt = 'Product image',
|
alt = 'Product image',
|
||||||
sx = {},
|
sx = {},
|
||||||
|
|
@ -20,7 +20,6 @@ const ProductImage = ({
|
||||||
}) => {
|
}) => {
|
||||||
const [imageError, setImageError] = useState(false);
|
const [imageError, setImageError] = useState(false);
|
||||||
|
|
||||||
// Determine which image to use
|
|
||||||
let imageSrc = placeholderImage;
|
let imageSrc = placeholderImage;
|
||||||
|
|
||||||
// Handle different types of image inputs
|
// Handle different types of image inputs
|
||||||
|
|
@ -52,6 +51,7 @@ const ProductImage = ({
|
||||||
src={imageError ? placeholderImage : imageSrc}
|
src={imageError ? placeholderImage : imageSrc}
|
||||||
alt={alt}
|
alt={alt}
|
||||||
onError={handleError}
|
onError={handleError}
|
||||||
|
loading="lazy"
|
||||||
sx={{
|
sx={{
|
||||||
display: 'block',
|
display: 'block',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
|
@ -62,6 +62,6 @@ const ProductImage = ({
|
||||||
{...rest}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
})
|
||||||
|
|
||||||
export default ProductImage;
|
export default ProductImage;
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import React from 'react';
|
import React, { memo } from 'react';
|
||||||
import { Box, Typography, Rating } from '@mui/material';
|
import { Box, Typography, Rating } from '@mui/material';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component to display product rating in a compact format
|
* Component to display product rating in a compact format
|
||||||
*/
|
*/
|
||||||
const ProductRatingDisplay = ({ rating, reviewCount, showEmpty = false }) => {
|
const ProductRatingDisplay = memo(({ rating, reviewCount, showEmpty = false }) => {
|
||||||
if (!rating && !reviewCount && !showEmpty) {
|
if (!rating && !reviewCount && !showEmpty) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -22,6 +22,6 @@ const ProductRatingDisplay = ({ rating, reviewCount, showEmpty = false }) => {
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
})
|
||||||
|
|
||||||
export default ProductRatingDisplay;
|
export default ProductRatingDisplay;
|
||||||
|
|
@ -29,23 +29,25 @@ const HomePage = () => {
|
||||||
const featuredProductsData = products && products.length > 0 ? {
|
const featuredProductsData = products && products.length > 0 ? {
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
"@type": "ItemList",
|
"@type": "ItemList",
|
||||||
"itemListElement": products.slice(0, 6).map((product, index) => ({
|
"itemListElement": products.slice(0, 6).map((product, index) => {
|
||||||
"@type": "ListItem",
|
return {
|
||||||
"position": index + 1,
|
"@type": "ListItem",
|
||||||
"item": {
|
"position": index + 1,
|
||||||
"@type": "Product",
|
"item": {
|
||||||
"name": product.name,
|
"@type": "Product",
|
||||||
"image": product.images && product.images.length > 0 ?
|
"name": product.name,
|
||||||
imageUtils.getImageUrl(product.images.find(img => img.isPrimary)?.path || product.images[0].path) : null,
|
"image": product.images && product.images.length > 0 ?
|
||||||
"description": product.description,
|
imageUtils.getImageUrl(product.images.find(img => img.isPrimary)?.path || product.images[0].path) : null,
|
||||||
"url": `${window.location.origin}/products/${product.id}`,
|
"description": product.description,
|
||||||
"offers": {
|
"url": `${window.location.origin}/products/${product.id}`,
|
||||||
"@type": "Offer",
|
"offers": {
|
||||||
"price": parseFloat(product.price).toFixed(2),
|
"@type": "Offer",
|
||||||
"priceCurrency": "CAD"
|
"price": parseFloat(product.price).toFixed(2),
|
||||||
|
"priceCurrency": "CAD"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
})
|
||||||
} : null;
|
} : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue