Skip to content

Commit b504490

Browse files
feat: implement core management modules for veils, treatments, gallery, and settings pages
1 parent 2d30b72 commit b504490

13 files changed

Lines changed: 363 additions & 243 deletions

frontend/src/pages/gallery/gallery.component.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
} from "@angular/core";
99
import { CommonModule } from "@angular/common";
1010
import { FormsModule } from "@angular/forms";
11-
import { GalleryService, GALLERY_CATEGORIES, GalleryCategories } from "@entities/gallery";
11+
import { GalleryService, GalleryCategories } from "@entities/gallery";
12+
import { AdminSettingsService } from "@entities/admin-settings";
1213
import { Gallery, ImageCategory } from "@shared/models";
1314
import { GalleryFormComponent } from "./ui/gallery-form/gallery-form.component";
1415
import { ImagePopupComponent, ListViewComponent, ListViewColumn, CardViewComponent, CardViewConfig } from "@shared/ui";
@@ -26,6 +27,7 @@ import { environment } from "@environments/environment";
2627
})
2728
export class GalleryComponent implements OnInit {
2829
private galleryService = inject(GalleryService);
30+
private adminSettingsService = inject(AdminSettingsService);
2931
env = signal(environment);
3032

3133
isDragging = signal(false);
@@ -35,7 +37,14 @@ export class GalleryComponent implements OnInit {
3537

3638
images = this.galleryService.images;
3739

38-
filters = signal<ImageCategory[]>(GALLERY_CATEGORIES);
40+
// Dynamic categories from admin settings.
41+
// Falls back to ['all'] if settings not loaded yet.
42+
filters = computed<ImageCategory[]>(() => {
43+
const settings = this.adminSettingsService.settings();
44+
const cats = settings?.galleryCategories ?? [];
45+
return ['all', ...cats] as ImageCategory[];
46+
});
47+
3948
activeFilter = signal<ImageCategory>(GalleryCategories.ALL);
4049

4150
columns = signal<ListViewColumn[]>([
@@ -69,15 +78,20 @@ export class GalleryComponent implements OnInit {
6978
currentImage!: Gallery;
7079

7180
ngOnInit() {
81+
// Load settings if not yet cached
82+
if (!this.adminSettingsService.settings()) {
83+
this.adminSettingsService.getSettings().subscribe();
84+
}
7285
this.galleryService.getImages().subscribe();
7386
}
7487

7588
getEmptyImage(): Gallery {
89+
const firstCat = this.filters().find(f => f !== 'all') ?? GalleryCategories.ALL;
7690
return {
7791
id: "",
7892
imageUrl: "",
7993
title: "",
80-
category: GalleryCategories.VISAGE, // Default
94+
category: firstCat,
8195
status: "draft",
8296
alt: "",
8397
};
@@ -89,7 +103,7 @@ export class GalleryComponent implements OnInit {
89103
}
90104

91105
openModal(image: Gallery) {
92-
this.currentImage = { ...image }; // Create a copy for editing
106+
this.currentImage = { ...image };
93107
this.isModalOpen.set(true);
94108
}
95109

@@ -104,12 +118,10 @@ export class GalleryComponent implements OnInit {
104118
const formData = excludeFormDataProperties(convertFormData(...args), ["id", "createdAt", "updatedAt"]);
105119

106120
if (!image.id) {
107-
// New image
108121
this.galleryService.createImage(formData).subscribe(() => {
109122
this.closeModal();
110123
});
111124
} else {
112-
// Update existing
113125
this.galleryService
114126
.updateImage(image.id, formData)
115127
.subscribe(() => {
@@ -150,7 +162,6 @@ export class GalleryComponent implements OnInit {
150162
const files = event.dataTransfer?.files;
151163
if (files && files.length > 0) {
152164
console.log(`${files.length} files dropped`);
153-
// Here you would handle the file upload logic
154165
}
155166
}
156167
}

frontend/src/pages/settings/settings.component.html

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
11

22
<div class="p-4 sm:p-8 max-w-6xl mx-auto animate-page-enter pb-20">
3+
4+
<!-- Save Status Toasts -->
5+
@if (isSaving()) {
6+
<div class="fixed top-6 right-6 z-50 flex items-center space-x-3 bg-white border border-gray-200 rounded-xl shadow-lg px-5 py-3 animate-page-enter">
7+
<svg class="animate-spin h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24">
8+
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
9+
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path>
10+
</svg>
11+
<span class="text-sm font-medium text-gray-700">Saving...</span>
12+
</div>
13+
}
14+
@if (saveSuccess()) {
15+
<div class="fixed top-6 right-6 z-50 flex items-center space-x-3 bg-green-50 border border-green-200 rounded-xl shadow-lg px-5 py-3 animate-page-enter">
16+
<span class="material-symbols-outlined text-green-600 text-xl">check_circle</span>
17+
<span class="text-sm font-medium text-green-700">Saved successfully!</span>
18+
</div>
19+
}
20+
@if (saveError()) {
21+
<div class="fixed top-6 right-6 z-50 flex items-center space-x-3 bg-red-50 border border-red-200 rounded-xl shadow-lg px-5 py-3 animate-page-enter">
22+
<span class="material-symbols-outlined text-red-500 text-xl">error</span>
23+
<span class="text-sm font-medium text-red-700">{{ saveError() }}</span>
24+
</div>
25+
}
26+
27+
328
<!-- Page Header -->
429
<div class="mb-8">
530
<h1 class="font-serif text-4xl text-gray-900 mb-2" i18n="@@settingsTitle">Management of 'About' & Core Info</h1>
@@ -77,11 +102,13 @@ <h1 class="font-serif text-4xl text-gray-900 mb-2" i18n="@@settingsTitle">Manage
77102
[veilFabrics]="veilFabrics()"
78103
[veilTrainLengths]="veilTrainLengths()"
79104
[veilNecklines]="veilNecklines()"
105+
[isSaving]="isSaving()"
80106
(addItem)="addItem($event)"
81107
(updateItem)="updateItem($event.type, $event.index, $event.value)"
82108
(removeItem)="removeItem($event.type, $event.index)"
83109
(save)="saveSelectionLists()"
84110
/>
111+
85112
}
86113

87114
</div>

0 commit comments

Comments
 (0)