Skip to content

Commit

Permalink
session check on page load
Browse files Browse the repository at this point in the history
  • Loading branch information
0age committed Dec 7, 2024
1 parent 00d0e70 commit cf0e946
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 3 deletions.
57 changes: 54 additions & 3 deletions frontend/src/hooks/useSessionPoller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,53 @@ export function useSessionPoller(
return;
}

// Set initial session
onSessionUpdate(sessionId);
// Immediately validate session on mount
const validateSession = async () => {
try {
const response = await fetch('/session', {
headers: {
'x-session-id': sessionId,
},
});

// Handle 401 Unauthorized explicitly
if (response.status === 401) {
localStorage.removeItem(`session-${address}`);
onSessionUpdate(null);
return;
}

const data: SessionResponse = await response.json();

// Check for invalid session error
if (data.error === 'Invalid session' || !response.ok) {
localStorage.removeItem(`session-${address}`);
onSessionUpdate(null);
return;
}

// Verify session belongs to current address
if (data.session?.address.toLowerCase() !== address.toLowerCase()) {
throw new Error('Session address mismatch');
}

// Check if session has expired
const expiryTime = new Date(data.session.expiresAt).getTime();
if (expiryTime < Date.now()) {
throw new Error('Session expired');
}

// Session is valid, set it
onSessionUpdate(sessionId);
} catch (error) {

Check failure on line 73 in frontend/src/hooks/useSessionPoller.ts

View workflow job for this annotation

GitHub Actions / build-and-test

'error' is defined but never used
// On any error, clear the session
localStorage.removeItem(`session-${address}`);
onSessionUpdate(null);
}
};

// Run initial validation
validateSession();

// Start polling
const intervalId = setInterval(async () => {
Expand All @@ -44,11 +89,17 @@ export function useSessionPoller(
},
});

// Handle 401 Unauthorized explicitly
if (response.status === 401) {
localStorage.removeItem(`session-${address}`);
onSessionUpdate(null);
return;
}

const data: SessionResponse = await response.json();

// Check for invalid session error
if (data.error === 'Invalid session' || !response.ok) {
// Clear the session and update state
localStorage.removeItem(`session-${address}`);
onSessionUpdate(null);
return;
Expand Down
125 changes: 125 additions & 0 deletions frontend/src/hooks/useWithdrawalStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { useState, useEffect, useCallback } from 'react';

interface Balance {
chainId: string;
lockId: string;
withdrawalStatus: number;
withdrawableAt: string;
}

interface WithdrawalStatus {
canExecute: boolean;
timeRemaining: string | null;
status: 'active' | 'ready' | 'pending';
}

type WithdrawalStatuses = Record<string, WithdrawalStatus>;

// Helper to create a unique key for each balance
function getStatusKey(chainId: string, lockId: string): string {
return `${chainId}-${lockId}`;
}

// Format time remaining helper
function formatTimeRemaining(expiryTimestamp: number): string {
const now = Math.floor(Date.now() / 1000);
const diff = expiryTimestamp - now;

if (diff <= 0) return 'Ready';

const days = Math.floor(diff / (24 * 60 * 60));
const hours = Math.floor((diff % (24 * 60 * 60)) / (60 * 60));
const minutes = Math.floor((diff % (60 * 60)) / 60);
const seconds = diff % 60;

if (days > 0) return `${days}d ${hours}h ${minutes}m`;
if (hours > 0) return `${hours}h ${minutes}m ${seconds}s`;
if (minutes > 0) return `${minutes}m ${seconds}s`;
return `${seconds}s`;
}

export function useWithdrawalStatus(balances: Balance[]): WithdrawalStatuses {
const [statuses, setStatuses] = useState<WithdrawalStatuses>({});

// Update all statuses
const updateStatuses = useCallback(() => {
const now = Math.floor(Date.now() / 1000);
const newStatuses: WithdrawalStatuses = {};

balances.forEach((balance) => {
const statusKey = getStatusKey(balance.chainId, balance.lockId);

console.log(
`[Chain ${balance.chainId}, Lock ${balance.lockId}] Status Check:`,
{
withdrawalStatus: balance.withdrawalStatus,
withdrawableAt: balance.withdrawableAt,
now,
}
);

if (balance.withdrawalStatus === 0) {
console.log(`[${statusKey}] -> ACTIVE (status=0)`);
newStatuses[statusKey] = {
canExecute: false,
timeRemaining: null,
status: 'active',
};
} else if (balance.withdrawalStatus === 1) {
// If withdrawableAt is undefined or invalid, treat it as pending with default time
const timestamp = balance.withdrawableAt
? parseInt(balance.withdrawableAt)
: now + 600; // default to 10 minutes if not set

if (timestamp <= now) {
console.log(`[${statusKey}] -> READY (status=1, time elapsed)`);
newStatuses[statusKey] = {
canExecute: true,
timeRemaining: 'Ready',
status: 'ready',
};
} else {
const remaining = formatTimeRemaining(timestamp);
console.log(
`[${statusKey}] -> PENDING (status=1, ${remaining} remaining)`
);
newStatuses[statusKey] = {
canExecute: false,
timeRemaining: remaining,
status: 'pending',
};
}
} else {
console.log(`[${statusKey}] -> DEFAULT to ACTIVE (unexpected state)`);
newStatuses[statusKey] = {
canExecute: false,
timeRemaining: null,
status: 'active',
};
}
});

console.log('Final Statuses:', newStatuses);
setStatuses(newStatuses);
}, [balances]);

// Update status every second if there are any pending withdrawals
useEffect(() => {
const hasPendingWithdrawals = balances.some(
(balance) =>
balance.withdrawalStatus === 1 &&
parseInt(balance.withdrawableAt || '0') > Math.floor(Date.now() / 1000)
);

updateStatuses();

if (!hasPendingWithdrawals) {
return;
}

const timer = setInterval(updateStatuses, 1000);
return () => clearInterval(timer);
}, [balances, updateStatuses]);

return statuses;
}

0 comments on commit cf0e946

Please sign in to comment.