diff --git a/public/duelfiassets/believe.svg b/public/duelfiassets/believe.svg
new file mode 100644
index 0000000..bcdd761
--- /dev/null
+++ b/public/duelfiassets/believe.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/duelfiassets/coingecko.svg b/public/duelfiassets/coingecko.svg
new file mode 100644
index 0000000..9da652d
--- /dev/null
+++ b/public/duelfiassets/coingecko.svg
@@ -0,0 +1,16 @@
+
\ No newline at end of file
diff --git a/public/duelfiassets/dexscreener.svg b/public/duelfiassets/dexscreener.svg
new file mode 100644
index 0000000..259b650
--- /dev/null
+++ b/public/duelfiassets/dexscreener.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/duelfiassets/meteora.svg b/public/duelfiassets/meteora.svg
new file mode 100644
index 0000000..58241f4
--- /dev/null
+++ b/public/duelfiassets/meteora.svg
@@ -0,0 +1,51 @@
+
\ No newline at end of file
diff --git a/src/components/Activities.tsx b/src/components/Activities.tsx
index 390ed3f..546f651 100644
--- a/src/components/Activities.tsx
+++ b/src/components/Activities.tsx
@@ -1,8 +1,9 @@
import Image from "next/image";
-import { useState, useEffect } from "react";
+import { useState, useEffect, useRef } from "react";
import { API_BASE_URL } from "@/data/shared";
import { PlusCircleIcon, XCircleIcon, UserPlusIcon, TrophyIcon } from '@heroicons/react/24/outline';
import { GetGameByID } from "@/data/games";
+import { toast } from "sonner";
interface Activity {
id: string;
@@ -28,12 +29,76 @@ export default function Activities() {
const [loading, setLoading] = useState(true);
const [failedImages, setFailedImages] = useState>(new Set());
const defaultPFP = '/duelfiassets/PFP (1).png';
+ const isFirstLoad = useRef(true);
+ const previousActivitiesRef = useRef([]);
+ const pendingToasts = useRef([]);
+
+ const formatActivityMessage = (activity: Activity) => {
+ const ownerUsername = userData[activity.owner_id]?.username || "Anonymous";
+ const joinerUsername = activity.joiner_id ? (userData[activity.joiner_id]?.username || "Anonymous") : null;
+ let amount = parseFloat(activity.amount);
+ if(activity.type == "won"){
+ amount = amount * 1.9;
+ }
+ const formattedAmount = amount > 0 ? `${amount} SOL` : "";
+ const gameData = GetGameByID(activity.game);
+ const gameName = gameData?.name || activity.game;
+ switch (activity.type) {
+ case "create":
+ return `${ownerUsername} created a ${gameName} game with a ${formattedAmount} entry fee.`;
+ case "close":
+ return `${ownerUsername} cancelled their ${gameName} game.`;
+ case "join":
+ return `${joinerUsername} joined ${gameName} with a ${formattedAmount} entry fee.`;
+ case "won":
+ return `${ownerUsername} won ${formattedAmount} in ${gameName}!`;
+ default:
+ return "Unknown activity";
+ }
+ };
+
+ useEffect(() => {
+ // Show pending toasts when userData is updated
+ if (Object.keys(userData).length > 0 && pendingToasts.current.length > 0) {
+ pendingToasts.current.forEach((activity) => {
+ const message = formatActivityMessage(activity);
+ const toastConfig = {
+ duration: 5000,
+ position: 'top-right' as const,
+ icon: activity.type === "create" ? "🎮" :
+ activity.type === "close" ? "❌" :
+ activity.type === "join" ? "👋" :
+ activity.type === "won" ? "🏆" : "📢"
+ };
+ toast(message, toastConfig);
+ });
+ pendingToasts.current = [];
+ }
+ }, [userData]);
useEffect(() => {
const fetchActivities = async () => {
try {
const response = await fetch("/api/v1/get_activities.php");
const data = await response.json();
+
+ // Don't show toasts on first load
+ if (!isFirstLoad.current) {
+ // Check for new activities using the ref
+ const newActivities = data.filter((activity: Activity) =>
+ !previousActivitiesRef.current.some(prevActivity => prevActivity.id === activity.id)
+ );
+
+ if (newActivities.length > 0) {
+ // Store new activities in pendingToasts
+ pendingToasts.current = newActivities;
+ }
+ } else {
+ isFirstLoad.current = false;
+ }
+
+ // Update the ref with current activities
+ previousActivitiesRef.current = data;
setActivities(data);
// Fetch user data for all unique user IDs
@@ -45,11 +110,8 @@ export default function Activities() {
const userDataPromises = Array.from(userIds).map(async (userId) => {
try {
- console.log('Fetching user data for ID:', userId);
-
const response = await fetch(`/api/v1/get_user_by_id.php?id=${userId}`);
const data = await response.json();
- console.log('Received user data:', data);
return [userId, data];
} catch (error) {
console.error(`Error fetching user data for ${userId}:`, error);
@@ -58,9 +120,7 @@ export default function Activities() {
});
const userDataResults = await Promise.all(userDataPromises);
- console.log('All user data results:', userDataResults);
const userDataMap = Object.fromEntries(userDataResults);
- console.log('Final user data map:', userDataMap);
setUserData(userDataMap);
} catch (error) {
console.error("Error fetching activities:", error);
@@ -77,31 +137,7 @@ export default function Activities() {
// Cleanup function to clear the interval when component unmounts
return () => clearInterval(intervalId);
- }, []);
-
- const formatActivityMessage = (activity: Activity) => {
- const ownerUsername = userData[activity.owner_id]?.username || "Anonymous";
- const joinerUsername = activity.joiner_id ? (userData[activity.joiner_id]?.username || "Anonymous") : null;
- let amount = parseFloat(activity.amount);
- if(activity.type == "won"){
- amount = amount * 1.9;
- }
- const formattedAmount = amount > 0 ? `${amount} SOL` : "";
- const gameData = GetGameByID(activity.game);
- const gameName = gameData?.name || activity.game;
- switch (activity.type) {
- case "create":
- return <>{ownerUsername} created a {gameName} game with a {formattedAmount} entry fee.>;
- case "close":
- return <>{ownerUsername} cancelled their {gameName} game.>;
- case "join":
- return <>{joinerUsername} joined {gameName} with a {formattedAmount} entry fee.>;
- case "won":
- return <>{ownerUsername} won {formattedAmount} in {gameName}!>;
- default:
- return "Unknown activity";
- }
- };
+ }, []); // Remove dependencies since we're using refs
const formatTimeAgo = (timestamp: string) => {
const date = new Date(timestamp + 'Z');
diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx
index fb9d188..99c4a8a 100644
--- a/src/components/Footer.tsx
+++ b/src/components/Footer.tsx
@@ -4,6 +4,13 @@ import { URL_TELEGRAM, URL_TWITTER } from "@/shared/constants";
import Image from "next/image";
import Link from "next/link";
+const TRACK_TRADE_LINKS = {
+ BELIEVE: "https://believe.app/coin/FiQBQdASK3AJVZfE7Nc5KwHvQiTd8YepsHAexopPF1eS",
+ COINGECKO: "https://www.coingecko.com/en/search_redirect?id=duel-fi&type=coin",
+ DEXSCREENER: "https://dexscreener.com/solana/2HuT5v8fG2c5VHxoq1thaN4c2ARwUunEnhbibyQJC1qX",
+ METEORA: "https://www.meteora.ag/dlmm/8CXwRcwLzwHgj8F6nXbeYa2CgEGTAtGsFHmtjJ9dhGQ9"
+};
+
export default function Footer() {
return (