feat: enhance ProductDetailPage to support partial data loading and improve user feedback with loading descriptions
This commit is contained in:
47
.vscode/launch.json
vendored
47
.vscode/launch.json
vendored
@@ -16,7 +16,8 @@
|
|||||||
"skipFiles": [
|
"skipFiles": [
|
||||||
"<node_internals>/**"
|
"<node_internals>/**"
|
||||||
]
|
]
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
"name": "Start",
|
"name": "Start",
|
||||||
"type": "node-terminal",
|
"type": "node-terminal",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
@@ -28,6 +29,50 @@
|
|||||||
"skipFiles": [
|
"skipFiles": [
|
||||||
"<node_internals>/**"
|
"<node_internals>/**"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "chrome",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch Chrome - Debug React App",
|
||||||
|
"url": "https://dev.seedheads.de",
|
||||||
|
"webRoot": "${workspaceFolder}/src",
|
||||||
|
"sourceMapPathOverrides": {
|
||||||
|
"webpack://reactshop/./src/*": "${webRoot}/*",
|
||||||
|
"webpack://reactshop/src/*": "${webRoot}/*",
|
||||||
|
"webpack:///src/*": "${webRoot}/*",
|
||||||
|
"webpack:///./src/*": "${webRoot}/*",
|
||||||
|
"webpack:///./*": "${workspaceFolder}/*",
|
||||||
|
"webpack:///./~/*": "${workspaceFolder}/node_modules/*",
|
||||||
|
"webpack://*": "${workspaceFolder}/*"
|
||||||
|
},
|
||||||
|
"smartStep": true,
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**",
|
||||||
|
"${workspaceFolder}/node_modules/**",
|
||||||
|
"${workspaceFolder}/dist/**"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "chrome",
|
||||||
|
"request": "attach",
|
||||||
|
"name": "Attach to Chrome - Debug React App",
|
||||||
|
"port": 9222,
|
||||||
|
"webRoot": "${workspaceFolder}/src",
|
||||||
|
"sourceMapPathOverrides": {
|
||||||
|
"webpack://reactshop/./src/*": "${webRoot}/*",
|
||||||
|
"webpack://reactshop/src/*": "${webRoot}/*",
|
||||||
|
"webpack:///src/*": "${webRoot}/*",
|
||||||
|
"webpack:///./src/*": "${webRoot}/*",
|
||||||
|
"webpack:///./*": "${workspaceFolder}/*",
|
||||||
|
"webpack:///./~/*": "${workspaceFolder}/node_modules/*",
|
||||||
|
"webpack://*": "${workspaceFolder}/*"
|
||||||
|
},
|
||||||
|
"smartStep": true,
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**",
|
||||||
|
"${workspaceFolder}/node_modules/**",
|
||||||
|
"${workspaceFolder}/dist/**"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,12 +21,34 @@ class ProductDetailPage extends Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
if (
|
// First try to find cached data by seoName (complete data)
|
||||||
window.productDetailCache &&
|
let cachedData = null;
|
||||||
window.productDetailCache[this.props.seoName]
|
let partialProduct = null;
|
||||||
) {
|
let isUpgrading = false;
|
||||||
const cachedData = window.productDetailCache[this.props.seoName];
|
|
||||||
|
if (window.productDetailCache && window.productDetailCache[this.props.seoName]) {
|
||||||
|
cachedData = window.productDetailCache[this.props.seoName];
|
||||||
|
} else if (window.productDetailCache) {
|
||||||
|
// If not found by seoName, search for partial data by checking all cached products
|
||||||
|
// Look for a product where the seoName matches this.props.seoName
|
||||||
|
for (const key in window.productDetailCache) {
|
||||||
|
const cached = window.productDetailCache[key];
|
||||||
|
if (cached && cached.seoName === this.props.seoName) {
|
||||||
|
partialProduct = cached;
|
||||||
|
isUpgrading = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Also check if cached is a product object directly (from category cache)
|
||||||
|
if (cached && typeof cached === 'object' && cached.seoName === this.props.seoName) {
|
||||||
|
partialProduct = cached;
|
||||||
|
isUpgrading = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cachedData) {
|
||||||
|
// Complete cached data found
|
||||||
// Clean up prerender fallback since we have cached data
|
// Clean up prerender fallback since we have cached data
|
||||||
if (typeof window !== "undefined" && window.__PRERENDER_FALLBACK__) {
|
if (typeof window !== "undefined" && window.__PRERENDER_FALLBACK__) {
|
||||||
delete window.__PRERENDER_FALLBACK__;
|
delete window.__PRERENDER_FALLBACK__;
|
||||||
@@ -46,6 +68,7 @@ class ProductDetailPage extends Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
product: cachedData.product,
|
product: cachedData.product,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
upgrading: false,
|
||||||
error: null,
|
error: null,
|
||||||
attributeImages: {},
|
attributeImages: {},
|
||||||
attributes: cachedData.attributes || [],
|
attributes: cachedData.attributes || [],
|
||||||
@@ -62,10 +85,52 @@ class ProductDetailPage extends Component {
|
|||||||
showRatingForm: false,
|
showRatingForm: false,
|
||||||
showAvailabilityForm: false
|
showAvailabilityForm: false
|
||||||
};
|
};
|
||||||
|
} else if (partialProduct && isUpgrading) {
|
||||||
|
// Partial product data found - enter upgrading state
|
||||||
|
console.log("ProductDetailPage: Found partial product data, entering upgrading state");
|
||||||
|
|
||||||
|
// Clean up prerender fallback since we have some data
|
||||||
|
if (typeof window !== "undefined" && window.__PRERENDER_FALLBACK__) {
|
||||||
|
delete window.__PRERENDER_FALLBACK__;
|
||||||
|
console.log("ProductDetailPage: Cleaned up prerender fallback using partial product data");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize komponenten from partial product data if available
|
||||||
|
const komponenten = [];
|
||||||
|
if(partialProduct.komponenten) {
|
||||||
|
for(const komponent of partialProduct.komponenten.split(",")) {
|
||||||
|
// Handle both "x" and "×" as separators
|
||||||
|
const [id, count] = komponent.split(/[x×]/);
|
||||||
|
komponenten.push({id: id.trim(), count: count.trim()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
product: partialProduct,
|
||||||
|
loading: false,
|
||||||
|
upgrading: true, // This indicates we have partial data and are loading complete data
|
||||||
|
error: null,
|
||||||
|
attributeImages: {},
|
||||||
|
attributes: [], // Will be loaded when upgrading
|
||||||
|
isSteckling: false,
|
||||||
|
imageDialogOpen: false,
|
||||||
|
komponenten: komponenten,
|
||||||
|
komponentenLoaded: komponenten.length === 0, // If no komponenten, mark as loaded
|
||||||
|
komponentenData: {}, // Store individual komponent data with loading states
|
||||||
|
komponentenImages: {}, // Store tiny pictures for komponenten
|
||||||
|
totalKomponentenPrice: 0,
|
||||||
|
totalSavings: 0,
|
||||||
|
// Collapsible sections state
|
||||||
|
showQuestionForm: false,
|
||||||
|
showRatingForm: false,
|
||||||
|
showAvailabilityForm: false
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
|
// No cached data found - full loading state
|
||||||
this.state = {
|
this.state = {
|
||||||
product: null,
|
product: null,
|
||||||
loading: true,
|
loading: true,
|
||||||
|
upgrading: false,
|
||||||
error: null,
|
error: null,
|
||||||
attributeImages: {},
|
attributeImages: {},
|
||||||
attributes: [],
|
attributes: [],
|
||||||
@@ -86,8 +151,8 @@ class ProductDetailPage extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
// Only load product data if not already cached
|
// Load product data if we have no product or if we're in upgrading state
|
||||||
if (!this.state.product) {
|
if (!this.state.product || this.state.upgrading) {
|
||||||
this.loadProductData();
|
this.loadProductData();
|
||||||
} else {
|
} else {
|
||||||
// Product is cached, but we still need to load komponenten if they exist
|
// Product is cached, but we still need to load komponenten if they exist
|
||||||
@@ -102,7 +167,7 @@ class ProductDetailPage extends Component {
|
|||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (prevProps.seoName !== this.props.seoName)
|
if (prevProps.seoName !== this.props.seoName)
|
||||||
this.setState(
|
this.setState(
|
||||||
{ product: null, loading: true, error: null, imageDialogOpen: false },
|
{ product: null, loading: true, upgrading: false, error: null, imageDialogOpen: false },
|
||||||
this.loadProductData
|
this.loadProductData
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -373,6 +438,7 @@ class ProductDetailPage extends Component {
|
|||||||
this.setState({
|
this.setState({
|
||||||
product: res.product,
|
product: res.product,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
upgrading: false, // Clear upgrading state since we now have complete data
|
||||||
error: null,
|
error: null,
|
||||||
imageDialogOpen: false,
|
imageDialogOpen: false,
|
||||||
attributes: res.attributes,
|
attributes: res.attributes,
|
||||||
@@ -526,14 +592,15 @@ class ProductDetailPage extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { product, loading, error, attributeImages, isSteckling, attributes, komponentenLoaded, komponentenData, komponentenImages, totalKomponentenPrice, totalSavings } =
|
const { product, loading, upgrading, error, attributeImages, isSteckling, attributes, komponentenLoaded, komponentenData, komponentenImages, totalKomponentenPrice, totalSavings } =
|
||||||
this.state;
|
this.state;
|
||||||
|
|
||||||
// Debug alerts removed
|
// Debug alerts removed
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (loading) {
|
if (loading && !upgrading) {
|
||||||
|
// Only show full loading screen when we have no product data at all
|
||||||
// Check if prerender fallback is available
|
// Check if prerender fallback is available
|
||||||
if (typeof window !== "undefined" && window.__PRERENDER_FALLBACK__) {
|
if (typeof window !== "undefined" && window.__PRERENDER_FALLBACK__) {
|
||||||
return (
|
return (
|
||||||
@@ -977,7 +1044,7 @@ class ProductDetailPage extends Component {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* Product full description */}
|
{/* Product full description */}
|
||||||
{product.description && (
|
{(product.description || upgrading) && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
mt: 4,
|
mt: 4,
|
||||||
@@ -995,7 +1062,15 @@ class ProductDetailPage extends Component {
|
|||||||
"& strong": { fontWeight: 600 },
|
"& strong": { fontWeight: 600 },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{parse(product.description)}
|
{product.description ? (
|
||||||
|
parse(product.description)
|
||||||
|
) : upgrading ? (
|
||||||
|
<Box sx={{ textAlign: "center", py: 2 }}>
|
||||||
|
<Typography variant="body1" color="text.secondary">
|
||||||
|
{this.props.t ? this.props.t('product.loadingDescription') : 'Produktbeschreibung wird geladen...'}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
) : null}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export default {
|
export default {
|
||||||
"loading": "Produkt wird geladen...",
|
"loading": "Produkt wird geladen...",
|
||||||
|
"loadingDescription": "Produktbeschreibung wird geladen...",
|
||||||
"notFound": "Produkt nicht gefunden",
|
"notFound": "Produkt nicht gefunden",
|
||||||
"notFoundDescription": "Das gesuchte Produkt existiert nicht oder wurde entfernt.",
|
"notFoundDescription": "Das gesuchte Produkt existiert nicht oder wurde entfernt.",
|
||||||
"backToHome": "Zurück zur Startseite",
|
"backToHome": "Zurück zur Startseite",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export default {
|
export default {
|
||||||
"loading": "Loading product...", // Produkt wird geladen...
|
"loading": "Loading product...", // Produkt wird geladen...
|
||||||
|
"loadingDescription": "Loading product description...", // Produktbeschreibung wird geladen...
|
||||||
"notFound": "Product not found", // Produkt nicht gefunden
|
"notFound": "Product not found", // Produkt nicht gefunden
|
||||||
"notFoundDescription": "The product you are looking for does not exist or has been removed.", // Das gesuchte Produkt existiert nicht oder wurde entfernt.
|
"notFoundDescription": "The product you are looking for does not exist or has been removed.", // Das gesuchte Produkt existiert nicht oder wurde entfernt.
|
||||||
"backToHome": "Back to homepage", // Zurück zur Startseite
|
"backToHome": "Back to homepage", // Zurück zur Startseite
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { io } from 'socket.io-client';
|
|||||||
class SocketManager {
|
class SocketManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.socket = io('', {
|
this.socket = io('', {
|
||||||
transports: ["websocket"],
|
transports: ["websocket", "polling"],
|
||||||
autoConnect: false
|
autoConnect: false
|
||||||
});
|
});
|
||||||
|
|
||||||
this.emit = this.emit.bind(this);
|
this.emit = this.emit.bind(this);
|
||||||
|
|||||||
Reference in New Issue
Block a user