rename&delete Deck, popover

This commit is contained in:
Andreas Knuth 2025-01-15 21:38:38 +00:00
parent f968f2ab38
commit 49c1185372
3 changed files with 150 additions and 18 deletions

View File

@ -15,14 +15,29 @@
<h2 class="text-xl font-semibold">{{ deck.name }}</h2>
<span class="text-gray-600">({{ deck.images.length }} images)</span>
</div>
<button (click)="toggleDeckExpansion(deck.name)" class="text-gray-500 hover:text-gray-700 focus:outline-none" title="Expand/Collapse Deck">
<svg *ngIf="!isDeckExpanded(deck.name)" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 transform rotate-0 transition-transform duration-200" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
<svg *ngIf="isDeckExpanded(deck.name)" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 transform rotate-180 transition-transform duration-200" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</button>
<div class="flex space-x-2">
<!-- Button zum Löschen -->
<button (click)="openDeletePopover(deck.name)" class="text-red-500 hover:text-red-700" title="Delete Deck">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
<!-- Button zum Umbenennen -->
<button (click)="openRenamePopover(deck)" class="text-yellow-500 hover:text-yellow-700" title="Rename Deck">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
</svg>
</button>
<button (click)="toggleDeckExpansion(deck.name)" class="text-gray-500 hover:text-gray-700 focus:outline-none" title="Expand/Collapse Deck">
<svg *ngIf="!isDeckExpanded(deck.name)" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 transform rotate-0 transition-transform duration-200" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
<svg *ngIf="isDeckExpanded(deck.name)" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 transform rotate-180 transition-transform duration-200" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</button>
</div>
</div>
<!-- Image list and action buttons only shown if the deck is expanded and no training is active -->
@ -96,4 +111,22 @@
(moveCompleted)="onImageMoved()"
(closed)="imageToMove = null">
</app-move-image-modal>
</div>
<!-- Popover für die Löschbestätigung -->
<div id="deletePopover" popover="manual" class="popover">
<p>Are you sure you want to delete this deck?</p>
<div class="flex justify-end space-x-2">
<button (click)="confirmDelete()" class="bg-red-500 text-white px-4 py-2 rounded">Delete</button>
<button (click)="cancelDelete()" class="bg-gray-500 text-white px-4 py-2 rounded">Cancel</button>
</div>
</div>
<!-- Popover für die Eingabe des neuen Decknamens -->
<div id="renamePopover" popover="manual" class="popover">
<p>Enter the new name for the deck:</p>
<input type="text" id="newDeckNameInput" class="w-full p-2 border rounded mb-2" />
<div class="flex justify-end space-x-2">
<button (click)="confirmRename()" class="bg-blue-500 text-white px-4 py-2 rounded">Rename</button>
<button (click)="cancelRename()" class="bg-gray-500 text-white px-4 py-2 rounded">Cancel</button>
</div>
</div>

View File

