Enhance App component with view management by adding Tabs for Dashboard and Table views. Update DataViewer to receive current view and handle export data accordingly. Refactor BUTable to improve form validation and handle vst values more robustly. Update admin routes to ensure vst is correctly processed.

This commit is contained in:
sebseb7
2025-08-01 10:39:41 +02:00
parent 5470bebfc4
commit 976c802b11
4 changed files with 68 additions and 26 deletions

View File

@@ -1,10 +1,11 @@
import React, { Component } from 'react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
import { Container, AppBar, Toolbar, Typography, Button, Box } from '@mui/material';
import { Container, AppBar, Toolbar, Typography, Button, Box, Tabs, Tab } from '@mui/material';
import LoginIcon from '@mui/icons-material/Login';
import DashboardIcon from '@mui/icons-material/Dashboard';
import DownloadIcon from '@mui/icons-material/Download';
import TableChart from '@mui/icons-material/TableChart';
import AuthService from './services/AuthService';
import DataViewer from './components/DataViewer';
import Login from './components/Login';
@@ -29,6 +30,7 @@ class App extends Component {
user: null,
loading: true,
exportData: null, // { selectedMonth, canExport, onExport }
currentView: 'dashboard', // 'dashboard' or 'tables'
};
this.authService = new AuthService();
}
@@ -77,8 +79,12 @@ class App extends Component {
this.setState({ exportData });
};
handleViewChange = (event, newValue) => {
this.setState({ currentView: newValue });
};
render() {
const { isAuthenticated, user, loading } = this.state;
const { isAuthenticated, user, loading, currentView } = this.state;
if (loading) {
return (
@@ -99,7 +105,7 @@ class App extends Component {
<AppBar position="static">
<Toolbar>
<DashboardIcon sx={{ mr: { xs: 1, sm: 2 } }} />
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
<Typography variant="h6" component="div" sx={{ mr: 3 }}>
FibDash
</Typography>
{isAuthenticated && user && (
@@ -107,12 +113,42 @@ class App extends Component {
<Typography
variant="body2"
sx={{
mr: { xs: 1, sm: 2 },
mr: { xs: 2, sm: 3 },
display: { xs: 'none', sm: 'block' }
}}
>
Willkommen, {user.name}
</Typography>
<Tabs
value={currentView}
onChange={this.handleViewChange}
sx={{
mr: 'auto',
'& .MuiTab-root': {
color: 'rgba(255, 255, 255, 0.7)',
minHeight: 48,
'&.Mui-selected': {
color: 'white'
}
},
'& .MuiTabs-indicator': {
backgroundColor: 'white'
}
}}
>
<Tab
icon={<DashboardIcon />}
label="Dashboard"
value="dashboard"
sx={{ minHeight: 48 }}
/>
<Tab
icon={<TableChart />}
label="Stammdaten"
value="tables"
sx={{ minHeight: 48 }}
/>
</Tabs>
{this.state.exportData && (
<Button
color="inherit"
@@ -153,7 +189,12 @@ class App extends Component {
<Box sx={{ height: 'calc(100vh - 64px)', display: 'flex', flexDirection: 'column' }}>
<Container maxWidth={false} sx={{ mt: 4, flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', width: '100%' }}>
{isAuthenticated ? (
<DataViewer user={user} onUpdateExportData={this.updateExportData} />
<DataViewer
user={user}
onUpdateExportData={this.updateExportData}
currentView={currentView}
onViewChange={this.handleViewChange}
/>
) : (
<Login onLogin={this.handleLogin} />
)}

View File

@@ -7,7 +7,6 @@ import {
import AuthService from '../services/AuthService';
import SummaryHeader from './SummaryHeader';
import TransactionsTable from './TransactionsTable';
import Navigation from './Navigation';
import Dashboard from './Dashboard';
import TableManagement from './TableManagement';
@@ -21,7 +20,7 @@ class DataViewer extends Component {
summary: null,
loading: true,
error: null,
currentView: 'dashboard', // 'dashboard' or 'tables'
};
this.authService = new AuthService();
}
@@ -114,21 +113,17 @@ class DataViewer extends Component {
if (this.props.onUpdateExportData) {
this.props.onUpdateExportData({
selectedMonth,
canExport: !!selectedMonth && !this.state.loading && this.state.currentView === 'dashboard',
canExport: !!selectedMonth && !this.state.loading && this.props.currentView === 'dashboard',
onExport: this.downloadDatev
});
}
};
handleViewChange = (event, newView) => {
this.setState({ currentView: newView });
// Update export data when view changes
this.updateExportData();
};
render() {
const { months, selectedMonth, transactions, summary, loading, error, currentView } = this.state;
const { user } = this.props;
const { months, selectedMonth, transactions, summary, loading, error } = this.state;
const { user, currentView } = this.props;
if (loading && !transactions.length) {
return (
@@ -148,11 +143,6 @@ class DataViewer extends Component {
return (
<Box sx={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
<Navigation
currentView={currentView}
onViewChange={this.handleViewChange}
/>
{currentView === 'dashboard' ? (
<>
<Box sx={{ flexShrink: 0 }}>

View File

@@ -72,7 +72,7 @@ class BUTable extends Component {
formData: bu ? {
bu: bu.bu,
name: bu.name,
vst: bu.vst || '',
vst: bu.vst !== null && bu.vst !== undefined ? bu.vst.toString() : '',
} : {
bu: '',
name: '',
@@ -102,13 +102,20 @@ class BUTable extends Component {
});
};
isFormValid = () => {
const { formData } = this.state;
return formData.bu.trim() !== '' &&
formData.name.trim() !== '' &&
formData.vst !== '';
};
handleSave = async () => {
const { editingBU, formData } = this.state;
// Convert vst to number or null
const payload = {
...formData,
vst: formData.vst ? parseFloat(formData.vst) : null,
vst: formData.vst !== '' ? parseFloat(formData.vst) : null,
};
try {
@@ -220,7 +227,7 @@ class BUTable extends Component {
<TableCell>{bu.bu}</TableCell>
<TableCell>{bu.name}</TableCell>
<TableCell align="right">
{bu.vst ? `${bu.vst}%` : '-'}
{bu.vst !== null && bu.vst !== undefined ? `${bu.vst}%` : '-'}
</TableCell>
<TableCell align="right">
<IconButton
@@ -287,7 +294,11 @@ class BUTable extends Component {
</DialogContent>
<DialogActions>
<Button onClick={this.handleCloseDialog}>Abbrechen</Button>
<Button onClick={this.handleSave} variant="contained">
<Button
onClick={this.handleSave}
variant="contained"
disabled={!this.isFormValid()}
>
Speichern
</Button>
</DialogActions>

View File

@@ -199,7 +199,7 @@ router.post('/buchungsschluessel', authenticateToken, async (req, res) => {
try {
await executeQuery(
'INSERT INTO fibdash.BU (bu, name, vst) VALUES (@bu, @name, @vst)',
{ bu, name, vst: vst || null }
{ bu, name, vst: vst !== undefined && vst !== '' ? vst : null }
);
res.json({ message: 'Buchungsschlüssel erfolgreich erstellt' });
} catch (error) {
@@ -224,7 +224,7 @@ router.put('/buchungsschluessel/:id', authenticateToken, async (req, res) => {
try {
await executeQuery(
'UPDATE fibdash.BU SET bu = @bu, name = @name, vst = @vst WHERE id = @id',
{ bu, name, vst: vst || null, id }
{ bu, name, vst: vst !== undefined && vst !== '' ? vst : null, id }
);
res.json({ message: 'Buchungsschlüssel erfolgreich aktualisiert' });
} catch (error) {