chore(ci): update project documentation and flyer import features

Update project documentation with recent CI improvements and flyer import enhancements:

- Add ESLint configuration for backend and Dart lints for Flutter
- Document Prisma query logging via PRISMA_LOG_QUERIES environment variable
- Update NEXT_STEPS.md, README.md, and TEKNISK_BESKRIVNING.md with new features
- Add isOffer, offerLimitText, comparisonPrice, comparisonUnit, parseConfidence, and parseReasons fields to FlyerImportItem
- Update FlyerImportResponse type to include new fields
- Extend file picker to support image formats (png, jpg, jpeg, webp)
- Add offer badge display and price formatting in Flutter UI
- Implement PDF preview functionality for flyer import
This commit is contained in:
Nils-Johan Gynther
2026-05-18 23:27:20 +02:00
parent 3f242f9a6d
commit e658f2e6f1
7 changed files with 563 additions and 388 deletions
@@ -1,43 +1,61 @@
class FlyerImportItem {
final int? flyerItemId;
final String rawName;
final String normalizedName;
final String? category;
final double? price;
final String? priceUnit;
final String? offerText;
final int? matchedProductId;
final String? matchedProductName;
final String? matchedVia;
final double? matchConfidence;
FlyerImportItem({
required this.flyerItemId,
required this.rawName,
required this.normalizedName,
this.category,
this.price,
this.priceUnit,
this.offerText,
this.matchedProductId,
this.matchedProductName,
this.matchedVia,
this.matchConfidence,
});
factory FlyerImportItem.fromJson(Map<String, dynamic> json) {
return FlyerImportItem(
flyerItemId: (json['flyerItemId'] as num?)?.toInt(),
rawName: json['rawName'] as String? ?? '',
normalizedName: json['normalizedName'] as String? ?? '',
category: json['category'] as String?,
price: (json['price'] as num?)?.toDouble(),
priceUnit: json['priceUnit'] as String?,
offerText: json['offerText'] as String?,
matchedProductId: (json['matchedProductId'] as num?)?.toInt(),
matchedProductName: json['matchedProductName'] as String?,
matchedVia: json['matchedVia'] as String?,
matchConfidence: (json['matchConfidence'] as num?)?.toDouble(),
);
}
}
class FlyerImportItem {
final int? flyerItemId;
final String rawName;
final String normalizedName;
final String? category;
final double? price;
final String? priceUnit;
final String? offerText;
final bool isOffer;
final String? offerLimitText;
final double? comparisonPrice;
final String? comparisonUnit;
final double? parseConfidence;
final List<String> parseReasons;
final int? matchedProductId;
final String? matchedProductName;
final String? matchedVia;
final double? matchConfidence;
FlyerImportItem({
required this.flyerItemId,
required this.rawName,
required this.normalizedName,
this.category,
this.price,
this.priceUnit,
this.offerText,
this.isOffer = false,
this.offerLimitText,
this.comparisonPrice,
this.comparisonUnit,
this.parseConfidence,
this.parseReasons = const [],
this.matchedProductId,
this.matchedProductName,
this.matchedVia,
this.matchConfidence,
});
factory FlyerImportItem.fromJson(Map<String, dynamic> json) {
return FlyerImportItem(
flyerItemId: (json['flyerItemId'] as num?)?.toInt(),
rawName: json['rawName'] as String? ?? '',
normalizedName: json['normalizedName'] as String? ?? '',
category: json['category'] as String?,
price: (json['price'] as num?)?.toDouble(),
priceUnit: json['priceUnit'] as String?,
offerText: json['offerText'] as String?,
isOffer: json['isOffer'] == true,
offerLimitText: json['offerLimitText'] as String?,
comparisonPrice: (json['comparisonPrice'] as num?)?.toDouble(),
comparisonUnit: json['comparisonUnit'] as String?,
parseConfidence: (json['parseConfidence'] as num?)?.toDouble(),
parseReasons: (json['parseReasons'] as List?)?.map((e) => e.toString()).toList() ?? const [],
matchedProductId: (json['matchedProductId'] as num?)?.toInt(),
matchedProductName: json['matchedProductName'] as String?,
matchedVia: json['matchedVia'] as String?,
matchConfidence: (json['matchConfidence'] as num?)?.toDouble(),
);
}
}