Files
Mimante/Mimante/Documentation/UI_PRODUCT_VALUE_IMPLEMENTATION.md
T
Alby96 ee67bedc31 Aggiunta calcolo valore prodotto e miglioramenti UI
Implementato il calcolo del valore reale dei prodotti in asta,
includendo il prezzo "Compra Subito", spese di spedizione e
risparmio stimato. Aggiunta una nuova sezione "Info Prodotto"
nella UI per visualizzare i dettagli estratti e i calcoli.

- **AuctionMonitorControl.xaml**: Aggiunta sezione fissa per
  mostrare informazioni prodotto e calcolo valore.
- **AuctionMonitorControl.xaml.cs**: Gestiti eventi per il
  caricamento e aggiornamento delle informazioni prodotto.
- **MainWindow**: Integrati handler per il calcolo e refresh
  delle informazioni prodotto.
- **AuctionInfo.cs**: Aggiunte proprietà per gestire prezzo
  "Compra Subito", spese di spedizione e limiti di vincita.
- **ProductValueCalculator.cs**: Nuova utility per calcolare
  il valore del prodotto e parsare informazioni dall'HTML.
- **AuctionViewModel.cs**: Binding per visualizzare risparmio,
  costo totale e convenienza nella UI.
- **Documentazione**: Aggiornata con dettagli sull'algoritmo
  di calcolo e layout UI.

Fix:
- Risolto problema di encoding UTF-8 per emoji nella UI.
- Migliorato parsing HTML per prezzi e limiti di vincita.

TODO:
- Testare parsing su più aste e gestire edge cases.
- Implementare caricamento automatico delle informazioni.
2025-11-21 16:55:21 +01:00

10 KiB
Raw Blame History

?? Product Value Calculator - Implementazione UI Completata

? Stato Implementazione

L'interfaccia grafica per il calcolo del valore del prodotto è stata completata e integrata nel pannello "Impostazioni Asta".

?? Dove Trovarla

Posizione UI

  1. Avvia l'applicazione
  2. Aggiungi un'asta alla lista monitorata
  3. Seleziona l'asta cliccando sulla riga nella griglia
  4. Nel pannello destro "Impostazioni" (in basso a sinistra)
  5. Troverai un Expander "?? Informazioni Prodotto"
  6. Clicca per espandere la sezione

Layout Visivo

?? IMPOSTAZIONI ??????????????????????????????
?                                             ?
? Nome Asta                                   ?
? https://it.bidoo.com/auction.php?a=...     ?
?                                             ?
? [Browser Interno] [Browser Esterno]        ?
? [Copia URL]       [Esporta]                 ?
?                                             ?
? ? ?? Informazioni Prodotto                 ?
? ?? Compra Subito: 20.00€                   ?
? ?? Spedizione: -                            ?
? ?? Limite: 1 volta ogni 30 giorni          ?
? ?                                           ?
? ?? ?? Valore Attuale                       ?
? ?  Prezzo attuale: 1.50€                   ?
? ?  Mie puntate: 10 (2.00€)                 ?
? ?  ??????????????????????                  ?
? ?  Costo totale: 3.50€                     ?
? ?  Risparmio: +16.50€ (82.5%)              ?
? ?                                           ?
? ?  ?? Raccomandazione:                     ?
? ?  Conveniente! Continua a puntare.        ?
? ?                                           ?
? ?? [?? Carica Info Prodotto]               ?
?                                             ?
? Anticipo (ms): [200]  Min EUR: [0]         ?
? Max EUR: [0]          Max Clicks: [0]      ?
? ? Verifica stato asta prima di puntare     ?
?                                             ?
? [Reset]                                     ?
???????????????????????????????????????????????

?? Componenti UI

