refactor + bilder injection safer
This commit is contained in:
211
src/pages/Company/CompanyPage.jsx
Normal file
211
src/pages/Company/CompanyPage.jsx
Normal file
@@ -0,0 +1,211 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import {
|
||||
Box, Typography, Alert, IconButton, Tooltip,
|
||||
Dialog, DialogTitle, DialogContent, DialogActions,
|
||||
Button, Stack, TextField, CircularProgress
|
||||
} from '@mui/material';
|
||||
import { DataGrid } from '@mui/x-data-grid';
|
||||
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import { Chip } from '@mui/material';
|
||||
import axiosInstance from '../../api/axiosInstance.js';
|
||||
import EditOutlinedIcon from "@mui/icons-material/EditOutlined";
|
||||
import {useNavigate} from "react-router-dom";
|
||||
|
||||
export default function CompanyPage() {
|
||||
const [rows, setRows] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [creating, setCreating] = useState(false);
|
||||
const [creatingError, setCreatingError] = useState('');
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [createForm, setCreateForm] = useState({
|
||||
name: '',
|
||||
email: ''
|
||||
});
|
||||
|
||||
const loadCompanies = async () => {
|
||||
try {
|
||||
const { data } = await axiosInstance.get('/company');
|
||||
setRows(data);
|
||||
} catch {
|
||||
setError('Fehler beim Laden der Unternehmen');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadCompanies();
|
||||
}, []);
|
||||
|
||||
const handleFormChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setCreateForm((prev) => ({ ...prev, [name]: value }));
|
||||
};
|
||||
|
||||
const handleCreate = async () => {
|
||||
setCreating(true);
|
||||
setCreatingError('');
|
||||
|
||||
try {
|
||||
const jsonPayload = {
|
||||
name: createForm.name,
|
||||
ownerEmail: createForm.email
|
||||
};
|
||||
|
||||
await axiosInstance.post('/company', jsonPayload);
|
||||
|
||||
await loadCompanies(); // Liste neu laden
|
||||
handleCreateClose();
|
||||
|
||||
} catch (err) {
|
||||
setCreatingError(err.response?.data?.message ?? 'Erstellen fehlgeschlagen');
|
||||
} finally {
|
||||
setCreating(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreateClose = () => {
|
||||
setOpen(false);
|
||||
setCreateForm({ name: '', email: '' });
|
||||
setCreatingError('');
|
||||
};
|
||||
|
||||
const handleDelete = async (id) => {
|
||||
if (!window.confirm('Unternehmen wirklich löschen?')) return;
|
||||
|
||||
try {
|
||||
await axiosInstance.delete(`/company/${id}`);
|
||||
setRows((prev) => prev.filter((r) => r.id !== id));
|
||||
} catch (err){
|
||||
alert(err.response?.data?.message ?? 'Löschen fehlgeschlagen');
|
||||
}
|
||||
};
|
||||
|
||||
const handleEdit = (id) => {
|
||||
navigate(`/companies/${id}/edit`);
|
||||
}
|
||||
|
||||
const columns = [
|
||||
{ field: 'id', headerName: 'ID', width: 70 },
|
||||
{ field: 'name', headerName: 'Name', flex: 1.5 },
|
||||
{
|
||||
field: 'ownerEmail',
|
||||
headerName: 'Verwalter',
|
||||
flex: 2,
|
||||
renderCell: ({ value }) => (
|
||||
<Box sx={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', color: 'text.secondary', fontSize: 13 }}>
|
||||
{value}
|
||||
</Box>
|
||||
),
|
||||
},
|
||||
{
|
||||
field: 'active',
|
||||
headerName: 'Status',
|
||||
width: 150,
|
||||
renderCell: ({ value }) => (
|
||||
<Chip
|
||||
label={value ? 'Aktiv' : 'Inaktiv'}
|
||||
color={value ? 'success' : 'default'}
|
||||
size="small"
|
||||
variant={value ? 'filled' : 'outlined'}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
field: 'actions',
|
||||
headerName: '',
|
||||
width: 120,
|
||||
sortable: false,
|
||||
renderCell: ({ row }) => (
|
||||
<Tooltip title="">
|
||||
<IconButton title="löschen" size="small" color="error" onClick={() => handleDelete(row.id)}>
|
||||
<DeleteOutlineIcon fontSize="small" />
|
||||
</IconButton>
|
||||
<IconButton title="bearbeiten" size="small" color="grey" onClick={() => handleEdit(row.id)}>
|
||||
<EditOutlinedIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Box>
|
||||
{/* Header */}
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 3 }}>
|
||||
<Typography variant="h5" fontWeight={600}>Unternehmen</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
startIcon={<AddIcon />}
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
Unternehmen erstellen
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
{error && <Alert severity="error" sx={{ mb: 2 }}>{error}</Alert>}
|
||||
|
||||
{/* Tabelle */}
|
||||
<Box sx={{ bgcolor: 'white', borderRadius: 2, border: '1px solid', borderColor: 'divider' }}>
|
||||
<DataGrid
|
||||
rows={rows}
|
||||
columns={columns}
|
||||
loading={loading}
|
||||
autoHeight
|
||||
pageSizeOptions={[25, 50, 100]}
|
||||
initialState={{ pagination: { paginationModel: { pageSize: 25 } } }}
|
||||
disableRowSelectionOnClick
|
||||
sx={{ border: 'none' }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{/* Create Dialog */}
|
||||
<Dialog open={open} onClose={handleCreateClose} maxWidth="sm" fullWidth>
|
||||
<DialogTitle sx={{ fontWeight: 600}}>Unternehmen erstellen</DialogTitle>
|
||||
|
||||
<DialogContent>
|
||||
<Stack spacing={2.5} sx={{ mt: 1 }}>
|
||||
{creatingError && <Alert severity="error">{creatingError}</Alert>}
|
||||
|
||||
<TextField
|
||||
label="Name"
|
||||
name="name"
|
||||
value={createForm.name}
|
||||
onChange={handleFormChange}
|
||||
fullWidth
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label="Verwalter Email"
|
||||
name="email"
|
||||
type="email"
|
||||
value={createForm.email}
|
||||
onChange={handleFormChange}
|
||||
fullWidth
|
||||
/>
|
||||
</Stack>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions sx={{ px: 3, pb: 2.5 }}>
|
||||
<Button onClick={handleCreateClose} disabled={creating}>
|
||||
Abbrechen
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleCreate}
|
||||
disabled={creating}
|
||||
startIcon={creating ? <CircularProgress size={16} color="inherit" /> : null}
|
||||
>
|
||||
Erstellen
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user