Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import { Researcher } from '@/types/report';

interface ResearcherCardProps {
researcher: Researcher;
userRank?: number; // For highlighting user's rank
}

const ResearcherCard: React.FC<ResearcherCardProps> = ({ researcher, userRank }) => {
const formatAddress = (address: string) => {
return `${address.slice(0, 6)}...${address.slice(-4)}`;
};

const formatCurrency = (amount: number) => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
}).format(amount);
};

const isUserRank = userRank && researcher.rank === userRank;

return (
<tr className={`border-b border-gray-800 hover:b transition-colors`}>
<td className="px-6 py-4 text-white font-medium relative">
{researcher.rank}

</td>
<td className="px-6 py-4 text-white font-medium">{researcher.username}</td>
<td className="px-6 py-4 text-gray-400 font-mono text-sm">
{formatAddress(researcher.address)}
</td>
<td className="px-6 py-4 text-white text-center">{researcher.reports}</td>
<td className="px-6 py-4 text-white text-center">{researcher.reputation}</td>
<td className="px-6 py-4 text-white font-semibold">
{formatCurrency(researcher.earned)}
</td>
</tr>
);
};

export default ResearcherCard;
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import { Researcher } from '@/types/report';
import ResearcherCard from './ResearcherCard';

interface ResearchersTableProps {
researchers: Researcher[];
userRank?: number;
}

const ResearchersTable: React.FC<ResearchersTableProps> = ({ researchers, userRank }) => {
return (
<div className="overflow-x-auto px-4">
<table className="w-full">
<thead className="border-b border-gray-700">
<tr>
<th className="px-6 py-4 text-left text-gray-400 font-medium text-sm uppercase tracking-wider">
Rank
</th>
<th className="px-6 py-4 text-left text-gray-400 font-medium text-sm uppercase tracking-wider">
User name
</th>
<th className="px-6 py-4 text-left text-gray-400 font-medium text-sm uppercase tracking-wider">
Address
</th>
<th className="px-6 py-4 text-center text-gray-400 font-medium text-sm uppercase tracking-wider">
Reports
</th>
<th className="px-6 py-4 text-center text-gray-400 font-medium text-sm uppercase tracking-wider">
Reputation
</th>
<th className="px-6 py-4 text-left text-gray-400 font-medium text-sm uppercase tracking-wider">
Earned
</th>
</tr>
</thead>
<tbody>
{researchers.map((researcher) => (
<ResearcherCard
key={researcher.address}
researcher={researcher}
userRank={userRank}
/>
))}
</tbody>
</table>
</div>
);
};

export default ResearchersTable;
38 changes: 38 additions & 0 deletions src/app/dashboard/researcher/rankings/components/TabNavigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';

interface Tab {
id: string;
label: string;
}

interface TabNavigationProps {
tabs: Tab[];
activeTab: string;
onTabChange: (tabId: string) => void;
}

const TabNavigation: React.FC<TabNavigationProps> = ({
tabs,
activeTab,
onTabChange,
}) => {
return (
<div className="flex bg-[#101011] w-fit rounded-full p-1 mb-6">
{tabs.map((tab) => (
<button
key={tab.id}
onClick={() => onTabChange(tab.id)}
className={` px-7 text-sm font-medium rounded-full transition-colors ${
activeTab === tab.id
? 'bg-[#312F2F] rounded-full py-1 px-2 text-white'
: 'border-transparent text-gray-400 hover:text-white '
}`}
>
{tab.label}
</button>
))}
</div>
);
};

export default TabNavigation;
37 changes: 37 additions & 0 deletions src/app/dashboard/researcher/rankings/components/ValidatorCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import { Validator } from '@/types/report';

interface ValidatorCardProps {
validator: Validator;
}

const ValidatorCard: React.FC<ValidatorCardProps> = ({ validator }) => {
const formatAddress = (address: string) => {
return `${address.slice(0, 6)}...${address.slice(-4)}`;
};

const formatCurrency = (amount: number) => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
}).format(amount);
};

return (
<tr className="border-b border-gray-800 hover:bg-gray-900/50 transition-colors">
<td className="px-6 py-4 text-white font-medium">{validator.rank}</td>
<td className="px-6 py-4 text-white font-medium">{validator.username}</td>
<td className="px-6 py-4 text-gray-400 font-mono text-sm">
{formatAddress(validator.address)}
</td>
<td className="px-6 py-4 text-white text-center">{validator.audits}</td>
<td className="px-6 py-4 text-white text-center">{validator.reputation}</td>
<td className="px-6 py-4 text-white font-semibold">
{formatCurrency(validator.earned)}
</td>
</tr>
);
};

