|
@@ -82,33 +82,15 @@ export const ThemeProvider: React.FC<{ children: ReactNode }> = ({ children }) =
|
|
|
return localStorage.getItem('vista_custom_footer_logo') || null;
|
|
return localStorage.getItem('vista_custom_footer_logo') || null;
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- const [heroImages, setHeroImages] = useState<string[]>(() => {
|
|
|
|
|
- const saved = localStorage.getItem('vista_hero_images');
|
|
|
|
|
- return saved ? JSON.parse(saved) : HERO_IMAGES;
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ const [heroImages, setHeroImages] = useState<string[]>(HERO_IMAGES);
|
|
|
|
|
|
|
|
- // Fetch hero images from API when component mounts
|
|
|
|
|
|
|
+ // Fetch hero images from API on every page refresh
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
- // Check if we already have hero images in localStorage to avoid unnecessary API calls
|
|
|
|
|
- const savedImages = localStorage.getItem('vista_hero_images');
|
|
|
|
|
- if (savedImages) {
|
|
|
|
|
- return; // Skip API call if we already have images saved
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
const loadHeroImagesFromApi = async () => {
|
|
const loadHeroImagesFromApi = async () => {
|
|
|
- // Add a flag to prevent duplicate API calls in React Strict Mode
|
|
|
|
|
- const apiCallFlag = 'vista_hero_images_api_called';
|
|
|
|
|
- if (sessionStorage.getItem(apiCallFlag)) {
|
|
|
|
|
- return; // Skip if we already made the call in this session
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
try {
|
|
try {
|
|
|
// Import the functions dynamically to avoid circular dependencies
|
|
// Import the functions dynamically to avoid circular dependencies
|
|
|
const { fetchHotArticles, extractHeroImagesFromArticles } =
|
|
const { fetchHotArticles, extractHeroImagesFromArticles } =
|
|
|
await import('../services/articleService.ts');
|
|
await import('../services/articleService.ts');
|
|
|
-
|
|
|
|
|
- // Mark that we're making the API call
|
|
|
|
|
- sessionStorage.setItem(apiCallFlag, 'true');
|
|
|
|
|
|
|
|
|
|
// Fetch hot articles from the API
|
|
// Fetch hot articles from the API
|
|
|
const articlesData = await fetchHotArticles(1, 6);
|
|
const articlesData = await fetchHotArticles(1, 6);
|
|
@@ -119,20 +101,46 @@ export const ThemeProvider: React.FC<{ children: ReactNode }> = ({ children }) =
|
|
|
// If we got images from the API, use them
|
|
// If we got images from the API, use them
|
|
|
if (apiHeroImages.length > 0) {
|
|
if (apiHeroImages.length > 0) {
|
|
|
setHeroImages(apiHeroImages);
|
|
setHeroImages(apiHeroImages);
|
|
|
- // Save to localStorage so we don't fetch on every page load
|
|
|
|
|
- localStorage.setItem('vista_hero_images', JSON.stringify(apiHeroImages));
|
|
|
|
|
}
|
|
}
|
|
|
- // Otherwise, keep the default HERO_IMAGES or saved images
|
|
|
|
|
|
|
+ // Otherwise, keep the default HERO_IMAGES
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error('Failed to fetch hero images from API:', error);
|
|
console.error('Failed to fetch hero images from API:', error);
|
|
|
- // Fallback to existing images if API fails
|
|
|
|
|
- // Clear the flag if the API call failed so we can try again
|
|
|
|
|
- sessionStorage.removeItem('vista_hero_images_api_called');
|
|
|
|
|
|
|
+ // Fallback to default HERO_IMAGES if API fails
|
|
|
|
|
+ setHeroImages(HERO_IMAGES);
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
loadHeroImagesFromApi();
|
|
loadHeroImagesFromApi();
|
|
|
- }, []); // Empty dependency array means this runs only once when component mounts
|
|
|
|
|
|
|
+ }, []); // Empty dependency array means this runs on every component mount (page refresh)
|
|
|
|
|
+
|
|
|
|
|
+ // Fetch video content from API on every page refresh
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ const loadVideoContentFromApi = async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // Import the functions dynamically to avoid circular dependencies
|
|
|
|
|
+ const { fetchVideoContent, extractVideoContentFromArticles } =
|
|
|
|
|
+ await import('../services/articleService.ts');
|
|
|
|
|
+
|
|
|
|
|
+ // Fetch video content from the API (lang=1 for Chinese)
|
|
|
|
|
+ const videoData = await fetchVideoContent(1);
|
|
|
|
|
+
|
|
|
|
|
+ // Extract video content from the articles data
|
|
|
|
|
+ const videoContent = extractVideoContentFromArticles(videoData);
|
|
|
|
|
+
|
|
|
|
|
+ // If we got video content from the API, use it
|
|
|
|
|
+ if (videoContent) {
|
|
|
|
|
+ setVideoSection(videoContent);
|
|
|
|
|
+ }
|
|
|
|
|
+ // Otherwise, keep the default video content
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('Failed to fetch video content from API:', error);
|
|
|
|
|
+ // Fallback to default video content if API fails
|
|
|
|
|
+ setVideoSection(DEFAULT_VIDEO);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ loadVideoContentFromApi();
|
|
|
|
|
+ }, []); // Empty dependency array means this runs on every component mount (page refresh)
|
|
|
|
|
|
|
|
// --- Content Sections ---
|
|
// --- Content Sections ---
|
|
|
const [itineraries, setItineraries] = useState<Itinerary[]>(() => {
|
|
const [itineraries, setItineraries] = useState<Itinerary[]>(() => {
|
|
@@ -150,10 +158,7 @@ export const ThemeProvider: React.FC<{ children: ReactNode }> = ({ children }) =
|
|
|
return saved ? JSON.parse(saved) : DEFAULT_DINING;
|
|
return saved ? JSON.parse(saved) : DEFAULT_DINING;
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- const [videoSection, setVideoSection] = useState<VideoSectionContent>(() => {
|
|
|
|
|
- const saved = localStorage.getItem('vista_video');
|
|
|
|
|
- return saved ? JSON.parse(saved) : DEFAULT_VIDEO;
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ const [videoSection, setVideoSection] = useState<VideoSectionContent>(DEFAULT_VIDEO);
|
|
|
|
|
|
|
|
const [shipsPageImages, setShipsPageImages] = useState<ShipsPageImages>(() => {
|
|
const [shipsPageImages, setShipsPageImages] = useState<ShipsPageImages>(() => {
|
|
|
const saved = localStorage.getItem('vista_ships_page_images');
|
|
const saved = localStorage.getItem('vista_ships_page_images');
|
|
@@ -171,9 +176,7 @@ export const ThemeProvider: React.FC<{ children: ReactNode }> = ({ children }) =
|
|
|
else localStorage.removeItem('vista_custom_footer_logo');
|
|
else localStorage.removeItem('vista_custom_footer_logo');
|
|
|
}, [customFooterLogo]);
|
|
}, [customFooterLogo]);
|
|
|
|
|
|
|
|
- useEffect(() => {
|
|
|
|
|
- localStorage.setItem('vista_hero_images', JSON.stringify(heroImages));
|
|
|
|
|
- }, [heroImages]);
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
localStorage.setItem('vista_itineraries', JSON.stringify(itineraries));
|
|
localStorage.setItem('vista_itineraries', JSON.stringify(itineraries));
|
|
@@ -187,9 +190,7 @@ export const ThemeProvider: React.FC<{ children: ReactNode }> = ({ children }) =
|
|
|
localStorage.setItem('vista_dining', JSON.stringify(dining));
|
|
localStorage.setItem('vista_dining', JSON.stringify(dining));
|
|
|
}, [dining]);
|
|
}, [dining]);
|
|
|
|
|
|
|
|
- useEffect(() => {
|
|
|
|
|
- localStorage.setItem('vista_video', JSON.stringify(videoSection));
|
|
|
|
|
- }, [videoSection]);
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
localStorage.setItem('vista_ships_page_images', JSON.stringify(shipsPageImages));
|
|
localStorage.setItem('vista_ships_page_images', JSON.stringify(shipsPageImages));
|