diff --git a/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/edit-image-dialog/edit-image-dialog.css b/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/edit-image-dialog/edit-image-dialog.css
new file mode 100644
index 0000000..b9cb93b
--- /dev/null
+++ b/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/edit-image-dialog/edit-image-dialog.css
@@ -0,0 +1,5 @@
+form {
+ display: flex;
+ flex-direction: column;
+ row-gap: 10px;
+}
diff --git a/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/edit-image-dialog/edit-image-dialog.html b/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/edit-image-dialog/edit-image-dialog.html
new file mode 100644
index 0000000..1b8a264
--- /dev/null
+++ b/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/edit-image-dialog/edit-image-dialog.html
@@ -0,0 +1,17 @@
+
+
+
diff --git a/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/edit-image-dialog/edit-image-dialog.spec.ts b/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/edit-image-dialog/edit-image-dialog.spec.ts
new file mode 100644
index 0000000..3659271
--- /dev/null
+++ b/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/edit-image-dialog/edit-image-dialog.spec.ts
@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { EditImageDialog } from './edit-image-dialog';
+
+describe('EditImageDialog', () => {
+ let component: EditImageDialog;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [EditImageDialog],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(EditImageDialog);
+ component = fixture.componentInstance;
+ await fixture.whenStable();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/edit-image-dialog/edit-image-dialog.ts b/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/edit-image-dialog/edit-image-dialog.ts
new file mode 100644
index 0000000..6180435
--- /dev/null
+++ b/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/edit-image-dialog/edit-image-dialog.ts
@@ -0,0 +1,54 @@
+import { Component, inject, input, OnInit } from '@angular/core';
+import { DialogContainer } from '../../../../../../shared/components/dialog-container/dialog-container';
+import { MatFormField, MatInput, MatLabel } from '@angular/material/input';
+import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
+import { ImageView } from '../../../../../../shared/models/ImageView.model';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { MatButton } from '@angular/material/button';
+import { ImageService } from '../../../../../../shared/services/ImageService';
+import { QueryClient } from '@tanstack/angular-query-experimental';
+
+@Component({
+ selector: 'app-edit-image-dialog',
+ imports: [DialogContainer, MatFormField, MatLabel, MatInput, ReactiveFormsModule, MatButton],
+ templateUrl: './edit-image-dialog.html',
+ styleUrl: './edit-image-dialog.css',
+})
+export class EditImageDialog implements OnInit {
+ protected readonly imageView: ImageView = inject(MAT_DIALOG_DATA);
+ private readonly imageService = inject(ImageService);
+ private readonly queryClient = inject(QueryClient);
+ private readonly dialogRef = inject(MatDialogRef);
+
+ protected readonly imageForm = new FormGroup({
+ filename: new FormControl(
+ {
+ value: '',
+ disabled: true,
+ },
+ Validators.required,
+ ),
+ alt: new FormControl(''),
+ caption: new FormControl(''),
+ });
+
+ public ngOnInit(): void {
+ this.imageForm.patchValue({
+ filename: this.imageView.filename,
+ alt: this.imageView.alt,
+ caption: this.imageView.alt,
+ });
+ }
+
+ public async onSubmit(event: SubmitEvent): Promise {
+ event.preventDefault();
+ await this.imageService.updateImage(this.imageView.owner.username, this.imageView.filename, {
+ alt: this.imageForm.value.alt,
+ caption: this.imageForm.value.caption,
+ });
+ await this.queryClient.invalidateQueries({
+ queryKey: ['image-views'],
+ });
+ this.dialogRef.close();
+ }
+}
diff --git a/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/image-select.css b/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/image-select.css
index 4a9b765..9b65a85 100644
--- a/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/image-select.css
+++ b/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/image-select.css
@@ -13,3 +13,8 @@
mat-card-content p {
overflow-wrap: anywhere;
}
+
+mat-card-actions {
+ display: flex;
+ justify-content: space-between;
+}
diff --git a/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/image-select.html b/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/image-select.html
index 5625fd0..7bb923b 100644
--- a/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/image-select.html
+++ b/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/image-select.html
@@ -26,7 +26,17 @@
Main image
+ >Main?
+
+
+
+
+
}
diff --git a/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/image-select.ts b/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/image-select.ts
index 77f43c0..516a8af 100644
--- a/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/image-select.ts
+++ b/src/app/pages/recipe-upload-page/steps/enter-recipe-data/image-select/image-select.ts
@@ -1,16 +1,35 @@
import { Component, computed, inject, input, output, signal } from '@angular/core';
import { MatPaginator, PageEvent } from '@angular/material/paginator';
import { ImageService } from '../../../../../shared/services/ImageService';
-import { injectQuery, keepPreviousData } from '@tanstack/angular-query-experimental';
+import { injectQuery, keepPreviousData, QueryClient } from '@tanstack/angular-query-experimental';
import { Spinner } from '../../../../../shared/components/spinner/spinner';
import { ImageView } from '../../../../../shared/models/ImageView.model';
import { injectQueries } from '@tanstack/angular-query-experimental/inject-queries-experimental';
import { MatCard, MatCardActions, MatCardContent, MatCardImage } from '@angular/material/card';
import { MatCheckbox } from '@angular/material/checkbox';
+import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu';
+import { FaIconComponent } from '@fortawesome/angular-fontawesome';
+import { faEllipsis } from '@fortawesome/free-solid-svg-icons';
+import { MatButton } from '@angular/material/button';
+import { MatDialog } from '@angular/material/dialog';
+import { EditImageDialog } from './edit-image-dialog/edit-image-dialog';
@Component({
selector: 'app-image-select',
- imports: [MatPaginator, Spinner, MatCard, MatCardImage, MatCardContent, MatCardActions, MatCheckbox],
+ imports: [
+ MatPaginator,
+ Spinner,
+ MatCard,
+ MatCardImage,
+ MatCardContent,
+ MatCardActions,
+ MatCheckbox,
+ MatMenuTrigger,
+ MatMenu,
+ FaIconComponent,
+ MatButton,
+ MatMenuItem,
+ ],
templateUrl: './image-select.html',
styleUrl: './image-select.css',
})
@@ -22,6 +41,8 @@ export class ImageSelect {
protected readonly pageSize = signal(9);
private readonly imageService = inject(ImageService);
+ private readonly dialog = inject(MatDialog);
+ private readonly queryClient = inject(QueryClient);
protected readonly imageViewsQuery = injectQuery(() => ({
queryKey: ['image-views', this.currentPage(), this.pageSize()],
@@ -90,4 +111,22 @@ export class ImageSelect {
}
return false;
}
+
+ protected editImage(imageView: ImageView): void {
+ this.dialog.open(EditImageDialog, {
+ data: imageView,
+ });
+ }
+
+ protected async deleteImage(imageView: ImageView): Promise {
+ await this.imageService.deleteImage(imageView.owner.username, imageView.filename);
+ await this.queryClient.invalidateQueries({
+ queryKey: ['image-views'],
+ });
+ await this.queryClient.invalidateQueries({
+ queryKey: ['images'],
+ });
+ }
+
+ protected readonly faEllipsis = faEllipsis;
}
diff --git a/src/app/shared/services/ImageService.ts b/src/app/shared/services/ImageService.ts
index 81f8a5a..abe6097 100644
--- a/src/app/shared/services/ImageService.ts
+++ b/src/app/shared/services/ImageService.ts
@@ -81,4 +81,27 @@ export class ImageService {
.pipe(map((view) => view.exists)),
);
}
+
+ public deleteImage(username: string, filename: string): Promise {
+ return firstValueFrom(
+ this.httpClient.delete(this.endpointService.getUrl('images', [username, filename])),
+ );
+ }
+
+ public updateImage(
+ username: string,
+ filename: string,
+ data: {
+ alt?: string | null;
+ caption?: string | null;
+ isPublic?: boolean | null;
+ viewersToAdd?: string[] | null;
+ viewersToRemove?: string[] | null;
+ clearAllViewers?: boolean | null;
+ },
+ ): Promise {
+ return firstValueFrom(
+ this.httpClient.put(this.endpointService.getUrl('images', [username, filename]), data),
+ );
+ }
}