mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-08-02 20:15:24 +02:00
feat(frontend): 👷 Add image operations to recipe page
Added/Fixed image upload/get process on the recipe pages as well as some additional styling
This commit is contained in:
parent
afcad2f701
commit
5ee0a57163
15 changed files with 238 additions and 114 deletions
|
@ -10,6 +10,36 @@ export interface CrudAPIInterface {
|
|||
// Methods
|
||||
}
|
||||
|
||||
export const crudMixins = <T>(
|
||||
requests: ApiRequestInstance,
|
||||
baseRoute: string,
|
||||
itemRoute: (itemId: string) => string
|
||||
) => {
|
||||
async function getAll(start = 0, limit = 9999) {
|
||||
return await requests.get<T[]>(baseRoute, {
|
||||
params: { start, limit },
|
||||
});
|
||||
}
|
||||
|
||||
async function getOne(itemId: string) {
|
||||
return await requests.get<T>(itemRoute(itemId));
|
||||
}
|
||||
|
||||
async function updateOne(itemId: string, payload: T) {
|
||||
return await requests.put<T>(itemRoute(itemId), payload);
|
||||
}
|
||||
|
||||
async function patchOne(itemId: string, payload: T) {
|
||||
return await requests.patch(itemRoute(itemId), payload);
|
||||
}
|
||||
|
||||
async function deleteOne(itemId: string) {
|
||||
return await requests.delete<T>(itemRoute(itemId));
|
||||
}
|
||||
|
||||
return { getAll, getOne, updateOne, patchOne, deleteOne };
|
||||
};
|
||||
|
||||
export abstract class BaseAPIClass<T> implements CrudAPIInterface {
|
||||
requests: ApiRequestInstance;
|
||||
|
||||
|
@ -30,11 +60,7 @@ export abstract class BaseAPIClass<T> implements CrudAPIInterface {
|
|||
return await this.requests.get<T>(this.itemRoute(itemId));
|
||||
}
|
||||
|
||||
async createOne(payload: T) {
|
||||
return await this.requests.post(this.baseRoute, payload);
|
||||
}
|
||||
|
||||
async updateOne(itemId: string, payload: T){
|
||||
async updateOne(itemId: string, payload: T) {
|
||||
return await this.requests.put<T>(this.itemRoute(itemId), payload);
|
||||
}
|
||||
|
||||
|
@ -45,5 +71,4 @@ export abstract class BaseAPIClass<T> implements CrudAPIInterface {
|
|||
async deleteOne(itemId: string) {
|
||||
return await this.requests.delete<T>(this.itemRoute(itemId));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { BaseAPIClass } from "./_base";
|
||||
import { BaseAPIClass, crudMixins } from "./_base";
|
||||
import { Recipe } from "~/types/api-types/admin";
|
||||
import { ApiRequestInstance } from "~/types/api";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
|
@ -10,7 +11,6 @@ const routes = {
|
|||
recipesTestScrapeUrl: `${prefix}/recipes/test-scrape-url`,
|
||||
recipesCreateUrl: `${prefix}/recipes/create-url`,
|
||||
recipesCreateFromZip: `${prefix}/recipes/create-from-zip`,
|
||||
|
||||
recipesCategory: `${prefix}/recipes/category`,
|
||||
|
||||
recipesRecipeSlug: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}`,
|
||||
|
@ -19,20 +19,45 @@ const routes = {
|
|||
recipesRecipeSlugAssets: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}/assets`,
|
||||
};
|
||||
|
||||
class RecipeAPI extends BaseAPIClass<Recipe> {
|
||||
export class RecipeAPI extends BaseAPIClass<Recipe> {
|
||||
baseRoute: string = routes.recipesSummary;
|
||||
itemRoute = (itemid: string) => routes.recipesRecipeSlug(itemid);
|
||||
itemRoute = routes.recipesRecipeSlug;
|
||||
|
||||
constructor(requests: ApiRequestInstance) {
|
||||
super(requests);
|
||||
const { getAll, getOne, updateOne, patchOne, deleteOne } = crudMixins<Recipe>(
|
||||
requests,
|
||||
routes.recipesSummary,
|
||||
routes.recipesRecipeSlug
|
||||
);
|
||||
|
||||
this.getAll = getAll;
|
||||
this.getOne = getOne;
|
||||
this.updateOne = updateOne;
|
||||
this.patchOne = patchOne;
|
||||
this.deleteOne = deleteOne;
|
||||
}
|
||||
|
||||
async getAllByCategory(categories: string[]) {
|
||||
return await this.requests.get<Recipe[]>(routes.recipesCategory, {
|
||||
categories
|
||||
categories,
|
||||
});
|
||||
}
|
||||
|
||||
// @ts-ignore - Override method doesn't take same arguments are parent class
|
||||
updateImage(slug: string, fileObject: File) {
|
||||
const formData = new FormData();
|
||||
formData.append("image", fileObject);
|
||||
formData.append("extension", fileObject.name.split(".").pop());
|
||||
|
||||
return this.requests.put<any>(routes.recipesRecipeSlugImage(slug), formData);
|
||||
}
|
||||
|
||||
updateImagebyURL(slug: string, url: string) {
|
||||
return this.requests.post(routes.recipesRecipeSlugImage(slug), { url });
|
||||
}
|
||||
|
||||
async createOne(name: string) {
|
||||
return await this.requests.post(routes.recipesBase, { name });
|
||||
return await this.requests.post<Recipe>(routes.recipesBase, { name });
|
||||
}
|
||||
|
||||
async createOneByUrl(url: string) {
|
||||
|
@ -56,5 +81,3 @@ class RecipeAPI extends BaseAPIClass<Recipe> {
|
|||
return `/api/media/recipes/${recipeSlug}/assets/${assetName}`;
|
||||
}
|
||||
}
|
||||
|
||||
export { RecipeAPI };
|
||||
|
|
31
frontend/api/class-interfaces/users.ts
Normal file
31
frontend/api/class-interfaces/users.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import { BaseAPIClass } from "./_base";
|
||||
import { UserOut } from "~/types/api-types/user";
|
||||
|
||||
const prefix = "/api";
|
||||
|
||||
const routes = {
|
||||
usersSelf: `${prefix}/users/self`,
|
||||
users: `${prefix}/users`,
|
||||
|
||||
usersIdImage: (id: string) => `${prefix}/users/${id}/image`,
|
||||
usersIdResetPassword: (id: string) => `${prefix}/users/${id}/reset-password`,
|
||||
usersId: (id: string) => `${prefix}/users/${id}`,
|
||||
usersIdPassword: (id: string) => `${prefix}/users/${id}/password`,
|
||||
usersIdFavorites: (id: string) => `${prefix}/users/${id}/favorites`,
|
||||
usersIdFavoritesSlug: (id: string, slug: string) => `${prefix}/users/${id}/favorites/${slug}`,
|
||||
};
|
||||
|
||||
export class UserApi extends BaseAPIClass<UserOut> {
|
||||
baseRoute: string = routes.users;
|
||||
itemRoute = (itemid: string) => routes.usersId(itemid);
|
||||
|
||||
async addFavorite(id: string, slug: string) {
|
||||
const response = await this.requests.post(routes.usersIdFavoritesSlug(id, slug), {});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async removeFavorite(id: string, slug: string) {
|
||||
const response = await this.requests.delete(routes.usersIdFavoritesSlug(id, slug));
|
||||
return response.data;
|
||||
}
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
import { RecipeAPI } from "./class-interfaces/recipes";
|
||||
import { UserApi } from "./class-interfaces/users";
|
||||
import { ApiRequestInstance } from "~/types/api";
|
||||
|
||||
class Api {
|
||||
private static instance: Api;
|
||||
public recipes: RecipeAPI;
|
||||
public users: UserApi;
|
||||
|
||||
constructor(requests: ApiRequestInstance) {
|
||||
if (Api.instance instanceof Api) {
|
||||
|
@ -11,6 +13,7 @@ class Api {
|
|||
}
|
||||
|
||||
this.recipes = new RecipeAPI(requests);
|
||||
this.users = new UserApi(requests);
|
||||
|
||||
Object.freeze(this);
|
||||
Api.instance = this;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue