Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a73f817
feat: add vote status bar & modify response structure
chickick Jul 23, 2025
2c11756
feat: modify some styles
chickick Jul 23, 2025
ae1e38d
feat: hide tooltip
chickick Jul 23, 2025
1961709
feat: minor changes
chickick Jul 24, 2025
747d334
feat(home): update vote data render logic
chickick Jul 24, 2025
bba1cb7
refactor: updated mock contract and perf renderVoteBar
chickick Jul 24, 2025
2cd3708
fix: minor type
chickick Jul 24, 2025
602cd9f
chore: update mainnet config
chickick Jul 24, 2025
807428f
chore: mainnet config
chickick Jul 24, 2025
1da6811
feat: minor changes
chickick Jul 24, 2025
8c4e16d
Merge branch 'feat/home-v2' of https://github.com/linear-protocol/val…
chickick Jul 24, 2025
ebdd290
fix: minor
chickick Jul 24, 2025
6fa6d80
chore: update mainnet api
chickick Jul 24, 2025
14d1056
feat: fetch vote result data
chickick Jul 24, 2025
49c1e57
Merge branch 'feat/home-v2' of https://github.com/linear-protocol/val…
chickick Jul 24, 2025
551f239
feat: update voting instructions
linguists Jul 25, 2025
cef61ee
feat: update voting instructions
linguists Jul 25, 2025
e3d8b68
chore: change tesnet contract ID
linguists Jul 25, 2025
b97dafc
chore: optimize codes
chickick Jul 25, 2025
f3053a2
chore: optimize codes
chickick Jul 25, 2025
d6f1755
chore: modify the number of decimal places
chickick Jul 25, 2025
22ffbee
chore: update testnet contract
chickick Jul 25, 2025
605d64e
Update src/pages/home/index.tsx
linguists Jul 25, 2025
566c3a7
feat: Modify progress bar
chickick Jul 30, 2025
bd7ee07
Merge branch 'feat/home-v2-progress-bar' into feat/home-v2
chickick Jul 30, 2025
ec17c86
chore: update text copy
chickick Jul 30, 2025
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
3 changes: 3 additions & 0 deletions src/assets/icons/no.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/icons/yes.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions src/config/mainnet.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const config: App.AppConfig = {
proposalContractId: 'reduce-inflation.near',
validatorApi: 'https://validator-voting-api.linearprotocol.org',
proposalContractId: 'test-proposal.near',
// validatorApi: 'https://validator-voting-api.linearprotocol.org',
validatorApi: "https://validator-voting-api-dev-7d3e8c25989f.herokuapp.com",
near: {
network: {
networkId: 'mainnet',
Expand Down
2 changes: 1 addition & 1 deletion src/config/testnet.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const config: App.AppConfig = {
proposalContractId: 'reduce-inflation.testnet',
proposalContractId: 'mock-proposal-alpha.testnet',
validatorApi: 'https://validator-voting-api.linearprotocol.org',
near: {
network: {
Expand Down
56 changes: 27 additions & 29 deletions src/containers/vote/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,21 @@ import { toast } from 'sonner';

interface VoteState {
isLoading: boolean;
voteResult: boolean;
deadline: number | null;
voteFinishedAt: number | null;
votes: Record<string, string>;
votesCount: number | null;
votes: Record<string, ['yes' | 'no', string]>;
yesVotesCount: number | null;
votedYeaStakeAmount: Big.Big;
votedStakeAmount: Big.Big;
totalVotedStakeAmount: Big.Big;
totalStakeAmount: Big.Big;
}

interface VoteComputed {
votedPercent: string;
progressList: number[];
}

const PROGRESS = [66.67];
const PROGRESS = [33.33];

type UseVoteContainer = VoteState & VoteComputed;
const contractId = config.proposalContractId;
Expand All @@ -32,39 +33,35 @@ function useVoteContainer(): UseVoteContainer {
const { viewFunction } = useNear();

const [deadline, setDeadline] = useState<number | null>(null);
const [voteFinishedAt, setVoteFinishedAt] = useState<number | null>(null);
const [votes, setVotes] = useState<Record<string, string>>({});
const [voteResult, setVoteResult] = useState(false);
const [votes, setVotes] = useState<Record<string, ['yes' | 'no', string]>>({});
const [votedStakeAmount, setVotedStakeAmount] = useState(Big(0));
const [totalVotedStakeAmount, setTotalVotedStakeAmount] = useState(Big(0));
const [votedYeaStakeAmount, setVotedYeaStakeAmount] = useState(Big(0));
const [totalStakeAmount, setTotalStakeAmount] = useState(Big(0));

const _votedPercent = useMemo(() => {
if (!totalVotedStakeAmount) return '0';
if (totalVotedStakeAmount.eq(0)) return '0';
return votedStakeAmount.div(totalVotedStakeAmount).times(100).toFixed(2) || '0';
}, [votedStakeAmount, totalVotedStakeAmount]);
if (!totalStakeAmount) return '0';
if (totalStakeAmount.eq(0)) return '0';
return votedStakeAmount.div(totalStakeAmount).times(100).toFixed(2) || '0';
}, [votedStakeAmount, totalStakeAmount]);

const votedPercent = useMemo(() => {
const _percent = Number(_votedPercent);
const lastProgress = PROGRESS[PROGRESS.length - 1];
if (voteFinishedAt) {
if (_percent >= lastProgress) return _votedPercent;
return lastProgress.toFixed(2);
}
return _votedPercent;
}, [_votedPercent, voteFinishedAt]);
}, [_votedPercent]);

const getTotalVotedStake = useCallback(async () => {
const data = await viewFunction({
contractId: contractId,
method: 'get_total_voted_stake',
});
logger.debug('get_total_voted_stake', data);
if (!Array.isArray(data) && data.length !== 2) {
if (!Array.isArray(data) || data.length !== 3) {
logger.error('get_total_voted_stake error', data);
return;
}
setVotedStakeAmount(Big(data[0]));
setTotalVotedStakeAmount(Big(data[1]));
setVotedYeaStakeAmount(Big(data[0]));
setVotedStakeAmount(Big(data[1]));
setTotalStakeAmount(Big(data[2]));
}, [viewFunction]);

const getResult = useCallback(async () => {
Expand All @@ -73,7 +70,7 @@ function useVoteContainer(): UseVoteContainer {
method: 'get_result',
});
logger.debug('get_result', data);
setVoteFinishedAt(data || null);
setVoteResult(data || false);
}, [viewFunction]);

const getVotes = useCallback(async () => {
Expand Down Expand Up @@ -105,17 +102,17 @@ function useVoteContainer(): UseVoteContainer {
const { isLoading, error } = useSWR(
'vote_data',
async () => {
const promises = Promise.all([getTotalVotedStake(), getResult(), getVotes(), getDeadline()]);
const promises = Promise.all([getTotalVotedStake(), getVotes(), getDeadline(), getResult()]);
return await promises;
},
// {
// revalidateOnFocus: false,
// revalidateOnReconnect: false,
// },
);
const votesCount = useMemo(() => {
const yesVotesCount = useMemo(() => {
if (error) return null;
return Object.keys(votes).length;
return Object.values(votes).filter(([vote]) => vote === 'yes').length;
}, [votes, error]);

useEffect(() => {
Expand All @@ -126,12 +123,13 @@ function useVoteContainer(): UseVoteContainer {

return {
isLoading,
voteResult,
deadline,
voteFinishedAt,
votes,
votesCount,
yesVotesCount,
votedStakeAmount,
totalVotedStakeAmount,
votedYeaStakeAmount,
totalStakeAmount,
votedPercent,
progressList: PROGRESS,
};
Expand Down
20 changes: 8 additions & 12 deletions src/pages/details/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ interface VotingPowerItem {
export default function Details() {
const navigate = useNavigate();

const { isLoading: voteDataLoading, votes, totalVotedStakeAmount } = VoteContainer.useContainer();
const { isLoading: voteDataLoading, votes, totalStakeAmount } = VoteContainer.useContainer();
const [loading, setLoading] = useState(false);
const [list, setList] = useState<ValidatorItem[]>([]);
const [powerOrder, setPowerOrder] = useState<'asc' | 'desc' | undefined>();
Expand All @@ -46,8 +46,8 @@ export default function Details() {
// });

return list.sort((a, b) => {
const aVote = a.vote === 'yes' ? votes[a.accountId] || '0' : a.totalStakedBalance;
const bVote = b.vote === 'yes' ? votes[b.accountId] || '0' : b.totalStakedBalance;
const aVote = votes[a.accountId] ? votes[a.accountId][1] : '0';
const bVote = votes[b.accountId] ? votes[b.accountId][1] : '0';
const aDate = a.lastVoteTimestamp || 0;
const bDate = b.lastVoteTimestamp || 0;

Expand All @@ -71,22 +71,18 @@ export default function Details() {

const getPercent = useCallback(
(n: string | number) => {
if (!totalVotedStakeAmount || !n) return '0';
if (Big(totalVotedStakeAmount).eq(0)) return '0';
return Big(n).div(totalVotedStakeAmount).times(100).toFixed(2);
if (!totalStakeAmount || !n) return '0';
if (Big(totalStakeAmount).eq(0)) return '0';
return Big(n).div(totalStakeAmount).times(100).toFixed(2);
},
[totalVotedStakeAmount],
[totalStakeAmount],
);

const votingPowerMap: Record<string, VotingPowerItem> = useMemo(() => {
const data: Record<string, VotingPowerItem> = {};
tableList.forEach((item) => {
const isYesVote = item.vote === 'yes';
let power = votes[item.accountId] || '0';
if (!isYesVote) {
power = item.totalStakedBalance || '0';
}

const power = votes[item.accountId] ? votes[item.accountId][1] : '0';
const formattedPower = power ? formatBigNumber(power, 24) : '0';
const percent = getPercent(power);

Expand Down
9 changes: 6 additions & 3 deletions src/pages/home/components/Countdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ export interface CountdownProps {
deadline: number | null;
}

export default function Countdown({ votedPercent, deadline }: CountdownProps) {
export default function Countdown({ deadline }: CountdownProps) {
const [isPageVisible, setPageVisibility] = useState(!document.hidden);
const [countdownSeconds, setCountdownSeconds] = useState<number | null>(null);

const finished = deadline && Date.now() > deadline;

const deadlineFromNow = useMemo(() => {
if (!countdownSeconds) return null;
const diffSeconds = countdownSeconds;
Expand Down Expand Up @@ -61,12 +63,13 @@ export default function Countdown({ votedPercent, deadline }: CountdownProps) {
);

if (!deadlineFromNow) return null;
if (finished) return null;

return (
<div className="flex flex-col items-center mb-10">
<h3 className="text-app-black-400 text-base sm:text-lg mb-4">
{/* <h3 className="text-app-black-400 text-base sm:text-lg mb-4">
{votedPercent}% of Stake Voted for YEA
</h3>
</h3> */}
<div className="flex items-center gap-x-5 sm:gap-x-9">
<div className="flex flex-col items-center">
<div className="text-app-black text-4xl sm:text-[56px] font-bold">
Expand Down
Loading