reward distribution fixed
This commit is contained in:
parent
a230c97078
commit
4c75d08d4a
|
|
@ -30,6 +30,114 @@ interface Opponent {
|
||||||
x_profile_url: string;
|
x_profile_url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GameHistoryItem = ({ game, user, gameImages, defaultPFP, failedImages, setFailedImages, handleViewTxClick }: {
|
||||||
|
game: GameHistory,
|
||||||
|
user: any,
|
||||||
|
gameImages: { [key: string]: string },
|
||||||
|
defaultPFP: string,
|
||||||
|
failedImages: Set<string>,
|
||||||
|
setFailedImages: React.Dispatch<React.SetStateAction<Set<string>>>,
|
||||||
|
handleViewTxClick: (address: string) => void
|
||||||
|
}) => {
|
||||||
|
const [opponent, setOpponent] = useState<any>(null);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchOpponent = async () => {
|
||||||
|
const opponentId = game.master_id == user.id ? game.client_id : game.master_id;
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`${API_URL}get_user_by_id.php?id=${opponentId}`);
|
||||||
|
setOpponent(response.data);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to fetch opponent info:", err);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchOpponent();
|
||||||
|
}, [game, user.id]);
|
||||||
|
|
||||||
|
const isUserMaster = game.master_id == user.id;
|
||||||
|
const userScore = isUserMaster ? game.master_score : game.client_score;
|
||||||
|
const opponentScore = isUserMaster ? game.client_score : game.master_score;
|
||||||
|
let didUserWin = false;
|
||||||
|
if(game.winner == "master"){
|
||||||
|
didUserWin = game.master_id == user.id;
|
||||||
|
} else if(game.winner == "client"){
|
||||||
|
didUserWin = game.client_id == user.id;
|
||||||
|
}
|
||||||
|
console.log(`isUserMaster: ${isUserMaster}, game.winner: ${game.winner}, didUserWin: ${didUserWin}`);
|
||||||
|
const wagerAmount = parseFloat(game.wager);
|
||||||
|
const outcomeText = didUserWin
|
||||||
|
? `+${(wagerAmount / 1e8) * 2 * WAGER_PRIZE_MULT} SOL`
|
||||||
|
: `-${(wagerAmount / 1e8)} SOL`;
|
||||||
|
|
||||||
|
if (loading) return <div className="animate-pulse">Loading...</div>;
|
||||||
|
|
||||||
|
const profileUrl = opponent?.x_profile_url || (opponent?.username ? `${API_URL}profile_picture/${opponent.username}.jpg` : "/duelfiassets/default-avatar.png");
|
||||||
|
const gameImageUrl = gameImages[game.game] || "/duelfiassets/default-game-thumbnail.png";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative border border-[rgb(30,30,30)] rounded-xl p-3 flex gap-3 items-center group">
|
||||||
|
<div className="flex-1">
|
||||||
|
<p className="text-sm font-semibold text-white">
|
||||||
|
{opponent?.username || "Unknown Opponent"}
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-gray-400">
|
||||||
|
Score: {userScore} - {opponentScore}
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-gray-400">
|
||||||
|
{new Date(game.ended_time).toLocaleString(undefined, {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'numeric',
|
||||||
|
day: 'numeric',
|
||||||
|
hour: 'numeric',
|
||||||
|
minute: 'numeric'
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
<p className={`text-sm font-semibold ${didUserWin ? "text-green-500" : "text-gray-500"}`}>
|
||||||
|
{didUserWin ? "You won" : "You lost"}
|
||||||
|
</p>
|
||||||
|
<p className={`text-xs ${didUserWin ? "text-green-500" : "text-red-500"}`}>
|
||||||
|
{outcomeText}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<Image
|
||||||
|
src={failedImages.has(profileUrl) ? defaultPFP : profileUrl}
|
||||||
|
alt="Profile"
|
||||||
|
width={40}
|
||||||
|
height={40}
|
||||||
|
className="w-10 h-10 rounded-full border border-gray-700 object-cover"
|
||||||
|
onError={(e) => {
|
||||||
|
// @ts-expect-error - Type mismatch expected
|
||||||
|
e.target.src = defaultPFP;
|
||||||
|
setFailedImages(prev => new Set(prev).add(profileUrl));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Image
|
||||||
|
src={failedImages.has(gameImageUrl) ? "/duelfiassets/default-game-thumbnail.png" : gameImageUrl}
|
||||||
|
alt="Game Thumbnail"
|
||||||
|
width={64}
|
||||||
|
height={64}
|
||||||
|
className="w-16 h-16 rounded-md object-cover ml-4"
|
||||||
|
onError={(e) => {
|
||||||
|
// @ts-expect-error - Type mismatch expected
|
||||||
|
e.target.src = "/duelfiassets/default-game-thumbnail.png";
|
||||||
|
setFailedImages(prev => new Set(prev).add(gameImageUrl));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="absolute top-0 right-0 h-full w-28 bg-blue-500 text-white flex items-center justify-center opacity-0 group-hover:opacity-100 group-hover:translate-x-0 transition-all">
|
||||||
|
<button
|
||||||
|
onClick={() => handleViewTxClick(game.address)}
|
||||||
|
className="px-4 py-2 text-sm font-semibold"
|
||||||
|
>
|
||||||
|
View TX
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default function PrivyButton() {
|
export default function PrivyButton() {
|
||||||
const { login, logout, user, linkTwitter, unlinkTwitter } = usePrivy();
|
const { login, logout, user, linkTwitter, unlinkTwitter } = usePrivy();
|
||||||
const { fundWallet } = useFundWallet();
|
const { fundWallet } = useFundWallet();
|
||||||
|
|
@ -527,97 +635,18 @@ export default function PrivyButton() {
|
||||||
<div className="space-y-4 max-h-96 overflow-y-auto">
|
<div className="space-y-4 max-h-96 overflow-y-auto">
|
||||||
{gamesHistory
|
{gamesHistory
|
||||||
.sort((a, b) => new Date(b.ended_time).getTime() - new Date(a.ended_time).getTime())
|
.sort((a, b) => new Date(b.ended_time).getTime() - new Date(a.ended_time).getTime())
|
||||||
.map((game, idx) => {
|
.map((game, idx) => (
|
||||||
const isUserMaster = game.master_id === user.id;
|
<GameHistoryItem
|
||||||
const userScore = isUserMaster
|
|
||||||
? game.master_score
|
|
||||||
: game.client_score;
|
|
||||||
const opponentScore = isUserMaster
|
|
||||||
? game.client_score
|
|
||||||
: game.master_score;
|
|
||||||
const opponentId = isUserMaster
|
|
||||||
? game.client_id
|
|
||||||
: game.master_id;
|
|
||||||
const didUserWin =
|
|
||||||
(isUserMaster && game.winner === "master") ||
|
|
||||||
(!isUserMaster && game.winner === "client");
|
|
||||||
|
|
||||||
const opponent = opponentInfo[opponentId];
|
|
||||||
const profileUrl =
|
|
||||||
opponent?.x_profile_url ||
|
|
||||||
(opponent?.username
|
|
||||||
? `${API_URL}profile_picture/${opponent.username}.jpg`
|
|
||||||
: "/duelfiassets/default-avatar.png");
|
|
||||||
|
|
||||||
const gameImageUrl = gameImages[game.game] || "/duelfiassets/default-game-thumbnail.png";
|
|
||||||
|
|
||||||
const wagerAmount = parseFloat(game.wager);
|
|
||||||
const outcomeText = didUserWin
|
|
||||||
? `+${(wagerAmount / 1e8) * 2 * WAGER_PRIZE_MULT} SOL`
|
|
||||||
: `-${(wagerAmount / 1e8)} SOL`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={idx}
|
key={idx}
|
||||||
className="relative border border-[rgb(30,30,30)] rounded-xl p-3 flex gap-3 items-center group"
|
game={game}
|
||||||
>
|
user={user}
|
||||||
<div className="flex-1">
|
gameImages={gameImages}
|
||||||
<p className="text-sm font-semibold text-white">
|
defaultPFP={defaultPFP}
|
||||||
{opponent?.username || "Unknown Opponent"}
|
failedImages={failedImages}
|
||||||
</p>
|
setFailedImages={setFailedImages}
|
||||||
<p className="text-xs text-gray-400">
|
handleViewTxClick={handleViewTxClick}
|
||||||
Score: {userScore} - {opponentScore}
|
|
||||||
</p>
|
|
||||||
<p className="text-xs text-gray-400">
|
|
||||||
{new Date(game.ended_time).toLocaleString()}
|
|
||||||
</p>
|
|
||||||
<p
|
|
||||||
className={`text-sm font-semibold ${
|
|
||||||
didUserWin ? "text-green-500" : "text-gray-500"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{didUserWin ? "You won" : "You lost"}
|
|
||||||
</p>
|
|
||||||
<p className={`text-xs ${didUserWin ? "text-green-500" : "text-red-500"}`}>
|
|
||||||
{outcomeText}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<Image
|
|
||||||
src={failedImages.has(profileUrl) ? defaultPFP : profileUrl}
|
|
||||||
alt="Profile"
|
|
||||||
width={40}
|
|
||||||
height={40}
|
|
||||||
className="w-10 h-10 rounded-full border border-gray-700 object-cover"
|
|
||||||
onError={(e) => {
|
|
||||||
// @ts-expect-error - Type mismatch expected
|
|
||||||
e.target.src = defaultPFP;
|
|
||||||
setFailedImages(prev => new Set(prev).add(profileUrl));
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<Image
|
))}
|
||||||
src={failedImages.has(gameImageUrl) ? "/duelfiassets/default-game-thumbnail.png" : gameImageUrl}
|
|
||||||
alt="Game Thumbnail"
|
|
||||||
width={64}
|
|
||||||
height={64}
|
|
||||||
className="w-16 h-16 rounded-md object-cover ml-4"
|
|
||||||
onError={(e) => {
|
|
||||||
// @ts-expect-error - Type mismatch expected
|
|
||||||
e.target.src = "/duelfiassets/default-game-thumbnail.png";
|
|
||||||
setFailedImages(prev => new Set(prev).add(gameImageUrl));
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="absolute top-0 right-0 h-full w-28 bg-blue-500 text-white flex items-center justify-center opacity-0 group-hover:opacity-100 group-hover:translate-x-0 transition-all">
|
|
||||||
<button
|
|
||||||
onClick={() => handleViewTxClick(game.address)}
|
|
||||||
className="px-4 py-2 text-sm font-semibold"
|
|
||||||
>
|
|
||||||
View TX
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user