feat: ability to edit suggestions when accepting

This commit is contained in:
2026-02-04 21:37:57 -08:00
parent 729f410443
commit 800b9f6c2d
5 changed files with 383 additions and 11 deletions
@@ -227,6 +227,166 @@ import { Suggestion, SuggestionStatus, SuggestionEntity } from '@library/shared-
</div>
</div>
}
@if (showEditModal()) {
<div class="modal-overlay" (click)="closeEditModal()">
<div class="modal edit-modal" (click)="$event.stopPropagation()">
<h3>Review & Edit Before Accepting</h3>
<p>Review and edit the details before adding to your collection.</p>
@if (editingSuggestion()) {
<form (ngSubmit)="confirmAcceptWithEdits()">
<div class="form-group">
<label for="edit-title">Title</label>
<input
type="text"
id="edit-title"
[(ngModel)]="editedData.title"
name="title"
required
>
</div>
@switch (editingSuggestion()!.entityType) {
@case ('BOOK') {
<div class="form-group">
<label for="edit-author">Author</label>
<input
type="text"
id="edit-author"
[(ngModel)]="editedData.author"
name="author"
required
>
</div>
<div class="form-group">
<label for="edit-isbn">ISBN</label>
<input
type="text"
id="edit-isbn"
[(ngModel)]="editedData.isbn"
name="isbn"
>
</div>
}
@case ('GAME') {
<div class="form-group">
<label for="edit-platform">Platform</label>
<input
type="text"
id="edit-platform"
[(ngModel)]="editedData.platform"
name="platform"
>
</div>
}
@case ('MUSIC') {
<div class="form-group">
<label for="edit-artist">Artist</label>
<input
type="text"
id="edit-artist"
[(ngModel)]="editedData.artist"
name="artist"
required
>
</div>
<div class="form-group">
<label for="edit-type">Type</label>
<select id="edit-type" [(ngModel)]="editedData.type" name="type" required>
<option value="ALBUM">Album</option>
<option value="SINGLE">Single</option>
<option value="EP">EP</option>
</select>
</div>
}
@case ('ART') {
<div class="form-group">
<label for="edit-artist">Artist</label>
<input
type="text"
id="edit-artist"
[(ngModel)]="editedData.artist"
name="artist"
required
>
</div>
<div class="form-group">
<label for="edit-description">Description</label>
<textarea
id="edit-description"
[(ngModel)]="editedData.description"
name="description"
rows="3"
></textarea>
</div>
<div class="form-group">
<label for="edit-imageUrl">Image URL</label>
<input
type="text"
id="edit-imageUrl"
[(ngModel)]="editedData.imageUrl"
name="imageUrl"
required
>
</div>
}
@case ('SHOW') {
<div class="form-group">
<label for="edit-type">Type</label>
<select id="edit-type" [(ngModel)]="editedData.type" name="type" required>
<option value="TV_SERIES">TV Series</option>
<option value="ANIME">Anime</option>
<option value="FILM">Film</option>
<option value="DOCUMENTARY">Documentary</option>
</select>
</div>
}
@case ('MANGA') {
<div class="form-group">
<label for="edit-author">Author</label>
<input
type="text"
id="edit-author"
[(ngModel)]="editedData.author"
name="author"
required
>
</div>
}
}
<div class="form-group">
<label for="edit-notes">Notes</label>
<textarea
id="edit-notes"
[(ngModel)]="editedData.notes"
name="notes"
rows="3"
></textarea>
</div>
@if (editingSuggestion()!.entityType !== 'ART') {
<div class="form-group">
<label for="edit-coverImage">Cover Image URL</label>
<input
type="text"
id="edit-coverImage"
[(ngModel)]="editedData.coverImage"
name="coverImage"
>
</div>
}
<div class="modal-actions">
<button type="submit" class="btn btn-accept">Accept with Edits</button>
<button type="button" (click)="closeEditModal()" class="btn btn-secondary">Cancel</button>
</div>
</form>
}
</div>
</div>
}
</div>
`,
styles: [`
@@ -503,6 +663,14 @@ import { Suggestion, SuggestionStatus, SuggestionEntity } from '@library/shared-
overflow-y: auto;
}
.edit-modal {
max-width: 650px;
}
.edit-modal form {
margin-top: 1rem;
}
.modal h3 {
margin: 0 0 1rem 0;
}
@@ -549,6 +717,11 @@ export class AdminSuggestionsComponent implements OnInit {
decliningsuggestion = signal<Suggestion | null>(null);
declineReason = '';
// Edit modal state
showEditModal = signal(false);
editingSuggestion = signal<Suggestion | null>(null);
editedData: any = {};
// Pagination state
currentPage = signal(1);
pageSize = signal(25);
@@ -637,15 +810,59 @@ export class AdminSuggestionsComponent implements OnInit {
}
async acceptSuggestion(suggestion: Suggestion) {
if (!confirm(`Accept "${suggestion.title}"? This will add it to your collection.`)) return;
this.editingSuggestion.set(suggestion);
try {
await this.suggestionService.acceptSuggestion(suggestion.id);
alert(`"${suggestion.title}" has been added to your collection!`);
this.loadSuggestions();
} catch {
alert('Failed to accept suggestion. Please try again.');
// Pre-populate the edit form with suggestion data
this.editedData = {
title: suggestion.title,
notes: '',
coverImage: '',
coverArt: ''
};
// Add entity-specific data
switch (suggestion.entityType) {
case 'BOOK':
const bookData = suggestion.bookData as any;
this.editedData.author = bookData?.author || '';
this.editedData.isbn = bookData?.isbn || '';
this.editedData.notes = bookData?.notes || '';
this.editedData.coverImage = bookData?.coverImage || '';
break;
case 'GAME':
const gameData = suggestion.gameData as any;
this.editedData.platform = gameData?.platform || '';
this.editedData.notes = gameData?.notes || '';
this.editedData.coverImage = gameData?.coverImage || '';
break;
case 'MUSIC':
const musicData = suggestion.musicData as any;
this.editedData.artist = musicData?.artist || '';
this.editedData.type = musicData?.type || 'ALBUM';
this.editedData.notes = musicData?.notes || '';
this.editedData.coverArt = musicData?.coverArt || '';
break;
case 'ART':
const artData = suggestion.artData as any;
this.editedData.artist = artData?.artist || '';
this.editedData.description = artData?.description || '';
this.editedData.imageUrl = artData?.imageUrl || '';
break;
case 'SHOW':
const showData = suggestion.showData as any;
this.editedData.type = showData?.type || 'TV_SERIES';
this.editedData.notes = showData?.notes || '';
this.editedData.coverImage = showData?.coverImage || '';
break;
case 'MANGA':
const mangaData = suggestion.mangaData as any;
this.editedData.author = mangaData?.author || '';
this.editedData.notes = mangaData?.notes || '';
this.editedData.coverImage = mangaData?.coverImage || '';
break;
}
this.showEditModal.set(true);
}
openDeclineModal(suggestion: Suggestion) {
@@ -660,6 +877,26 @@ export class AdminSuggestionsComponent implements OnInit {
this.declineReason = '';
}
closeEditModal() {
this.showEditModal.set(false);
this.editingSuggestion.set(null);
this.editedData = {};
}
async confirmAcceptWithEdits() {
const suggestion = this.editingSuggestion();
if (!suggestion) return;
try {
await this.suggestionService.acceptSuggestionWithEdits(suggestion.id, this.editedData);
alert(`"${this.editedData.title}" has been added to your collection with your edits!`);
this.closeEditModal();
this.loadSuggestions();
} catch (error) {
alert('Failed to accept suggestion. Please try again.');
}
}
async confirmDecline() {
const suggestion = this.decliningsuggestion();
if (!suggestion) return;