Skip to content

Commit

Permalink
42424
Browse files Browse the repository at this point in the history
  • Loading branch information
0xjaqbek committed Jul 17, 2024
1 parent 6a91b08 commit cfe63d4
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 82 deletions.
2 changes: 1 addition & 1 deletion src/IndexPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ const IndexPage: FC = () => {
<LeaderboardPage
elapsedTime={(endTime - startTime) / 1000}
onClose={() => setShowLeaderboard(false)} // Close the leaderboard page
/>
telegramId={null} />
)}

{calculateElapsedTime() || (userId ? userId : "...")}
Expand Down
107 changes: 70 additions & 37 deletions src/LeaderboardPage.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
// LeaderboardPage.tsx

import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import { StyledButton } from './StyledButton';
import { TonConnectButton } from "@tonconnect/ui-react";
import { useTonAddress } from "@tonconnect/ui-react";
import { getLeaderboard, updateLeaderboard } from './gistService';
import { getLeaderboard, updateLeaderboard, LeaderboardEntry } from './gistService'; // Ensure LeaderboardEntry is imported

interface LeaderboardPageProps {
elapsedTime: number;
onClose: () => void;
telegramId: string | null; // Assuming you pass telegramId as a prop
}

const LeaderboardContainer = styled.div`
Expand Down Expand Up @@ -46,7 +49,7 @@ const ActionsContainer = styled.div`
flex-direction: column;
align-items: center;
margin-top: 5px;
background-color: black;
background-color: black;
`;

const LeaderboardList = styled.ul`
Expand All @@ -68,7 +71,7 @@ const LeaderboardItem = styled.li`
`;

