refactor: remove socket context dependencies and streamline socket handling in components for improved performance and readability
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
import React, { useState, useEffect, useContext } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import Box from '@mui/material/Box';
|
import Box from '@mui/material/Box';
|
||||||
import Paper from '@mui/material/Paper';
|
import Paper from '@mui/material/Paper';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import SocketContext from '../contexts/SocketContext.js';
|
|
||||||
|
|
||||||
// @note SwashingtonCP font is now loaded globally via index.css
|
// @note SwashingtonCP font is now loaded globally via index.css
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ const CategoryBox = ({
|
|||||||
const [imageUrl, setImageUrl] = useState(null);
|
const [imageUrl, setImageUrl] = useState(null);
|
||||||
const [imageError, setImageError] = useState(false);
|
const [imageError, setImageError] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const context = useContext(SocketContext);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let objectUrl = null;
|
let objectUrl = null;
|
||||||
@@ -60,11 +60,10 @@ const CategoryBox = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If socket is available and connected, fetch the image
|
if (id && !isLoading) {
|
||||||
if (context && context.socket /*&& context.socket.connected*/ && id && !isLoading) {
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
context.socket.emit('getCategoryPic', { categoryId: id }, (response) => {
|
window.socketManager.emit('getCategoryPic', { categoryId: id }, (response) => {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
@@ -119,7 +118,7 @@ const CategoryBox = ({
|
|||||||
URL.revokeObjectURL(objectUrl);
|
URL.revokeObjectURL(objectUrl);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [context, context?.socket?.connected, id, isLoading]);
|
}, [id, isLoading]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper
|
<Paper
|
||||||
|
|||||||
@@ -224,19 +224,6 @@ class Content extends Component {
|
|||||||
this.fetchSearchData(this.props.searchParams?.get('q'));
|
this.fetchSearchData(this.props.searchParams?.get('q'));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.loaded) {
|
|
||||||
// Socket just connected and we haven't loaded data yet, retry loading
|
|
||||||
if (this.props.params.categoryId) {
|
|
||||||
this.fetchCategoryData(this.props.params.categoryId);
|
|
||||||
} else if (this.props.searchParams?.get('q')) {
|
|
||||||
this.fetchSearchData(this.props.searchParams?.get('q'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
processData(response) {
|
processData(response) {
|
||||||
@@ -278,19 +265,13 @@ class Content extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (!this.props.socket || !this.props.socket.connected) {
|
|
||||||
// Socket not connected yet, but don't show error immediately on first load
|
|
||||||
// The componentDidUpdate will retry when socket connects
|
|
||||||
// console.log("Socket not connected yet, waiting for connection to fetch category data");
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
console.log(`productList:${categoryId}`);
|
console.log(`productList:${categoryId}`);
|
||||||
this.props.socket.off(`productList:${categoryId}`);
|
window.socketManager.off(`productList:${categoryId}`);
|
||||||
|
|
||||||
// Track if we've received the full response to ignore stub response if needed
|
// Track if we've received the full response to ignore stub response if needed
|
||||||
let receivedFullResponse = false;
|
let receivedFullResponse = false;
|
||||||
|
|
||||||
this.props.socket.on(`productList:${categoryId}`,(response) => {
|
window.socketManager.on(`productList:${categoryId}`,(response) => {
|
||||||
console.log("getCategoryProducts full response", response);
|
console.log("getCategoryProducts full response", response);
|
||||||
receivedFullResponse = true;
|
receivedFullResponse = true;
|
||||||
setCachedCategoryData(categoryId, response);
|
setCachedCategoryData(categoryId, response);
|
||||||
@@ -301,7 +282,7 @@ class Content extends Component {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.props.socket.emit("getCategoryProducts", { categoryId: categoryId },
|
window.socketManager.emit("getCategoryProducts", { categoryId: categoryId },
|
||||||
(response) => {
|
(response) => {
|
||||||
console.log("getCategoryProducts stub response", response);
|
console.log("getCategoryProducts stub response", response);
|
||||||
// Only process stub response if we haven't received the full response yet
|
// Only process stub response if we haven't received the full response yet
|
||||||
@@ -365,14 +346,7 @@ class Content extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fetchSearchData(query) {
|
fetchSearchData(query) {
|
||||||
// if (!this.props.socket || !this.props.socket.connected) {
|
window.socketManager.emit("getSearchProducts", { query },
|
||||||
// Socket not connected yet, but don't show error immediately on first load
|
|
||||||
// The componentDidUpdate will retry when socket connects
|
|
||||||
// console.log("Socket not connected yet, waiting for connection to fetch search data");
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
this.props.socket.emit("getSearchProducts", { query },
|
|
||||||
(response) => {
|
(response) => {
|
||||||
if (response && response.products) {
|
if (response && response.products) {
|
||||||
this.processData(response);
|
this.processData(response);
|
||||||
@@ -734,8 +708,6 @@ class Content extends Component {
|
|||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<ProductList
|
<ProductList
|
||||||
socket={this.props.socket}
|
|
||||||
socketB={this.props.socketB}
|
|
||||||
totalProductCount={(this.state.unfilteredProducts || []).length}
|
totalProductCount={(this.state.unfilteredProducts || []).length}
|
||||||
products={this.state.filteredProducts || []}
|
products={this.state.filteredProducts || []}
|
||||||
activeAttributeFilters={this.state.activeAttributeFilters || []}
|
activeAttributeFilters={this.state.activeAttributeFilters || []}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import LoupeIcon from '@mui/icons-material/Loupe';
|
|||||||
class Images extends Component {
|
class Images extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = { mainPic:0,pics:[], needsSocketRetry: false };
|
this.state = { mainPic:0,pics:[] };
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
@@ -22,15 +22,6 @@ class Images extends Component {
|
|||||||
if (prevProps.fullscreenOpen !== this.props.fullscreenOpen) {
|
if (prevProps.fullscreenOpen !== this.props.fullscreenOpen) {
|
||||||
this.updatePics();
|
this.updatePics();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retry loading images if socket just became available
|
|
||||||
const wasConnected = prevProps.socketB && prevProps.socketB.connected;
|
|
||||||
const isNowConnected = this.props.socketB && this.props.socketB.connected;
|
|
||||||
|
|
||||||
if (!wasConnected && isNowConnected && this.state.needsSocketRetry) {
|
|
||||||
this.setState({ needsSocketRetry: false });
|
|
||||||
this.updatePics();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePics = (newMainPic = this.state.mainPic) => {
|
updatePics = (newMainPic = this.state.mainPic) => {
|
||||||
@@ -85,14 +76,9 @@ class Images extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadPic = (size,bildId,index) => {
|
loadPic = (size,bildId,index) => {
|
||||||
// Check if socketB is available and connected before emitting
|
|
||||||
if (!this.props.socketB || !this.props.socketB.connected) {
|
|
||||||
console.log("Images: socketB not available, will retry when connected");
|
|
||||||
this.setState({ needsSocketRetry: true });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.socketB.emit('getPic', { bildId, size }, (res) => {
|
|
||||||
|
window.socketManager.emit('getPic', { bildId, size }, (res) => {
|
||||||
if(res.success){
|
if(res.success){
|
||||||
const url = URL.createObjectURL(new Blob([res.imageBuffer], { type: 'image/jpeg' }));
|
const url = URL.createObjectURL(new Blob([res.imageBuffer], { type: 'image/jpeg' }));
|
||||||
|
|
||||||
@@ -116,44 +102,6 @@ class Images extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
// Prerender detection - if no sockets, render simple CardMedia with static path
|
|
||||||
if (!this.props.socketB) {
|
|
||||||
const getImagePath = (pictureList) => {
|
|
||||||
if (!pictureList || !pictureList.trim()) {
|
|
||||||
return '/assets/images/nopicture.jpg';
|
|
||||||
}
|
|
||||||
return `/assets/images/prod${pictureList.split(',')[0].trim()}.jpg`;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Box sx={{ position: 'relative', display: 'inline-block', width: '499px', maxWidth: '100%' }}>
|
|
||||||
<CardMedia
|
|
||||||
component="img"
|
|
||||||
height="400"
|
|
||||||
image={getImagePath(this.props.pictureList)}
|
|
||||||
alt={this.props.productName || 'Produktbild'}
|
|
||||||
fetchPriority="high"
|
|
||||||
loading="eager"
|
|
||||||
sx={{
|
|
||||||
objectFit: 'contain',
|
|
||||||
cursor: 'pointer',
|
|
||||||
transition: 'transform 0.2s ease-in-out',
|
|
||||||
width: '499px',
|
|
||||||
maxWidth: '100%',
|
|
||||||
'&:hover': {
|
|
||||||
transform: 'scale(1.02)'
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
<Stack direction="row" spacing={2} sx={{ justifyContent: 'flex-start', mt: 1, mb: 1 }}>
|
|
||||||
{/* Empty thumbnail gallery for prerender - reserves the mt+mb spacing (16px) */}
|
|
||||||
</Stack>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SPA version - full functionality with static fallback
|
// SPA version - full functionality with static fallback
|
||||||
const getImageSrc = () => {
|
const getImageSrc = () => {
|
||||||
// If dynamic image is loaded, use it
|
// If dynamic image is loaded, use it
|
||||||
|
|||||||
@@ -27,17 +27,8 @@ class Product extends Component {
|
|||||||
this.state = {image:window.smallPicCache[bildId],loading:false, error: false}
|
this.state = {image:window.smallPicCache[bildId],loading:false, error: false}
|
||||||
}else{
|
}else{
|
||||||
this.state = {image: null, loading: true, error: false};
|
this.state = {image: null, loading: true, error: false};
|
||||||
console.log("Product: Fetching image from socketB", this.props.socketB);
|
|
||||||
|
|
||||||
// Check if socketB is available and connected before emitting
|
this.loadImage(bildId);
|
||||||
if (this.props.socketB && this.props.socketB.connected) {
|
|
||||||
this.loadImage(bildId);
|
|
||||||
} else {
|
|
||||||
// Socket not available, set error state or wait
|
|
||||||
console.log("Product: socketB not available, will retry when connected");
|
|
||||||
this.state.error = true;
|
|
||||||
this.state.loading = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
this.state = {image: null, loading: false, error: false};
|
this.state = {image: null, loading: false, error: false};
|
||||||
@@ -48,24 +39,9 @@ class Product extends Component {
|
|||||||
this._isMounted = true;
|
this._isMounted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
// Retry loading image if socket just became available
|
|
||||||
const wasConnected = prevProps.socketB && prevProps.socketB.connected;
|
|
||||||
const isNowConnected = this.props.socketB && this.props.socketB.connected;
|
|
||||||
|
|
||||||
if (!wasConnected && isNowConnected && this.state.error && this.props.pictureList) {
|
|
||||||
// Socket just connected and we had an error, retry loading
|
|
||||||
const bildId = this.props.pictureList.split(',')[0];
|
|
||||||
if (!window.smallPicCache[bildId]) {
|
|
||||||
this.setState({loading: true, error: false});
|
|
||||||
this.loadImage(bildId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadImage = (bildId) => {
|
loadImage = (bildId) => {
|
||||||
if (this.props.socketB && this.props.socketB.connected) {
|
|
||||||
this.props.socketB.emit('getPic', { bildId, size:'small' }, (res) => {
|
window.socketManager.emit('getPic', { bildId, size:'small' }, (res) => {
|
||||||
if(res.success){
|
if(res.success){
|
||||||
window.smallPicCache[bildId] = URL.createObjectURL(new Blob([res.imageBuffer], { type: 'image/jpeg' }));
|
window.smallPicCache[bildId] = URL.createObjectURL(new Blob([res.imageBuffer], { type: 'image/jpeg' }));
|
||||||
if (this._isMounted) {
|
if (this._isMounted) {
|
||||||
@@ -85,7 +61,7 @@ class Product extends Component {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this._isMounted = false;
|
this._isMounted = false;
|
||||||
|
|||||||
@@ -105,15 +105,6 @@ class ProductDetailPage extends Component {
|
|||||||
{ product: null, loading: true, error: null, imageDialogOpen: false },
|
{ product: null, loading: true, error: null, imageDialogOpen: false },
|
||||||
this.loadProductData
|
this.loadProductData
|
||||||
);
|
);
|
||||||
|
|
||||||
// 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.loading) {
|
|
||||||
// Socket just connected and we're still loading, retry loading data
|
|
||||||
this.loadProductData();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadKomponentImage = (komponentId, pictureList) => {
|
loadKomponentImage = (komponentId, pictureList) => {
|
||||||
@@ -141,14 +132,8 @@ class ProductDetailPage extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if socketB is available
|
|
||||||
if (!this.props.socketB || !this.props.socketB.connected) {
|
|
||||||
console.log("SocketB not connected yet, skipping image load for komponent:", komponentId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch image from server
|
// Fetch image from server
|
||||||
this.props.socketB.emit('getPic', { bildId, size: 'small' }, (res) => {
|
window.socketManager.emit('getPic', { bildId, size: 'small' }, (res) => {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
// Cache the image
|
// Cache the image
|
||||||
window.smallPicCache[bildId] = URL.createObjectURL(new Blob([res.imageBuffer], { type: 'image/jpeg' }));
|
window.smallPicCache[bildId] = URL.createObjectURL(new Blob([res.imageBuffer], { type: 'image/jpeg' }));
|
||||||
@@ -229,12 +214,6 @@ class ProductDetailPage extends Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not cached, fetch from server (similar to loadProductData)
|
|
||||||
//if (!this.props.socket || !this.props.socket.connected) {
|
|
||||||
// console.log("Socket not connected yet, waiting for connection to load komponent data");
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Mark this komponent as loading
|
// Mark this komponent as loading
|
||||||
this.setState(prevState => ({
|
this.setState(prevState => ({
|
||||||
komponentenData: {
|
komponentenData: {
|
||||||
@@ -248,7 +227,7 @@ class ProductDetailPage extends Component {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.props.socket.emit(
|
window.socketManager.emit(
|
||||||
"getProductView",
|
"getProductView",
|
||||||
{ articleId: id },
|
{ articleId: id },
|
||||||
(res) => {
|
(res) => {
|
||||||
@@ -359,13 +338,8 @@ class ProductDetailPage extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadProductData = () => {
|
loadProductData = () => {
|
||||||
if (!this.props.socket || !this.props.socket.connected) {
|
|
||||||
// Socket not connected yet, but don't show error immediately on first load
|
|
||||||
// The componentDidUpdate will retry when socket connects
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.socket.emit(
|
window.socketManager.emit(
|
||||||
"getProductView",
|
"getProductView",
|
||||||
{ seoName: this.props.seoName },
|
{ seoName: this.props.seoName },
|
||||||
(res) => {
|
(res) => {
|
||||||
@@ -434,8 +408,8 @@ class ProductDetailPage extends Component {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Not in cache, fetch from server
|
// Not in cache, fetch from server
|
||||||
if (this.props.socketB && this.props.socketB.connected) {
|
|
||||||
this.props.socketB.emit(
|
window.socketManager.emit(
|
||||||
"getAttributePicture",
|
"getAttributePicture",
|
||||||
{ id: cacheKey },
|
{ id: cacheKey },
|
||||||
(res) => {
|
(res) => {
|
||||||
@@ -469,7 +443,7 @@ class ProductDetailPage extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -698,8 +672,6 @@ class ProductDetailPage extends Component {
|
|||||||
>
|
>
|
||||||
<ProductImage
|
<ProductImage
|
||||||
product={product}
|
product={product}
|
||||||
socket={this.props.socket}
|
|
||||||
socketB={this.props.socketB}
|
|
||||||
fullscreenOpen={this.state.imageDialogOpen}
|
fullscreenOpen={this.state.imageDialogOpen}
|
||||||
onOpenFullscreen={this.handleOpenDialog}
|
onOpenFullscreen={this.handleOpenDialog}
|
||||||
onCloseFullscreen={this.handleCloseDialog}
|
onCloseFullscreen={this.handleCloseDialog}
|
||||||
@@ -1032,7 +1004,6 @@ class ProductDetailPage extends Component {
|
|||||||
<ArticleQuestionForm
|
<ArticleQuestionForm
|
||||||
productId={product.id}
|
productId={product.id}
|
||||||
productName={cleanProductName(product.name)}
|
productName={cleanProductName(product.name)}
|
||||||
socket={this.props.socket}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
@@ -1043,7 +1014,6 @@ class ProductDetailPage extends Component {
|
|||||||
<ArticleRatingForm
|
<ArticleRatingForm
|
||||||
productId={product.id}
|
productId={product.id}
|
||||||
productName={cleanProductName(product.name)}
|
productName={cleanProductName(product.name)}
|
||||||
socket={this.props.socket}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
@@ -1054,7 +1024,6 @@ class ProductDetailPage extends Component {
|
|||||||
<ArticleAvailabilityForm
|
<ArticleAvailabilityForm
|
||||||
productId={product.id}
|
productId={product.id}
|
||||||
productName={cleanProductName(product.name)}
|
productName={cleanProductName(product.name)}
|
||||||
socket={this.props.socket}
|
|
||||||
/>
|
/>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useParams, useNavigate, useLocation } from 'react-router-dom';
|
import { useParams, useNavigate, useLocation } from 'react-router-dom';
|
||||||
import SocketContext from '../contexts/SocketContext.js';
|
|
||||||
import ProductDetailPage from './ProductDetailPage.js';
|
import ProductDetailPage from './ProductDetailPage.js';
|
||||||
|
|
||||||
// Wrapper component for individual product detail page with socket
|
|
||||||
const ProductDetailWithSocket = () => {
|
const ProductDetailWithSocket = () => {
|
||||||
const { seoName } = useParams();
|
const { seoName } = useParams();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SocketContext.Consumer>
|
<ProductDetailPage seoName={seoName} navigate={navigate} location={location} />
|
||||||
{({socket,socketB}) => <ProductDetailPage seoName={seoName} navigate={navigate} location={location} socket={socket} socketB={socketB} />}
|
|
||||||
</SocketContext.Consumer>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import React, { useContext, useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import IconButton from "@mui/material/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import ChevronLeft from "@mui/icons-material/ChevronLeft";
|
import ChevronLeft from "@mui/icons-material/ChevronLeft";
|
||||||
import ChevronRight from "@mui/icons-material/ChevronRight";
|
import ChevronRight from "@mui/icons-material/ChevronRight";
|
||||||
import CategoryBox from "./CategoryBox.js";
|
import CategoryBox from "./CategoryBox.js";
|
||||||
import SocketContext from "../contexts/SocketContext.js";
|
|
||||||
import { useCarousel } from "../contexts/CarouselContext.js";
|
import { useCarousel } from "../contexts/CarouselContext.js";
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
@@ -62,7 +61,6 @@ const initializeCategories = (language = 'en') => {
|
|||||||
|
|
||||||
const SharedCarousel = () => {
|
const SharedCarousel = () => {
|
||||||
const { carouselRef, filteredCategories, setFilteredCategories, moveCarousel } = useCarousel();
|
const { carouselRef, filteredCategories, setFilteredCategories, moveCarousel } = useCarousel();
|
||||||
const context = useContext(SocketContext);
|
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const [rootCategories, setRootCategories] = useState([]);
|
const [rootCategories, setRootCategories] = useState([]);
|
||||||
const [currentLanguage, setCurrentLanguage] = useState(i18n.language || 'de');
|
const [currentLanguage, setCurrentLanguage] = useState(i18n.language || 'de');
|
||||||
@@ -94,13 +92,11 @@ const SharedCarousel = () => {
|
|||||||
}, [i18n]);
|
}, [i18n]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Only fetch from socket if we don't already have categories
|
|
||||||
if (
|
if (
|
||||||
rootCategories.length === 0 &&
|
rootCategories.length === 0 &&
|
||||||
context && context.socket && context.socket.connected &&
|
|
||||||
typeof window !== "undefined"
|
typeof window !== "undefined"
|
||||||
) {
|
) {
|
||||||
context.socket.emit("categoryList", { categoryId: 209, language: currentLanguage, requestTranslation: true }, (response) => {
|
window.socketManager.emit("categoryList", { categoryId: 209, language: currentLanguage, requestTranslation: true }, (response) => {
|
||||||
if (response && response.success) {
|
if (response && response.success) {
|
||||||
// Use translated data if available, otherwise fall back to original
|
// Use translated data if available, otherwise fall back to original
|
||||||
const categoryTreeToUse = response.translation || response.categoryTree;
|
const categoryTreeToUse = response.translation || response.categoryTree;
|
||||||
@@ -136,7 +132,7 @@ const SharedCarousel = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [context, context?.socket?.connected, rootCategories.length, currentLanguage]);
|
}, [rootCategories.length, currentLanguage]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const filtered = rootCategories.filter(
|
const filtered = rootCategories.filter(
|
||||||
|
|||||||
@@ -3,32 +3,90 @@ import { io } from 'socket.io-client';
|
|||||||
|
|
||||||
class SocketManager {
|
class SocketManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
||||||
this.socket = io('', {
|
this.socket = io('', {
|
||||||
transports: ["websocket"],
|
transports: ["websocket"],
|
||||||
autoConnect: false
|
autoConnect: false
|
||||||
});
|
});
|
||||||
|
|
||||||
this.emit = this.emit.bind(this);
|
this.emit = this.emit.bind(this);
|
||||||
|
this.on = this.on.bind(this);
|
||||||
|
this.off = this.off.bind(this);
|
||||||
|
this.connectPromise = null;
|
||||||
|
this.pendingListeners = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
on(event, callback) {
|
||||||
|
// If socket is already connected, register the listener directly
|
||||||
|
if (this.socket.connected) {
|
||||||
|
this.socket.on(event, callback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the listener to be registered when connection is established
|
||||||
|
if (!this.pendingListeners.has(event)) {
|
||||||
|
this.pendingListeners.set(event, new Set());
|
||||||
|
}
|
||||||
|
this.pendingListeners.get(event).add(callback);
|
||||||
|
|
||||||
|
// If not already connecting, initiate connection
|
||||||
|
if (!this.connectPromise) {
|
||||||
|
this.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the listener now, it will receive events once connected
|
||||||
|
this.socket.on(event, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
off(event, callback) {
|
||||||
|
// Remove from socket listeners
|
||||||
|
this.socket.off(event, callback);
|
||||||
|
|
||||||
|
// Remove from pending listeners if present
|
||||||
|
if (this.pendingListeners.has(event)) {
|
||||||
|
const listeners = this.pendingListeners.get(event);
|
||||||
|
listeners.delete(callback);
|
||||||
|
if (listeners.size === 0) {
|
||||||
|
this.pendingListeners.delete(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
if (this.connectPromise) return this.connectPromise;
|
||||||
|
|
||||||
|
this.connectPromise = new Promise((resolve, reject) => {
|
||||||
|
this.socket.connect();
|
||||||
|
|
||||||
|
this.socket.once('connect', () => {
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.once('connect_error', (error) => {
|
||||||
|
this.connectPromise = null;
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.connectPromise;
|
||||||
|
}
|
||||||
|
|
||||||
emit(event, ...args) {
|
emit(event, ...args) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!this.socket.connected) {
|
if (!this.socket.connected) {
|
||||||
// Connect the socket first
|
// If not already connecting, start connection
|
||||||
this.socket.connect();
|
if (!this.connectPromise) {
|
||||||
|
this.connect();
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for connection before emitting
|
// Wait for connection before emitting
|
||||||
this.socket.once('connect', () => {
|
this.connectPromise
|
||||||
this.socket.emit(event, ...args);
|
.then(() => {
|
||||||
resolve();
|
this.socket.emit(event, ...args);
|
||||||
});
|
resolve();
|
||||||
|
})
|
||||||
// Handle connection error
|
.catch((error) => {
|
||||||
this.socket.once('connect_error', (error) => {
|
reject(error);
|
||||||
reject(error);
|
});
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
// Socket already connected, emit directly
|
// Socket already connected, emit directly
|
||||||
this.socket.emit(event, ...args);
|
this.socket.emit(event, ...args);
|
||||||
@@ -36,7 +94,6 @@ class SocketManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create singleton instance
|
// Create singleton instance
|
||||||
|
|||||||
Reference in New Issue
Block a user