Refactor App component to replace Home page with MainPageLayout, integrating CarouselProvider for improved page structure. Added new routes for Presseverleih and ThcTest pages, enhancing navigation and organization. Updated Header component to support new page states for Aktionen and Filiale.
This commit is contained in:
225
src/contexts/CarouselContext.js
Normal file
225
src/contexts/CarouselContext.js
Normal file
@@ -0,0 +1,225 @@
|
||||
import React, { createContext, useContext, useRef, useEffect, useState } from 'react';
|
||||
|
||||
const CarouselContext = createContext();
|
||||
|
||||
export const useCarousel = () => {
|
||||
const context = useContext(CarouselContext);
|
||||
if (!context) {
|
||||
throw new Error('useCarousel must be used within a CarouselProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
export const CarouselProvider = ({ children }) => {
|
||||
const carouselRef = useRef(null);
|
||||
const scrollPositionRef = useRef(0);
|
||||
const animationIdRef = useRef(null);
|
||||
const isPausedRef = useRef(false);
|
||||
const resumeTimeoutRef = useRef(null);
|
||||
|
||||
const [filteredCategories, setFilteredCategories] = useState([]);
|
||||
|
||||
// Initialize refs properly
|
||||
useEffect(() => {
|
||||
isPausedRef.current = false;
|
||||
scrollPositionRef.current = 0;
|
||||
}, []);
|
||||
|
||||
// Auto-scroll effect
|
||||
useEffect(() => {
|
||||
if (filteredCategories.length === 0) return;
|
||||
|
||||
const startAnimation = () => {
|
||||
if (!carouselRef.current) {
|
||||
return false;
|
||||
}
|
||||
|
||||
isPausedRef.current = false;
|
||||
|
||||
const itemWidth = 146; // 130px + 16px gap
|
||||
const totalWidth = filteredCategories.length * itemWidth;
|
||||
|
||||
const animate = () => {
|
||||
if (!animationIdRef.current || isPausedRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
scrollPositionRef.current += 0.5;
|
||||
|
||||
if (scrollPositionRef.current >= totalWidth) {
|
||||
scrollPositionRef.current = 0;
|
||||
}
|
||||
|
||||
if (carouselRef.current) {
|
||||
const transform = `translateX(-${scrollPositionRef.current}px)`;
|
||||
carouselRef.current.style.transform = transform;
|
||||
}
|
||||
|
||||
animationIdRef.current = requestAnimationFrame(animate);
|
||||
};
|
||||
|
||||
if (!isPausedRef.current) {
|
||||
animationIdRef.current = requestAnimationFrame(animate);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Try immediately, then with increasing delays
|
||||
if (!startAnimation()) {
|
||||
const timeout1 = setTimeout(() => {
|
||||
if (!startAnimation()) {
|
||||
const timeout2 = setTimeout(() => {
|
||||
if (!startAnimation()) {
|
||||
const timeout3 = setTimeout(startAnimation, 2000);
|
||||
return () => clearTimeout(timeout3);
|
||||
}
|
||||
}, 1000);
|
||||
return () => clearTimeout(timeout2);
|
||||
}
|
||||
}, 100);
|
||||
|
||||
return () => {
|
||||
isPausedRef.current = true;
|
||||
clearTimeout(timeout1);
|
||||
if (animationIdRef.current) {
|
||||
cancelAnimationFrame(animationIdRef.current);
|
||||
}
|
||||
if (resumeTimeoutRef.current) {
|
||||
clearTimeout(resumeTimeoutRef.current);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return () => {
|
||||
isPausedRef.current = true;
|
||||
if (animationIdRef.current) {
|
||||
cancelAnimationFrame(animationIdRef.current);
|
||||
}
|
||||
if (resumeTimeoutRef.current) {
|
||||
clearTimeout(resumeTimeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, [filteredCategories]);
|
||||
|
||||
// Additional effect for when ref becomes available
|
||||
useEffect(() => {
|
||||
if (filteredCategories.length > 0 && carouselRef.current && !animationIdRef.current) {
|
||||
isPausedRef.current = false;
|
||||
|
||||
const itemWidth = 146;
|
||||
const totalWidth = filteredCategories.length * itemWidth;
|
||||
|
||||
const animate = () => {
|
||||
if (!animationIdRef.current || isPausedRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
scrollPositionRef.current += 0.5;
|
||||
|
||||
if (scrollPositionRef.current >= totalWidth) {
|
||||
scrollPositionRef.current = 0;
|
||||
}
|
||||
|
||||
if (carouselRef.current) {
|
||||
const transform = `translateX(-${scrollPositionRef.current}px)`;
|
||||
carouselRef.current.style.transform = transform;
|
||||
}
|
||||
|
||||
animationIdRef.current = requestAnimationFrame(animate);
|
||||
};
|
||||
|
||||
if (!isPausedRef.current) {
|
||||
animationIdRef.current = requestAnimationFrame(animate);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Manual navigation
|
||||
const moveCarousel = (direction) => {
|
||||
if (!carouselRef.current) return;
|
||||
|
||||
// Pause auto-scroll
|
||||
isPausedRef.current = true;
|
||||
if (animationIdRef.current) {
|
||||
cancelAnimationFrame(animationIdRef.current);
|
||||
animationIdRef.current = null;
|
||||
}
|
||||
|
||||
const itemWidth = 146;
|
||||
const moveAmount = itemWidth * 3;
|
||||
const totalWidth = filteredCategories.length * itemWidth;
|
||||
|
||||
if (direction === "left") {
|
||||
scrollPositionRef.current -= moveAmount;
|
||||
if (scrollPositionRef.current < 0) {
|
||||
scrollPositionRef.current = totalWidth + scrollPositionRef.current;
|
||||
}
|
||||
} else {
|
||||
scrollPositionRef.current += moveAmount;
|
||||
if (scrollPositionRef.current >= totalWidth) {
|
||||
scrollPositionRef.current = scrollPositionRef.current % totalWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply smooth transition
|
||||
carouselRef.current.style.transition = "transform 0.5s ease-in-out";
|
||||
carouselRef.current.style.transform = `translateX(-${scrollPositionRef.current}px)`;
|
||||
|
||||
// Remove transition after animation
|
||||
setTimeout(() => {
|
||||
if (carouselRef.current) {
|
||||
carouselRef.current.style.transition = "none";
|
||||
}
|
||||
}, 500);
|
||||
|
||||
// Clear existing timeout
|
||||
if (resumeTimeoutRef.current) {
|
||||
clearTimeout(resumeTimeoutRef.current);
|
||||
}
|
||||
|
||||
// Resume auto-scroll after 3 seconds
|
||||
resumeTimeoutRef.current = setTimeout(() => {
|
||||
isPausedRef.current = false;
|
||||
|
||||
const animate = () => {
|
||||
if (!animationIdRef.current || isPausedRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
scrollPositionRef.current += 0.5;
|
||||
|
||||
if (scrollPositionRef.current >= totalWidth) {
|
||||
scrollPositionRef.current = 0;
|
||||
}
|
||||
|
||||
if (carouselRef.current) {
|
||||
carouselRef.current.style.transform = `translateX(-${scrollPositionRef.current}px)`;
|
||||
}
|
||||
|
||||
animationIdRef.current = requestAnimationFrame(animate);
|
||||
};
|
||||
|
||||
animationIdRef.current = requestAnimationFrame(animate);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
const value = {
|
||||
carouselRef,
|
||||
scrollPositionRef,
|
||||
animationIdRef,
|
||||
isPausedRef,
|
||||
resumeTimeoutRef,
|
||||
filteredCategories,
|
||||
setFilteredCategories,
|
||||
moveCarousel
|
||||
};
|
||||
|
||||
return (
|
||||
<CarouselContext.Provider value={value}>
|
||||
{children}
|
||||
</CarouselContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default CarouselContext;
|
||||
Reference in New Issue
Block a user