export default ValidatorCard;
197 changes: 197 additions & 0 deletions src/app/dashboard/researcher/rankings/components/ValidatorsRanking.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
"use client"
import React, { useState } from 'react';
import TabNavigation from './TabNavigation';
import ValidatorsTable from './ValidatorsTable';
import ResearchersTable from './ResearchersTable';
import { Validator, Researcher } from '@/types/report';

// Sample data for validators
const mockValidators: Validator[] = [
{
rank: 1,
username: 'Ebube',
address: '0x4A7d5cB676...',
audits: 8,
reputation: 90,
earned: 15000,
},
{
rank: 2,
username: 'Chika',
address: '0x5B8f6cF45d...',
audits: 12,
reputation: 85,
earned: 12500,
},
{
rank: 3,
username: 'Uche',
address: '0x7C8e7fCeB3...',
audits: 15,
reputation: 92,
earned: 18000,
},
{
rank: 4,
username: 'Adaobi',
address: '0x8D9b5cC8A...',
audits: 10,
reputation: 88,
earned: 14200,
},
{
rank: 5,
username: 'Ifij',
address: '0x9E2gbcC98...',
audits: 20,
reputation: 91,
earned: 19500,
},
{
rank: 6,
username: 'Nnamdi',
address: '0xAf4dD5B3c...',
audits: 6,
reputation: 80,
earned: 11000,
},
{
rank: 7,
username: 'Obinna',
address: '0xB3eC9AHD7f...',
audits: 18,
reputation: 87,
earned: 16750,
},
{
rank: 8,
username: 'Kelechi',
address: '0xC5eB6F3E2...',
audits: 14,
reputation: 89,
earned: 17000,
},
];

// Sample data for researchers
const mockResearchers: Researcher[] = [
{
rank: 1,
username: 'Ebube',
address: '0x4A7d5cB676...',
reports: 8,
reputation: 90,
earned: 15000,
},
{
rank: 2,
username: 'Chika',
address: '0x5B8f6cF45d...',
reports: 12,
reputation: 85,
earned: 12500,
},
{
rank: 3,
username: 'Uche',
address: '0x7C8e7fCeB3...',
reports: 15,
reputation: 92,
earned: 18000,
},
{
rank: 4,
username: 'Adaobi',
address: '0x8D9b5cC8A...',
reports: 10,
reputation: 88,
earned: 14200,
},
{
rank: 5,
username: 'Ifij',
address: '0x9E2gbcC98...',
reports: 20,
reputation: 91,
earned: 19500,
},
{
rank: 6,
username: 'Nnamdi',
address: '0xAf4dD5B3c...',
reports: 6,
reputation: 80,
earned: 11000,
},
{
rank: 7,
username: 'Obinna',
address: '0xB3eC9AHD7f...',
reports: 18,
reputation: 87,
earned: 16750,
},
{
rank: 8,
username: 'Kelechi',
address: '0xC5eB6F3E2...',
reports: 14,
reputation: 89,
earned: 17000,
},
];

const tabs = [
{ id: 'researchers', label: 'Researchers Ranking' },
{ id: 'validators', label: 'Validators Ranking' },
];

interface ValidatorsRankingProps {
userRank?: number; // Optional prop to highlight user's position
}

const ValidatorsRanking: React.FC<ValidatorsRankingProps> = ({ userRank = 1 }) => {
const [activeTab, setActiveTab] = useState('researchers'); // Default to researchers tab

return (
<div className=" min-h-screen p-6">
<div className="max-w-7xl mx-auto">
<TabNavigation
tabs={tabs}
activeTab={activeTab}
onTabChange={setActiveTab}
/>

{activeTab === 'researchers' && (
<div>
<div className="flex justify-between items-center mb-6">
<h1 className="text-2xl font-bold text-white">
Researchers Ranking
</h1>
<div className="bg-[#1F1F1F] text-white text-sm px-3 py-2 rounded-lg">
<span className="text-gray-400">Your Rank |</span>
<span className="ml-2 text-white font-semibold">{userRank}</span>
</div>
</div>
<div className=" rounded-lg border border-gray-800">
<ResearchersTable researchers={mockResearchers} userRank={userRank} />
</div>
</div>
)}

{activeTab === 'validators' && (
<div>
<h1 className="text-2xl font-bold text-white mb-6">
Validators Ranking
</h1>
<div className=" rounded-lg border border-gray-800">
<ValidatorsTable validators={mockValidators} />
</div>
</div>
)}
</div>
</div>
);
};

export default ValidatorsRanking;
Loading
Loading