HomeTestimonial.tsx 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import { Review } from "../../../services/content/types";
  2. import TestimonialCard from "../../../components/TestimonialCard";
  3. import { useQuery } from "@tanstack/react-query";
  4. import { DataCacheKey, staleTime } from "../../../global/constants";
  5. import {
  6. startLoading,
  7. stopLoading,
  8. } from "../../../features/loading/loadingSlice";
  9. import { contentApi } from "../../../apis/contentApi";
  10. import { useAppDispatch } from "../../../hooks/useRedux";
  11. import { useTranslation } from "react-i18next";
  12. const HomeTestimonial = () => {
  13. const dispatch = useAppDispatch();
  14. const { t } = useTranslation();
  15. const { data: loadReviewData = [] } = useQuery<Review[]>({
  16. queryKey: [DataCacheKey.REVIEWS],
  17. queryFn: async (): Promise<Review[]> => {
  18. try {
  19. dispatch(startLoading({}));
  20. const res = await contentApi.LoadReview({
  21. pageNumber: 0,
  22. pageSize: 10,
  23. isFeatured: true,
  24. });
  25. return res.data.reviews as Review[];
  26. } catch (error) {
  27. console.error(error);
  28. return []; // 🔴 bắt buộc
  29. } finally {
  30. dispatch(stopLoading());
  31. }
  32. },
  33. staleTime: staleTime,
  34. });
  35. return (
  36. <section className="relative overflow-hidden bg-[#EE0434] py-10 md:py-20 lg:py-24">
  37. <div className="absolute top-0 right-0 w-[600px] h-[600px] bg-white/5 rounded-full blur-[100px] -translate-y-1/2 translate-x-1/2"></div>
  38. <div className="absolute bottom-0 left-0 w-[400px] h-[400px] bg-black/5 rounded-full blur-[80px] translate-y-1/2 -translate-x-1/2"></div>
  39. <div className="max-w-7xl mx-auto relative z-10 px-4 sm:px-6 lg:px-8">
  40. <div className="grid grid-cols-1 lg:grid-cols-12 gap-8 lg:gap-12 items-center">
  41. <div className="lg:col-span-4 text-white space-y-4 md:space-y-6 text-center lg:text-left">
  42. <h2 className="text-2xl md:text-4xl lg:text-[36px] font-black leading-tight tracking-tight">
  43. {t("whatUs")} <br className="hidden lg:block" /> {t("sayAboutUs")}
  44. </h2>
  45. <p className="text-sm md:text-xl font-medium text-white/80 max-w-sm mx-auto lg:mx-0">
  46. {t("overMillionSatisfiedCustomers")}
  47. </p>
  48. </div>
  49. <div className="hidden lg:col-span-8 lg:grid grid-cols-2 gap-6 h-[550px] overflow-hidden relative">
  50. <div className="absolute inset-x-0 top-0 h-20 bg-gradient-to-b from-[#EE0434] to-transparent z-20"></div>
  51. <div className="absolute inset-x-0 bottom-0 h-20 bg-gradient-to-t from-[#EE0434] to-transparent z-20"></div>
  52. <div className="flex flex-col space-y-6 animate-marquee-up hover:[animation-play-state:paused]">
  53. {loadReviewData.map((item, i) => (
  54. <TestimonialCard key={i} item={item} />
  55. ))}
  56. </div>
  57. <div className="flex flex-col space-y-6 animate-marquee-down hover:[animation-play-state:paused]">
  58. {loadReviewData
  59. .slice()
  60. .reverse()
  61. .map((item, i) => (
  62. <TestimonialCard key={i} item={item} />
  63. ))}
  64. </div>
  65. </div>
  66. </div>
  67. </div>
  68. <div className="lg:hidden w-screen overflow-hidden py-8 relative -ml-4">
  69. <div className="flex space-x-6 animate-scroll-x whitespace-nowrap px-4">
  70. {[...loadReviewData, ...loadReviewData, ...loadReviewData].map(
  71. (item, i) => (
  72. <div key={i} className="inline-block whitespace-normal align-top">
  73. <TestimonialCard item={item} />
  74. </div>
  75. )
  76. )}
  77. </div>
  78. </div>
  79. </section>
  80. );
  81. };
  82. export default HomeTestimonial;