Skip to content

Commit

Permalink
Fix babel not found issue
Browse files Browse the repository at this point in the history
  • Loading branch information
Ahmedbennaya committed Oct 12, 2024
1 parent f8153ff commit 6081efd
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 27 deletions.
2 changes: 0 additions & 2 deletions backend/Utils/sendEmail.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// File: sendEmail.js
import nodemailer from 'nodemailer';
import dotenv from 'dotenv';
import jwt from 'jsonwebtoken';

dotenv.config();

Expand Down
1 change: 0 additions & 1 deletion frontend/src/admin/AdminDashboard.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// src/components/AdminDashboard.js
import React from 'react';
import { Link, Outlet } from 'react-router-dom';

Expand Down
1 change: 0 additions & 1 deletion frontend/src/components/CartSidebar.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// CartSidebar.js
import React, { useEffect, useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import PropTypes from 'prop-types';
Expand Down
9 changes: 6 additions & 3 deletions frontend/src/components/CookieConsent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ const CookieConsent = () => {
const { preferences, loading, error } = useSelector((state) => state.preference);
const [isVisible, setIsVisible] = useState(true);

// Load preferences when the component mounts
useEffect(() => {
dispatch(loadPreferences());
}, [dispatch]);

// Hide the banner if preferences are already set
useEffect(() => {
if (preferences && preferences.thirdParty !== undefined && isVisible) {
if (preferences && preferences.thirdParty !== undefined) {
setIsVisible(false);
}
}, [preferences, isVisible]);
}, [preferences]);

const handleAcceptAll = () => {
dispatch(savePreferences({ thirdParty: true }));
Expand All @@ -27,6 +29,7 @@ const CookieConsent = () => {
setIsVisible(false);
};

// If the banner is not visible, don't render anything
if (!isVisible) return null;

return (
Expand Down Expand Up @@ -78,4 +81,4 @@ const CookieConsent = () => {
);
};

export default CookieConsent;
export default CookieConsent;
3 changes: 2 additions & 1 deletion frontend/src/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import AdminOrders from './admin/AdminOrders';
import BookConsultation from './components/BookConsultation';
import ContactUs from './components/ContactUs';
import OurStory from './components/OurStory';
import AdminRoute from './admin/AdminRoute'; // AdminRoute component for protected admin routes
import ProductPage from './pages/ProductPage'; // Import the ProductPage component

const router = createBrowserRouter(
createRoutesFromElements(
Expand All @@ -50,6 +50,7 @@ const router = createBrowserRouter(
<Route path="franchise" element={<Franchise />} />
<Route path="profile" element={<Profile />} />
<Route path="checkout" element={<Checkout />} />
<Route path="product/:id" element={<ProductPage />} /> {/* Dynamic route for product details */}

{/* New route for the Book Consultation form */}
<Route path="book-consultation" element={<BookConsultation />} />
Expand Down
43 changes: 26 additions & 17 deletions frontend/src/pages/CurtainsDrapes.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom'; // Added to enable navigation to details page
import ClipLoader from 'react-spinners/ClipLoader';
import { useDispatch, useSelector } from 'react-redux';
import { addToCart } from '../redux/features/cartSlice';
Expand Down Expand Up @@ -102,7 +103,7 @@ const FilterSection = ({ filters, handleFilterChange, handleClearFilters }) => (
);


const ProductCard = ({ title, imageUrl, price, description, onAddToCart }) => {
const ProductCard = ({ product, onAddToCart }) => {
const [isModalOpen, setIsModalOpen] = useState(false);

const openModal = () => setIsModalOpen(true);
Expand All @@ -112,23 +113,34 @@ const ProductCard = ({ title, imageUrl, price, description, onAddToCart }) => {
<div className={`${sharedClasses.card} mb-8 transform hover:scale-105 transition-transform duration-300`}>
<div className="relative w-full h-64 overflow-hidden rounded-lg mb-4 cursor-pointer" onClick={openModal}>
<img
src={imageUrl}
alt={title}
src={product.imageUrl}
alt={product.name}
className="w-full h-full object-cover transition-transform duration-300 hover:scale-110"
/>
</div>
<h3 className="text-2xl font-bold mb-2 text-gray-900">{title}</h3>
<h4 className="text-xl font-semibold mb-2 text-gray-900">From DT {price.toFixed(2)}</h4>
<p className="text-gray-600 mb-4">{description}</p>
<button
onClick={onAddToCart}
className={`${sharedClasses.primaryButton} ${sharedClasses.button} w-full`}
>
Add to Cart
</button>
<h3 className="text-2xl font-bold mb-2 text-gray-900">{product.name}</h3>
<h4 className="text-xl font-semibold mb-2 text-gray-900">From DT {product.price.toFixed(2)}</h4>
<p className="text-gray-600 mb-4">{product.description}</p>

<div className="flex justify-between items-center">
<button
onClick={onAddToCart}
className={`${sharedClasses.primaryButton} ${sharedClasses.button} w-1/2 mr-2`}
>
Add to Cart
</button>

{/* Details Button */}
<Link
to={`/product/${product._id}`} // Link to the product details page
className={`${sharedClasses.primaryButton} ${sharedClasses.button} w-1/2 text-center`}
>
Details
</Link>
</div>

{isModalOpen && (
<ImageModal imageUrl={imageUrl} title={title} onClose={closeModal} />
<ImageModal imageUrl={product.imageUrl} title={product.name} onClose={closeModal} />
)}
</div>
);
Expand All @@ -139,10 +151,7 @@ const ProductGallery = ({ products, handleAddToCart }) => (
{products.map((product) => (
<ProductCard
key={product._id}
title={product.name}
imageUrl={product.imageUrl}
price={product.price}
description={product.description}
product={product} // Pass product object to ProductCard
onAddToCart={() => handleAddToCart(product)}
/>
))}
Expand Down
109 changes: 109 additions & 0 deletions frontend/src/pages/ProductPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import React, { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import axios from 'axios';
import ClipLoader from 'react-spinners/ClipLoader';

const ProductPage = () => {
const { id } = useParams(); // Get product ID from URL params
const [product, setProduct] = useState(null);
const [images, setImages] = useState({});
const [activeImg, setActiveImage] = useState('');
const [amount, setAmount] = useState(1);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
const fetchProduct = async () => {
setLoading(true);
try {
const response = await axios.get(`https://mern-site-z5gs.onrender.com/api/products/${id}`);
setProduct(response.data);
setImages({
img1: response.data.imageUrl,
img2: response.data.imageUrl2,
img3: response.data.imageUrl3,
img4: response.data.imageUrl4,
});
setActiveImage(response.data.imageUrl); // Set default image
setLoading(false);
} catch (error) {
setError('Failed to load product details');
setLoading(false);
}
};
fetchProduct();
}, [id]);

const handleAmountChange = (change) => {
setAmount((prev) => Math.max(1, prev + change)); // Ensure amount doesn't go below 1
};

if (loading) {
return (
<div className="flex justify-center items-center h-screen">
<ClipLoader size={50} color="#4A90E2" />
</div>
);
}

if (error) {
return <p className="text-center text-red-600 mt-10">{error}</p>;
}

return (
<div className='flex flex-col justify-between lg:flex-row gap-16 lg:items-start p-6 lg:p-12'>
{/* IMAGES */}
<div className='flex flex-col gap-6 lg:w-2/4'>
<img
src={activeImg}
alt={product.name}
className='w-full h-full aspect-square object-cover rounded-xl transition-transform duration-300 ease-in-out'
/>
<div className='flex gap-4 justify-center'>
{Object.values(images).map((imageUrl, index) => (
<img
key={index}
src={imageUrl}
alt={`Product ${index + 1}`}
className={`w-24 h-24 rounded-md cursor-pointer transition-transform duration-200 ${activeImg === imageUrl ? 'scale-110 border-2 border-violet-800' : ''}`}
onClick={() => setActiveImage(imageUrl)}
/>
))}
</div>
</div>

{/* ABOUT */}
<div className='flex flex-col gap-4 lg:w-2/4'>
<span className='text-violet-600 font-semibold uppercase'>Exclusive Collection</span>
<h1 className='text-4xl font-bold text-gray-900'>{product.name}</h1>
<p className='text-gray-700'>{product.description}</p>
<h6 className='text-3xl font-semibold text-gray-900'>${product.price}</h6>

{/* QUANTITY SELECTOR */}
<div className='flex items-center gap-8 mt-4'>
<div className='flex items-center'>
<button
className='bg-gray-300 px-4 py-2 rounded-l-lg text-violet-800 font-semibold'
onClick={() => handleAmountChange(-1)}
>
-
</button>
<span className='px-6 py-3 text-xl font-semibold'>{amount}</span>
<button
className='bg-gray-300 px-4 py-2 rounded-r-lg text-violet-800 font-semibold'
onClick={() => handleAmountChange(1)}
>
+
</button>
</div>

<button className='bg-violet-800 text-white font-semibold py-3 px-16 rounded-lg h-full hover:bg-violet-900'>
Add to Cart
</button>
</div>
</div>
</div>
);
};

export default ProductPage;
4 changes: 2 additions & 2 deletions frontend/src/redux/features/preferenceSlice.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ export const savePreferences = createAsyncThunk(
'preference/savePreferences',
async (preference, { getState }) => {
const { auth } = getState(); // Assuming you have auth state
const userId = auth.userInfo ? auth.userInfo.id : null;
const userId = auth.userInfo ? auth.userInfo._id : null; // Use _id from MongoDB

// Save preferences to backend only if userId exists
// Save preferences to backend only if userId (_id) exists
if (userId) {
await axios.post('https://mern-site-z5gs.onrender.com/api/preferences/savePreferences', { userId, preference });
}
Expand Down

0 comments on commit 6081efd

Please sign in to comment.