Files
pwap/web/src/components/TrustScoreCalculator.tsx
T
pezkuwichain 4f683538d3 feat: complete i18n support for all components (6 languages)
Add full internationalization across 127+ components and pages.
790+ translation keys in en, tr, kmr, ckb, ar, fa locales.
Remove duplicate keys and delete unused .json locale files.
2026-02-22 04:48:20 +03:00

255 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { Calculator, TrendingUp, Users, BookOpen, Award } from 'lucide-react';
const TrustScoreCalculator: React.FC = () => {
const { t } = useTranslation();
const [stakedAmount, setStakedAmount] = useState(100);
const [stakingMonths, setStakingMonths] = useState(6);
const [referralCount, setReferralCount] = useState(5);
const [perwerdeScore, setPerwerdeScore] = useState(30);
const [tikiScore, setTikiScore] = useState(40);
const [finalScore, setFinalScore] = useState(0);
// Calculate base amount score based on pallet_staking_score logic
const getAmountScore = (amount: number) => {
if (amount <= 100) return 20;
if (amount <= 250) return 30;
if (amount <= 750) return 40;
return 50; // 751+ HEZ
};
// Calculate staking multiplier based on months
const getStakingMultiplier = (months: number) => {
if (months < 1) return 1.0;
if (months < 3) return 1.2;
if (months < 6) return 1.4;
if (months < 12) return 1.7;
return 2.0;
};
// Calculate referral score (matches pezpallet-referral tiered scoring)
const getReferralScore = (count: number) => {
if (count === 0) return 0;
if (count <= 10) return count * 10;
if (count <= 50) return 100 + ((count - 10) * 5);
if (count <= 100) return 300 + ((count - 50) * 4);
return 500;
};
useEffect(() => {
const amountScore = getAmountScore(stakedAmount);
const multiplier = getStakingMultiplier(stakingMonths);
const adjustedStaking = Math.min(amountScore * multiplier, 100);
const adjustedReferral = getReferralScore(referralCount);
const weightedSum =
adjustedStaking * 100 +
adjustedReferral * 300 +
perwerdeScore * 300 +
tikiScore * 300;
const score = (adjustedStaking * weightedSum) / 10000;
setFinalScore(Math.round(score));
}, [stakedAmount, stakingMonths, referralCount, perwerdeScore, tikiScore]);
return (
<section className="py-20 bg-gray-950">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-4xl font-bold mb-4 bg-gradient-to-r from-purple-400 to-cyan-400 bg-clip-text text-transparent">
{t('trustCalc.title')}
</h2>
<p className="text-gray-400 text-lg max-w-2xl mx-auto">
{t('trustCalc.description')}
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
{/* Calculator Inputs */}
<div className="space-y-6">
{/* Staking Score */}
<div className="bg-gray-900/50 backdrop-blur-sm rounded-xl border border-gray-800 p-6">
<div className="flex items-center mb-4">
<TrendingUp className="w-5 h-5 text-purple-400 mr-3" />
<h3 className="text-lg font-semibold text-white">{t('trustCalc.stakingTitle')}</h3>
</div>
<div className="space-y-4">
<div>
<label className="text-gray-400 text-sm">{t('trustCalc.stakedAmount')}</label>
<input
type="range"
min="0"
max="1000"
step="10"
value={stakedAmount}
onChange={(e) => setStakedAmount(parseInt(e.target.value))}
className="w-full mt-2"
/>
<div className="flex justify-between items-center mt-2">
<span className="text-cyan-400">{stakedAmount} HEZ</span>
<span className="text-purple-400">{t('trustCalc.score', { score: getAmountScore(stakedAmount) })}</span>
</div>
</div>
<div>
<label className="text-gray-400 text-sm">{t('trustCalc.stakingDuration')}</label>
<input
type="range"
min="0"
max="24"
value={stakingMonths}
onChange={(e) => setStakingMonths(parseInt(e.target.value))}
className="w-full mt-2"
/>
<div className="flex justify-between items-center mt-2">
<span className="text-cyan-400">{t('trustCalc.months', { count: stakingMonths })}</span>
<span className="text-purple-400">{t('trustCalc.multiplier', { value: getStakingMultiplier(stakingMonths).toFixed(1) })}</span>
</div>
</div>
</div>
</div>
{/* Referral Score */}
<div className="bg-gray-900/50 backdrop-blur-sm rounded-xl border border-gray-800 p-6">
<div className="flex items-center mb-4">
<Users className="w-5 h-5 text-cyan-400 mr-3" />
<h3 className="text-lg font-semibold text-white">{t('trustCalc.referralTitle')}</h3>
</div>
<div>
<label className="text-gray-400 text-sm">{t('trustCalc.referralCount')}</label>
<input
type="number"
min="0"
max="150"
value={referralCount}
onChange={(e) => setReferralCount(parseInt(e.target.value) || 0)}
className="w-full mt-2 px-4 py-2 bg-gray-800 text-white rounded-lg border border-gray-700 focus:border-cyan-500 focus:outline-none"
/>
<div className="mt-2 text-sm text-cyan-400">
{t('trustCalc.scorePoints', { score: getReferralScore(referralCount) })}
</div>
</div>
</div>
{/* Other Scores */}
<div className="grid grid-cols-2 gap-4">
<div className="bg-gray-900/50 backdrop-blur-sm rounded-xl border border-gray-800 p-6">
<div className="flex items-center mb-4">
<BookOpen className="w-5 h-5 text-teal-400 mr-3" />
<h3 className="text-sm font-semibold text-white">{t('trustCalc.perwerdeTitle')}</h3>
</div>
<input
type="range"
min="0"
max="100"
value={perwerdeScore}
onChange={(e) => setPerwerdeScore(parseInt(e.target.value))}
className="w-full"
/>
<div className="text-center mt-2 text-teal-400">{perwerdeScore}</div>
</div>
<div className="bg-gray-900/50 backdrop-blur-sm rounded-xl border border-gray-800 p-6">
<div className="flex items-center mb-4">
<Award className="w-5 h-5 text-purple-400 mr-3" />
<h3 className="text-sm font-semibold text-white">{t('trustCalc.tikiTitle')}</h3>
</div>
<input
type="range"
min="0"
max="250"
value={tikiScore}
onChange={(e) => setTikiScore(parseInt(e.target.value))}
className="w-full"
/>
<div className="text-center mt-2 text-purple-400">{tikiScore}</div>
</div>
</div>
</div>
{/* Results and Formula */}
<div className="space-y-6">
{/* Final Score */}
<div className="bg-gradient-to-br from-purple-900/30 to-cyan-900/30 backdrop-blur-sm rounded-xl border border-purple-500/50 p-8 text-center">
<Calculator className="w-12 h-12 text-cyan-400 mx-auto mb-4" />
<h3 className="text-2xl font-semibold text-white mb-2">{t('trustCalc.resultTitle')}</h3>
<div className="text-6xl font-bold bg-gradient-to-r from-purple-400 to-cyan-400 bg-clip-text text-transparent">
{finalScore}
</div>
<div className="mt-4 text-gray-400">
{t('trustCalc.resultHint')}
</div>
</div>
{/* Formula Breakdown */}
<div className="bg-gray-900/50 backdrop-blur-sm rounded-xl border border-gray-800 p-6">
<h3 className="text-lg font-semibold text-white mb-4">{t('trustCalc.formulaTitle')}</h3>
<div className="bg-gray-950/50 rounded-lg p-4 font-mono text-sm">
<div className="text-purple-400 mb-2">
weighted_sum =
</div>
<div className="text-gray-300 ml-4">
staking × 100 +
</div>
<div className="text-gray-300 ml-4">
referral × 300 +
</div>
<div className="text-gray-300 ml-4">
perwerde × 300 +
</div>
<div className="text-gray-300 ml-4 mb-2">
tiki × 300
</div>
<div className="text-cyan-400">
final_score = staking × weighted_sum / 10000
</div>
</div>
<div className="mt-4 space-y-2">
<div className="flex justify-between text-sm">
<span className="text-gray-400">{t('trustCalc.formulaStaking')}:</span>
<span className="text-purple-400">{Math.min(Math.round(getAmountScore(stakedAmount) * getStakingMultiplier(stakingMonths)), 100)} × 100</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-400">{t('trustCalc.formulaReferral')}:</span>
<span className="text-cyan-400">{getReferralScore(referralCount)} × 300</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-400">{t('trustCalc.formulaPerwerde')}:</span>
<span className="text-teal-400">{perwerdeScore} × 300</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-gray-400">{t('trustCalc.formulaTiki')}:</span>
<span className="text-purple-400">{tikiScore} × 300</span>
</div>
</div>
</div>
{/* Score Impact */}
<div className="bg-gray-900/50 backdrop-blur-sm rounded-xl border border-gray-800 p-6">
<h3 className="text-lg font-semibold text-white mb-4">{t('trustCalc.impactTitle')}</h3>
<div className="space-y-3">
<div className="flex items-center justify-between p-3 bg-gray-800/50 rounded-lg">
<span className="text-gray-400">{t('trustCalc.rewards')}</span>
<span className={`px-3 py-1 rounded-full text-sm ${finalScore > 100 ? 'bg-green-900/30 text-green-400' : 'bg-red-900/30 text-red-400'}`}>
{finalScore > 100 ? t('trustCalc.eligible') : t('trustCalc.notEligible')}
</span>
</div>
<div className="flex items-center justify-between p-3 bg-gray-800/50 rounded-lg">
<span className="text-gray-400">{t('trustCalc.votingWeight')}</span>
<span className="text-cyan-400 font-semibold">{Math.min(Math.floor(finalScore / 100), 10)}x</span>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
);
};
export default TrustScoreCalculator;