generated from nhcarrigan/template
feat: add suggestion feature
This commit is contained in:
@@ -11,7 +11,8 @@ import { ArtService } from '../../services/art.service';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { CommentsService } from '../../services/comments.service';
|
||||
import { SanitizeService } from '../../services/sanitize.service';
|
||||
import { Art, CreateArtDto, UpdateArtDto, Comment } from '@library/shared-types';
|
||||
import { SuggestionService } from '../../services/suggestion.service';
|
||||
import { Art, CreateArtDto, UpdateArtDto, Comment, SuggestionEntity } from '@library/shared-types';
|
||||
|
||||
@Component({
|
||||
selector: 'app-art-gallery',
|
||||
@@ -26,6 +27,10 @@ import { Art, CreateArtDto, UpdateArtDto, Comment } from '@library/shared-types'
|
||||
<button (click)="toggleAddForm()" class="btn btn-primary">
|
||||
{{ showAddForm() ? 'Cancel' : 'Add Art' }}
|
||||
</button>
|
||||
} @else if (authService.isAuthenticated() && !authService.user()?.isBanned) {
|
||||
<button (click)="toggleSuggestForm()" class="btn btn-primary">
|
||||
{{ showSuggestForm() ? 'Cancel' : 'Suggest Art' }}
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -104,6 +109,71 @@ import { Art, CreateArtDto, UpdateArtDto, Comment } from '@library/shared-types'
|
||||
</form>
|
||||
}
|
||||
|
||||
@if (showSuggestForm() && !authService.isAdmin() && authService.isAuthenticated()) {
|
||||
<form (ngSubmit)="submitSuggestion()" class="add-form suggest-form">
|
||||
<h3>Suggest Art</h3>
|
||||
<p class="suggest-note">Your suggestion will be reviewed by Naomi. If accepted, it will be added to the gallery!</p>
|
||||
<div class="form-group">
|
||||
<label for="suggest-title">Title</label>
|
||||
<input
|
||||
type="text"
|
||||
id="suggest-title"
|
||||
[(ngModel)]="suggestedArt.title"
|
||||
name="title"
|
||||
required
|
||||
placeholder="Artwork title"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="suggest-artist">Artist</label>
|
||||
<input
|
||||
type="text"
|
||||
id="suggest-artist"
|
||||
[(ngModel)]="suggestedArt.artist"
|
||||
name="artist"
|
||||
required
|
||||
placeholder="Who created this artwork"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="suggest-imageUrl">Image URL</label>
|
||||
<input
|
||||
type="url"
|
||||
id="suggest-imageUrl"
|
||||
[(ngModel)]="suggestedArt.imageUrl"
|
||||
name="imageUrl"
|
||||
required
|
||||
placeholder="https://example.com/image.png"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="suggest-description">Description (optional, used as alt text)</label>
|
||||
<textarea
|
||||
id="suggest-description"
|
||||
[(ngModel)]="suggestedArt.description"
|
||||
name="description"
|
||||
rows="2"
|
||||
placeholder="Describe the artwork for accessibility..."
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
@if (suggestedArt.imageUrl) {
|
||||
<div class="image-preview">
|
||||
<p>Preview:</p>
|
||||
<img [src]="suggestedArt.imageUrl" [alt]="suggestedArt.description || 'Preview'" (error)="onImageError($event)">
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">Submit Suggestion</button>
|
||||
<button type="button" (click)="toggleSuggestForm()" class="btn btn-secondary">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
|
||||
@if (editingArt() && authService.isAdmin()) {
|
||||
<form (ngSubmit)="saveEdit()" class="add-form">
|
||||
<h3>Edit Artwork</h3>
|
||||
@@ -367,6 +437,18 @@ import { Art, CreateArtDto, UpdateArtDto, Comment } from '@library/shared-types'
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.suggest-form {
|
||||
border: 2px solid #fdcb6e;
|
||||
background: #fffdf5;
|
||||
}
|
||||
|
||||
.suggest-note {
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 1rem;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
@@ -737,6 +819,7 @@ export class ArtGalleryComponent implements OnInit {
|
||||
authService = inject(AuthService);
|
||||
commentsService = inject(CommentsService);
|
||||
sanitizeService = inject(SanitizeService);
|
||||
suggestionService = inject(SuggestionService);
|
||||
|
||||
artPieces = signal<Art[]>([]);
|
||||
loading = signal(true);
|
||||
@@ -752,6 +835,15 @@ export class ArtGalleryComponent implements OnInit {
|
||||
editingCommentId = signal<string | null>(null);
|
||||
editCommentContent = '';
|
||||
|
||||
// Suggestion state
|
||||
showSuggestForm = signal(false);
|
||||
suggestedArt: { title: string; artist: string; imageUrl: string; description?: string } = {
|
||||
title: '',
|
||||
artist: '',
|
||||
imageUrl: '',
|
||||
description: ''
|
||||
};
|
||||
|
||||
newArt: Partial<CreateArtDto> = {
|
||||
title: '',
|
||||
artist: '',
|
||||
@@ -971,4 +1063,39 @@ export class ArtGalleryComponent implements OnInit {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Suggestion methods
|
||||
toggleSuggestForm() {
|
||||
this.showSuggestForm.update(v => !v);
|
||||
if (!this.showSuggestForm()) {
|
||||
this.resetSuggestForm();
|
||||
}
|
||||
}
|
||||
|
||||
resetSuggestForm() {
|
||||
this.suggestedArt = {
|
||||
title: '',
|
||||
artist: '',
|
||||
imageUrl: '',
|
||||
description: ''
|
||||
};
|
||||
}
|
||||
|
||||
async submitSuggestion() {
|
||||
if (!this.suggestedArt.title || !this.suggestedArt.artist || !this.suggestedArt.imageUrl) return;
|
||||
|
||||
try {
|
||||
await this.suggestionService.createSuggestion({
|
||||
entityType: SuggestionEntity.ART,
|
||||
title: this.suggestedArt.title,
|
||||
artist: this.suggestedArt.artist,
|
||||
imageUrl: this.suggestedArt.imageUrl,
|
||||
description: this.suggestedArt.description
|
||||
});
|
||||
alert('Thank you for your suggestion! It will be reviewed soon.');
|
||||
this.toggleSuggestForm();
|
||||
} catch {
|
||||
alert('Failed to submit suggestion. Please try again.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user