Files
DeineDorfApp-Admin-Panel/src/pages/Company/CompanyPage.jsx

256 lines
8.9 KiB
JavaScript

import { useEffect, useState } from 'react';
import {
Box, Typography, Alert, IconButton, Tooltip,
Dialog, DialogTitle, DialogContent, DialogActions,
Button, Stack, TextField, CircularProgress, Autocomplete
} 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 [userOptions, setUserOptions] = useState([]);
const [usersLoading, setUsersLoading] = useState(false);
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 loadUsers = async () => {
setUsersLoading(true);
try {
const { data } = await axiosInstance.get('/users');
setUserOptions(data.map(u => u.email));
} catch {
setUserOptions([]);
} finally {
setUsersLoading(false);
}
}
const handleOpen = () => {
setOpen(true);
loadUsers();
}
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?.error ?? '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?.error ?? '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={() => handleOpen()}
>
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
/>
<Autocomplete
options={userOptions}
loading={usersLoading}
value={createForm.email}
onChange={(_, newValue) => {
setCreateForm(prev => ({ ...prev, email: newValue ?? '' }));
}}
onInputChange={(_, newInputValue) => {
setCreateForm(prev => ({ ...prev, email: newInputValue }));
}}
freeSolo
filterOptions={(options, { inputValue }) =>
options.filter(o => o.toLowerCase().includes(inputValue.toLowerCase()))
}
renderInput={(params) => (
<TextField
{...params}
label="Verwalter Email"
name="email"
type="email"
fullWidth
InputProps={{
...params.InputProps,
endAdornment: (
<>
{usersLoading ? <CircularProgress size={16} /> : null}
{params.InputProps.endAdornment}
</>
),
}}
/>
)}
/>
</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>
);
}