File size: 5,467 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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import { useEffect, useState, useRef } from 'react';
import MovieSection from './MovieSection.jsx';
import CombinedRegionSection from './CombinedRegionSection.jsx';

const SECTION_CONFIGS = [
  { type: 'newest', title: 'Phim mới cập nhật', href: '/danh-sach/phim-moi-cap-nhat' },
  { type: 'series', title: 'Phim bộ đặc sắc', href: '/danh-sach/phim-bo' },
  { type: 'single', title: 'Phim Điện Ảnh Mới Coóng', href: '/danh-sach/phim-le' },
  { category: 'phim-chieu-rap', title: 'Mãn Nhãn với Phim Chiếu Rạp', href: '/the-loai/phim-chieu-rap' },
  { type: 'cartoon', title: 'Thế giới hoạt hình', href: '/danh-sach/hoat-hinh' },
  { country: 'trung-quoc', title: 'Phim Trung Quốc mới', href: '/quoc-gia/trung-quoc' },
  { country: 'han-quoc', title: 'Phim Hàn Quốc mới', href: '/quoc-gia/han-quoc' },
  { country: 'au-my', title: 'Phim Âu-Mỹ mới', href: '/quoc-gia/au-my' }
];

export default function HomeSectionsLoader() {
  const [loadedSections, setLoadedSections] = useState([]);
  const [loading, setLoading] = useState(false);
  const [currentIndex, setCurrentIndex] = useState(0);
  const loaderRef = useRef(null);

  const fetchSectionData = async (config) => {
    try {
      const params = new URLSearchParams();
      if (config.type) params.append('type', config.type);
      if (config.category) params.append('category', config.category);
      if (config.country) params.append('country', config.country);

      const res = await fetch(`/api/movies?${params.toString()}`);
      if (!res.ok) throw new Error('Failed to fetch movies');
      const data = await res.json();
      return data.items || [];
    } catch (e) {
      console.error(`[HomeSectionsLoader] Error loading ${config.title}:`, e);
      return [];
    }
  };

  // Tải danh mục tiếp theo khi cuộn xuống
  const loadNextSection = async () => {
    if (loading || currentIndex >= SECTION_CONFIGS.length) return;
    
    setLoading(true);
    const config = SECTION_CONFIGS[currentIndex];
    const movies = await fetchSectionData(config);
    
    if (movies.length > 0) {
      setLoadedSections(prev => {
        if (prev.some(s => s.title === config.title)) return prev;
        return [...prev, { ...config, movies }];
      });
    }
    
    setCurrentIndex(prev => prev + 1);
    setLoading(false);
  };

  // Lần đầu tải 2 Section đầu tiên để lấp đầy khung nhìn ngay lập tức
  useEffect(() => {
    let active = true;

    const initLoad = async () => {
      setLoading(true);
      
      // Load Section 1
      const config1 = SECTION_CONFIGS[0];
      const movies1 = await fetchSectionData(config1);
      if (active && movies1.length > 0) {
        setLoadedSections([{ ...config1, movies: movies1 }]);
      }
      
      // Load Section 2
      const config2 = SECTION_CONFIGS[1];
      const movies2 = await fetchSectionData(config2);
      if (active && movies2.length > 0) {
        setLoadedSections(prev => [...prev, { ...config2, movies: movies2 }]);
      }
      
      if (active) {
        setCurrentIndex(2);
        setLoading(false);
      }
    };

    initLoad();

    return () => {
      active = false;
    };
  }, []);

  // Lắng nghe Intersection Observer để kích hoạt tải Section tiếp theo khi cuộn xuống gần cuối
  useEffect(() => {
    if (!loaderRef.current || currentIndex >= SECTION_CONFIGS.length || loading) return;

    const observer = new IntersectionObserver((entries) => {
      const target = entries[0];
      if (target.isIntersecting && !loading) {
        loadNextSection();
      }
    }, {
      rootMargin: '350px', // Bắt đầu tải ngầm trước khi cuộn tới 350px để tạo trải nghiệm bất tận mượt mà
      threshold: 0.1
    });

    observer.observe(loaderRef.current);
    return () => observer.disconnect();
  }, [currentIndex, loading]);

  const normalSections = loadedSections.filter(sec => !['trung-quoc', 'han-quoc', 'au-my'].includes(sec.country));
  const regionSections = loadedSections.filter(sec => ['trung-quoc', 'han-quoc', 'au-my'].includes(sec.country));

  return (
    <div className="space-y-4">
      {normalSections.map((sec, i) => (
        <MovieSection 
          key={`${sec.type || sec.category || sec.country}-${i}`} 
          title={sec.title} 
          movies={sec.movies} 
          href={sec.href} 
        />
      ))}

      {regionSections.length > 0 && (
        <CombinedRegionSection sections={regionSections} />
      )}

      {/* Điểm kích hoạt cuộn tải Section */}
      {currentIndex < SECTION_CONFIGS.length && (
        <div ref={loaderRef} className="flex flex-col items-center justify-center py-12">
          {loading && (
            <>
              <div className="relative flex h-16 w-16 items-center justify-center">
                {/* Vòng quay hiệu ứng Neon cao cấp */}
                <div className="absolute inset-0 animate-spin rounded-full border-4 border-t-primary border-r-accent border-b-transparent border-l-transparent"></div>
                <div className="h-6 w-6 animate-pulse rounded-full bg-primary/80 blur-[2px]"></div>
              </div>
              <span className="mt-4 text-xs font-black uppercase tracking-widest text-gray-500 animate-pulse">
                Đang tải thêm danh mục phim...
              </span>
            </>
          )}
        </div>
      )}
    </div>
  );
}