File size: 4,329 Bytes
4bea261
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { useState, useRef } from 'react';
import MovieCard from './MovieCard';
import Pagination from './Pagination';

export default function PaginatedGrid({ initialData, category, title, query, topic, country, type }) {
  const [data, setData] = useState(initialData);
  const [loading, setLoading] = useState(false);
  const containerRef = useRef(null);

  const moviesList = data?.items || [];
  const currentPage = data?.pagination?.currentPage || 1;
  const totalPages = data?.pagination?.totalPages || 1;

  // Xây dựng đường dẫn cơ sở basePath động chuẩn chỉnh cho chuyển trang
  let basePath = '';
  if (typeof window !== 'undefined') {
    const url = new URL(window.location.href);
    url.searchParams.delete('page');
    // Giữ nguyên các tham số tìm kiếm khác (như q) nếu có
    basePath = url.pathname + url.search;
  } else {
    // Giải pháp dự phòng khi Render trên máy chủ (SSR Fallback)
    if (query) {
      basePath = `/tim-kiem?q=${encodeURIComponent(query)}`;
    } else if (topic) {
      basePath = `/chu-de/${topic}`;
    } else {
      basePath = category ? `/the-loai/${category}` : '';
    }
  }

  const handlePageChange = async (pageNum) => {
    if (pageNum === currentPage || loading) return;
    setLoading(true);

    // Cuộn mượt mà lên đầu danh sách/bảng phim với offset hợp lý
    if (containerRef.current) {
      containerRef.current.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }

    try {
      let apiUrl = `/api/movies?page=${pageNum}`;
      if (category) apiUrl += `&category=${encodeURIComponent(category)}`;
      if (topic) apiUrl += `&topic=${encodeURIComponent(topic)}`;
      if (country) apiUrl += `&country=${encodeURIComponent(country)}`;
      if (query) apiUrl += `&q=${encodeURIComponent(query)}`;
      if (type) apiUrl += `&type=${encodeURIComponent(type)}`;

      const res = await fetch(apiUrl);
      if (!res.ok) throw new Error(`HTTP error ${res.status}`);
      const json = await res.json();

      // Giãn cách một chút (300ms) để hiệu ứng chuyển trang trông premium, mượt mà và trực quan
      await new Promise((resolve) => setTimeout(resolve, 300));
      setData(json);

      // Cập nhật địa chỉ URL trình duyệt mà không gây tải lại toàn bộ trang
      const newUrl = new URL(window.location.href);
      newUrl.searchParams.set('page', String(pageNum));
      window.history.pushState({}, '', newUrl.toString());
    } catch (err) {
      console.error('Lỗi khi tải trang mới:', err);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div ref={containerRef} className="space-y-12 relative scroll-mt-28">
      {/* Hiệu ứng phủ kính Glassmorphism Loading Siêu Sang Trọng */}
      {loading && (
        <div className="absolute inset-0 z-50 bg-black/40 backdrop-blur-[2px] rounded-3xl flex items-center justify-center transition-all duration-300 animate-fade-in">
          <div className="flex flex-col items-center gap-3 bg-[#12141d]/85 border border-white/10 rounded-2xl p-6 shadow-2xl">
            <div className="h-10 w-10 border-4 border-primary/20 border-t-primary rounded-full animate-spin"></div>
            <span className="text-xs font-black uppercase tracking-widest text-primary animate-pulse">Đang cập nhật...</span>
          </div>
        </div>
      )}

      {moviesList.length === 0 ? (
        <div className="py-20 text-center text-gray-500 font-bold uppercase tracking-widest text-xs">
          Không tìm thấy phim nào
        </div>
      ) : (
        <>
          {/* Grid hiển thị danh sách phim hiện tại */}
          <div className={`grid grid-cols-2 gap-4 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 transition-all duration-300 ${loading ? 'opacity-30 blur-[1px]' : 'opacity-100'}`}>
            {moviesList.map((movie) => (
              <MovieCard key={movie._id || movie.slug} movie={movie} />
            ))}
          </div>

          {/* Phân trang tiêu chuẩn cao cấp bằng AJAX */}
          <Pagination 
            currentPage={currentPage} 
            totalPages={totalPages} 
            basePath={basePath} 
            onPageChange={handlePageChange} 
          />
        </>
      )}
    </div>
  );
}