feat: Multiple Features, Accessibility, Security, and UX Improvements #59

Merged
naomi merged 27 commits from feat/polish into main 2026-02-20 01:51:25 -08:00
4 changed files with 464 additions and 3 deletions
Showing only changes of commit 5ad9b50dc8 - Show all commits
@@ -116,6 +116,34 @@ import { Book, BookStatus, CreateBookDto, UpdateBookDto, Comment, SuggestionEnti
> >
</div> </div>
<div class="form-row">
<div class="form-group">
<label for="timeHours">Time Spent (Hours)</label>
<input
type="number"
id="timeHours"
[(ngModel)]="newBookTimeHours"
name="timeHours"
min="0"
placeholder="0"
(ngModelChange)="updateNewBookTimeSpent()"
>
</div>
<div class="form-group">
<label for="timeMinutes">Time Spent (Minutes)</label>
<input
type="number"
id="timeMinutes"
[(ngModel)]="newBookTimeMinutes"
name="timeMinutes"
min="0"
max="59"
placeholder="0"
(ngModelChange)="updateNewBookTimeSpent()"
>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="notes">Notes</label> <label for="notes">Notes</label>
<textarea <textarea
@@ -301,6 +329,34 @@ import { Book, BookStatus, CreateBookDto, UpdateBookDto, Comment, SuggestionEnti
> >
</div> </div>
<div class="form-row">
<div class="form-group">
<label for="edit-timeHours">Time Spent (Hours)</label>
<input
type="number"
id="edit-timeHours"
[(ngModel)]="editBookTimeHours"
name="timeHours"
min="0"
placeholder="0"
(ngModelChange)="updateEditBookTimeSpent()"
>
</div>
<div class="form-group">
<label for="edit-timeMinutes">Time Spent (Minutes)</label>
<input
type="number"
id="edit-timeMinutes"
[(ngModel)]="editBookTimeMinutes"
name="timeMinutes"
min="0"
max="59"
placeholder="0"
(ngModelChange)="updateEditBookTimeSpent()"
>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="edit-notes">Notes</label> <label for="edit-notes">Notes</label>
<textarea <textarea
@@ -613,6 +669,12 @@ import { Book, BookStatus, CreateBookDto, UpdateBookDto, Comment, SuggestionEnti
</div> </div>
} }
@if (book.timeSpent) {
<p class="time-spent">
📖 Reading Time: {{ formatTimeSpent(book.timeSpent) }}
</p>
}
<app-like-button <app-like-button
entityType="book" entityType="book"
[entityId]="book.id" [entityId]="book.id"
@@ -770,6 +832,13 @@ import { Book, BookStatus, CreateBookDto, UpdateBookDto, Comment, SuggestionEnti
font-style: italic; font-style: italic;
} }
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin-bottom: 1rem;
}
.form-group { .form-group {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
@@ -1058,6 +1127,13 @@ import { Book, BookStatus, CreateBookDto, UpdateBookDto, Comment, SuggestionEnti
color: var(--witch-rose); color: var(--witch-rose);
} }
.time-spent {
font-size: 0.9rem;
color: #10b981;
font-weight: 500;
margin: 0.5rem 0;
}
.isbn { .isbn {
font-size: 0.8rem; font-size: 0.8rem;
color: var(--witch-mauve); color: var(--witch-mauve);
@@ -1567,6 +1643,11 @@ export class BooksListComponent implements OnInit {
editBook: Partial<UpdateBookDto> = {}; editBook: Partial<UpdateBookDto> = {};
newBookTimeHours = 0;
newBookTimeMinutes = 0;
editBookTimeHours = 0;
editBookTimeMinutes = 0;
// Tags and links input state // Tags and links input state
newTagInput = ''; newTagInput = '';
editTagInput = ''; editTagInput = '';
@@ -1669,6 +1750,8 @@ export class BooksListComponent implements OnInit {
this.newTagInput = ''; this.newTagInput = '';
this.newLinkTitle = ''; this.newLinkTitle = '';
this.newLinkUrl = ''; this.newLinkUrl = '';
this.newBookTimeHours = 0;
this.newBookTimeMinutes = 0;
} }
addTag(target: 'new' | 'edit') { addTag(target: 'new' | 'edit') {
@@ -1770,6 +1853,13 @@ export class BooksListComponent implements OnInit {
this.editTagInput = ''; this.editTagInput = '';
this.editLinkTitle = ''; this.editLinkTitle = '';
this.editLinkUrl = ''; this.editLinkUrl = '';
if (book.timeSpent) {
this.editBookTimeHours = Math.floor(book.timeSpent / 60);
this.editBookTimeMinutes = book.timeSpent % 60;
} else {
this.editBookTimeHours = 0;
this.editBookTimeMinutes = 0;
}
} }
cancelEdit() { cancelEdit() {
@@ -1802,6 +1892,29 @@ export class BooksListComponent implements OnInit {
return new Date(date).toLocaleDateString(); return new Date(date).toLocaleDateString();
} }
updateNewBookTimeSpent() {
const totalMinutes = (this.newBookTimeHours * 60) + this.newBookTimeMinutes;
this.newBook.timeSpent = totalMinutes > 0 ? totalMinutes : undefined;
}
updateEditBookTimeSpent() {
const totalMinutes = (this.editBookTimeHours * 60) + this.editBookTimeMinutes;
this.editBook.timeSpent = totalMinutes > 0 ? totalMinutes : undefined;
}
formatTimeSpent(minutes: number): string {
const hours = Math.floor(minutes / 60);
const mins = minutes % 60;
if (hours === 0) {
return `${mins}m`;
} else if (mins === 0) {
return `${hours}h`;
} else {
return `${hours}h ${mins}m`;
}
}
// Image handling methods // Image handling methods
onImageSelected(event: Event, target: 'new' | 'edit' | 'suggest') { onImageSelected(event: Event, target: 'new' | 'edit' | 'suggest') {
const input = event.target as HTMLInputElement; const input = event.target as HTMLInputElement;
@@ -105,6 +105,34 @@ import { Manga, MangaStatus, CreateMangaDto, UpdateMangaDto, Comment, Suggestion
> >
</div> </div>
<div class="form-row">
<div class="form-group">
<label for="timeHours">Time Spent (Hours)</label>
<input
type="number"
id="timeHours"
[(ngModel)]="newMangaTimeHours"
name="timeHours"
min="0"
placeholder="0"
(ngModelChange)="updateNewMangaTimeSpent()"
>
</div>
<div class="form-group">
<label for="timeMinutes">Time Spent (Minutes)</label>
<input
type="number"
id="timeMinutes"
[(ngModel)]="newMangaTimeMinutes"
name="timeMinutes"
min="0"
max="59"
placeholder="0"
(ngModelChange)="updateNewMangaTimeSpent()"
>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="notes">Notes</label> <label for="notes">Notes</label>
<textarea <textarea
@@ -256,6 +284,34 @@ import { Manga, MangaStatus, CreateMangaDto, UpdateMangaDto, Comment, Suggestion
> >
</div> </div>
<div class="form-row">
<div class="form-group">
<label for="edit-timeHours">Time Spent (Hours)</label>
<input
type="number"
id="edit-timeHours"
[(ngModel)]="editMangaTimeHours"
name="timeHours"
min="0"
placeholder="0"
(ngModelChange)="updateEditMangaTimeSpent()"
>
</div>
<div class="form-group">
<label for="edit-timeMinutes">Time Spent (Minutes)</label>
<input
type="number"
id="edit-timeMinutes"
[(ngModel)]="editMangaTimeMinutes"
name="timeMinutes"
min="0"
max="59"
placeholder="0"
(ngModelChange)="updateEditMangaTimeSpent()"
>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="edit-notes">Notes</label> <label for="edit-notes">Notes</label>
<textarea <textarea
@@ -524,6 +580,12 @@ import { Manga, MangaStatus, CreateMangaDto, UpdateMangaDto, Comment, Suggestion
</div> </div>
} }
@if (manga.timeSpent) {
<p class="time-spent">
📚 Reading Time: {{ formatTimeSpent(manga.timeSpent) }}
</p>
}
<app-like-button <app-like-button
entityType="manga" entityType="manga"
[entityId]="manga.id" [entityId]="manga.id"
@@ -691,6 +753,13 @@ import { Manga, MangaStatus, CreateMangaDto, UpdateMangaDto, Comment, Suggestion
font-size: 1rem; font-size: 1rem;
} }
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin-bottom: 1rem;
}
.form-actions { .form-actions {
display: flex; display: flex;
gap: 1rem; gap: 1rem;
@@ -886,6 +955,13 @@ import { Manga, MangaStatus, CreateMangaDto, UpdateMangaDto, Comment, Suggestion
margin: 0.5rem 0; margin: 0.5rem 0;
} }
.time-spent {
font-size: 0.9rem;
color: #10b981;
font-weight: 500;
margin: 0.5rem 0;
}
.date-started, .date-started,
.date-finished, .date-finished,
.date-added, .date-added,
@@ -1313,6 +1389,12 @@ export class MangaListComponent implements OnInit {
editManga: Partial<UpdateMangaDto> = {}; editManga: Partial<UpdateMangaDto> = {};
// Time tracking state
newMangaTimeHours = 0;
newMangaTimeMinutes = 0;
editMangaTimeHours = 0;
editMangaTimeMinutes = 0;
// Tags and links input state // Tags and links input state
newTagInput = ''; newTagInput = '';
editTagInput = ''; editTagInput = '';
@@ -1405,6 +1487,8 @@ export class MangaListComponent implements OnInit {
tags: [], tags: [],
links: [] links: []
}; };
this.newMangaTimeHours = 0;
this.newMangaTimeMinutes = 0;
this.newMangaImagePreview.set(null); this.newMangaImagePreview.set(null);
this.imageError.set(null); this.imageError.set(null);
this.newTagInput = ''; this.newTagInput = '';
@@ -1412,6 +1496,16 @@ export class MangaListComponent implements OnInit {
this.newLinkUrl = ''; this.newLinkUrl = '';
} }
updateNewMangaTimeSpent() {
const totalMinutes = (this.newMangaTimeHours * 60) + this.newMangaTimeMinutes;
this.newManga.timeSpent = totalMinutes > 0 ? totalMinutes : undefined;
}
updateEditMangaTimeSpent() {
const totalMinutes = (this.editMangaTimeHours * 60) + this.editMangaTimeMinutes;
this.editManga.timeSpent = totalMinutes > 0 ? totalMinutes : undefined;
}
addTag(target: 'new' | 'edit') { addTag(target: 'new' | 'edit') {
const input = target === 'new' ? this.newTagInput.trim() : this.editTagInput.trim(); const input = target === 'new' ? this.newTagInput.trim() : this.editTagInput.trim();
if (!input) return; if (!input) return;
@@ -1499,8 +1593,17 @@ export class MangaListComponent implements OnInit {
notes: manga.notes, notes: manga.notes,
coverImage: manga.coverImage, coverImage: manga.coverImage,
tags: [...(manga.tags || [])], tags: [...(manga.tags || [])],
links: [...(manga.links || [])] links: [...(manga.links || [])],
timeSpent: manga.timeSpent
}; };
// Populate time fields from existing timeSpent
if (manga.timeSpent) {
this.editMangaTimeHours = Math.floor(manga.timeSpent / 60);
this.editMangaTimeMinutes = manga.timeSpent % 60;
} else {
this.editMangaTimeHours = 0;
this.editMangaTimeMinutes = 0;
}
this.editMangaImagePreview.set(manga.coverImage || null); this.editMangaImagePreview.set(manga.coverImage || null);
this.showAddForm.set(false); this.showAddForm.set(false);
this.imageError.set(null); this.imageError.set(null);
@@ -1590,6 +1693,19 @@ export class MangaListComponent implements OnInit {
return new Date(date).toLocaleDateString(); return new Date(date).toLocaleDateString();
} }
formatTimeSpent(minutes: number): string {
const hours = Math.floor(minutes / 60);
const mins = minutes % 60;
if (hours === 0) {
return `${mins}m`;
} else if (mins === 0) {
return `${hours}h`;
} else {
return `${hours}h ${mins}m`;
}
}
toggleComments(mangaId: string) { toggleComments(mangaId: string) {
const expanded = this.expandedComments(); const expanded = this.expandedComments();
const isCurrentlyExpanded = expanded[mangaId]; const isCurrentlyExpanded = expanded[mangaId];
@@ -114,6 +114,34 @@ import { Music, MusicStatus, MusicType, CreateMusicDto, UpdateMusicDto, Comment,
> >
</div> </div>
<div class="form-row">
<div class="form-group">
<label for="timeHours">Time Spent (Hours)</label>
<input
type="number"
id="timeHours"
[(ngModel)]="newMusicTimeHours"
name="timeHours"
min="0"
placeholder="0"
(ngModelChange)="updateNewMusicTimeSpent()"
>
</div>
<div class="form-group">
<label for="timeMinutes">Time Spent (Minutes)</label>
<input
type="number"
id="timeMinutes"
[(ngModel)]="newMusicTimeMinutes"
name="timeMinutes"
min="0"
max="59"
placeholder="0"
(ngModelChange)="updateNewMusicTimeSpent()"
>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="notes">Notes</label> <label for="notes">Notes</label>
<textarea <textarea
@@ -274,6 +302,34 @@ import { Music, MusicStatus, MusicType, CreateMusicDto, UpdateMusicDto, Comment,
> >
</div> </div>
<div class="form-row">
<div class="form-group">
<label for="edit-timeHours">Time Spent (Hours)</label>
<input
type="number"
id="edit-timeHours"
[(ngModel)]="editMusicTimeHours"
name="timeHours"
min="0"
placeholder="0"
(ngModelChange)="updateEditMusicTimeSpent()"
>
</div>
<div class="form-group">
<label for="edit-timeMinutes">Time Spent (Minutes)</label>
<input
type="number"
id="edit-timeMinutes"
[(ngModel)]="editMusicTimeMinutes"
name="timeMinutes"
min="0"
max="59"
placeholder="0"
(ngModelChange)="updateEditMusicTimeSpent()"
>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="edit-notes">Notes</label> <label for="edit-notes">Notes</label>
<textarea <textarea
@@ -600,6 +656,12 @@ import { Music, MusicStatus, MusicType, CreateMusicDto, UpdateMusicDto, Comment,
</div> </div>
} }
@if (music.timeSpent) {
<p class="time-spent">
🎵 Listening Time: {{ formatTimeSpent(music.timeSpent) }}
</p>
}
<app-like-button <app-like-button
entityType="music" entityType="music"
[entityId]="music.id" [entityId]="music.id"
@@ -780,6 +842,13 @@ import { Music, MusicStatus, MusicType, CreateMusicDto, UpdateMusicDto, Comment,
box-shadow: 0 0 0 3px rgba(168, 87, 126, 0.2); box-shadow: 0 0 0 3px rgba(168, 87, 126, 0.2);
} }
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin-bottom: 1rem;
}
.form-actions { .form-actions {
display: flex; display: flex;
gap: 1rem; gap: 1rem;
@@ -1036,6 +1105,13 @@ import { Music, MusicStatus, MusicType, CreateMusicDto, UpdateMusicDto, Comment,
margin: 0.5rem 0; margin: 0.5rem 0;
} }
.time-spent {
font-size: 0.9rem;
color: #8b5cf6;
font-weight: 500;
margin: 0.5rem 0;
}
.date-started, .date-started,
.date-finished, .date-finished,
.date-added, .date-added,
@@ -1526,6 +1602,12 @@ export class MusicListComponent implements OnInit {
editMusicData: Partial<UpdateMusicDto> = {}; editMusicData: Partial<UpdateMusicDto> = {};
// Time tracking state
newMusicTimeHours = 0;
newMusicTimeMinutes = 0;
editMusicTimeHours = 0;
editMusicTimeMinutes = 0;
// Tags and links input state // Tags and links input state
newTagInput = ''; newTagInput = '';
editTagInput = ''; editTagInput = '';
@@ -1633,6 +1715,8 @@ export class MusicListComponent implements OnInit {
tags: [], tags: [],
links: [] links: []
}; };
this.newMusicTimeHours = 0;
this.newMusicTimeMinutes = 0;
this.newMusicImagePreview.set(null); this.newMusicImagePreview.set(null);
this.imageError.set(null); this.imageError.set(null);
this.newTagInput = ''; this.newTagInput = '';
@@ -1640,6 +1724,16 @@ export class MusicListComponent implements OnInit {
this.newLinkUrl = ''; this.newLinkUrl = '';
} }
updateNewMusicTimeSpent() {
const totalMinutes = (this.newMusicTimeHours * 60) + this.newMusicTimeMinutes;
this.newMusic.timeSpent = totalMinutes > 0 ? totalMinutes : undefined;
}
updateEditMusicTimeSpent() {
const totalMinutes = (this.editMusicTimeHours * 60) + this.editMusicTimeMinutes;
this.editMusicData.timeSpent = totalMinutes > 0 ? totalMinutes : undefined;
}
addTag(target: 'new' | 'edit') { addTag(target: 'new' | 'edit') {
const input = target === 'new' ? this.newTagInput.trim() : this.editTagInput.trim(); const input = target === 'new' ? this.newTagInput.trim() : this.editTagInput.trim();
if (!input) return; if (!input) return;
@@ -1729,8 +1823,17 @@ export class MusicListComponent implements OnInit {
notes: music.notes, notes: music.notes,
coverArt: music.coverArt, coverArt: music.coverArt,
tags: [...(music.tags || [])], tags: [...(music.tags || [])],
links: [...(music.links || [])] links: [...(music.links || [])],
timeSpent: music.timeSpent
}; };
// Populate time fields from existing timeSpent
if (music.timeSpent) {
this.editMusicTimeHours = Math.floor(music.timeSpent / 60);
this.editMusicTimeMinutes = music.timeSpent % 60;
} else {
this.editMusicTimeHours = 0;
this.editMusicTimeMinutes = 0;
}
this.editMusicImagePreview.set(music.coverArt || null); this.editMusicImagePreview.set(music.coverArt || null);
this.showAddForm.set(false); this.showAddForm.set(false);
this.imageError.set(null); this.imageError.set(null);
@@ -1769,6 +1872,19 @@ export class MusicListComponent implements OnInit {
return new Date(date).toLocaleDateString(); return new Date(date).toLocaleDateString();
} }
formatTimeSpent(minutes: number): string {
const hours = Math.floor(minutes / 60);
const mins = minutes % 60;
if (hours === 0) {
return `${mins}m`;
} else if (mins === 0) {
return `${hours}h`;
} else {
return `${hours}h ${mins}m`;
}
}
// Image handling methods // Image handling methods
onImageSelected(event: Event, target: 'new' | 'edit' | 'suggest') { onImageSelected(event: Event, target: 'new' | 'edit' | 'suggest') {
const input = event.target as HTMLInputElement; const input = event.target as HTMLInputElement;
@@ -103,6 +103,34 @@ import { Show, ShowStatus, ShowType, CreateShowDto, UpdateShowDto, Comment, Sugg
> >
</div> </div>
<div class="form-row">
<div class="form-group">
<label for="timeHours">Time Spent (Hours)</label>
<input
type="number"
id="timeHours"
[(ngModel)]="newShowTimeHours"
name="timeHours"
min="0"
placeholder="0"
(ngModelChange)="updateNewShowTimeSpent()"
>
</div>
<div class="form-group">
<label for="timeMinutes">Time Spent (Minutes)</label>
<input
type="number"
id="timeMinutes"
[(ngModel)]="newShowTimeMinutes"
name="timeMinutes"
min="0"
max="59"
placeholder="0"
(ngModelChange)="updateNewShowTimeSpent()"
>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="notes">Notes</label> <label for="notes">Notes</label>
<textarea <textarea
@@ -252,6 +280,34 @@ import { Show, ShowStatus, ShowType, CreateShowDto, UpdateShowDto, Comment, Sugg
> >
</div> </div>
<div class="form-row">
<div class="form-group">
<label for="edit-timeHours">Time Spent (Hours)</label>
<input
type="number"
id="edit-timeHours"
[(ngModel)]="editShowTimeHours"
name="timeHours"
min="0"
placeholder="0"
(ngModelChange)="updateEditShowTimeSpent()"
>
</div>
<div class="form-group">
<label for="edit-timeMinutes">Time Spent (Minutes)</label>
<input
type="number"
id="edit-timeMinutes"
[(ngModel)]="editShowTimeMinutes"
name="timeMinutes"
min="0"
max="59"
placeholder="0"
(ngModelChange)="updateEditShowTimeSpent()"
>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="edit-notes">Notes</label> <label for="edit-notes">Notes</label>
<textarea <textarea
@@ -518,6 +574,12 @@ import { Show, ShowStatus, ShowType, CreateShowDto, UpdateShowDto, Comment, Sugg
</div> </div>
} }
@if (show.timeSpent) {
<p class="time-spent">
📺 Watch Time: {{ formatTimeSpent(show.timeSpent) }}
</p>
}
<app-like-button <app-like-button
entityType="show" entityType="show"
[entityId]="show.id" [entityId]="show.id"
@@ -685,6 +747,13 @@ import { Show, ShowStatus, ShowType, CreateShowDto, UpdateShowDto, Comment, Sugg
font-size: 1rem; font-size: 1rem;
} }
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin-bottom: 1rem;
}
.form-actions { .form-actions {
display: flex; display: flex;
gap: 1rem; gap: 1rem;
@@ -879,6 +948,13 @@ import { Show, ShowStatus, ShowType, CreateShowDto, UpdateShowDto, Comment, Sugg
margin: 0.5rem 0; margin: 0.5rem 0;
} }
.time-spent {
font-size: 0.9rem;
color: #8b5cf6;
font-weight: 500;
margin: 0.5rem 0;
}
.date-started, .date-started,
.date-finished, .date-finished,
.date-added, .date-added,
@@ -1307,6 +1383,12 @@ export class ShowsListComponent implements OnInit {
editShow: Partial<UpdateShowDto> = {}; editShow: Partial<UpdateShowDto> = {};
// Time tracking state
newShowTimeHours = 0;
newShowTimeMinutes = 0;
editShowTimeHours = 0;
editShowTimeMinutes = 0;
// Tags and links input state // Tags and links input state
newTagInput = ''; newTagInput = '';
editTagInput = ''; editTagInput = '';
@@ -1408,6 +1490,8 @@ export class ShowsListComponent implements OnInit {
tags: [], tags: [],
links: [] links: []
}; };
this.newShowTimeHours = 0;
this.newShowTimeMinutes = 0;
this.newShowImagePreview.set(null); this.newShowImagePreview.set(null);
this.imageError.set(null); this.imageError.set(null);
this.newTagInput = ''; this.newTagInput = '';
@@ -1415,6 +1499,16 @@ export class ShowsListComponent implements OnInit {
this.newLinkUrl = ''; this.newLinkUrl = '';
} }
updateNewShowTimeSpent() {
const totalMinutes = (this.newShowTimeHours * 60) + this.newShowTimeMinutes;
this.newShow.timeSpent = totalMinutes > 0 ? totalMinutes : undefined;
}
updateEditShowTimeSpent() {
const totalMinutes = (this.editShowTimeHours * 60) + this.editShowTimeMinutes;
this.editShow.timeSpent = totalMinutes > 0 ? totalMinutes : undefined;
}
addTag(target: 'new' | 'edit') { addTag(target: 'new' | 'edit') {
const input = target === 'new' ? this.newTagInput.trim() : this.editTagInput.trim(); const input = target === 'new' ? this.newTagInput.trim() : this.editTagInput.trim();
if (!input) return; if (!input) return;
@@ -1502,8 +1596,17 @@ export class ShowsListComponent implements OnInit {
notes: show.notes, notes: show.notes,
coverImage: show.coverImage, coverImage: show.coverImage,
tags: [...(show.tags || [])], tags: [...(show.tags || [])],
links: [...(show.links || [])] links: [...(show.links || [])],
timeSpent: show.timeSpent
}; };
// Populate time fields from existing timeSpent
if (show.timeSpent) {
this.editShowTimeHours = Math.floor(show.timeSpent / 60);
this.editShowTimeMinutes = show.timeSpent % 60;
} else {
this.editShowTimeHours = 0;
this.editShowTimeMinutes = 0;
}
this.editShowImagePreview.set(show.coverImage || null); this.editShowImagePreview.set(show.coverImage || null);
this.showAddForm.set(false); this.showAddForm.set(false);
this.imageError.set(null); this.imageError.set(null);
@@ -1593,6 +1696,19 @@ export class ShowsListComponent implements OnInit {
return new Date(date).toLocaleDateString(); return new Date(date).toLocaleDateString();
} }
formatTimeSpent(minutes: number): string {
const hours = Math.floor(minutes / 60);
const mins = minutes % 60;
if (hours === 0) {
return `${mins}m`;
} else if (mins === 0) {
return `${hours}h`;
} else {
return `${hours}h ${mins}m`;
}
}
toggleComments(showId: string) { toggleComments(showId: string) {
const expanded = this.expandedComments(); const expanded = this.expandedComments();
const isCurrentlyExpanded = expanded[showId]; const isCurrentlyExpanded = expanded[showId];