diff --git a/frontend/src/pages/DashboardPage.tsx b/frontend/src/pages/DashboardPage.tsx
index 8de8b1f..1eab148 100644
--- a/frontend/src/pages/DashboardPage.tsx
+++ b/frontend/src/pages/DashboardPage.tsx
@@ -1,6 +1,6 @@
import { useState } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
-import { characterApi } from '../api/endpoints';
+import { characterApi, itemApi } from '../api/endpoints';
import { Bar } from '../components/Bar';
import { Zap, Heart, Star, Coins, Sword, Shield, BedDouble } from 'lucide-react';
@@ -134,6 +134,42 @@ function StatDistributor({ char }: { char: any }) {
);
}
+function CombatStatsPanel({ char }: { char: any }) {
+ const { data: inventory } = useQuery({ queryKey: ['inventory'], queryFn: itemApi.inventory });
+
+ const weapon = inventory?.find((ci: any) => ci.equipped && ci.item.type === 'weapon');
+ const armor = inventory?.find((ci: any) => ci.equipped && ci.item.type === 'armor');
+
+ const weaponATK = weapon ? weapon.item.attackBonus + weapon.forgeLevel * 2 : 0;
+ const armorDEF = armor ? armor.item.defenseBonus + armor.forgeLevel * 2 : 0;
+ const baseDmg = 3 + weaponATK + Math.floor(char.force * 1.5);
+
+ return (
+
+
Combat actuel
+
+
+
+ Attaque :
+ {baseDmg}
+ {weapon && ({weapon.item.name} {weapon.forgeLevel > 0 ? `+${weapon.forgeLevel}` : ''})}
+
+
+
+ Défense :
+ {armorDEF}
+ {armor && ({armor.item.name} {armor.forgeLevel > 0 ? `+${armor.forgeLevel}` : ''})}
+
+
+
+ Critique :
+ {(5 + char.chance * 0.2).toFixed(1)}%
+
+
+
+ );
+}
+
export function DashboardPage() {
const qc = useQueryClient();
const { data: char, isLoading, isError } = useQuery({
@@ -266,26 +302,7 @@ export function DashboardPage() {
)}
{/* Équipement résumé */}
-
-
Combat actuel
-
-
-
- Attaque :
- {Math.floor(char.force * 1.5)}
-
-
-
- Critique :
- {(5 + char.chance * 0.2).toFixed(1)}%
-
-
-
- Esquive :
- {(5 + char.chance * 0.1).toFixed(1)}%
-
-
-
+
);
diff --git a/frontend/src/pages/InventoryPage.tsx b/frontend/src/pages/InventoryPage.tsx
index 6361576..2bb12e6 100644
--- a/frontend/src/pages/InventoryPage.tsx
+++ b/frontend/src/pages/InventoryPage.tsx
@@ -1,17 +1,26 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { itemApi, materialApi } from '../api/endpoints';
+import { api } from '../api/client';
import type { CharacterItem } from '../api/types';
-import { Package, Sword, Shield } from 'lucide-react';
+import { Package, Sword, Shield, Coins } from 'lucide-react';
const RARITY_LABEL: Record = {
common: 'Commun', rare: 'Rare', epic: 'Épique', legendary: 'Légendaire',
};
-function ItemCard({ ci, onEquip, onUnequip }: { ci: CharacterItem; onEquip: () => void; onUnequip: () => void }) {
+function ItemCard({ ci, onEquip, onUnequip, onSell, selling }: {
+ ci: CharacterItem; onEquip: () => void; onUnequip: () => void; onSell: () => void; selling: boolean;
+}) {
const { item } = ci;
+ const forgeBonusATK = item.type === 'weapon' ? ci.forgeLevel * 2 : 0;
+ const forgeBonusDEF = item.type === 'armor' ? ci.forgeLevel * 2 : 0;
+ const totalATK = item.attackBonus + forgeBonusATK;
+ const totalDEF = item.defenseBonus + forgeBonusDEF;
+ const sellPrice = Math.floor((item as any).buyPrice * 0.4) || 0;
+
const bonuses = [
- item.attackBonus && `+${item.attackBonus} ATK`,
- item.defenseBonus && `+${item.defenseBonus} DEF`,
+ totalATK > 0 && `+${totalATK} ATK${forgeBonusATK > 0 ? ` (${item.attackBonus}+${forgeBonusATK})` : ''}`,
+ totalDEF > 0 && `+${totalDEF} DEF${forgeBonusDEF > 0 ? ` (${item.defenseBonus}+${forgeBonusDEF})` : ''}`,
item.forceBonus && `+${item.forceBonus} FOR`,
item.agiliteBonus && `+${item.agiliteBonus} AGI`,
item.intelligenceBonus && `+${item.intelligenceBonus} INT`,
@@ -37,11 +46,17 @@ function ItemCard({ ci, onEquip, onUnequip }: { ci: CharacterItem; onEquip: () =
{bonuses && {bonuses}
}
-
+
{!ci.equipped
?
:
}
+ {!ci.equipped && sellPrice > 0 && (
+
+ )}
);
@@ -70,6 +85,14 @@ export function InventoryPage() {
onSuccess: () => qc.invalidateQueries({ queryKey: ['inventory'] }),
});
+ const sellMut = useMutation({
+ mutationFn: (charItemId: string) => api.post(`/shop/sell/${charItemId}`),
+ onSuccess: () => {
+ qc.invalidateQueries({ queryKey: ['inventory'] });
+ qc.invalidateQueries({ queryKey: ['character'] });
+ },
+ });
+
if (loadInv || loadMat) return Chargement…
;
const weapons = inventory?.filter(ci => ci.item.type === 'weapon') ?? [];
@@ -99,6 +122,8 @@ export function InventoryPage() {
key={ci.id} ci={ci}
onEquip={() => equipMut.mutate(ci.id)}
onUnequip={() => unequipMut.mutate('weapon')}
+ onSell={() => sellMut.mutate(ci.id)}
+ selling={sellMut.isPending}
/>
))}
@@ -117,6 +142,8 @@ export function InventoryPage() {
key={ci.id} ci={ci}
onEquip={() => equipMut.mutate(ci.id)}
onUnequip={() => unequipMut.mutate('armor')}
+ onSell={() => sellMut.mutate(ci.id)}
+ selling={sellMut.isPending}
/>
))}