From 245f5067ed8d9554fa4e7f8f466c3d10ad8090ab Mon Sep 17 00:00:00 2001 From: seb Date: Thu, 3 Jul 2025 05:36:41 +0200 Subject: [PATCH] Refactor socket handling across components to support dual socket connections, enhancing data fetching capabilities and improving overall communication. --- src/App.js | 15 ++-- src/components/CategoryBox.js | 2 +- src/components/Content.js | 1 + src/components/Header.js | 6 +- src/components/Images.js | 2 +- src/components/Product.js | 3 +- src/components/ProductDetailPage.js | 5 +- src/components/ProductDetailWithSocket.js | 2 +- src/components/ProductList.js | 1 + src/components/header/CategoryList.js | 6 +- src/components/header/SearchBar.js | 2 +- src/components/profile/CartTab.js | 6 +- .../profile/OrderProcessingService.js | 14 ++-- src/components/profile/OrdersTab.js | 2 +- src/pages/Home.js | 2 +- src/pages/ProfilePage.js | 4 +- src/pages/Sitemap.js | 3 +- src/providers/SocketProvider.js | 68 ++++++++++++++++++- webpack.config.js | 6 +- 19 files changed, 113 insertions(+), 37 deletions(-) diff --git a/src/App.js b/src/App.js index 7d18584..ecac0a7 100644 --- a/src/App.js +++ b/src/App.js @@ -165,7 +165,8 @@ const AppContent = ({ currentTheme, onThemeChange }) => { // Check if we're in development mode const isDevelopment = process.env.NODE_ENV === "development"; - const socket = useContext(SocketContext); + const {socket,socketB} = useContext(SocketContext); + console.log("AppContent: socket", socket); return ( { {/* Category page - Render Content in parallel */} } + element={} /> {/* Single product page */} { /> {/* Search page - Render Content in parallel */} - } /> + } /> {/* Profile page */} } /> @@ -218,17 +219,17 @@ const AppContent = ({ currentTheme, onThemeChange }) => { {/* Reset password page */} } + element={} /> {/* Admin page */} - } /> + } /> {/* Admin Users page */} - } /> + } /> {/* Admin Server Logs page */} - } /> + } /> {/* Legal pages */} } /> diff --git a/src/components/CategoryBox.js b/src/components/CategoryBox.js index d1d55e9..5bf2063 100644 --- a/src/components/CategoryBox.js +++ b/src/components/CategoryBox.js @@ -22,7 +22,7 @@ const CategoryBox = ({ const [imageUrl, setImageUrl] = useState(null); const [imageError, setImageError] = useState(false); const [isLoading, setIsLoading] = useState(false); - const socket = useContext(SocketContext); + const {socket} = useContext(SocketContext); useEffect(() => { let objectUrl = null; diff --git a/src/components/Content.js b/src/components/Content.js index 04c352b..4888d5b 100644 --- a/src/components/Content.js +++ b/src/components/Content.js @@ -685,6 +685,7 @@ class Content extends Component { - {(isHomePage || this.props.categoryId || isProfilePage) && } + {(isHomePage || this.props.categoryId || isProfilePage) && } ); } @@ -91,7 +91,7 @@ const HeaderWithContext = (props) => { return ( - {socket =>
} + {({socket,socketB}) =>
} ); }; diff --git a/src/components/Images.js b/src/components/Images.js index 5cd4d54..04c6a5e 100644 --- a/src/components/Images.js +++ b/src/components/Images.js @@ -77,7 +77,7 @@ class Images extends Component { } loadPic = (size,bildId,index) => { - this.props.socket.emit('getPic', { bildId, size }, (res) => { + this.props.socketB.emit('getPic', { bildId, size }, (res) => { if(res.success){ const url = URL.createObjectURL(new Blob([res.imageBuffer], { type: 'image/jpeg' })); diff --git a/src/components/Product.js b/src/components/Product.js index 701dc58..c72386e 100644 --- a/src/components/Product.js +++ b/src/components/Product.js @@ -26,7 +26,8 @@ class Product extends Component { this.state = {image:window.smallPicCache[bildId],loading:false, error: false} }else{ this.state = {image: null, loading: true, error: false}; - this.props.socket.emit('getPic', { bildId, size:'small' }, (res) => { + console.log("Product: Fetching image from socketB", this.props.socketB); + this.props.socketB.emit('getPic', { bildId, size:'small' }, (res) => { if(res.success){ window.smallPicCache[bildId] = URL.createObjectURL(new Blob([res.imageBuffer], { type: 'image/jpeg' })); if (this._isMounted) { diff --git a/src/components/ProductDetailPage.js b/src/components/ProductDetailPage.js index a4ccad8..5e84826 100644 --- a/src/components/ProductDetailPage.js +++ b/src/components/ProductDetailPage.js @@ -110,8 +110,8 @@ class ProductDetailPage extends Component { } } else { // Not in cache, fetch from server - if (this.props.socket && this.props.socket.connected) { - this.props.socket.emit( + if (this.props.socketB && this.props.socketB.connected) { + this.props.socketB.emit( "getAttributePicture", { id: cacheKey }, (res) => { @@ -334,6 +334,7 @@ class ProductDetailPage extends Component { {product.pictureList && ( { return ( - {socket => } + {({socket,socketB}) => } ); }; diff --git a/src/components/ProductList.js b/src/components/ProductList.js index fb1dc80..d4d6f39 100644 --- a/src/components/ProductList.js +++ b/src/components/ProductList.js @@ -331,6 +331,7 @@ class ProductList extends Component { versandklasse={product.versandklasse} weight={product.weight} socket={this.props.socket} + socketB={this.props.socketB} pictureList={product.pictureList} availableSupplier={product.availableSupplier} /> diff --git a/src/components/header/CategoryList.js b/src/components/header/CategoryList.js index 7f367e9..93cbb4f 100644 --- a/src/components/header/CategoryList.js +++ b/src/components/header/CategoryList.js @@ -124,11 +124,13 @@ class CategoryList extends Component { componentDidUpdate(prevProps) { // Handle socket connection changes + const wasConnected = prevProps.socket && prevProps.socket.connected; const isNowConnected = this.props.socket && this.props.socket.connected; if (!wasConnected && isNowConnected && !this.state.fetchedCategories) { // Socket just connected and we haven't fetched categories yet + this.setState( { fetchedCategories: false, @@ -158,7 +160,7 @@ class CategoryList extends Component { } if (this.state.fetchedCategories) { - //console.log('Categories already fetched, skipping'); + console.log('Categories already fetched, skipping'); return; } @@ -222,7 +224,6 @@ class CategoryList extends Component { //console.log('CategoryList: Fetching categories from socket'); socket.emit("categoryList", { categoryId: 209 }, (response) => { if (response && response.categoryTree) { - //console.log('Category tree received:', response.categoryTree); // Store in global cache with timestamp try { @@ -237,7 +238,6 @@ class CategoryList extends Component { } catch (err) { console.error("Error writing to cache:", err); } - this.processCategoryTree(response.categoryTree); } else { try { diff --git a/src/components/header/SearchBar.js b/src/components/header/SearchBar.js index 8e440a9..52b97bd 100644 --- a/src/components/header/SearchBar.js +++ b/src/components/header/SearchBar.js @@ -15,7 +15,7 @@ import SocketContext from "../../contexts/SocketContext.js"; const SearchBar = () => { const navigate = useNavigate(); const location = useLocation(); - const socket = React.useContext(SocketContext); + const {socket} = React.useContext(SocketContext); const searchParams = new URLSearchParams(location.search); // State management diff --git a/src/components/profile/CartTab.js b/src/components/profile/CartTab.js index 273f60b..e44d42e 100644 --- a/src/components/profile/CartTab.js +++ b/src/components/profile/CartTab.js @@ -67,8 +67,8 @@ class CartTab extends Component { // @note Add method to fetch and apply order template prefill data fetchOrderTemplate = () => { - if (this.context && this.context.connected) { - this.context.emit('getOrderTemplate', (response) => { + if (this.context && this.context.socket && this.context.socket.connected) { + this.context.socket.emit('getOrderTemplate', (response) => { if (response.success && response.orderTemplate) { const template = response.orderTemplate; @@ -433,7 +433,7 @@ class CartTab extends Component { {!showPaymentConfirmation && ( { const context = this.getContext(); - if (context && context.connected) { + if (context && context.socket && context.socket.connected) { const { isLoggedIn: isAuthenticated } = isUserLoggedIn(); const state = this.getState(); @@ -189,7 +189,7 @@ class OrderProcessingService { // Emit stripe order to backend via socket.io const context = this.getContext(); - context.emit("issueStripeOrder", orderData, (response) => { + context.socket.emit("issueStripeOrder", orderData, (response) => { if (response.success) { this.setState({ isCompletingOrder: false, @@ -208,8 +208,8 @@ class OrderProcessingService { // Process regular (non-Stripe) orders processRegularOrder(orderData) { const context = this.getContext(); - if (context) { - context.emit("issueOrder", orderData, (response) => { + if (context && context.socket && context.socket.connected) { + context.socket.emit("issueOrder", orderData, (response) => { if (response.success) { // Clear the cart window.cart = []; @@ -246,8 +246,8 @@ class OrderProcessingService { // Create Stripe payment intent createStripeIntent(totalAmount, loadStripeComponent) { const context = this.getContext(); - if (context) { - context.emit( + if (context && context.socket && context.socket.connected) { + context.socket.emit( "createStripeIntent", { amount: totalAmount }, (response) => { diff --git a/src/components/profile/OrdersTab.js b/src/components/profile/OrdersTab.js index fd6af0f..ad7029f 100644 --- a/src/components/profile/OrdersTab.js +++ b/src/components/profile/OrdersTab.js @@ -68,7 +68,7 @@ const OrdersTab = ({ orderIdFromHash }) => { const [selectedOrder, setSelectedOrder] = useState(null); const [isDetailsDialogOpen, setIsDetailsDialogOpen] = useState(false); - const socket = useContext(SocketContext); + const {socket} = useContext(SocketContext); const navigate = useNavigate(); const handleViewDetails = useCallback( diff --git a/src/pages/Home.js b/src/pages/Home.js index 275ae45..025621f 100644 --- a/src/pages/Home.js +++ b/src/pages/Home.js @@ -151,7 +151,7 @@ const Home = () => { const [rootCategories, setRootCategories] = useState(() => initializeCategories() ); - const socket = useContext(SocketContext); + const {socket} = useContext(SocketContext); useEffect(() => { // Only fetch from socket if we don't already have categories and we're in browser diff --git a/src/pages/ProfilePage.js b/src/pages/ProfilePage.js index f26afd8..fe6db8f 100644 --- a/src/pages/ProfilePage.js +++ b/src/pages/ProfilePage.js @@ -225,8 +225,8 @@ const ProfilePage = (props) => { // Wrap with socket context const ProfilePageWithSocket = (props) => { - const socket = useContext(SocketContext); - return ; + const {socket,socketB} = useContext(SocketContext); + return ; }; export default ProfilePageWithSocket; \ No newline at end of file diff --git a/src/pages/Sitemap.js b/src/pages/Sitemap.js index c8520b9..5d420e9 100644 --- a/src/pages/Sitemap.js +++ b/src/pages/Sitemap.js @@ -36,7 +36,8 @@ const collectAllCategories = (categoryNode, categories = [], level = 0) => { const Sitemap = () => { const [categories, setCategories] = useState([]); const [loading, setLoading] = useState(true); - const socket = useContext(SocketContext); + const {socket} = useContext(SocketContext); + const sitemapLinks = [ { title: 'Startseite', url: '/' }, diff --git a/src/providers/SocketProvider.js b/src/providers/SocketProvider.js index bd8241e..0aa8106 100644 --- a/src/providers/SocketProvider.js +++ b/src/providers/SocketProvider.js @@ -7,8 +7,10 @@ class SocketProvider extends Component { constructor(props) { super(props); this.socket = null; + this.socketB = null; this.state = { connected: false, + connectedB: false, showPrerenderFallback: true, }; } @@ -77,6 +79,66 @@ class SocketProvider extends Component { console.error("SocketProvider: Failed to reconnect"); this.handleConnectionFailure(); }); + + this.socketB = io(url, { + transports: ["websocket"], + }); + + this.socketB.on("connect", () => { + console.log("SocketProvider: connectedB"); + //this.setState({ connectedB: true }); + }); + + this.socketB.on("disconnect", () => { + //this.setState({ connectedB: false }); + console.log("SocketProvider: Socket disconnectedB"); + }); + + this.socketB.on("connect_error", (error) => { + console.error("SocketProvider: Connection errorB:", error); + }); + + this.socketB.on("reconnect_attempt", (attemptNumber) => { + console.log(`SocketProvider: Reconnection attemptB ${attemptNumber}`); + }); + + this.socketB.on("reconnect_failed", () => { + console.error("SocketProvider: Failed to reconnectB"); + }); + this.socketB.waitForConnect = (timeout = 10000) => { + return new Promise((resolve, reject) => { + if (this.socketB.connected) { + resolve(); + return; + } + + let timeoutId; + const connectHandler = () => { + clearTimeout(timeoutId); + this.socketB.off("connect", connectHandler); + this.socketB.off("connect_error", errorHandler); + resolve(); + }; + + const errorHandler = (error) => { + clearTimeout(timeoutId); + this.socketB.off("connect", connectHandler); + this.socketB.off("connect_error", errorHandler); + reject(new Error(`Socket connection failed: ${error.message}`)); + }; + + // Set up timeout + timeoutId = setTimeout(() => { + this.socketB.off("connect", connectHandler); + this.socketB.off("connect_error", errorHandler); + reject(new Error(`Socket connection timeout after ${timeout}ms`)); + }, timeout); + + // Add event listeners + this.socketB.on("connect", connectHandler); + this.socketB.on("connect_error", errorHandler); + }); + }; } handleConnectionFailure() { @@ -96,6 +158,10 @@ class SocketProvider extends Component { console.log("SocketProvider: Disconnecting socket"); this.socket.disconnect(); } + if (this.socketB) { + console.log("SocketProvider: Disconnecting socketB"); + this.socketB.disconnect(); + } } render() { @@ -104,7 +170,7 @@ class SocketProvider extends Component { window.__PRERENDER_FALLBACK__; return ( - + {/* Always render children but control visibility */}
{this.props.children} diff --git a/webpack.config.js b/webpack.config.js index 36a7573..d3a8638 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -314,7 +314,11 @@ export default { hot: true, port: 9500, open: false, - historyApiFallback: true, + historyApiFallback: { + index: '/index.html', + disableDotRule: true, + htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'] + }, client: { logging: 'verbose', overlay: {