200 lines
9.4 KiB
TypeScript
200 lines
9.4 KiB
TypeScript
"use client";
|
||
import React, { useState } from "react";
|
||
import { Play, Star, ShieldCheck, X } from "lucide-react";
|
||
import { motion, AnimatePresence } from "motion/react";
|
||
import Link from "next/link";
|
||
import SafeImage from "./SafeImage";
|
||
import { useSettingsStore } from "../lib/store/settingsStore";
|
||
import { videoService, Video } from "../lib/services/videoService";
|
||
|
||
export interface TestimonialItem {
|
||
id?: string;
|
||
authorName?: string;
|
||
roleTitle?: string;
|
||
avatarUrl?: string;
|
||
content?: string;
|
||
clinicName?: string;
|
||
vetName?: string;
|
||
imageUrl?: string;
|
||
quote?: string;
|
||
title?: string;
|
||
thumbnail?: string;
|
||
videoUrl?: string;
|
||
description?: string;
|
||
isActive?: boolean;
|
||
}
|
||
|
||
const FALLBACK_VIDEOS = [
|
||
{
|
||
id: "v1",
|
||
title: "نحوه آمادهسازی کانیهیدروکس GAG",
|
||
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",
|
||
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: "/assets/images/regenerated_image_1779109861747.png",
|
||
videoUrl: "https://www.w3schools.com/html/mov_bbb.mp4",
|
||
description: "دوز مصرفی مکملهای کلسیم در نژادهای بزرگ برای جلوگیری از بدشکلیهای استخوانی."
|
||
}
|
||
];
|
||
|
||
interface DisplayVideoItem {
|
||
id: string;
|
||
title?: string;
|
||
doctor?: string;
|
||
duration?: string;
|
||
thumbnail?: string;
|
||
videoUrl?: string;
|
||
description?: string;
|
||
quote?: string;
|
||
imageUrl?: string;
|
||
vetName?: string;
|
||
}
|
||
|
||
export default function VetGallery({ testimonials = [] }: { testimonials?: TestimonialItem[] }) {
|
||
const getText = useSettingsStore(state => state.getText);
|
||
const [apiVideos, setApiVideos] = useState<Video[]>([]);
|
||
const [selectedVideo, setSelectedVideo] = useState<DisplayVideoItem | null>(null);
|
||
|
||
React.useEffect(() => {
|
||
videoService.getVideos({ featured: true, limit: 3 }).then((data) => {
|
||
if (data && data.length > 0) {
|
||
setApiVideos(data);
|
||
}
|
||
});
|
||
}, []);
|
||
|
||
const activeTestimonials = testimonials.filter(t => t.isActive !== false);
|
||
const displayItems: DisplayVideoItem[] = activeTestimonials.length > 0
|
||
? activeTestimonials.map((t, idx) => ({
|
||
id: t.id || `t-${idx}`,
|
||
title: (t.authorName || t.vetName || '') + (t.roleTitle ? ` — ${t.roleTitle}` : (t.clinicName ? ` — ${t.clinicName}` : '')),
|
||
doctor: (t.authorName || t.vetName || '') + (t.roleTitle ? ` (${t.roleTitle})` : ''),
|
||
duration: "۰۲:۰۰",
|
||
thumbnail: t.avatarUrl || t.imageUrl || "https://images.unsplash.com/photo-1576091160550-217359f42f8c?auto=format&fit=crop&q=80&w=400",
|
||
videoUrl: "https://www.w3schools.com/html/mov_bbb.mp4",
|
||
description: t.content || t.quote || '',
|
||
quote: t.content || t.quote || ''
|
||
}))
|
||
: (apiVideos.length > 0 ? apiVideos : FALLBACK_VIDEOS);
|
||
|
||
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>
|
||
<Link
|
||
href="/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" />
|
||
</Link>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||
{displayItems.map((video, index) => (
|
||
<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" />
|
||
<SafeImage
|
||
src={video.thumbnail || video.imageUrl || '/images/vets/vet1.webp'}
|
||
alt={video.title || video.vetName || 'ویدیو دامپزشک'}
|
||
className="w-full h-full"
|
||
imgClassName="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 ? 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>
|
||
);
|
||
}
|