@ -12,6 +12,16 @@ import { MoveImageModalComponent } from './move-image-modal/move-image-modal.com
selector: 'app-deck-list',
templateUrl: './deck-list.component.html',
standalone: true,
styles:`
.popover {
padding: 1rem;
border: 1px solid #ccc;
border-radius: 0.5rem;
background-color: white;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
max-width: 300px;
}
`,
imports: [
CommonModule,
CreateDeckModalComponent,
@ -25,7 +35,10 @@ import { MoveImageModalComponent } from './move-image-modal/move-image-modal.com
export class DeckListComponent implements OnInit {
decks: Deck[] = [];
selectedDeck: Deck | null = null;
// Zustandsvariablen für die Popover-Interaktion
private deckToDelete: string | null = null;
private deckToRename: Deck | null = null;
@ViewChild(CreateDeckModalComponent) createDeckModal!: CreateDeckModalComponent;
@ViewChild(UploadImageModalComponent) uploadImageModal!: UploadImageModalComponent;
@ViewChild(EditImageModalComponent) editModal!: EditImageModalComponent;
@ -54,17 +67,101 @@ export class DeckListComponent implements OnInit {
error: (err) => console.error('Error loading decks', err)
});
}
deleteDeck(deckName: string): void {
if (!confirm(`Are you sure you want to delete the deck "${deckName}"?`)) {
return;
// Methode zum Öffnen des Lösch-Popovers
openDeletePopover(deckName: string): void {
this.deckToDelete = deckName;
const deletePopover = document.getElementById('deletePopover');
if (deletePopover) {
deletePopover.showPopover();
}
this.deckService.deleteDeck(deckName).subscribe({
next: () => this.loadDecks(),
error: (err) => console.error('Error deleting deck', err)
});
}
// Methode zum Bestätigen des Löschens
confirmDelete(): void {
if (this.deckToDelete) {
this.deckService.deleteDeck(this.deckToDelete).subscribe({
next: () => {
this.loadDecks();
this.closeDeletePopover();
},
error: (err) => console.error('Error deleting deck', err),
});
}
}
// Methode zum Abbrechen des Löschens
cancelDelete(): void {
this.closeDeletePopover();
}
// Methode zum Schließen des Lösch-Popovers
closeDeletePopover(): void {
const deletePopover = document.getElementById('deletePopover');
if (deletePopover) {
deletePopover.hidePopover();
}
this.deckToDelete = null;
}
// Methode zum Öffnen des Umbenennungs-Popovers
openRenamePopover(deck: Deck): void {
this.deckToRename = deck;
const renamePopover = document.getElementById('renamePopover');
if (renamePopover) {
renamePopover.showPopover();
}
}
// Methode zum Bestätigen des Umbenennens
confirmRename(): void {
const newDeckNameInput = document.getElementById('newDeckNameInput') as HTMLInputElement;
if (newDeckNameInput && this.deckToRename) {
const newDeckName = newDeckNameInput.value.trim();
if (newDeckName && newDeckName !== this.deckToRename.name) {
this.deckService.renameDeck(this.deckToRename.name, newDeckName).subscribe({
next: () => {
this.loadDecks();
this.closeRenamePopover();
},
error: (err) => console.error('Error renaming deck', err),
});
}
}
}
// Methode zum Abbrechen des Umbenennens
cancelRename(): void {
this.closeRenamePopover();
}
// Methode zum Schließen des Umbenennungs-Popovers
closeRenamePopover(): void {
const renamePopover = document.getElementById('renamePopover');
if (renamePopover) {
renamePopover.hidePopover();
}
this.deckToRename = null;
}
// deleteDeck(deckName: string): void {
// if (!confirm(`Are you sure you want to delete the deck "${deckName}"?`)) {
// return;
// }
// this.deckService.deleteDeck(deckName).subscribe({
// next: () => this.loadDecks(),
// error: (err) => console.error('Error deleting deck', err)
// });
// }
// renameDeck(deck: Deck): void {
// const newDeckName = prompt('Enter the new name for the deck:', deck.name);
// if (newDeckName && newDeckName !== deck.name) {
// this.deckService.renameDeck(deck.name, newDeckName).subscribe({
// next: () => this.loadDecks(),
// error: (err) => console.error('Error renaming deck', err)
// });
// }
// }
deleteImage(deck: Deck, image: DeckImage): void {
if (!confirm(`Are you sure you want to delete the image "${image.name}"?`)) {
return;

View File

@ -109,7 +109,9 @@ export class DeckService {
deleteDeck(deckName: string): Observable<any> {
return this.http.delete(`${this.apiUrl}/${encodeURIComponent(deckName)}`);
}
renameDeck(oldDeckName: string, newDeckName: string): Observable<any> {
return this.http.put(`${this.apiUrl}/${encodeURIComponent(oldDeckName)}/rename`, { newDeckName });
}
saveImageData(data: any): Observable<any> {
return this.http.post(`${this.apiUrl}/image`, data);
}