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
@@ -94,6 +94,65 @@ class RecipeRepository {
}
}
Future<Recipe> setRecipeVisibility(int id, {required bool isPublic, String? token}) async {
try {
final data = await _api.patchJson(
RecipeApiPaths.setVisibility(id),
body: {'isPublic': isPublic},
token: token,
);
if (data is! Map<String, dynamic>) {
throw const ApiException(
type: ApiErrorType.unknown, message: 'Ogiltigt svar från servern.');
}
return Recipe.fromJson(data);
} on ApiException {
rethrow;
} catch (_) {
throw const ApiException(
type: ApiErrorType.network, message: 'Kunde inte uppdatera synlighet.');
}
}
Future<Recipe> shareRecipeWithUsername(int id, {required String username, String? token}) async {
try {
final data = await _api.postJson(
RecipeApiPaths.share(id),
body: {'username': username},
token: token,
);
if (data is! Map<String, dynamic>) {
throw const ApiException(
type: ApiErrorType.unknown, message: 'Ogiltigt svar från servern.');
}
return Recipe.fromJson(data);
} on ApiException {
rethrow;
} catch (_) {
throw const ApiException(
type: ApiErrorType.network, message: 'Kunde inte dela receptet.');
}
}
Future<Recipe> unshareRecipeWithUsername(int id, {required String username, String? token}) async {
try {
final data = await _api.deleteJson(
RecipeApiPaths.unshare(id, username),
token: token,
);
if (data is! Map<String, dynamic>) {
throw const ApiException(
type: ApiErrorType.unknown, message: 'Ogiltigt svar från servern.');
}
return Recipe.fromJson(data);
} on ApiException {
rethrow;
} catch (_) {
throw const ApiException(
type: ApiErrorType.network, message: 'Kunde inte ta bort delning.');
}
}
Future<InventoryPreview> fetchInventoryPreview(int id,
{String? token}) async {
try {