1. Informazioni Statiche

  • Compra Subito: Prezzo "Compra Subito" del prodotto (estratto dall'HTML)
  • Spedizione: Spese di spedizione (se disponibili)
  • Limite: Limite di vincita (es: "1 volta ogni 30 giorni")

2. Valore Calcolato (Dinamico)

Appare solo quando il valore è stato calcolato:

  • Prezzo attuale: Prezzo corrente dell'asta
  • Mie puntate: Numero puntate × costo (default 0.20€/puntata)
  • Costo totale: Prezzo + Puntate + Spedizione
  • Risparmio: Differenza vs Compra Subito (+ verde, - rosso)

3. Raccomandazione

Messaggio intelligente basato sulla convenienza:

  • ? Conveniente: "Conveniente! Continua a puntare."
  • ? Non conveniente: "Non conviene più. Stai spendendo troppo."
  • ?? Neutro: "Valuta attentamente prima di continuare."

4. Pulsante Azione

  • ?? Carica Info Prodotto: Scarica dati dalla pagina dell'asta
    • Al clic: Scarica HTML, estrae info, aggiorna UI
    • Stato caricamento mostrato sotto il pulsante

?? Quando Si Caricano i Dati

Opzione 1: Manuale (Attuale)

  1. Selezioni l'asta
  2. Espandi "?? Informazioni Prodotto"
  3. Clicchi "?? Carica Info Prodotto"
  4. Attendi qualche secondo
  5. Le informazioni appaiono

Opzione 2: Automatico (Da Implementare)

  • All'aggiunta dell'asta: Carica automaticamente in background
  • Ad ogni puntata: Aggiorna il valore calcolato
  • Ogni N secondi: Refresh automatico durante il monitoraggio

?? Dati Estratti dall'HTML

Prezzo "Compra Subito"

Cerca questi pattern nell'HTML:

<!-- Pattern 1: buy-rapid-now -->
<div class="btn-rapid buy-rapid-now">€ 20,00</div>

<!-- Pattern 2: buy-now -->
<a class="buy-now">20,00 €</a>

<!-- Pattern 3: reserved-price (fallback) -->
<span class="reserved-price">
  <span>Valore:</span> 20,00 €
</span>

Limite Vincita

<i class="bi bi-limit-win" 
   title="Puoi vincere questo prodotto 1 volta ogni 30 giorni">
</i>

?? Calcolo del Valore

Formula

Costo Puntate = Numero Puntate Utente × 0.20€
Costo Totale = Prezzo Attuale + Costo Puntate + Spese Spedizione
Risparmio = (Compra Subito + Spedizione) - Costo Totale
Percentuale = (Risparmio / (Compra Subito + Spedizione)) × 100

Esempio Pratico

  • Asta: 47 Puntate (valore 9.40€)
  • Prezzo attuale: 0.33€
  • Mie puntate: 10 × 0.20€ = 2.00€
  • Spedizione: 0€ (digitale)
  • Costo totale: 0.33€ + 2.00€ = 2.33€
  • Compra Subito: 9.40€
  • Risparmio: 9.40€ - 2.33€ = +7.07€ (75.2%) ?

Raccomandazione: Conveniente! Vale la pena continuare.

?? Completamento Implementazione

Mancano Solo (2 Step):

Step 1: Binding Evento nel MainWindow.xaml

Aggiungi alla definizione del AuctionMonitorControl:

<controls:AuctionMonitorControl x:Name="AuctionMonitor"
    ...
    RefreshProductInfoClicked="AuctionMonitor_RefreshProductInfoClicked"
    .../>

Step 2: Handler nel MainWindow

File: Core/MainWindow.ControlEvents.cs

private void AuctionMonitor_RefreshProductInfoClicked(object sender, RoutedEventArgs e)
{
    RefreshProductInfo_Click(sender, e);
}

File: Core/MainWindow.ButtonHandlers.cs (o nuovo file)

private async void RefreshProductInfo_Click(object sender, RoutedEventArgs e)
{
    if (_selectedAuction == null)
    {
        MessageBox.Show(
            "Seleziona un'asta dalla griglia",
            "Nessuna Selezione",
            MessageBoxButton.OK,
            MessageBoxImage.Information);
        return;
    }

    try
    {
        // Mostra stato caricamento
        AuctionMonitor.ProductInfoStatusText.Text = "Caricamento...";
        
        // Scarica info prodotto
        var apiClient = new BidooApiClient();
        var session = _auctionMonitor.GetSession();
        apiClient.InitializeSession(session.AuthToken, session.Username);
        
        bool extracted = await AuctionMonitorProductValueExtensions.InitializeProductInfoAsync(
            apiClient,
            _selectedAuction.AuctionInfo
        );
        
        if (extracted)
        {
            // Aggiorna UI con i dati estratti
            UpdateProductInfoDisplay(_selectedAuction);
            AuctionMonitor.ProductInfoStatusText.Text = "Informazioni caricate";
            Log($"[INFO] Informazioni prodotto caricate per: {_selectedAuction.Name}", LogLevel.Success);
        }
        else
        {
            AuctionMonitor.ProductInfoStatusText.Text = "Nessuna informazione trovata";
            Log($"[WARN] Impossibile estrarre info prodotto per: {_selectedAuction.Name}", LogLevel.Warn);
        }
    }
    catch (Exception ex)
    {
        AuctionMonitor.ProductInfoStatusText.Text = $"Errore: {ex.Message}";
        Log($"[ERROR] Caricamento info prodotto: {ex.Message}", LogLevel.Error);
        MessageBox.Show($"Errore durante il caricamento:\n{ex.Message}", "Errore", MessageBoxButton.OK, MessageBoxImage.Error);
    }
}

private void UpdateProductInfoDisplay(AuctionViewModel vm)
{
    var auction = vm.AuctionInfo;
    
    // Aggiorna campi statici
    if (auction.BuyNowPrice.HasValue)
    {
        AuctionMonitor.ProductBuyNowPriceText.Text = $"{auction.BuyNowPrice.Value:F2}€";
    }
    else
    {
        AuctionMonitor.ProductBuyNowPriceText.Text = "-";
    }
    
    if (auction.ShippingCost.HasValue && auction.ShippingCost.Value > 0)
    {
        AuctionMonitor.ProductShippingCostText.Text = $"{auction.ShippingCost.Value:F2}€";
    }
    else
    {
        AuctionMonitor.ProductShippingCostText.Text = "-";
    }
    
    if (auction.HasWinLimit && !string.IsNullOrWhiteSpace(auction.WinLimitDescription))
    {
        AuctionMonitor.ProductWinLimitText.Text = auction.WinLimitDescription;
    }
    else
    {
        AuctionMonitor.ProductWinLimitText.Text = "Nessun limite";
    }
    
    // Calcola e mostra valore se disponibile
    if (auction.CalculatedValue != null)
    {
        UpdateProductValueDisplay(auction.CalculatedValue);
    }
}

private void UpdateProductValueDisplay(ProductValue value)
{
    // Mostra il pannello valore
    AuctionMonitor.ProductValueBorder.Visibility = Visibility.Visible;
    
    // Aggiorna campi
    AuctionMonitor.ValueCurrentPriceText.Text = $"{value.CurrentPrice:F2}€";
    AuctionMonitor.ValueMyBidsText.Text = $"{value.MyBids} × 0.20€ = {value.MyBidsCost:F2}€";
    AuctionMonitor.ValueTotalCostText.Text = $"{value.TotalCostIfWin:F2}€";
    
    if (value.Savings.HasValue)
    {
        var savingsText = value.Savings.Value >= 0 
            ? $"+{value.Savings.Value:F2}€ ({value.SavingsPercentage:F1}%)"
            : $"{value.Savings.Value:F2}€ ({value.SavingsPercentage:F1}%)";
        
        AuctionMonitor.ValueSavingsText.Text = savingsText;
        AuctionMonitor.ValueSavingsText.Foreground = value.IsWorthIt 
            ? new SolidColorBrush(Color.FromRgb(0, 216, 0))  // Verde
            : new SolidColorBrush(Color.FromRgb(232, 17, 35)); // Rosso
        
        // Mostra raccomandazione
        AuctionMonitor.ValueRecommendationBorder.Visibility = Visibility.Visible;
        
        if (value.IsWorthIt)
        {
            AuctionMonitor.ValueRecommendationText.Text = 
                "Conveniente! Vale la pena continuare a puntare.";
        }
        else
        {
            AuctionMonitor.ValueRecommendationText.Text = 
                "Non conviene più. Il costo totale supera il prezzo 'Compra Subito'.";
        }
    }
}

?? Note Implementative

Aggiornamento Automatico del Valore

Per aggiornare il valore durante il monitoraggio, aggiungi in Monitor_OnAuctionUpdated:

// Aggiorna valore ogni 10 reset per ridurre overhead
if (auction.ResetCount % 10 == 0 && auction.CalculatedValue != null)
{
    AuctionMonitorProductValueExtensions.UpdateProductValue(auction, state);
    
    if (_selectedAuction == auction)
    {
        UpdateProductValueDisplay(auction.CalculatedValue);
    }
}

Persistenza

Le informazioni del prodotto vengono salvate automaticamente nel file JSON delle aste:

  • BuyNowPrice
  • ShippingCost
  • HasWinLimit
  • WinLimitDescription

? Testing

  1. Test caricamento info:

    • Aggiungi asta, seleziona, clicca "Carica Info Prodotto"
    • Verifica che i campi si popolino
  2. Test calcolo valore:

    • Dopo aver caricato info, fai alcune puntate
    • Verifica che il valore si aggiorni
  3. Test risparmio positivo/negativo:

    • Con asta economica: Vedi risparmio positivo (verde)
    • Con asta costosa: Vedi risparmio negativo (rosso)
  4. Test limite vincita:

    • Asta con limite: Vedi "1 volta ogni X giorni"
    • Asta senza limite: Vedi "Nessun limite"

?? Ready!

L'UI è pronta e funzionale. Mancano solo i 2 piccoli step finali per collegare l'handler!