mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-22 07:57:55 +00:00
4f683538d3
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.
255 lines
11 KiB
TypeScript
255 lines
11 KiB
TypeScript
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; |