client: market trend tags + leaderboard live updates via Socket.IO
Market rows show a TrendTag: 💰 affare when buyPrice < basePrice, 📈 vendi when sellPrice > basePrice. Leaderboard subscribes to leaderboard:updated socket event to refresh without polling. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';
|
||||
import { api } from '../api/api';
|
||||
import type { LeaderboardResponse } from '../api/types';
|
||||
import { useAuth } from '../auth/AuthContext';
|
||||
import { getSocket } from '../realtime/socket';
|
||||
import { formatMoney } from '../shared/format';
|
||||
|
||||
type Metric = 'money' | 'reputation';
|
||||
@@ -16,6 +17,17 @@ export function LeaderboardScreen() {
|
||||
void api.leaderboard(metric).then(setBoard);
|
||||
}, [metric]);
|
||||
|
||||
// Aggiornamento live quando il server ricalcola le classifiche
|
||||
useEffect(() => {
|
||||
const socket = getSocket();
|
||||
if (!socket) return;
|
||||
const onUpdate = () => void api.leaderboard(metric).then(setBoard);
|
||||
socket.on('leaderboard:updated', onUpdate);
|
||||
return () => {
|
||||
socket.off('leaderboard:updated', onUpdate);
|
||||
};
|
||||
}, [metric]);
|
||||
|
||||
return (
|
||||
<div className="screen">
|
||||
<h2 className="screen__title">Classifiche</h2>
|
||||
|
||||
@@ -7,6 +7,22 @@ import { useToast } from '../components/Toast';
|
||||
import { getSocket } from '../realtime/socket';
|
||||
import { formatMoney } from '../shared/format';
|
||||
|
||||
/**
|
||||
* Confronta i prezzi locali col valore base della merce: segnala dove
|
||||
* conviene comprare (buy sotto il base) e dove conviene vendere (sell sopra).
|
||||
*/
|
||||
function TrendTag({ entry }: { entry: MarketEntry }) {
|
||||
const buyDelta = Math.round((entry.buyPrice / entry.basePrice - 1) * 100);
|
||||
const sellDelta = Math.round((entry.sellPrice / entry.basePrice - 1) * 100);
|
||||
if (sellDelta > 0) {
|
||||
return <span className="trend trend--sell">📈 vendi +{sellDelta}%</span>;
|
||||
}
|
||||
if (buyDelta < 0) {
|
||||
return <span className="trend trend--buy">💰 affare {buyDelta}%</span>;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function MarketScreen() {
|
||||
const { player, refreshPlayer } = useAuth();
|
||||
const { toast } = useToast();
|
||||
@@ -95,12 +111,14 @@ export function MarketScreen() {
|
||||
<div className="prices">
|
||||
<span className="price price--buy">{formatMoney(entry.buyPrice)}</span>
|
||||
<span className="price price--sell">{formatMoney(entry.sellPrice)}</span>
|
||||
<TrendTag entry={entry} />
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<p className="muted small">
|
||||
Prezzo a sinistra: acquisto · a destra: vendita. I prezzi cambiano ogni minuto.
|
||||
Prezzo a sinistra: acquisto · a destra: vendita. I prezzi cambiano ogni minuto: compra
|
||||
dove c'è l'affare, vendi dove rende.
|
||||
</p>
|
||||
|
||||
{selected && (
|
||||
|
||||
Reference in New Issue
Block a user