feat(ui): implement share functionality in ProductDetailPage

Add a share button with a popper menu to the ProductDetailPage, allowing users to share products via various platforms including WhatsApp, Facebook, and email. Implement snackbar notifications for user feedback on successful actions. Enhance state management to handle share popper and snackbar visibility.
This commit is contained in:
sebseb7
2025-09-18 15:35:13 +02:00
parent 33ad3dd20b
commit a13c786b0b

View File

@@ -1,5 +1,12 @@
import React, { Component } from "react";
import { Box, Container, Typography, CardMedia, Stack, Chip, Button, Collapse } from "@mui/material";
import { Box, Container, Typography, CardMedia, Stack, Chip, Button, Collapse, Popper, ClickAwayListener, MenuList, MenuItem, ListItemIcon, ListItemText, Snackbar, Alert } from "@mui/material";
import ShareIcon from "@mui/icons-material/Share";
import WhatsAppIcon from "@mui/icons-material/WhatsApp";
import FacebookIcon from "@mui/icons-material/Facebook";
import TelegramIcon from "@mui/icons-material/Telegram";
import EmailIcon from "@mui/icons-material/Email";
import LinkIcon from "@mui/icons-material/Link";
import CodeIcon from "@mui/icons-material/Code";
import { Link } from "react-router-dom";
import parse from "html-react-parser";
import AddToCartButton from "./AddToCartButton.js";
@@ -83,7 +90,14 @@ class ProductDetailPage extends Component {
// Collapsible sections state
showQuestionForm: false,
showRatingForm: false,
showAvailabilityForm: false
showAvailabilityForm: false,
// Share popper state
shareAnchorEl: null,
sharePopperOpen: false,
// Snackbar state
snackbarOpen: false,
snackbarMessage: "",
snackbarSeverity: "success"
};
} else if (partialProduct && isUpgrading) {
// Partial product data found - enter upgrading state
@@ -123,7 +137,14 @@ class ProductDetailPage extends Component {
// Collapsible sections state
showQuestionForm: false,
showRatingForm: false,
showAvailabilityForm: false
showAvailabilityForm: false,
// Share popper state
shareAnchorEl: null,
sharePopperOpen: false,
// Snackbar state
snackbarOpen: false,
snackbarMessage: "",
snackbarSeverity: "success"
};
} else {
// No cached data found - full loading state
@@ -145,7 +166,14 @@ class ProductDetailPage extends Component {
// Collapsible sections state
showQuestionForm: false,
showRatingForm: false,
showAvailabilityForm: false
showAvailabilityForm: false,
// Share popper state
shareAnchorEl: null,
sharePopperOpen: false,
// Snackbar state
snackbarOpen: false,
snackbarMessage: "",
snackbarSeverity: "success"
};
}
}
@@ -634,8 +662,116 @@ class ProductDetailPage extends Component {
}
};
// Share functionality
handleShareClick = (event) => {
this.setState({
shareAnchorEl: event.currentTarget,
sharePopperOpen: true
});
};
handleShareClose = () => {
this.setState({
shareAnchorEl: null,
sharePopperOpen: false
});
};
showSnackbar = (message, severity = "success") => {
this.setState({
snackbarOpen: true,
snackbarMessage: message,
snackbarSeverity: severity
});
};
handleSnackbarClose = (event, reason) => {
if (reason === 'clickaway') {
return;
}
this.setState({ snackbarOpen: false });
};
getProductUrl = () => {
return `${window.location.origin}/Artikel/${this.props.seoName}`;
};
handleEmbedShare = () => {
const embedCode = `<iframe src="${this.getProductUrl()}" width="100%" height="600" frameborder="0"></iframe>`;
navigator.clipboard.writeText(embedCode).then(() => {
this.showSnackbar("Einbettungscode wurde in die Zwischenablage kopiert!");
}).catch(() => {
// Fallback for older browsers
try {
const textArea = document.createElement('textarea');
textArea.value = embedCode;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
this.showSnackbar("Einbettungscode wurde in die Zwischenablage kopiert!");
} catch {
this.showSnackbar("Fehler beim Kopieren des Einbettungscodes", "error");
}
});
this.handleShareClose();
};
handleWhatsAppShare = () => {
const url = this.getProductUrl();
const text = `Schau dir dieses Produkt an: ${cleanProductName(this.state.product.name)}`;
const whatsappUrl = `https://wa.me/?text=${encodeURIComponent(text + ' ' + url)}`;
window.open(whatsappUrl, '_blank');
this.handleShareClose();
};
handleFacebookShare = () => {
const url = this.getProductUrl();
const facebookUrl = `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url)}`;
window.open(facebookUrl, '_blank');
this.handleShareClose();
};
handleTelegramShare = () => {
const url = this.getProductUrl();
const text = `Schau dir dieses Produkt an: ${cleanProductName(this.state.product.name)}`;
const telegramUrl = `https://t.me/share/url?url=${encodeURIComponent(url)}&text=${encodeURIComponent(text)}`;
window.open(telegramUrl, '_blank');
this.handleShareClose();
};
handleEmailShare = () => {
const url = this.getProductUrl();
const subject = `Produktempfehlung: ${cleanProductName(this.state.product.name)}`;
const body = `Hallo,\n\nich möchte dir dieses Produkt empfehlen:\n\n${cleanProductName(this.state.product.name)}\n${url}\n\nViele Grüße`;
const emailUrl = `mailto:?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
window.location.href = emailUrl;
this.handleShareClose();
};
handleLinkCopy = () => {
const url = this.getProductUrl();
navigator.clipboard.writeText(url).then(() => {
this.showSnackbar("Link wurde in die Zwischenablage kopiert!");
}).catch(() => {
// Fallback for older browsers
try {
const textArea = document.createElement('textarea');
textArea.value = url;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
this.showSnackbar("Link wurde in die Zwischenablage kopiert!");
} catch {
this.showSnackbar("Fehler beim Kopieren des Links", "error");
}
});
this.handleShareClose();
};
render() {
const { product, loading, upgrading, error, attributeImages, isSteckling, attributes, komponentenLoaded, komponentenData, komponentenImages, totalKomponentenPrice, totalSavings } =
const { product, loading, upgrading, error, attributeImages, isSteckling, attributes, komponentenLoaded, komponentenData, komponentenImages, totalKomponentenPrice, totalSavings, shareAnchorEl, sharePopperOpen, snackbarOpen, snackbarMessage, snackbarSeverity } =
this.state;
// Debug alerts removed
@@ -1127,8 +1263,32 @@ class ProductDetailPage extends Component {
background: "#fff",
borderRadius: 2,
boxShadow: "0 2px 8px rgba(0,0,0,0.08)",
position: "relative",
}}
>
{/* Share button */}
<Button
onClick={this.handleShareClick}
startIcon={<ShareIcon fontSize="small" />}
sx={{
position: "absolute",
top: 8,
right: 8,
backgroundColor: "#f5f5f5",
"&:hover": {
backgroundColor: "#e0e0e0",
},
zIndex: 1,
fontSize: "0.75rem",
px: 1.5,
py: 0.5,
minWidth: "auto",
textTransform: "none",
}}
size="small"
>
Teilen
</Button>
<Box
sx={{
mt: 2,
@@ -1150,6 +1310,65 @@ class ProductDetailPage extends Component {
</Box>
)}
{/* Share Popper */}
<Popper
open={sharePopperOpen}
anchorEl={shareAnchorEl}
placement="bottom-end"
sx={{ zIndex: 1300 }}
>
<ClickAwayListener onClickAway={this.handleShareClose}>
<Box
sx={{
bgcolor: "background.paper",
border: "1px solid #ccc",
borderRadius: 1,
boxShadow: "0 4px 8px rgba(0,0,0,0.1)",
minWidth: 200,
}}
>
<MenuList>
<MenuItem onClick={this.handleEmbedShare}>
<ListItemIcon>
<CodeIcon fontSize="small" />
</ListItemIcon>
<ListItemText primary="Einbetten" />
</MenuItem>
<MenuItem onClick={this.handleWhatsAppShare}>
<ListItemIcon>
<WhatsAppIcon fontSize="small" sx={{ color: "#25D366" }} />
</ListItemIcon>
<ListItemText primary="WhatsApp" />
</MenuItem>
<MenuItem onClick={this.handleTelegramShare}>
<ListItemIcon>
<TelegramIcon fontSize="small" sx={{ color: "#0088CC" }} />
</ListItemIcon>
<ListItemText primary="Telegram" />
</MenuItem>
<MenuItem onClick={this.handleFacebookShare}>
<ListItemIcon>
<FacebookIcon fontSize="small" sx={{ color: "#1877F2" }} />
</ListItemIcon>
<ListItemText primary="Facebook" />
</MenuItem>
<MenuItem onClick={this.handleEmailShare}>
<ListItemIcon>
<EmailIcon fontSize="small" />
</ListItemIcon>
<ListItemText primary="E-Mail" />
</MenuItem>
<MenuItem onClick={this.handleLinkCopy}>
<ListItemIcon>
<LinkIcon fontSize="small" />
</ListItemIcon>
<ListItemText primary="Link kopieren" />
</MenuItem>
</MenuList>
</Box>
</ClickAwayListener>
</Popper>
{/* Article Question Form */}
<Collapse in={this.state.showQuestionForm}>
<div id="question-form">
@@ -1379,9 +1598,26 @@ class ProductDetailPage extends Component {
</Box>
</Box>
)}
{/* Snackbar for user feedback */}
<Snackbar
open={snackbarOpen}
autoHideDuration={4000}
onClose={this.handleSnackbarClose}
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
>
<Alert
onClose={this.handleSnackbarClose}
severity={snackbarSeverity}
sx={{ width: '100%' }}
>
{snackbarMessage}
</Alert>
</Snackbar>
</Container>
);
}
}
export default withI18n()(ProductDetailPage);