meals-made-easy-app/src/app/shared/services/RecipeDraftService.ts

136 lines
5.1 KiB
TypeScript

import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { delay, firstValueFrom, map, Observable, of } from 'rxjs';
import { RecipeUploadClientModel } from '../client-models/RecipeUploadClientModel';
import { RecipeUploadStep } from '../client-models/RecipeUploadStep';
import { RecipeDraftViewModel } from '../models/RecipeDraftView.model';
import { EndpointService } from './EndpointService';
import { WithStringDates } from '../util';
import { Recipe } from '../models/Recipe.model';
import { ImageView } from '../models/ImageView.model';
import { SetImageBody } from '../models/SetImageBody';
import { ImageService } from './ImageService';
@Injectable({
providedIn: 'root',
})
export class RecipeDraftService {
private readonly http = inject(HttpClient);
private readonly endpointService = inject(EndpointService);
private readonly imageService = inject(ImageService);
private hydrateView(rawView: WithStringDates<RecipeDraftViewModel>): RecipeDraftViewModel {
return {
...rawView,
created: new Date(rawView.created),
modified: rawView.modified ? new Date(rawView.modified) : undefined,
mainImage: rawView.mainImage ? this.imageService.hydrateImageView(rawView.mainImage) : undefined,
lastInference: rawView.lastInference
? {
...rawView.lastInference,
inferredAt: new Date(rawView.lastInference.inferredAt),
}
: undefined,
};
}
public getInProgressDrafts(): Promise<RecipeDraftViewModel[]> {
return firstValueFrom(
this.http.get<WithStringDates<RecipeDraftViewModel>[]>(this.endpointService.getUrl('recipeDrafts')).pipe(
map((rawViews) => {
return rawViews.map((rawView) => this.hydrateView(rawView));
}),
),
);
}
public getRecipeUploadClientModel(draftId: string): Observable<RecipeUploadClientModel> {
return this.http
.get<WithStringDates<RecipeDraftViewModel>>(this.endpointService.getUrl('recipeDrafts', [draftId]))
.pipe(
map((rawDraft) => {
return this.hydrateView(rawDraft);
}),
map((draft) => {
return {
draft,
inProgressStep:
draft.state === 'ENTER_DATA' ? RecipeUploadStep.ENTER_DATA : RecipeUploadStep.INFER,
};
}),
);
}
public createManualDraft(): Promise<RecipeUploadClientModel> {
return firstValueFrom(
this.http
.post<
WithStringDates<RecipeDraftViewModel>
>(this.endpointService.getUrl('recipeDrafts', ['manual']), null)
.pipe(
map((rawDraft) => this.hydrateView(rawDraft)),
map((draft) => ({
draft,
inProgressStep: RecipeUploadStep.ENTER_DATA,
})),
),
);
}
public updateDraft(
id: string,
data: {
title?: string | null;
slug?: string | null;
ingredients?: Array<{
amount?: string | null;
name: string;
notes?: string | null;
}>;
mainImage?: ImageView | null;
rawText?: string | null;
},
): Promise<RecipeUploadClientModel> {
return firstValueFrom(
this.http
.put<WithStringDates<RecipeDraftViewModel>>(this.endpointService.getUrl('recipeDrafts', [id]), {
...data,
mainImage: data.mainImage
? ({
username: data.mainImage.owner.username,
userFilename: data.mainImage.filename,
} satisfies SetImageBody)
: undefined,
})
.pipe(
map((rawView) => this.hydrateView(rawView)),
map((draft) => ({
draft,
inProgressStep: RecipeUploadStep.ENTER_DATA,
})),
),
);
}
public publish(id: string): Promise<Recipe> {
return firstValueFrom(
this.http.post<Recipe>(this.endpointService.getUrl('recipeDrafts', [id, 'publish']), null),
);
}
public deleteDraft(id: string): Promise<void> {
return firstValueFrom(this.http.delete<void>(this.endpointService.getUrl('recipeDrafts', [id])));
}
public doInference(model: RecipeUploadClientModel): Observable<RecipeUploadClientModel> {
return of({
inProgressStep: RecipeUploadStep.ENTER_DATA,
id: 16,
inferredTitle: 'Some recipe',
inferredSlug: 'some-recipe',
inferredText: 'Some text.',
inferredIngredients: [],
}).pipe(delay(5_000));
}
}