feat(recipes): add recipe visibility and sharing features

- Implemented functionality to set recipe visibility (public/private) with appropriate checks for user permissions.
- Added ability to share recipes with other users, including validation for existing users and permissions.
- Introduced new DTOs for setting visibility and sharing recipes.
- Updated RecipesController and RecipesService to handle new endpoints for visibility and sharing.
- Enhanced inventory preview to consider user permissions and shared recipes.
- Updated front-end to support new sharing and visibility features, including UI changes for recipe detail and admin user management.
This commit is contained in:
Nils-Johan Gynther
2026-05-02 09:19:59 +02:00
parent f67bf8baef
commit 41ae7d4d06
17 changed files with 742 additions and 124 deletions
@@ -8,6 +8,10 @@ class Recipe {
final int? servings;
final String? instructions;
final List<RecipeIngredient> ingredients;
final bool isPublic;
final int? ownerId;
final String? ownerUsername;
final List<int> sharedWithUserIds;
const Recipe({
required this.id,
@@ -17,6 +21,10 @@ class Recipe {
this.servings,
this.instructions,
this.ingredients = const [],
this.isPublic = false,
this.ownerId,
this.ownerUsername,
this.sharedWithUserIds = const [],
});
factory Recipe.fromJson(Map<String, dynamic> json) {
@@ -27,6 +35,8 @@ class Recipe {
final dynamic rawServings = json['servings'];
final rawIngredients = json['ingredients'] as List<dynamic>? ?? [];
final normalizedImageUrl = rawImageUrl?.toString().trim();
final ownerJson = json['owner'] as Map<String, dynamic>?;
final sharesJson = json['shares'] as List<dynamic>? ?? const [];
return Recipe(
id: rawId is num ? rawId.toInt() : int.parse(rawId.toString()),
@@ -45,6 +55,18 @@ class Recipe {
ingredients: rawIngredients
.map((i) => RecipeIngredient.fromJson(i as Map<String, dynamic>))
.toList(),
isPublic: json['isPublic'] == true,
ownerId: ownerJson == null
? null
: (ownerJson['id'] is num
? (ownerJson['id'] as num).toInt()
: int.tryParse('${ownerJson['id']}')),
ownerUsername: ownerJson?['username']?.toString(),
sharedWithUserIds: sharesJson
.map((s) => (s as Map<String, dynamic>)['userId'])
.whereType<num>()
.map((id) => id.toInt())
.toList(),
);
}
}