Skip to content

Commit

Permalink
Added animated testimonial section
Browse files Browse the repository at this point in the history
  • Loading branch information
Sawan-Kushwah committed Oct 19, 2024
1 parent bd83a25 commit 93b7c8b
Showing 1 changed file with 113 additions and 158 deletions.
271 changes: 113 additions & 158 deletions frontend/src/components/ui/ReviewCarousel.jsx
Original file line number Diff line number Diff line change
@@ -1,187 +1,142 @@
import { useState, useEffect } from 'react';
import { MdStars, MdArrowBackIos, MdArrowForwardIos } from 'react-icons/md';
import { LazyLoadImage } from 'react-lazy-load-image-component';
import 'react-lazy-load-image-component/src/effects/blur.css';
import React, { useEffect, useState } from 'react';

const ReviewCarousel = () => {
const reviews = [
const [active, setActive] = useState(3);
const items = [
{
name: 'Jane Smith',
review:
'Great games and coffee. The perfect spot to unwind with friends!',
img: 'https://randomuser.me/api/portraits/men/51.jpg',
rating: 5,
img: "https://www.gravatar.com/avatar/2c7d99fe281ecd3bcd65ab915bac6dd5?s=250",
stars: "★★★★★",
text: "The PlayCafe website project has been an incredible experience for me. The collaborative environment and innovative ideas helped me enhance my skills in web development and user experience design. I’m proud to be part of this initiative!",
name: "- Arjun Sharma",
jobTitle: "Frontend Developer",
location: "Location: Bengaluru, India"
},
{
name: 'Sophia Lee',
review: 'Cozy place with a fantastic selection of snacks and games!',
img: 'https://randomuser.me/api/portraits/women/90.jpg',
rating: 4,
img: "https://img.freepik.com/free-vector/illustration-user-avatar-icon_53876-5907.jpg?ga=GA1.1.713761379.1679213202&semt=ais_hybrid",
stars: "★★★★",
text: "Working on the PlayCafe project has truly expanded my horizons. I love how we're building a vibrant online space for board game enthusiasts, making it easy for them to connect and enjoy. This project has greatly improved my project management skills!",
name: "- Priya Desai",
jobTitle: "UI/UX Designer",
location: "Location: Mumbai, India"
},
{
name: 'Emily Davis',
review: 'Friendly staff and delicious food make for a great experience.',
img: 'https://randomuser.me/api/portraits/women/63.jpg',
rating: 5,
img: "https://img.freepik.com/free-vector/gradient-professional-sarah-smith-linkedin-personal-profile-picture_742173-13011.jpg?ga=GA1.1.713761379.1679213202&semt=ais_hybrid",
stars: "★★★★★",
text: "The PlayCafe initiative has been a game-changer for my professional journey. The chance to work with a talented team and contribute to a meaningful project has been fulfilling. I can’t wait to see how our work transforms the cafe experience!",
name: "- Rohan Patel",
jobTitle: "Backend Developer",
location: "Location: Ahmedabad, India"
},
{
name: 'Chris Wilson',
review: 'Amazing variety of games and excellent drinks to enjoy.',
img: 'https://randomuser.me/api/portraits/men/22.jpg',
rating: 5,
img: "https://img.freepik.com/free-vector/profile-picture-template-design_742173-22027.jpg?ga=GA1.1.713761379.1679213202&semt=ais_hybrid",
stars: "★★★★",
text: "Participating in the PlayCafe project has ignited my passion for web development. The creativity and teamwork involved in building this platform have not only sharpened my technical skills but also my ability to collaborate effectively.",
name: "- Neha Iyer",
jobTitle: "Content Writer",
location: "Location: Chennai, India"
},
{
name: 'Michael Johnson',
review: 'Had a fantastic time with the games and tasty beverages!',
img: 'https://randomuser.me/api/portraits/men/85.jpg',
rating: 5,
img: "https://i.pravatar.cc/[email protected]",
stars: "★★★★★",
text: "The PlayCafe website project has been an amazing platform for me to learn and grow. I am thrilled to contribute to a project that brings joy to board game lovers and creates a community. The support from my team has been fantastic!",
name: "- Rahul Singh",
jobTitle: "Full Stack Developer",
location: "Location: Hyderabad, India"
},
{
name: 'Jia Wang',
review: 'Loved the games, the ambiance, and the overall vibe here!',
img: 'https://randomuser.me/api/portraits/women/61.jpg',
rating: 5,
},
{
name: 'Olivia Green',
review:
'Great atmosphere and an excellent selection of board games. Will be back!',
img: 'https://randomuser.me/api/portraits/women/72.jpg',
rating: 4,
},
{
name: 'Ethan White',
review:
'The vibe is amazing, and the staff is super friendly. Highly recommend!',
img: 'https://randomuser.me/api/portraits/men/33.jpg',
rating: 5,
img: "https://www.gravatar.com/avatar/2c7d99fe281ecd3bcd65ab915bac6dd5?s=250",
stars: "★★★★★",
text: "Being part of the PlayCafe initiative has been a rewarding experience. I’ve learned so much about web development while helping create an engaging space for board game enthusiasts. I’m excited to see our vision come to life!",
name: "- Kavita Nair",
jobTitle: "Software Tester",
location: "Location: Pune, India"
},
];

const [currentIndex, setCurrentIndex] = useState(0);
const [showMoreStates, setShowMoreStates] = useState(
reviews.map(() => false)
);

const toggleShowMore = (index) => {
const updatedStates = [...showMoreStates];
updatedStates[index] = !updatedStates[index];
setShowMoreStates(updatedStates);
};

const nextSlide = () => {
setCurrentIndex((prevIndex) =>
prevIndex === reviews.length - 4 ? 0 : prevIndex + 1
);
};

const prevSlide = () => {
setCurrentIndex((prevIndex) =>
prevIndex === 0 ? reviews.length - 4 : prevIndex - 1
);
};
const [cardsToShow, setCardsToShow] = useState(1);
useEffect(() => {
loadShow();
}, [active]);

const updateCardsToShow = () => {
if (window.innerWidth >= 768) {
setCardsToShow(4);
} else {
setCardsToShow(1);
const loadShow = () => {
const itemsElement = document.querySelectorAll('.slider .item');
itemsElement[active].style.transform = `none`;
itemsElement[active].style.zIndex = 1;
itemsElement[active].style.filter = 'none';
itemsElement[active].style.opacity = 1;
// Show after
let stt = 0;
for (let i = active + 1; i < itemsElement.length; i++) {
stt++;
itemsElement[i].style.transform = `translateX(${120 * stt}px) scale(${1 - 0.2 * stt}) perspective(16px) rotateY(-1deg)`;
itemsElement[i].style.zIndex = 0;
itemsElement[i].style.filter = 'blur(5px)';
itemsElement[i].style.opacity = stt > 2 ? 0 : 0.6;
}
stt = 0;
for (let i = (active - 1); i >= 0; i--) {
stt++;
itemsElement[i].style.transform = `translateX(${-120 * stt}px) scale(${1 - 0.2 * stt}) perspective(16px) rotateY(1deg)`;
itemsElement[i].style.zIndex = 0;
itemsElement[i].style.filter = 'blur(5px)';
itemsElement[i].style.opacity = stt > 2 ? 0 : 0.6;
}
};

useEffect(() => {
updateCardsToShow();
window.addEventListener('resize', updateCardsToShow);

return () => {
window.removeEventListener('resize', updateCardsToShow);
};
}, []);

return (
<div className="mb-20">
<div className="flex items-center justify-center p-20 mb-10">
<h1 className="md:text-6xl text-4xl pl-3 pr-3 text-center font-bold text-[#004D43]">
Customer Feedback
</h1>
</div>
<div>

<div className="bg-[#004D43] h-full p-4 md:p-20 items-center justify-center flex relative ">
<div className="w-full overflow-x-auto max-w-7xl md:overflow-hidden ">
<div
className="flex transition-transform duration-300 ease-in-out"
style={{
transform: `translateX(-${currentIndex * (100 / cardsToShow)}%)`, // Moves the grid based on cardsToShow
width: `${(reviews.length / cardsToShow) * 100}%`, // Dynamic width based on the number of cards
}}
>
{reviews.map((review, index) => (
<div
key={index}
className="w-full p-2 sm:w-1/2 md:w-1/3 lg:w-1/4"
>
<div className="relative min-h-[250px] max-h-[350px] md:min-h-[300px] md:max-h-[400px] p-4 rounded-xl bg-amber-200 z-10 overflow-hidden">
<div className="flex flex-col items-center justify-center mb-1">
{/* <img
src={review.img}
alt=""
className="w-20 h-20 rounded-full"
/> */}
<LazyLoadImage
alt={`${index}img`}
effect="blur"
className="w-20 h-20 rounded-full"
wrapperProps={{
style: { transitionDelay: '1s' },
}}
src={review.img}
/>
<h1 className="text-xl font-semibold text-center">
{review.name}
</h1>
<div className="flex">
{Array(review.rating)
.fill()
.map((_, i) => (
<MdStars key={i} className="text-[#004D43]" />
))}
</div>
</div>

<p className="text-lg leading-6 tracking-wide text-center">
{showMoreStates[index]
? review.review
: `${review.review.substring(0, 50)}...`}
<span
className="text-blue-500 cursor-pointer"
onClick={() => toggleShowMore(index)}
>
{showMoreStates[index] ? ' Show less' : ' Read more'}
</span>
</p>
</div>
</div>
))}
<div className="slider" style={{ position: 'relative', marginTop: '100px', width: '100%', height: '550px', overflow: 'hidden' }}>
{items.map((item, index) => (
<div className="item" key={index} style={{
position: 'absolute',
width: '350px',
height: '500px',
textAlign: 'justify',
background: '#016457', // Dark green to light yellow gradient
borderRadius: '12px',
padding: '20px',
transition: '0.5s',
left: 'calc(50% - 150px)',
top: '0',
marginBottom: '100px',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
boxShadow: '0 4px 15px rgba(0, 0, 0, 0.1)', // Soft shadow for depth
overflow: 'hidden', // Ensures the image does not overflow
color: 'white',
}}>
<img
src={item.img}
alt="User Avatar"
className='w-[150px] h-[150px] rounded-lg object-cover mb-[20px] cursor-pointer'
style={{
transition: 'transform 0.3s ease, filter 0.3s ease',
border: '3px solid #d0e7b0' // Green border for the image
}}
onMouseOver={e => {
e.currentTarget.style.transform = 'scale(1.1)';
e.currentTarget.style.filter = 'brightness(1.1)'; // Brightness effect on hover
}}
onMouseOut={e => {
e.currentTarget.style.transform = 'scale(1)';
e.currentTarget.style.filter = 'brightness(1)'; // Reset brightness
}}
/>
<div className="stars text-[#ffd700] text-2xl mt-auto">{item.stars}</div>
<p className='text-justify mb-[20px]'>{item.text}</p>
<h2 className='mb-[10px] text-xl font-semibold'>{item.name}</h2>
<div className="job-title text-[#007BFF] font-bold mb-[5px]">{item.jobTitle}</div>
<div className="location text-[#4A4A4A] mb-[15px]">{item.location}</div>
</div>
</div>

{reviews.length > 4 && (
<>
<button
onClick={prevSlide}
className="absolute hidden p-2 transform -translate-y-1/2 bg-white rounded-full md:block left-10 top-1/2"
>
<MdArrowBackIos className="text-[#004D43]" size={18} />
</button>
<button
onClick={nextSlide}
className="absolute hidden p-2 transform -translate-y-1/2 bg-white rounded-full md:block right-10 top-1/2"
>
<MdArrowForwardIos className="text-[#004D43]" size={18} />
</button>
</>
)}

))}

<button id="next" className=' absolute top-[40%] text-green-900 bg-none border-none text-6xl font-mono font-bold opacity-80 transition-opacity z-10 right-[50px]' onClick={() => setActive(prev => (prev + 1 < items.length ? prev + 1 : prev))}>{">>"}</button>
<button id="prev" className=' absolute top-[40%] text-green-900 bg-none border-none text-6xl font-mono font-bold opacity-0 transition-opacity z-10 left-[50px]' onClick={() => setActive(prev => (prev - 1 >= 0 ? prev - 1 : prev))}> {"<<"}</button>
</div>
</div>
);
Expand Down

0 comments on commit 93b7c8b

Please sign in to comment.