autocomplete und login fehlermeldung fix

This commit is contained in:
2026-04-20 11:18:38 +02:00
parent adb797e709
commit 0b65dc5550
3 changed files with 108 additions and 17 deletions

View File

@@ -25,7 +25,7 @@ export default function LoginPage() {
await login(email, password); await login(email, password);
navigate('/'); navigate('/');
} catch (err) { } catch (err) {
setError(err.response?.data?.message ?? 'Login fehlgeschlagen'); setError(err.response?.data?.error ?? 'Login fehlgeschlagen');
} finally { } finally {
setLoading(false); setLoading(false);
} }

View File

@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
import { import {
Box, Typography, Alert, IconButton, Tooltip, Box, Typography, Alert, IconButton, Tooltip,
Dialog, DialogTitle, DialogContent, DialogActions, Dialog, DialogTitle, DialogContent, DialogActions,
Button, Stack, TextField, CircularProgress Button, Stack, TextField, CircularProgress, Autocomplete
} from '@mui/material'; } from '@mui/material';
import { DataGrid } from '@mui/x-data-grid'; import { DataGrid } from '@mui/x-data-grid';
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline'; import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
@@ -17,6 +17,9 @@ export default function CompanyPage() {
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState(''); const [error, setError] = useState('');
const [userOptions, setUserOptions] = useState([]);
const [usersLoading, setUsersLoading] = useState(false);
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [creating, setCreating] = useState(false); const [creating, setCreating] = useState(false);
const [creatingError, setCreatingError] = useState(''); const [creatingError, setCreatingError] = useState('');
@@ -47,6 +50,23 @@ export default function CompanyPage() {
setCreateForm((prev) => ({ ...prev, [name]: value })); 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 () => { const handleCreate = async () => {
setCreating(true); setCreating(true);
setCreatingError(''); setCreatingError('');
@@ -142,7 +162,7 @@ export default function CompanyPage() {
<Button <Button
variant="contained" variant="contained"
startIcon={<AddIcon />} startIcon={<AddIcon />}
onClick={() => setOpen(true)} onClick={() => handleOpen()}
> >
Unternehmen erstellen Unternehmen erstellen
</Button> </Button>
@@ -180,13 +200,38 @@ export default function CompanyPage() {
fullWidth 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 <TextField
{...params}
label="Verwalter Email" label="Verwalter Email"
name="email" name="email"
type="email" type="email"
value={createForm.email}
onChange={handleFormChange}
fullWidth fullWidth
InputProps={{
...params.InputProps,
endAdornment: (
<>
{usersLoading ? <CircularProgress size={16} /> : null}
{params.InputProps.endAdornment}
</>
),
}}
/>
)}
/> />
</Stack> </Stack>
</DialogContent> </DialogContent>

View File

@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
import { import {
Box, Typography, Alert, IconButton, Tooltip, Box, Typography, Alert, IconButton, Tooltip,
Dialog, DialogTitle, DialogContent, DialogActions, Dialog, DialogTitle, DialogContent, DialogActions,
Button, Stack, TextField, CircularProgress Button, Stack, TextField, CircularProgress, Autocomplete
} from '@mui/material'; } from '@mui/material';
import { DataGrid } from '@mui/x-data-grid'; import { DataGrid } from '@mui/x-data-grid';
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline'; import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
@@ -17,6 +17,9 @@ export default function OrganizationPage() {
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState(''); const [error, setError] = useState('');
const [userOptions, setUserOptions] = useState([]);
const [usersLoading, setUsersLoading] = useState(false);
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [creating, setCreating] = useState(false); const [creating, setCreating] = useState(false);
const [creatingError, setCreatingError] = useState(''); const [creatingError, setCreatingError] = useState('');
@@ -38,10 +41,28 @@ export default function OrganizationPage() {
} }
}; };
const handleOpen = () => {
setOpen(true);
loadUsers();
}
useEffect(() => { useEffect(() => {
loadOrganizations(); loadOrganizations();
}, []); }, []);
const loadUsers = async () => {
setUsersLoading(true);
try {
const { data } = await axiosInstance.get('/users');
setUserOptions(data.map(u => u.email));
} catch {
setUserOptions([]);
} finally {
setUsersLoading(false);
}
}
const handleFormChange = (e) => { const handleFormChange = (e) => {
const { name, value } = e.target; const { name, value } = e.target;
setCreateForm((prev) => ({ ...prev, [name]: value })); setCreateForm((prev) => ({ ...prev, [name]: value }));
@@ -142,7 +163,7 @@ export default function OrganizationPage() {
<Button <Button
variant="contained" variant="contained"
startIcon={<AddIcon />} startIcon={<AddIcon />}
onClick={() => setOpen(true)} onClick={() => handleOpen()}
> >
Organisation erstellen Organisation erstellen
</Button> </Button>
@@ -180,13 +201,38 @@ export default function OrganizationPage() {
fullWidth 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 <TextField
{...params}
label="Verwalter Email" label="Verwalter Email"
name="email" name="email"
type="email" type="email"
value={createForm.email}
onChange={handleFormChange}
fullWidth fullWidth
InputProps={{
...params.InputProps,
endAdornment: (
<>
{usersLoading ? <CircularProgress size={16} /> : null}
{params.InputProps.endAdornment}
</>
),
}}
/>
)}
/> />
</Stack> </Stack>
</DialogContent> </DialogContent>