- Fix seed-products.ts TS error (implicit any) and BOM handling - Re-run full seed to restore correct Persian encoding in DB - Fix productService query→search param mismatch - Fix IngredientWiki hardcoded port 4000→use settingsStore - Restore seed-products-data.json from git after accidental corruption
190 lines
8.8 KiB
TypeScript
190 lines
8.8 KiB
TypeScript
"use client";
|
||
import React, { useState } from "react";
|
||
import { motion, AnimatePresence } from "motion/react";
|
||
import { ChevronRight, PlayCircle, Star, ShieldCheck, X, Search, Clock, User } from "lucide-react";
|
||
|
||
|
||
const ALL_VIDEOS = [
|
||
{
|
||
id: "v1",
|
||
title: "نحوه آمادهسازی کانیهیدروکس",
|
||
doctor: "دکتر کلاوس هنینگ",
|
||
duration: "۱:۴۵",
|
||
thumbnail: "https://images.unsplash.com/photo-1576091160550-217359f42f8c?auto=format&fit=crop&q=80&w=600",
|
||
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=600",
|
||
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=600",
|
||
videoUrl: "https://www.w3schools.com/html/mov_bbb.mp4",
|
||
description: "دوز مصرفی مکملهای کلسیم در نژادهای بزرگ برای جلوگیری از بدشکلیهای استخوانی."
|
||
},
|
||
{
|
||
id: "v4",
|
||
title: "تاثیر امگا ۳ بر ریزش مو فصلی",
|
||
doctor: "دکتر ماری کونیگ",
|
||
duration: "۵:۱۵",
|
||
thumbnail: "https://images.unsplash.com/photo-1516734212186-a967f81ad0d7?auto=format&fit=crop&q=80&w=600",
|
||
videoUrl: "https://www.w3schools.com/html/movie.mp4",
|
||
description: "چربیهای ضروری چگونه لایه محافظ پوست را بازسازی میکنند."
|
||
},
|
||
{
|
||
id: "v5",
|
||
title: "سمزدایی گوارشی با اسید هومیک",
|
||
doctor: "دکتر ریکاردو کوخ",
|
||
duration: "۴:۰۰",
|
||
thumbnail: "https://images.unsplash.com/photo-1581594693702-fbdc51b2763b?auto=format&fit=crop&q=80&w=600",
|
||
videoUrl: "https://www.w3schools.com/html/mov_bbb.mp4",
|
||
description: "مکانیزم عمل Moor-Tranke در جذب توکسینهای رودهای."
|
||
}
|
||
];
|
||
|
||
import { useRouter } from 'next/navigation';
|
||
|
||
export default function VideosPage() {
|
||
const router = useRouter();
|
||
const [selectedVideo, setSelectedVideo] = useState<typeof ALL_VIDEOS[0] | null>(null);
|
||
const [search, setSearch] = useState("");
|
||
|
||
const filteredVideos = ALL_VIDEOS.filter(v =>
|
||
v.title.includes(search) || v.doctor.includes(search)
|
||
);
|
||
|
||
return (
|
||
<div className="min-h-screen bg-medical-gray-900 pt-8 pb-20 px-4 font-vazir" dir="rtl">
|
||
<div className="max-w-7xl mx-auto">
|
||
{/* Header */}
|
||
<div className="flex flex-col md:flex-row items-center justify-between mb-16 gap-6">
|
||
<div className="text-right">
|
||
<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">
|
||
<PlayCircle className="w-3 h-3" />
|
||
Video Academy
|
||
</div>
|
||
<h1 className="text-4xl lg:text-6xl font-black text-white italic leading-tight">
|
||
آکادمی ویدئویی <span className="text-canina-blue">کانینا</span>
|
||
</h1>
|
||
</div>
|
||
<button
|
||
onClick={() => router.push('/')}
|
||
className="px-8 py-3 bg-white/5 border border-white/10 rounded-2xl text-white shadow-sm flex items-center gap-2 font-black hover:bg-white/10 transition-all"
|
||
>
|
||
<ChevronRight className="w-5 h-5" />
|
||
بازگشت
|
||
</button>
|
||
</div>
|
||
|
||
{/* Search Bar */}
|
||
<div className="mb-12 relative max-w-2xl">
|
||
<Search className="absolute right-6 top-1/2 -translate-y-1/2 text-white/30 w-5 h-5" />
|
||
<input
|
||
type="text"
|
||
placeholder="جستجو در ویدئوهای آموزشی..."
|
||
value={search}
|
||
onChange={e => setSearch(e.target.value)}
|
||
className="w-full bg-white/5 border border-white/10 rounded-[2rem] py-5 pr-14 pl-6 text-white outline-none focus:bg-white/10 transition-all font-bold"
|
||
/>
|
||
</div>
|
||
|
||
{/* Video Grid */}
|
||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||
{filteredVideos.map((video, idx) => (
|
||
<motion.div
|
||
key={video.id}
|
||
initial={{ opacity: 0, y: 20 }}
|
||
animate={{ opacity: 1, y: 0 }}
|
||
transition={{ delay: idx * 0.1 }}
|
||
className="group cursor-pointer"
|
||
onClick={() => setSelectedVideo(video)}
|
||
>
|
||
<div className="relative aspect-video rounded-[2.5rem] overflow-hidden mb-6 shadow-2xl border border-white/5">
|
||
<img
|
||
src={video.thumbnail}
|
||
alt={video.title}
|
||
className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-700 opacity-60 group-hover:opacity-100"
|
||
referrerPolicy="no-referrer"
|
||
/>
|
||
<div className="absolute inset-0 flex items-center justify-center">
|
||
<div className="w-16 h-16 bg-canina-blue rounded-full flex items-center justify-center text-white shadow-2xl group-hover:scale-110 transition-transform">
|
||
<PlayCircle className="w-10 h-10" />
|
||
</div>
|
||
</div>
|
||
<div className="absolute bottom-4 right-4 bg-black/60 backdrop-blur-md text-white px-3 py-1 rounded-lg text-[10px] font-black">
|
||
{video.duration}
|
||
</div>
|
||
</div>
|
||
<div className="px-4">
|
||
<h3 className="text-xl font-black text-white group-hover:text-canina-blue transition-colors mb-2">{video.title}</h3>
|
||
<div className="flex items-center gap-4 text-xs font-bold text-white/40">
|
||
<div className="flex items-center gap-1">
|
||
<User className="w-3 h-3" />
|
||
{video.doctor}
|
||
</div>
|
||
<div className="flex items-center gap-1">
|
||
<Clock className="w-3 h-3" />
|
||
دسترسی دائمی
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</motion.div>
|
||
))}
|
||
</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-black/95 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-white/5 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-10 bg-gradient-to-t from-black/90 to-transparent">
|
||
<div className="flex items-center gap-2 text-canina-blue text-xs font-black mb-2 uppercase tracking-widest">
|
||
<ShieldCheck className="w-4 h-4" />
|
||
Verified Insight
|
||
</div>
|
||
<h3 className="text-white text-3xl font-black mb-2 italic">{selectedVideo.title}</h3>
|
||
<p className="text-white/60 text-lg font-medium">{selectedVideo.doctor}</p>
|
||
</div>
|
||
</motion.div>
|
||
</div>
|
||
)}
|
||
</AnimatePresence>
|
||
</div>
|
||
);
|
||
}
|