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 { api } from '../api/api';
|
||||||
import type { LeaderboardResponse } from '../api/types';
|
import type { LeaderboardResponse } from '../api/types';
|
||||||
import { useAuth } from '../auth/AuthContext';
|
import { useAuth } from '../auth/AuthContext';
|
||||||
|
import { getSocket } from '../realtime/socket';
|
||||||
import { formatMoney } from '../shared/format';
|
import { formatMoney } from '../shared/format';
|
||||||
|
|
||||||
type Metric = 'money' | 'reputation';
|
type Metric = 'money' | 'reputation';
|
||||||
@@ -16,6 +17,17 @@ export function LeaderboardScreen() {
|
|||||||
void api.leaderboard(metric).then(setBoard);
|
void api.leaderboard(metric).then(setBoard);
|
||||||
}, [metric]);
|
}, [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 (
|
return (
|
||||||
<div className="screen">
|
<div className="screen">
|
||||||
<h2 className="screen__title">Classifiche</h2>
|
<h2 className="screen__title">Classifiche</h2>
|
||||||
|
|||||||
@@ -7,6 +7,22 @@ import { useToast } from '../components/Toast';
|
|||||||
import { getSocket } from '../realtime/socket';
|
import { getSocket } from '../realtime/socket';
|
||||||
import { formatMoney } from '../shared/format';
|
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() {
|
export function MarketScreen() {
|
||||||
const { player, refreshPlayer } = useAuth();
|
const { player, refreshPlayer } = useAuth();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
@@ -95,12 +111,14 @@ export function MarketScreen() {
|
|||||||
<div className="prices">
|
<div className="prices">
|
||||||
<span className="price price--buy">{formatMoney(entry.buyPrice)}</span>
|
<span className="price price--buy">{formatMoney(entry.buyPrice)}</span>
|
||||||
<span className="price price--sell">{formatMoney(entry.sellPrice)}</span>
|
<span className="price price--sell">{formatMoney(entry.sellPrice)}</span>
|
||||||
|
<TrendTag entry={entry} />
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
<p className="muted small">
|
<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>
|
</p>
|
||||||
|
|
||||||
{selected && (
|
{selected && (
|
||||||
|
|||||||
Reference in New Issue
Block a user