System komentarzy i zaangażowania jak na YouTube.
1interface Comment {
2 id: number;
3 author: string;
4 content: string;
5 likes: number;
6 replies: Comment[];
7 createdAt: string;
8}
9
10function CommentsList({ videoId }: { videoId: number }) {
11 const [comments, setComments] = useState<Comment[]>([]);
12 const [newComment, setNewComment] = useState("");
13
14 const handleSubmit = async (e: React.FormEvent) => {
15 e.preventDefault();
16 const res = await fetch(`/api/videos/${videoId}/comments`, {
17 method: 'POST',
18 body: JSON.stringify({ content: newComment }),
19 headers: { 'Content-Type': 'application/json' }
20 });
21 const data = await res.json();
22 setComments([data.comment, ...comments]);
23 setNewComment("");
24 };
25
26 return (
27 <div>
28 <form onSubmit={handleSubmit} className="mb-6">
29 <textarea
30 value={newComment}
31 onChange={(e) => setNewComment(e.target.value)}
32 className="w-full border rounded p-3"
33 />
34 <button
35 type="submit"
36 className="bg-blue-600 text-white px-4 py-2 rounded mt-2"
37 >
38 Comment
39 </button>
40 </form>
41
42 <div className="space-y-4">
43 {comments.map(comment => (
44 <CommentCard key={comment.id} comment={comment} />
45 ))}
46 </div>
47 </div>
48 );
49}
50
51function CommentCard({ comment }: { comment: Comment }) {
52 return (
53 <div className="flex gap-3">
54 <div className="w-10 h-10 bg-gray-300 rounded-full" />
55 <div className="flex-1">
56 <div className="flex items-center gap-2 mb-1">
57 <span className="font-bold">{comment.author}</span>
58 <span className="text-sm text-gray-500">{comment.createdAt}</span>
59 </div>
60 <p className="text-gray-800 mb-2">{comment.content}</p>
61 <div className="flex gap-4 text-sm">
62 <button className="hover:text-blue-600">
63 👍 {comment.likes}
64 </button>
65 <button className="hover:text-blue-600">Reply</button>
66 </div>
67 </div>
68 </div>
69 );
70}1function EngagementButtons({ videoId }: { videoId: number }) {
2 const [liked, setLiked] = useState(false);
3 const [subscribed, setSubscribed] = useState(false);
4 const [likes, setLikes] = useState(0);
5
6 const handleLike = async () => {
7 await fetch(`/api/videos/${videoId}/like`, { method: 'POST' });
8 setLiked(!liked);
9 setLikes(liked ? likes - 1 : likes + 1);
10 };
11
12 const handleSubscribe = async () => {
13 await fetch(`/api/channels/subscribe`, { method: 'POST' });
14 setSubscribed(!subscribed);
15 };
16
17 return (
18 <div className="flex gap-4">
19 <button
20 onClick={handleLike}
21 className={`px-4 py-2 rounded ${liked ? 'bg-blue-600 text-white' : 'bg-gray-200'}`}
22 >
23 👍 {likes}
24 </button>
25 <button
26 onClick={handleSubscribe}
27 className={`px-6 py-2 rounded ${subscribed ? 'bg-gray-800 text-white' : 'bg-red-600 text-white'}`}
28 >
29 {subscribed ? 'Subscribed' : 'Subscribe'}
30 </button>
31 </div>
32 );
33}1function NotificationBell() {
2 const [notifications, setNotifications] = useState<Notification[]>([]);
3 const [open, setOpen] = useState(false);
4
5 useEffect(() => {
6 // Poll for new notifications
7 const interval = setInterval(async () => {
8 const res = await fetch('/api/notifications');
9 const data = await res.json();
10 setNotifications(data.notifications);
11 }, 30000); // Every 30s
12
13 return () => clearInterval(interval);
14 }, []);
15
16 return (
17 <div className="relative">
18 <button onClick={() => setOpen(!open)} className="relative">
19 🔔
20 {notifications.length > 0 && (
21 <span className="absolute -top-1 -right-1 bg-red-600 text-white text-xs rounded-full w-5 h-5 flex items-center justify-center">
22 {notifications.length}
23 </span>
24 )}
25 </button>
26
27 {open && (
28 <div className="absolute top-full right-0 w-80 bg-white border rounded shadow-lg mt-2 max-h-96 overflow-auto">
29 {notifications.map(notif => (
30 <div key={notif.id} className="p-3 border-b hover:bg-gray-50">
31 <p className="text-sm">{notif.message}</p>
32 <span className="text-xs text-gray-500">{notif.createdAt}</span>
33 </div>
34 ))}
35 </div>
36 )}
37 </div>
38 );
39}✅ Comments - nested replies, threading ✅ Like/Dislike - engagement buttons ✅ Subscribe - channel subscriptions ✅ Notifications - real-time updates
Do zobaczenia! 🚀