const StyledButtonSecondary = styled(StyledButton)`
background-color: gray; /* Green */
background-color: gray;
border: 2px solid;
border-color: #CCCCCC;
color: white;
Expand Down Expand Up @@ -105,11 +108,20 @@ const SaveScoreWindowContent = styled.div`
text-align: center;
`;

const LeaderboardPage: React.FC<LeaderboardPageProps> = ({ elapsedTime, onClose }) => {
const NickInput = styled.input`
padding: 10px;
margin-top: 10px;
border: 1px solid #ddd;
border-radius: 5px;
width: 80%;
`;

const LeaderboardPage: React.FC<LeaderboardPageProps> = ({ elapsedTime, onClose, telegramId }) => {
const rawAddress = useTonAddress(true); // false for raw address
const [leaderboard, setLeaderboard] = useState<{ address: string; time: number }[]>([]);
const [leaderboard, setLeaderboard] = useState<LeaderboardEntry[]>([]);
const [pageIndex, setPageIndex] = useState(0);
const [showSaveScoreWindow, setShowSaveScoreWindow] = useState(false);
const [nick, setNick] = useState('');
const itemsPerPage = 3;

useEffect(() => {
Expand All @@ -125,47 +137,62 @@ const LeaderboardPage: React.FC<LeaderboardPageProps> = ({ elapsedTime, onClose
};

const handleSaveScoreConfirm = async () => {
if (rawAddress) {
const existingScore = leaderboard.find(score => score.address === rawAddress);
if (existingScore) {
if (elapsedTime < existingScore.time) {
const updatedLeaderboard = leaderboard.map(score =>
score.address === rawAddress ? { address: rawAddress, time: elapsedTime } : score
);
setLeaderboard(updatedLeaderboard);
await updateLeaderboard(updatedLeaderboard);
console.log(`Wallet Address: ${rawAddress}`);
console.log(`Elapsed Time: ${elapsedTime.toFixed(2)} seconds`);
} else {
const timeDifference = (elapsedTime - existingScore.time).toFixed(2);
alert(`Eee, slower by ${timeDifference} seconds than before.`);
}
} else {
const newScore = { address: rawAddress, time: elapsedTime };
const updatedLeaderboard = [...leaderboard, newScore];
if (!rawAddress && !telegramId) {
alert("Please connect your wallet or provide a Telegram ID.");
return;
}
if (!nick) {
alert("Please enter a nickname.");
return;
}

// Check if the nickname is already used by another user
const nicknameExists = leaderboard.some(entry => entry.nick === nick && (entry.playerId !== telegramId || entry.address !== rawAddress));
if (nicknameExists) {
alert("This nickname is already taken by another user.");
return;
}

const newScore: LeaderboardEntry = {
address: rawAddress || '',
time: elapsedTime,
playerId: telegramId || '',
nick: nick,
};

const existingScore = leaderboard.find(score => score.address === rawAddress || score.playerId === telegramId);
if (existingScore) {
if (elapsedTime < existingScore.time) {
const updatedLeaderboard = leaderboard.map(score =>
(score.address === rawAddress || score.playerId === telegramId) ? newScore : score
);
setLeaderboard(updatedLeaderboard);
await updateLeaderboard(updatedLeaderboard);
console.log(`Wallet Address: ${rawAddress}`);
console.log(`Elapsed Time: ${elapsedTime.toFixed(2)} seconds`);
} else {
const timeDifference = (elapsedTime - existingScore.time).toFixed(2);
alert(`Eee, slower by ${timeDifference} seconds than before.`);
}
setShowSaveScoreWindow(false);
} else {
alert("Please connect your wallet first.");
const updatedLeaderboard = [...leaderboard, newScore];
setLeaderboard(updatedLeaderboard);
await updateLeaderboard(updatedLeaderboard);
console.log(`Wallet Address: ${rawAddress}`);
console.log(`Elapsed Time: ${elapsedTime.toFixed(2)} seconds`);
}
setShowSaveScoreWindow(false);
};

const getTopScores = (scores: { address: string; time: number }[]) => {
// Filter to keep only the highest score per address
const getTopScores = (scores: LeaderboardEntry[]) => {
const highestScores = scores.reduce((acc, score) => {
if (!acc[score.address] || acc[score.address].time > score.time) {
acc[score.address] = score;
if (!acc[score.address || score.playerId] || acc[score.address || score.playerId].time > score.time) {
acc[score.address || score.playerId] = score;
}
return acc;
}, {} as Record<string, { address: string; time: number }>);

const sortedScores = Object.values(highestScores)
.sort((a, b) => a.time - b.time); // Sort ascending by time
}, {} as Record<string, LeaderboardEntry>);

const sortedScores = Object.values(highestScores).sort((a, b) => a.time - b.time);
return sortedScores;
};

Expand Down Expand Up @@ -209,7 +236,7 @@ const LeaderboardPage: React.FC<LeaderboardPageProps> = ({ elapsedTime, onClose
<LeaderboardList>
{paginatedScores.map((entry, index) => (
<LeaderboardItem key={index}>
{pageIndex * itemsPerPage + index + 1}. {formatAddress(entry.address)} - {entry.time.toFixed(2)} seconds
{pageIndex * itemsPerPage + index + 1}. {entry.nick || formatAddress(entry.address)} - {entry.time.toFixed(2)} seconds
</LeaderboardItem>
))}
</LeaderboardList>
Expand All @@ -226,9 +253,15 @@ const LeaderboardPage: React.FC<LeaderboardPageProps> = ({ elapsedTime, onClose
<SaveScoreWindowContainer>
<SaveScoreWindowContent>
<p>Connect your wallet to set user Id and save your score:</p>
<TonConnectButton /><br></br>
<StyledButton onClick={handleSaveScoreConfirm} style={{ marginTop: '10px' }}>Save Score</StyledButton><br></br><br></br><br></br>
<StyledButton onClick={handleCloseSaveScoreWindow} style={{ marginTop: '10px' }}>Close</StyledButton><br></br>
<TonConnectButton />
<NickInput
type="text"
placeholder="Enter your nickname"
value={nick}
onChange={(e) => setNick(e.target.value)}
/>
<StyledButton onClick={handleSaveScoreConfirm} style={{ marginTop: '10px' }}>Save Score</StyledButton>
<StyledButton onClick={handleCloseSaveScoreWindow} style={{ marginTop: '10px' }}>Close</StyledButton>
</SaveScoreWindowContent>
</SaveScoreWindowContainer>
)}
Expand Down
97 changes: 53 additions & 44 deletions src/gistService.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
// gistService.ts
import axios, { AxiosError } from 'axios';
import dotenv from 'dotenv';
import { initializeApp } from 'firebase/app';
import { getDatabase, ref, set, onValue, get, update } from 'firebase/database';

dotenv.config();
import { getDatabase, ref, get, set, update } from 'firebase/database';

// Replace with your Firebase config
const firebaseConfig = {
Expand All @@ -17,60 +15,71 @@ const firebaseConfig = {
databaseURL: "https://tapracesprint-default-rtdb.europe-west1.firebasedatabase.app/"
};

// Initialize Firebase app
const app = initializeApp(firebaseConfig);
const db = getDatabase(app);

// Firebase references
const leaderboardRef = ref(db, 'leaderboard');
const usersRef = ref(db, 'users');

// Function to check if error is AxiosError
const isAxiosError = (error: unknown): error is AxiosError => {
return axios.isAxiosError(error);
return axios.isAxiosError(error);
};

// Fetch leaderboard function
export const getLeaderboard = async () => {
try {
console.log('Fetching leaderboard...');
const snapshot = await get(leaderboardRef);
const leaderboard = snapshot.val();
console.log('Leaderboard:', leaderboard);
return leaderboard || [];
} catch (error: unknown) {
if (isAxiosError(error)) {
console.error('Error fetching leaderboard:', error.response ? error.response.data : error.message);
} else {
console.error('Unexpected error fetching leaderboard:', error);
}
return [];
try {
console.log('Fetching leaderboard...');
const snapshot = await get(leaderboardRef);
const leaderboard = snapshot.val();
console.log('Leaderboard:', leaderboard);
return leaderboard || [];
} catch (error: unknown) {
if (isAxiosError(error)) {
console.error('Error fetching leaderboard:', error.response ? error.response.data : error.message);
} else {
console.error('Unexpected error fetching leaderboard:', error);
}
return [];
}
};

export const updateLeaderboard = async (leaderboard: { address: string; time: number; }[]) => {
try {
console.log('Updating leaderboard...');
await set(leaderboardRef, leaderboard);
console.log('Leaderboard updated successfully.');
// Update leaderboard function
export const updateLeaderboard = async (leaderboard: LeaderboardEntry[]) => {
try {
console.log('Updating leaderboard...');
await set(leaderboardRef, leaderboard);
console.log('Leaderboard updated successfully.');

// Update user scores
for (const entry of leaderboard) {
const userRef = ref(db, `users/${entry.address}`);
const userSnapshot = await get(userRef);
const existingScores = userSnapshot.exists() ? userSnapshot.val().scores : [];
const newScores = [...existingScores, { time: entry.time, timestamp: new Date().toISOString() }];
await update(userRef, { scores: newScores });
}
// Update user scores
for (const entry of leaderboard) {
if (!entry.address) {
continue; // Skip if address is missing or null
}
const userRef = ref(db, `users/${entry.address}`);
const userSnapshot = await get(userRef);
const existingScores = userSnapshot.exists() ? userSnapshot.val().scores : [];
const newScores = [...existingScores, { time: entry.time, timestamp: new Date().toISOString() }];
await update(userRef, { scores: newScores, nick: entry.nick });
}

return true;
} catch (error: unknown) {
if (isAxiosError(error)) {
console.error('Error updating leaderboard:', error.response ? error.response.data : error.message);
} else {
console.error('Unexpected error updating leaderboard:', error);
}
return false;
return true;
} catch (error: unknown) {
if (isAxiosError(error)) {
console.error('Error updating leaderboard:', error.response ? error.response.data : error.message);
} else {
console.error('Unexpected error updating leaderboard:', error);
}
return false;
}
};

onValue(usersRef, (snapshot) => {
const data = snapshot.val();
console.log('Data:', data);
// Do something with the users data here
});
// Export other necessary functions or interfaces as needed
export interface LeaderboardEntry {
playerId: string;
address: string;
time: number;
nick?: string;
}

0 comments on commit cfe63d4

Please sign in to comment.