/** * Copyright since 2025 Mifos Initiative * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import { Component, inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef, MatDialogTitle, MatDialogContent, MatDialogActions } from '@angular/material/dialog'; import { KeyboardShortcutService, ShortcutItem } from '../../core/services/keyboard-shortcut.service'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; import { FormsModule } from '@angular/forms'; import { MatButton } from '@angular/material/button'; import { MatFormField, MatLabel, MatError } from '@angular/material/form-field'; import { MatInput } from '@angular/material/input'; import { take } from 'rxjs/operators'; @Component({ selector: 'mifosx-inline-create-shortcut-dialog', templateUrl: './inline-create-shortcut-dialog.component.html', styleUrls: ['../keyboard-shortcuts-dialog/keyboard-shortcuts-dialog.component.scss'], imports: [ ...STANDALONE_SHARED_IMPORTS, MatDialogTitle, MatDialogContent, MatDialogActions, MatButton, FormsModule, MatFormField, MatLabel, MatInput ] }) export class InlineCreateShortcutDialogComponent { dialogRef = inject>(MatDialogRef); data = inject(MAT_DIALOG_DATA); private keyboardShortcutService = inject(KeyboardShortcutService); newShortcut: Partial = { title: this.data.pageName, route: this.data.route, action: 'navigate', key: '', ctrlKey: false, shiftKey: false, altKey: false, custom: true, id: 'custom_' + Date.now() }; validationError: string | null = null; formatShortcut(item: Partial): string { if (!item || (!item.key && !item.ctrlKey && !item.shiftKey && !item.altKey)) return ''; const parts = []; if (item.ctrlKey) parts.push('Ctrl'); if (item.shiftKey) parts.push('Shift'); if (item.altKey) parts.push('Alt'); if (item.key) parts.push(item.key.toUpperCase()); return parts.join(' + '); } onKeyDown(event: KeyboardEvent) { event.preventDefault(); event.stopPropagation(); // Ignore if only modifier keys are pressed if ([ 'Control', 'Shift', 'Alt', 'Meta' ].includes(event.key)) { return; } this.newShortcut.ctrlKey = event.ctrlKey; this.newShortcut.shiftKey = event.shiftKey; this.newShortcut.altKey = event.altKey; this.newShortcut.key = event.key.toLowerCase(); this.validationError = null; } save() { if (!this.newShortcut.title || this.newShortcut.title.trim() === '') { this.validationError = 'Shortcut Name is required'; return; } if (!this.newShortcut.key) { this.validationError = 'Key combination is required'; return; } const keyStr = `${!!this.newShortcut.ctrlKey}-${!!this.newShortcut.shiftKey}-${!!this.newShortcut.altKey}-${this.newShortcut.key.toLowerCase()}`; this.keyboardShortcutService.activeShortcuts$.pipe(take(1)).subscribe((shortcuts) => { // Check for duplicates const seen = new Set(); for (const s of shortcuts) { seen.add(`${!!s.ctrlKey}-${!!s.shiftKey}-${!!s.altKey}-${s.key.toLowerCase()}`); } if (seen.has(keyStr)) { this.validationError = `Duplicate shortcut detected: ${this.formatShortcut(this.newShortcut)}`; return; } // Add and save if (this.newShortcut.route) { this.newShortcut.route = this.keyboardShortcutService.normalizeRouteStr(this.newShortcut.route); } shortcuts.push(this.newShortcut as ShortcutItem); this.keyboardShortcutService.updateShortcuts(shortcuts); this.dialogRef.close(true); }); } cancel() { this.dialogRef.close(false); } }