chore: build

This commit is contained in:
2026-06-09 19:57:56 +02:00
parent 72c8003acf
commit 7262d44f5a
7 changed files with 341 additions and 48 deletions
@@ -10,8 +10,10 @@ import {
isUserAuthenticated,
getPublicSettings,
getReferralBalance,
getMyPointsRewards,
claimMyReward,
} from "../../api/api";
import type { PublicSettings } from "../../api/api";
import type { PublicSettings, PointsPoolInfo, PointsRewardConfig } from "../../api/api";
import type {
CompletedOrder,
ClientStats,
@@ -59,6 +61,13 @@ function ConsultationHistorique() {
two_fa_enabled: false,
});
const [referralBalance, setReferralBalance] = useState<number>(0);
const [pointsRewards, setPointsRewards] = useState<{
enabled: boolean;
pools: PointsPoolInfo[];
reward: PointsRewardConfig | null;
} | null>(null);
const [claimingPool, setClaimingPool] = useState<string | null>(null);
const [claimFeedback, setClaimFeedback] = useState<{ pool: string; type: "success" | "error"; text: string } | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string>("");
@@ -86,6 +95,9 @@ function ConsultationHistorique() {
});
}
});
getMyPointsRewards().then((r) => {
if (r.success && r.enabled) setPointsRewards(r);
});
}, []); // eslint-disable-line react-hooks/exhaustive-deps
const fetchHistory = async () => {
@@ -157,6 +169,19 @@ function ConsultationHistorique() {
);
}
const handleClaim = async (poolKey: string) => {
setClaimingPool(poolKey);
setClaimFeedback(null);
const res = await claimMyReward(poolKey);
setClaimingPool(null);
if (res.success) {
setClaimFeedback({ pool: poolKey, type: "success", text: res.description || "Récompense réclamée !" });
getMyPointsRewards().then((r) => { if (r.success) setPointsRewards(r); });
} else {
setClaimFeedback({ pool: poolKey, type: "error", text: res.error || "Erreur" });
}
};
const poolNames = clientStats?.pool_names?.length
? clientStats.pool_names
: appSettings.pool_names;
@@ -268,6 +293,65 @@ function ConsultationHistorique() {
)}
</div>
{/* Section récompenses par palier */}
{pointsRewards?.enabled && pointsRewards.reward && pointsRewards.pools.length > 0 && (
<div className="rewards-section">
<p className="rewards-section-title">
<FontAwesomeIcon icon={faTrophy} className="rewards-section-icon" />
Récompenses
</p>
<p className="rewards-section-desc">{pointsRewards.reward.description}</p>
<div className="rewards-pools">
{pointsRewards.pools.map((pool) => {
const threshold = pointsRewards.reward!.threshold;
const progress = Math.min(100, Math.round((pool.points % threshold) / threshold * 100));
const remaining = threshold - (pool.points % threshold);
const isClaiming = claimingPool === pool.key;
const feedback = claimFeedback?.pool === pool.key ? claimFeedback : null;
return (
<div key={pool.key} className="reward-pool-card">
<div className="reward-pool-header">
<span className="reward-pool-name">{pool.name}</span>
<span className="reward-pool-pts">{pool.points} pts</span>
</div>
{pool.eligible_configs.length > 0 && (
<div className="reward-eligible-cats">
{pool.eligible_configs.map((cfg) => (
<span key={cfg.category} className="reward-eligible-cat">
{cfg.category}{cfg.amount > 0 ? `${cfg.amount}` : ""}
</span>
))}
</div>
)}
<div className="reward-progress-bar">
<div className="reward-progress-fill" style={{ width: `${progress}%` }} />
</div>
<div className="reward-pool-info">
{pool.rewards_available > 0 ? (
<span className="reward-available">{pool.rewards_available} récompense{pool.rewards_available > 1 ? "s" : ""} disponible{pool.rewards_available > 1 ? "s" : ""}</span>
) : (
<span className="reward-remaining">Encore {remaining} pts pour une récompense</span>
)}
</div>
{feedback && (
<p className={`reward-feedback reward-feedback-${feedback.type}`}>{feedback.text}</p>
)}
{pool.rewards_available > 0 && (
<button
className="reward-claim-btn"
onClick={() => handleClaim(pool.key)}
disabled={isClaiming}
>
{isClaiming ? "..." : "Réclamer ma récompense"}
</button>
)}
</div>
);
})}
</div>
</div>
)}
{/* Bouton parrainage */}
{appSettings.referral_enabled && (
<div