Add article interaction forms: Implemented ArticleAvailabilityForm, ArticleQuestionForm, and ArticleRatingForm components for user inquiries, ratings, and availability requests. Integrated photo upload functionality and enhanced user experience with collapsible sections in ProductDetailPage for better interaction with product details.
This commit is contained in:
225
src/components/ArticleQuestionForm.js
Normal file
225
src/components/ArticleQuestionForm.js
Normal file
@@ -0,0 +1,225 @@
|
||||
import React, { Component } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
TextField,
|
||||
Button,
|
||||
Paper,
|
||||
Alert,
|
||||
CircularProgress
|
||||
} from '@mui/material';
|
||||
import { withI18n } from '../i18n/withTranslation.js';
|
||||
import PhotoUpload from './PhotoUpload.js';
|
||||
|
||||
class ArticleQuestionForm extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
name: '',
|
||||
email: '',
|
||||
question: '',
|
||||
photos: [],
|
||||
loading: false,
|
||||
success: false,
|
||||
error: null
|
||||
};
|
||||
}
|
||||
|
||||
handleInputChange = (field) => (event) => {
|
||||
this.setState({ [field]: event.target.value });
|
||||
};
|
||||
|
||||
handlePhotosChange = (files) => {
|
||||
this.setState({ photos: files });
|
||||
};
|
||||
|
||||
convertPhotosToBase64 = (photos) => {
|
||||
return Promise.all(
|
||||
photos.map(photo => {
|
||||
return new Promise((resolve, _reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
resolve({
|
||||
name: photo.name,
|
||||
type: photo.type,
|
||||
size: photo.size,
|
||||
data: e.target.result // base64 string
|
||||
});
|
||||
};
|
||||
reader.readAsDataURL(photo);
|
||||
});
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
this.setState({ loading: true });
|
||||
|
||||
try {
|
||||
// Convert photos to base64
|
||||
const photosBase64 = await this.convertPhotosToBase64(this.state.photos);
|
||||
|
||||
// Prepare data for API emission
|
||||
const questionData = {
|
||||
type: 'article_question',
|
||||
productId: this.props.productId,
|
||||
productName: this.props.productName,
|
||||
name: this.state.name,
|
||||
email: this.state.email,
|
||||
question: this.state.question,
|
||||
photos: photosBase64,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
// Emit data via socket
|
||||
console.log('Article Question Data to emit:', questionData);
|
||||
|
||||
if (this.props.socket) {
|
||||
this.props.socket.emit('article_question_submit', questionData);
|
||||
|
||||
// Set up response handler
|
||||
this.props.socket.once('article_question_response', (response) => {
|
||||
if (response.success) {
|
||||
this.setState({
|
||||
loading: false,
|
||||
success: true,
|
||||
name: '',
|
||||
email: '',
|
||||
question: '',
|
||||
photos: []
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
loading: false,
|
||||
error: response.error || 'Ein Fehler ist aufgetreten'
|
||||
});
|
||||
}
|
||||
|
||||
// Clear messages after 3 seconds
|
||||
setTimeout(() => {
|
||||
this.setState({ success: false, error: null });
|
||||
}, 3000);
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
this.setState({
|
||||
loading: false,
|
||||
error: 'Fehler beim Verarbeiten der Fotos'
|
||||
});
|
||||
}
|
||||
|
||||
// Fallback timeout in case backend doesn't respond
|
||||
setTimeout(() => {
|
||||
if (this.state.loading) {
|
||||
this.setState({
|
||||
loading: false,
|
||||
success: true,
|
||||
name: '',
|
||||
email: '',
|
||||
question: '',
|
||||
photos: []
|
||||
});
|
||||
|
||||
// Clear success message after 3 seconds
|
||||
setTimeout(() => {
|
||||
this.setState({ success: false });
|
||||
}, 3000);
|
||||
}
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { name, email, question, loading, success, error } = this.state;
|
||||
|
||||
return (
|
||||
<Paper sx={{ p: 3, mt: 4, borderRadius: 2, boxShadow: "0 2px 8px rgba(0,0,0,0.08)" }}>
|
||||
<Typography variant="h5" gutterBottom sx={{ fontWeight: 600, color: '#333' }}>
|
||||
Frage zum Artikel
|
||||
</Typography>
|
||||
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
|
||||
Haben Sie eine Frage zu diesem Artikel? Wir helfen Ihnen gerne weiter.
|
||||
</Typography>
|
||||
|
||||
{success && (
|
||||
<Alert severity="success" sx={{ mb: 3 }}>
|
||||
Vielen Dank für Ihre Frage! Wir werden uns schnellstmöglich bei Ihnen melden.
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<Alert severity="error" sx={{ mb: 3 }}>
|
||||
{error}
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Box component="form" onSubmit={this.handleSubmit} sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||||
<TextField
|
||||
label="Name"
|
||||
value={name}
|
||||
onChange={this.handleInputChange('name')}
|
||||
required
|
||||
fullWidth
|
||||
disabled={loading}
|
||||
placeholder="Ihr Name"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label="E-Mail"
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={this.handleInputChange('email')}
|
||||
required
|
||||
fullWidth
|
||||
disabled={loading}
|
||||
placeholder="ihre.email@example.com"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label="Ihre Frage"
|
||||
value={question}
|
||||
onChange={this.handleInputChange('question')}
|
||||
required
|
||||
fullWidth
|
||||
multiline
|
||||
rows={4}
|
||||
disabled={loading}
|
||||
placeholder="Beschreiben Sie Ihre Frage zu diesem Artikel..."
|
||||
/>
|
||||
|
||||
<PhotoUpload
|
||||
onChange={this.handlePhotosChange}
|
||||
disabled={loading}
|
||||
maxFiles={3}
|
||||
label="Fotos zur Frage anhängen (optional)"
|
||||
/>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
disabled={loading || !name || !email || !question}
|
||||
sx={{
|
||||
mt: 2,
|
||||
py: 1.5,
|
||||
fontSize: '1rem',
|
||||
fontWeight: 600
|
||||
}}
|
||||
>
|
||||
{loading ? (
|
||||
<>
|
||||
<CircularProgress size={20} sx={{ mr: 1 }} />
|
||||
Wird gesendet...
|
||||
</>
|
||||
) : (
|
||||
'Frage senden'
|
||||
)}
|
||||
</Button>
|
||||
</Box>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withI18n()(ArticleQuestionForm);
|
||||
Reference in New Issue
Block a user