canina/frontend/application/components/VetGallery.tsx
parsa aghaei 508356b8d3 feat: add Persian fonts, fix UI bugs, improve frontend quality
- Add local Persian fonts: Vazirmatn, Sahel, Shabnam, Lalezar, IranNastaliq
- Configure @font-face in globals.css with all font weights
- Set Vazirmatn as primary font, Lalezar for headings, Sahel for alt text
- Fix Hero image loading with crossOrigin and error fallback
- Fix SmartAdvisor disabled button contrast (WCAG compliance)
- Add visible labels for form inputs in SmartAdvisor step 1
- Fix UserDashboard null safety for walletBalance
- Fix announcement bar hydration mismatch (loading state guard)
- Fix UserDashboard null checks for profile fields
- Improve overall frontend robustness and data-loading guards
2026-07-11 19:48:43 +03:30

146 lines
7.7 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import React, { useState } from "react";
import { Play, PlayCircle, Star, ShieldCheck, X } from "lucide-react";
import { motion, AnimatePresence } from "motion/react";
import { useRouter } from "next/navigation";
import { useSettingsStore } from "../lib/store/settingsStore";
const VIDEOS = [
{
id: "v1",
title: "نحوه آماده‌سازی کانی‌هیدروکس",
doctor: "دکتر کلاوس هنینگ",
duration: "۱:۴۵",
thumbnail: "https://images.unsplash.com/photo-1576091160550-217359f42f8c?auto=format&fit=crop&q=80&w=400",
videoUrl: "https://www.w3schools.com/html/mov_bbb.mp4", // Placeholder real-looking video
description: "آموزش گام به گام آماده‌سازی پودر Canhydrox GAG برای جذب حداکثری در دستگاه گوارش."
},
{
id: "v2",
title: "اهمیت صدف لب‌سبز",
doctor: "دکتر النا اشمیت",
duration: "۲:۲۰",
thumbnail: "https://images.unsplash.com/photo-1599443015574-be5fe8a05783?auto=format&fit=crop&q=80&w=400",
videoUrl: "https://www.w3schools.com/html/movie.mp4",
description: "چرا صدف لب‌سبز نیوزیلندی نایاب‌ترین و موثرترین ماده برای بازسازی مفصل است؟"
},
{
id: "v3",
title: "تغذیه هوشمند توله‌سگ‌ها",
doctor: "دکتر هلگا فیشر",
duration: "۳:۱۰",
thumbnail: "https://images.unsplash.com/photo-1583337130417-3346a1be7dee?auto=format&fit=crop&q=80&w=400",
videoUrl: "https://www.w3schools.com/html/mov_bbb.mp4",
description: "دوز مصرفی مکمل‌های کلسیم در نژادهای بزرگ برای جلوگیری از بدشکلی‌های استخوانی."
}
];
export default function VetGallery({ testimonials = [] }: { testimonials?: any[] }) {
const router = useRouter();
const getText = useSettingsStore(state => state.getText);
const displayItems = testimonials.length > 0 ? testimonials : VIDEOS;
const [selectedVideo, setSelectedVideo] = useState<any>(null);
return (
<section className="py-24 bg-white font-vazir" dir="rtl">
<div className="max-w-7xl mx-auto px-4">
<div className="flex flex-col md:flex-row md:items-end justify-between mb-16 gap-6">
<div className="max-w-2xl">
<div className="inline-flex items-center gap-2 px-3 py-1 bg-canina-blue/10 text-canina-blue rounded-full text-[10px] font-black uppercase tracking-widest mb-4">
<Star className="w-3 h-3" />
{getText('videos_badge', "Vet Insights")}
</div>
<h2 className="text-4xl md:text-5xl font-black text-medical-gray-900 leading-tight font-lalezar tracking-wide">
{getText('videos_title', "مشاوره ویدئویی")} <span className="text-canina-blue underline decoration-4 decoration-canina-blue/20 underline-offset-8">{getText('videos_title_highlight', "دوست دامپزشک پت شما")}</span>
</h2>
<p className="text-lg text-medical-gray-500 font-medium mt-6">
{getText('videos_desc', "متخصصین آلمانی کانینا مستقیماً با شما صحبت می‌کنند. نحوه مصرف، مزایای رقابتی و دانش تخصصی پشت هر محصول.")}
</p>
</div>
<button
onClick={() => router.push('/videos')}
className="inline-flex items-center gap-2 text-canina-blue font-bold text-sm hover:translate-x-1 transition-transform rtl:hover:-translate-x-1"
>
{getText('videos_view_all', "مشاهده همه ویدئوها")}
<Play className="w-4 h-4" />
</button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{displayItems.map((video: any, index: number) => (
<motion.button
key={video.id}
whileHover={{ y: -8 }}
onClick={() => setSelectedVideo(video)}
className="w-full text-right block group cursor-pointer focus-visible:ring-4 focus-visible:ring-canina-blue/30 focus-visible:outline-none rounded-[2rem] p-2"
>
<div className="relative aspect-video rounded-[2rem] overflow-hidden mb-4 shadow-xl">
<div className="absolute inset-0 bg-medical-gray-900/20 group-hover:bg-transparent transition-colors z-10" />
<img
src={video.thumbnail || video.imageUrl || '/images/vets/vet1.webp'}
alt={video.title || video.vetName}
className="w-full h-full object-cover grayscale-[30%] group-hover:grayscale-0 transition-all duration-700"
/>
<div className="absolute inset-0 flex items-center justify-center z-20">
<div className="w-16 h-16 bg-white/90 backdrop-blur-sm rounded-full flex items-center justify-center text-canina-blue scale-90 group-hover:scale-100 group-hover:bg-white transition-all shadow-xl">
<Play className="w-6 h-6 ml-1" />
</div>
</div>
<div className="absolute bottom-4 right-4 bg-black/60 backdrop-blur-md text-white px-2 py-1 rounded-lg text-xs font-black z-20 font-vazir flex items-center gap-1 shadow-lg">
<span></span>
<span>{video.duration || (index === 0 ? '۱:۴۵' : index === 1 ? '۲:۲۰' : '۳:۱۰')}</span>
</div>
</div>
<h4 className="text-lg font-black text-medical-gray-900 mb-2 group-hover:text-canina-blue transition-colors leading-tight font-vazir">
{video.title || video.quote?.substring(0, 40) + '...'}
</h4>
<div className="flex items-center gap-2 text-medical-gray-500 font-bold text-sm font-vazir">
<ShieldCheck className="w-4 h-4 text-canina-blue" />
{video.doctor || video.vetName}
</div>
</motion.button>
))}
</div>
</div>
{/* Video Modal */}
<AnimatePresence>
{selectedVideo && (
<div className="fixed inset-0 z-[110] flex items-center justify-center p-4">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={() => setSelectedVideo(null)}
className="absolute inset-0 bg-medical-gray-900/90 backdrop-blur-xl"
/>
<motion.div
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.9 }}
className="bg-black w-full max-w-5xl aspect-video rounded-[3rem] overflow-hidden relative z-10 shadow-2xl border border-white/10"
>
<button
onClick={() => setSelectedVideo(null)}
className="absolute top-6 left-6 text-white/50 hover:text-white z-20 transition-colors bg-black/20 p-2 rounded-full"
>
<X className="w-8 h-8" />
</button>
<video
src={selectedVideo.videoUrl}
controls
autoPlay
className="w-full h-full object-contain"
/>
<div className="absolute bottom-0 left-0 right-0 p-8 bg-gradient-to-t from-black/80 to-transparent">
<h3 className="text-white text-2xl font-black mb-2">{selectedVideo.title}</h3>
<p className="text-white/60 text-sm font-medium">{selectedVideo.doctor}</p>
</div>
</motion.div>
</div>
)}
</AnimatePresence>
</section>
);
}