/** * Recipes service - API communication layer * Handles all recipe-related HTTP requests using the API client * Mirrors backend endpoints exactly for tenant-dependent operations */ import { apiClient } from '../client/apiClient'; import type { RecipeResponse, RecipeCreate, RecipeUpdate, RecipeSearchParams, RecipeDuplicateRequest, RecipeFeasibilityResponse, RecipeStatisticsResponse, RecipeCategoriesResponse, } from '../types/recipes'; /** * Recipes API service * All methods return promises that resolve to the response data * Follows tenant-dependent routing pattern: /tenants/{tenant_id}/recipes */ export class RecipesService { /** * Get tenant-scoped base URL for recipes */ private getBaseUrl(tenantId: string): string { return `/tenants/${tenantId}/recipes`; } /** * Create a new recipe * POST /tenants/{tenant_id}/recipes */ async createRecipe(tenantId: string, recipeData: RecipeCreate): Promise { const baseUrl = this.getBaseUrl(tenantId); return apiClient.post(baseUrl, recipeData); } /** * Get recipe by ID with ingredients * GET /tenants/{tenant_id}/recipes/{recipe_id} */ async getRecipe(tenantId: string, recipeId: string): Promise { const baseUrl = this.getBaseUrl(tenantId); return apiClient.get(`${baseUrl}/${recipeId}`); } /** * Update an existing recipe * PUT /tenants/{tenant_id}/recipes/{recipe_id} */ async updateRecipe(tenantId: string, recipeId: string, recipeData: RecipeUpdate): Promise { const baseUrl = this.getBaseUrl(tenantId); return apiClient.put(`${baseUrl}/${recipeId}`, recipeData); } /** * Delete a recipe * DELETE /tenants/{tenant_id}/recipes/{recipe_id} */ async deleteRecipe(tenantId: string, recipeId: string): Promise<{ message: string }> { const baseUrl = this.getBaseUrl(tenantId); return apiClient.delete<{ message: string }>(`${baseUrl}/${recipeId}`); } /** * Search recipes with filters * GET /tenants/{tenant_id}/recipes */ async searchRecipes(tenantId: string, params: RecipeSearchParams = {}): Promise { const baseUrl = this.getBaseUrl(tenantId); const searchParams = new URLSearchParams(); // Add all non-empty parameters to the query string Object.entries(params).forEach(([key, value]) => { if (value !== undefined && value !== null && value !== '') { searchParams.append(key, String(value)); } }); const queryString = searchParams.toString(); const url = queryString ? `${baseUrl}?${queryString}` : baseUrl; return apiClient.get(url); } /** * Get all recipes (shorthand for search without filters) * GET /tenants/{tenant_id}/recipes */ async getRecipes(tenantId: string): Promise { return this.searchRecipes(tenantId); } /** * Duplicate an existing recipe * POST /tenants/{tenant_id}/recipes/{recipe_id}/duplicate */ async duplicateRecipe(tenantId: string, recipeId: string, duplicateData: RecipeDuplicateRequest): Promise { const baseUrl = this.getBaseUrl(tenantId); return apiClient.post(`${baseUrl}/${recipeId}/duplicate`, duplicateData); } /** * Activate a recipe for production * POST /tenants/{tenant_id}/recipes/{recipe_id}/activate */ async activateRecipe(tenantId: string, recipeId: string): Promise { const baseUrl = this.getBaseUrl(tenantId); return apiClient.post(`${baseUrl}/${recipeId}/activate`); } /** * Check if recipe can be produced with current inventory * GET /tenants/{tenant_id}/recipes/{recipe_id}/feasibility */ async checkRecipeFeasibility(tenantId: string, recipeId: string, batchMultiplier: number = 1.0): Promise { const baseUrl = this.getBaseUrl(tenantId); const params = new URLSearchParams({ batch_multiplier: String(batchMultiplier) }); return apiClient.get(`${baseUrl}/${recipeId}/feasibility?${params}`); } /** * Get recipe statistics for dashboard * GET /tenants/{tenant_id}/recipes/statistics/dashboard */ async getRecipeStatistics(tenantId: string): Promise { const baseUrl = this.getBaseUrl(tenantId); return apiClient.get(`${baseUrl}/statistics/dashboard`); } /** * Get list of recipe categories used by tenant * GET /tenants/{tenant_id}/recipes/categories/list */ async getRecipeCategories(tenantId: string): Promise { const baseUrl = this.getBaseUrl(tenantId); return apiClient.get(`${baseUrl}/categories/list`); } } // Create and export singleton instance export const recipesService = new RecipesService(); export default recipesService;