fix: g+f+p
This commit is contained in:
@@ -1,8 +1,20 @@
|
||||
import { ThemeProvider, createTheme } from '@mui/material/styles';
|
||||
import CssBaseline from '@mui/material/CssBaseline';
|
||||
import logo from './logo.svg';
|
||||
import './App.css';
|
||||
|
||||
const theme = createTheme({
|
||||
palette: {
|
||||
primary: {
|
||||
main: '#1976d2',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<CssBaseline />
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<img src={logo} className="App-logo" alt="logo" />
|
||||
@@ -19,6 +31,7 @@ function App() {
|
||||
</a>
|
||||
</header>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,14 +37,14 @@ function GraphContainer({ vector }) {
|
||||
const options = {
|
||||
nodes: {
|
||||
borderWidth: 2,
|
||||
color: { border: '#800', background: '#F0E0D6' },
|
||||
color: { border: '#42A5F5', background: '#F0E0D6' },
|
||||
font: { size: 14 }
|
||||
},
|
||||
edges: {
|
||||
color: '#800',
|
||||
color: '#42A5F5',
|
||||
width: 2,
|
||||
arrows: 'to',
|
||||
smooth: { type: 'curvedCW' }
|
||||
smooth: { type: 'curvedCW' },
|
||||
arrows: 'none'
|
||||
},
|
||||
physics: {
|
||||
stabilization: true,
|
||||
|
||||
@@ -1,60 +1,151 @@
|
||||
import { useFormik } from 'formik';
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
TextField,
|
||||
CircularProgress,
|
||||
InputAdornment,
|
||||
IconButton,
|
||||
Snackbar,
|
||||
Alert,
|
||||
Typography,
|
||||
Paper
|
||||
} from '@mui/material';
|
||||
import { PhotoCamera, Close } from '@mui/icons-material';
|
||||
import { API_URL } from '../config';
|
||||
|
||||
function PostForm({ onPostCreated }) {
|
||||
const [text, setText] = useState('');
|
||||
const [image, setImage] = useState(null);
|
||||
const [preview, setPreview] = useState('');
|
||||
const [snackbar, setSnackbar] = useState({ open: false, message: '', severity: 'success' });
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
const formData = new FormData();
|
||||
if (text) formData.append('text', text);
|
||||
if (image) formData.append('image', image);
|
||||
const formik = useFormik({
|
||||
initialValues: {
|
||||
text: '',
|
||||
image: null
|
||||
},
|
||||
onSubmit: async (values, { setSubmitting, resetForm }) => {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
if (values.text) formData.append('text', values.text);
|
||||
if (values.image) formData.append('image', values.image);
|
||||
|
||||
const response = await fetch(`${API_URL}/posts/`, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error('Ошибка сервера');
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/posts/`, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
onPostCreated(data.vector);
|
||||
setText('');
|
||||
setImage(null);
|
||||
resetForm();
|
||||
setPreview('');
|
||||
showSnackbar('Пост успешно создан!', 'success');
|
||||
} catch (error) {
|
||||
showSnackbar(error.message || 'Ошибка создания поста', 'error');
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Post creation error:', error);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const handleImageChange = (e) => {
|
||||
const file = e.target.files[0];
|
||||
if (file) {
|
||||
setImage(file);
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => setPreview(reader.result);
|
||||
reader.readAsDataURL(file);
|
||||
formik.setFieldValue('image', file);
|
||||
setPreview(URL.createObjectURL(file));
|
||||
}
|
||||
};
|
||||
|
||||
const showSnackbar = (message, severity) => {
|
||||
setSnackbar({ open: true, message, severity });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="post-form">
|
||||
<h2>Новый пост</h2>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<textarea
|
||||
value={text}
|
||||
onChange={(e) => setText(e.target.value)}
|
||||
rows="4"
|
||||
placeholder="Текст поста"
|
||||
<Paper elevation={3} sx={{ p: 3, mb: 4, maxWidth: 600, mx: 'auto' }}>
|
||||
<Typography variant="h5" gutterBottom component="div">
|
||||
Новый пост
|
||||
</Typography>
|
||||
|
||||
<form onSubmit={formik.handleSubmit}>
|
||||
<TextField
|
||||
fullWidth
|
||||
multiline
|
||||
minRows={4}
|
||||
name="text"
|
||||
value={formik.values.text}
|
||||
onChange={formik.handleChange}
|
||||
placeholder="Текст поста..."
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
<input
|
||||
accept="image/*"
|
||||
style={{ display: 'none' }}
|
||||
id="image-upload"
|
||||
type="file"
|
||||
onChange={handleImageChange}
|
||||
/>
|
||||
<label htmlFor="image-upload">
|
||||
<IconButton component="span" color="primary">
|
||||
<PhotoCamera />
|
||||
</IconButton>
|
||||
</label>
|
||||
</InputAdornment>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<input type="file" onChange={handleImageChange} accept="image/*" />
|
||||
{preview && <img src={preview} className="preview-image" alt="Preview" />}
|
||||
<button type="submit">Отправить</button>
|
||||
|
||||
{preview && (
|
||||
<Box sx={{ mt: 2, position: 'relative' }}>
|
||||
<img
|
||||
src={preview}
|
||||
alt="Preview"
|
||||
style={{
|
||||
maxWidth: '100%',
|
||||
borderRadius: 4,
|
||||
maxHeight: 200,
|
||||
objectFit: 'cover'
|
||||
}}
|
||||
/>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
formik.setFieldValue('image', null);
|
||||
setPreview('');
|
||||
}}
|
||||
sx={{ position: 'absolute', right: 8, top: 8, bgcolor: 'background.paper' }}
|
||||
>
|
||||
<Close />
|
||||
</IconButton>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Box sx={{ mt: 3, display: 'flex', justifyContent: 'flex-end' }}>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={formik.isSubmitting || (!formik.values.text && !formik.values.image)}
|
||||
startIcon={formik.isSubmitting && <CircularProgress size={20} />}
|
||||
>
|
||||
{formik.isSubmitting ? 'Отправка...' : 'Опубликовать'}
|
||||
</Button>
|
||||
</Box>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<Snackbar
|
||||
open={snackbar.open}
|
||||
autoHideDuration={6000}
|
||||
onClose={() => setSnackbar(prev => ({ ...prev, open: false }))}
|
||||
>
|
||||
<Alert severity={snackbar.severity} sx={{ width: '100%' }}>
|
||||
{snackbar.message}
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user