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:
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user