diff --git a/client/public/index.html b/client/public/index.html
index 075fc78..32879a4 100644
--- a/client/public/index.html
+++ b/client/public/index.html
@@ -70,9 +70,7 @@
setTimeout(() => {
const betragHeader = document.querySelector('.ag-header-cell[col-id="numericAmount"]');
if (betragHeader) {
- console.log('Found Betrag header:', betragHeader);
console.log('Header classes:', betragHeader.className);
- console.log('Header HTML:', betragHeader.innerHTML);
} else {
console.log('Could not find Betrag header with col-id="numericAmount"');
// Try to find it by text content
diff --git a/client/src/components/KreditorSelector.js b/client/src/components/KreditorSelector.js
index 5f635b2..5b6a37d 100644
--- a/client/src/components/KreditorSelector.js
+++ b/client/src/components/KreditorSelector.js
@@ -41,12 +41,48 @@ class KreditorSelector extends Component {
componentDidMount() {
this.loadKreditors();
+
+ // If prefilled data is provided, set it in the newKreditor state
+ const updates = {};
+ if (this.props.prefilledIban) {
+ updates.iban = this.props.prefilledIban;
+ }
+ if (this.props.prefilledName) {
+ updates.name = this.props.prefilledName;
+ }
+
+ if (Object.keys(updates).length > 0) {
+ this.setState({
+ newKreditor: {
+ ...this.state.newKreditor,
+ ...updates
+ }
+ });
+ }
}
componentDidUpdate(prevProps) {
if (prevProps.selectedKreditorId !== this.props.selectedKreditorId) {
this.setState({ selectedKreditorId: this.props.selectedKreditorId || '' });
}
+
+ // If prefilled props change, update the newKreditor state
+ const updates = {};
+ if (prevProps.prefilledIban !== this.props.prefilledIban && this.props.prefilledIban) {
+ updates.iban = this.props.prefilledIban;
+ }
+ if (prevProps.prefilledName !== this.props.prefilledName && this.props.prefilledName) {
+ updates.name = this.props.prefilledName;
+ }
+
+ if (Object.keys(updates).length > 0) {
+ this.setState({
+ newKreditor: {
+ ...this.state.newKreditor,
+ ...updates
+ }
+ });
+ }
}
loadKreditors = async () => {
@@ -83,7 +119,11 @@ class KreditorSelector extends Component {
handleCreateDialogClose = () => {
this.setState({
createDialogOpen: false,
- newKreditor: { iban: '', name: '', kreditorId: '' },
+ newKreditor: {
+ iban: this.props.prefilledIban || '',
+ name: this.props.prefilledName || '',
+ kreditorId: ''
+ },
validationErrors: [],
error: null
});
@@ -181,10 +221,12 @@ class KreditorSelector extends Component {
{kreditor.name} ({kreditor.kreditorId}) - {kreditor.iban}
))}
-
+ {(this.props.allowCreate !== false) && (
+
+ )}
diff --git a/client/src/components/TransactionsTable.js b/client/src/components/TransactionsTable.js
index dd3ba74..e2bb612 100644
--- a/client/src/components/TransactionsTable.js
+++ b/client/src/components/TransactionsTable.js
@@ -51,6 +51,31 @@ class TransactionsTable extends Component {
};
window.addEventListener('resize', this.handleResize);
+
+ // Add dialog open listener to blur grid focus
+ this.handleDialogOpen = () => {
+ if (this.gridApi) {
+ // Clear any focused cells to prevent aria-hidden conflicts
+ this.gridApi.clearFocusedCell();
+ // Also blur any focused elements within the grid
+ const gridElement = document.querySelector('.ag-root-wrapper');
+ if (gridElement) {
+ const focusedElement = gridElement.querySelector(':focus');
+ if (focusedElement) {
+ focusedElement.blur();
+ }
+ }
+ }
+ };
+
+ // Listen for dialog open events (Material-UI dialogs)
+ this.handleFocusIn = (event) => {
+ // If focus moves to a dialog, blur the grid
+ if (event.target.closest('[role="dialog"]')) {
+ this.handleDialogOpen();
+ }
+ };
+ document.addEventListener('focusin', this.handleFocusIn);
}
componentWillUnmount() {
@@ -59,7 +84,13 @@ class TransactionsTable extends Component {
window.removeEventListener('resize', this.handleResize);
}
- if (this.gridApi) {
+ // Clean up dialog focus listener
+ if (this.handleFocusIn) {
+ document.removeEventListener('focusin', this.handleFocusIn);
+ }
+
+ // Check if grid API is still valid before removing listeners
+ if (this.gridApi && !this.gridApi.isDestroyed()) {
this.gridApi.removeEventListener('modelUpdated', this.onModelUpdated);
this.gridApi.removeEventListener('filterChanged', this.onFilterChanged);
}
@@ -317,7 +348,6 @@ class TransactionsTable extends Component {
animateRows={true}
// Maintain state across data updates
maintainColumnOrder={true}
- suppressColumnStateEvents={false}
/>
diff --git a/client/src/components/admin/BUTable.js b/client/src/components/admin/BUTable.js
index aaf91e3..01924cb 100644
--- a/client/src/components/admin/BUTable.js
+++ b/client/src/components/admin/BUTable.js
@@ -44,6 +44,11 @@ class BUTable extends Component {
},
};
this.authService = new AuthService();
+
+ // Focus management refs
+ this.triggerRef = React.createRef();
+ this.dialogRef = React.createRef();
+ this.confirmDialogRef = React.createRef();
}
componentDidMount() {
@@ -66,6 +71,9 @@ class BUTable extends Component {
};
handleOpenDialog = (bu = null) => {
+ // Store reference to the trigger element for focus restoration
+ this.triggerRef.current = document.activeElement;
+
this.setState({
dialogOpen: true,
editingBU: bu,
@@ -91,6 +99,13 @@ class BUTable extends Component {
vst: '',
},
});
+
+ // Restore focus to the trigger element after dialog closes
+ setTimeout(() => {
+ if (this.triggerRef.current && this.triggerRef.current.focus) {
+ this.triggerRef.current.focus();
+ }
+ }, 100);
};
handleInputChange = (field) => (event) => {
@@ -145,6 +160,9 @@ class BUTable extends Component {
};
handleDeleteClick = (bu) => {
+ // Store reference to the trigger element for focus restoration
+ this.triggerRef.current = document.activeElement;
+
this.setState({
confirmDialogOpen: true,
itemToDelete: bu,
@@ -156,6 +174,13 @@ class BUTable extends Component {
if (!itemToDelete) return;
this.setState({ confirmDialogOpen: false, itemToDelete: null });
+
+ // Restore focus to the trigger element after dialog closes
+ setTimeout(() => {
+ if (this.triggerRef.current && this.triggerRef.current.focus) {
+ this.triggerRef.current.focus();
+ }
+ }, 100);
try {
const response = await this.authService.apiCall(`/admin/buchungsschluessel/${itemToDelete.id}`, {
@@ -179,6 +204,13 @@ class BUTable extends Component {
confirmDialogOpen: false,
itemToDelete: null,
});
+
+ // Restore focus to the trigger element after dialog closes
+ setTimeout(() => {
+ if (this.triggerRef.current && this.triggerRef.current.focus) {
+ this.triggerRef.current.focus();
+ }
+ }, 100);
};
render() {
@@ -250,11 +282,22 @@ class BUTable extends Component {
-