Add product price retrieval feature in cities

- Implemented a new endpoint in FalukantController to fetch product prices in various cities based on product ID and current price.
- Developed the corresponding service method in FalukantService to calculate and return prices, considering user knowledge and city branches.
- Updated frontend components (RevenueSection and SaleSection) to display better prices for products, including loading logic and UI enhancements for price visibility.
- Added styling for price indicators based on branch types to improve user experience.
This commit is contained in:
Torsten Schulz (local)
2025-12-01 16:42:54 +01:00
parent 8c8841705c
commit adc7132404
5 changed files with 260 additions and 0 deletions

View File

@@ -3518,6 +3518,86 @@ class FalukantService extends BaseService {
return regions;
}
async getProductPricesInCities(hashedUserId, productId, currentPrice) {
const user = await this.getFalukantUserByHashedId(hashedUserId);
const character = await FalukantCharacter.findOne({ where: { userId: user.id } });
if (!character) {
throw new Error(`No FalukantCharacter found for user with id ${user.id}`);
}
// Produkt abrufen
const product = await ProductType.findOne({ where: { id: productId } });
if (!product) {
throw new Error(`Product not found with id ${productId}`);
}
// Knowledge für dieses Produkt abrufen
const knowledge = await Knowledge.findOne({
where: { characterId: character.id, productId: productId }
});
const knowledgeFactor = knowledge?.knowledge || 0;
// Alle Städte abrufen
const cities = await RegionData.findAll({
attributes: ['id', 'name'],
include: [
{
model: RegionType,
as: 'regionType',
where: { labelTr: 'city' },
attributes: ['labelTr']
},
{
model: Branch,
as: 'branches',
where: { falukantUserId: user.id },
include: [
{
model: BranchType,
as: 'branchType',
attributes: ['labelTr']
}
],
attributes: ['branchTypeId'],
required: false
}
]
});
// Für jede Stadt den Preis berechnen und Branch-Typ bestimmen
const results = [];
for (const city of cities) {
const priceInCity = calcSellPrice(product, knowledgeFactor);
// Nur Städte zurückgeben, wo der Preis höher ist
if (priceInCity > currentPrice) {
// Branch-Typ bestimmen
let branchType = null; // null = kein Branch
if (city.branches && city.branches.length > 0) {
// Finde den "besten" Branch-Typ (store/fullstack > production)
const branchTypes = city.branches.map(b => b.branchType?.labelTr).filter(Boolean);
if (branchTypes.includes('store') || branchTypes.includes('fullstack')) {
branchType = 'store'; // Grün
} else if (branchTypes.includes('production')) {
branchType = 'production'; // Orange
}
}
results.push({
regionId: city.id,
regionName: city.name,
price: priceInCity,
branchType: branchType // 'store' (grün), 'production' (orange), null (rot)
});
}
}
// Sortiere nach Preis (höchster zuerst)
results.sort((a, b) => b.price - a.price);
return results;
}
async renovate(hashedUserId, element) {
const user = await getFalukantUserOrFail(hashedUserId);
const house = await UserHouse.findOne({