fix(router): adjust type check for extra parameter in navigation
fix(import): ensure correct typing for passing markdown and imageUrl fix(recipes): delete local image file on recipe deletion to avoid orphan files
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
import { Prisma } from '@prisma/client';
|
import { Prisma } from '@prisma/client';
|
||||||
|
import * as fs from 'node:fs/promises';
|
||||||
|
import * as path from 'node:path';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
import { CreateRecipeDto } from './dto/create-recipe.dto';
|
import { CreateRecipeDto } from './dto/create-recipe.dto';
|
||||||
import { ParseMarkdownDto } from './dto/parse-markdown.dto';
|
import { ParseMarkdownDto } from './dto/parse-markdown.dto';
|
||||||
@@ -272,6 +274,15 @@ export class RecipesService {
|
|||||||
|
|
||||||
await this.prisma.recipeIngredient.deleteMany({ where: { recipeId: id } });
|
await this.prisma.recipeIngredient.deleteMany({ where: { recipeId: id } });
|
||||||
await this.prisma.recipe.delete({ where: { id } });
|
await this.prisma.recipe.delete({ where: { id } });
|
||||||
|
|
||||||
|
// Radera lokal bildfil om den finns (undviker orphan-filer på disk).
|
||||||
|
if (existingRecipe.imageUrl?.startsWith('/images/')) {
|
||||||
|
const filename = path.basename(existingRecipe.imageUrl);
|
||||||
|
const filePath = path.join(IMAGE_DEST_DIR, filename);
|
||||||
|
await fs.unlink(filePath).catch(() => {
|
||||||
|
// Filen kanske redan är borttagen — ignorera felet.
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateImage(id: number, sourceUrl: string) {
|
async updateImage(id: number, sourceUrl: string) {
|
||||||
|
|||||||
@@ -71,7 +71,9 @@ final appRouterProvider = Provider<GoRouter>((ref) {
|
|||||||
final extra = state.extra;
|
final extra = state.extra;
|
||||||
String? initialMarkdown;
|
String? initialMarkdown;
|
||||||
String? initialImageUrl;
|
String? initialImageUrl;
|
||||||
if (extra is Map<String, dynamic>) {
|
// Use 'is Map' without type params — Dart reifies generics, so
|
||||||
|
// Map<String,String?> does NOT match Map<String,dynamic> at runtime.
|
||||||
|
if (extra is Map) {
|
||||||
initialMarkdown = extra['markdown'] as String?;
|
initialMarkdown = extra['markdown'] as String?;
|
||||||
initialImageUrl = extra['imageUrl'] as String?;
|
initialImageUrl = extra['imageUrl'] as String?;
|
||||||
} else if (extra is String) {
|
} else if (extra is String) {
|
||||||
|
|||||||
@@ -78,8 +78,9 @@ class _RecipeImportTabState extends ConsumerState<RecipeImportTab> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
// Pass both markdown and imageUrl so CreateRecipeScreen can pre-fill both.
|
// Explicitly typed as <String, dynamic> so the router's
|
||||||
context.push('/recipes/create', extra: {
|
// 'is Map<String, dynamic>' runtime check succeeds.
|
||||||
|
context.push('/recipes/create', extra: <String, dynamic>{
|
||||||
'markdown': result.markdown,
|
'markdown': result.markdown,
|
||||||
'imageUrl': result.imageUrl,
|
'imageUrl': result.imageUrl,
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user