From 7d30afec4c1a4630c4583680fa632e0c1b0d1bb8 Mon Sep 17 00:00:00 2001 From: Harshal Dulera Date: Sun, 8 Dec 2024 08:18:08 +0530 Subject: [PATCH] feat: add RainbowKit and React Query dependencies; update layout and components for integration --- package.json | 2 + packages/nextjs/app/layout.tsx | 26 ++- packages/nextjs/app/leaderboard/page.tsx | 2 +- packages/nextjs/app/login/page.tsx | 3 +- packages/nextjs/app/page.tsx | 204 +++++++++--------- packages/nextjs/app/providers.tsx | 34 +++ packages/nextjs/components/ChatSearchBar.tsx | 81 ++++--- packages/nextjs/components/NewHeader.tsx | 150 ++++++------- .../ScaffoldEthAppWithProviders.tsx | 39 ++-- packages/nextjs/utils/rainbowConfig.ts | 24 +++ yarn.lock | 41 ++++ 11 files changed, 353 insertions(+), 253 deletions(-) create mode 100644 packages/nextjs/app/providers.tsx create mode 100644 packages/nextjs/utils/rainbowConfig.ts diff --git a/package.json b/package.json index b1d2eef..3967946 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,8 @@ "@apollo/experimental-nextjs-app-support": "^0.11.7", "@ethereum-attestation-service/eas-sdk": "^2.7.0", "@graphprotocol/graph-cli": "^0.91.1", + "@rainbow-me/rainbowkit": "^2.2.1", + "@tanstack/react-query": "^5.62.3", "axios": "^1.7.9", "ethereum-blockies": "^0.1.1", "framer-motion": "^11.13.1", diff --git a/packages/nextjs/app/layout.tsx b/packages/nextjs/app/layout.tsx index 3b20cce..b9c5c4c 100644 --- a/packages/nextjs/app/layout.tsx +++ b/packages/nextjs/app/layout.tsx @@ -11,6 +11,12 @@ import { FitnessProvider, useFitness } from "~~/context/FitnessContext"; import "~~/styles/globals.css"; import { useAuth, AuthProvider } from "~~/context/AuthContext"; import { useRouter } from "next/navigation"; +// import { RainbowKitProvider, darkTheme } from '@rainbow-me/rainbowkit'; +import { RainbowKitProviders } from './providers'; +import { config } from '~~/utils/rainbowConfig'; +import "@rainbow-me/rainbowkit/styles.css"; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { WagmiProvider } from 'wagmi'; const TokenHandler = ({ children }: { children: React.ReactNode }) => { const { setTokens, accessToken } = useAuth(); @@ -93,15 +99,17 @@ const ScaffoldEthApp = ({ children }: { children: React.ReactNode }) => { - - - - - {children} - - - - + {/* */} + + + + + {children} + + + + + {/* */} diff --git a/packages/nextjs/app/leaderboard/page.tsx b/packages/nextjs/app/leaderboard/page.tsx index 8181b74..d3889a9 100644 --- a/packages/nextjs/app/leaderboard/page.tsx +++ b/packages/nextjs/app/leaderboard/page.tsx @@ -223,7 +223,7 @@ export default function Leaderboard() { router.back()} - className="absolute left-6 top-1/2 -translate-y-1/2 + className="absolute left-6 top-1/4 -translate-y-1/2 text-[#11ce6f] hover:text-[#3b82f6] transition-colors" > diff --git a/packages/nextjs/app/login/page.tsx b/packages/nextjs/app/login/page.tsx index 127cd2a..5a7277f 100644 --- a/packages/nextjs/app/login/page.tsx +++ b/packages/nextjs/app/login/page.tsx @@ -11,7 +11,8 @@ const LoginPage = () => { const handleSignUp = () => { setIsLoading(true); - const localUrl = "http://localhost:3000"; + // const localUrl = "http://localhost:3000"; + const localUrl = "https://17ca-14-195-142-82.ngrok-free.app" window.location.href = `https://small-mouse-2759.arnabbhowmik019.workers.dev/google/auth?redirect_url=${encodeURIComponent(localUrl)}/`; }; diff --git a/packages/nextjs/app/page.tsx b/packages/nextjs/app/page.tsx index e9a9139..851006f 100644 --- a/packages/nextjs/app/page.tsx +++ b/packages/nextjs/app/page.tsx @@ -39,6 +39,7 @@ const Home: NextPage = () => { } else { y.set(0); } + setIsDragging(false); }; return ( @@ -60,15 +61,16 @@ const Home: NextPage = () => { {/* Scrollable Container */}
- {/* Main Content */} + {/* Draggable Header Section */} {/* Pull Down Indicator */} { - {/* Content Container */} -
- {/* Logo and Title */} + {/* Logo and Title Section */} + + StakeFit Logo - StakeFit Logo - - -

- - Welcome to StakeFit - - - A Bet on your Fitness - -

+ animate={{ opacity: [0, 1, 0] }} + transition={{ + duration: 2, + repeat: Infinity, + repeatType: "reverse" + }} + className="absolute inset-0 bg-gradient-to-r from-transparent via-[#11ce6f20] to-transparent" + />
+

+ + Welcome to StakeFit + + + A Bet on your Fitness + +

+
+
- {/* Stats Section */} - - - - + {/* Regular Scrollable Content */} +
+ {/* Stats Section */} + + + + - {/* Stake Card Section */} - -
- -
-
+ {/* Stake Card Section */} + +
+ +
+
- {/* Connected Address */} - {connectedAddress && ( - - Connected: -
- - )} - - {/* Additional Content Section */} + {/* Connected Address */} + {connectedAddress && ( - {/* How It Works */} -
-

- How StakeFit Works -

-
-

1. Connect your wallet and stake ETH

-

2. Complete your daily step goals

-

3. Earn rewards for staying active

-
-
+ Connected: +
+ + )} - {/* Tips Section */} -
-

- Fitness Tips -

-
-

• Stay consistent with your daily steps

-

• Set achievable goals

-

• Track your progress regularly

-
+ {/* Additional Content Section */} + + {/* How It Works */} +
+

+ How StakeFit Works +

+
+

1. Connect your wallet and stake ETH

+

2. Complete your daily step goals

+

3. Earn rewards for staying active

- -
-
+
+ + {/* Tips Section */} +
+

+ Fitness Tips +

+
+

• Stay consistent with your daily steps

+

• Set achievable goals

+

• Track your progress regularly

+
+
+ +
{/* ChatSearchBar - Fixed on top */} diff --git a/packages/nextjs/app/providers.tsx b/packages/nextjs/app/providers.tsx new file mode 100644 index 0000000..db5a547 --- /dev/null +++ b/packages/nextjs/app/providers.tsx @@ -0,0 +1,34 @@ +'use client'; + +import React, { useState, useEffect } from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { WagmiProvider } from 'wagmi'; +import { RainbowKitProvider, darkTheme } from '@rainbow-me/rainbowkit'; +import { config } from '~~/utils/rainbowConfig'; + +// Create QueryClient outside of component +const queryClient = new QueryClient(); + +export function RainbowKitProviders({ children }: { children: React.ReactNode }) { + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + return ( + + + + {mounted && children} + + + + ); +} \ No newline at end of file diff --git a/packages/nextjs/components/ChatSearchBar.tsx b/packages/nextjs/components/ChatSearchBar.tsx index aa1417c..384959c 100644 --- a/packages/nextjs/components/ChatSearchBar.tsx +++ b/packages/nextjs/components/ChatSearchBar.tsx @@ -1,14 +1,20 @@ import { FC, useEffect, useState } from "react"; import { AnimatePresence, motion } from "framer-motion"; -import { MagnifyingGlassIcon, PaperAirplaneIcon, TrophyIcon, XMarkIcon, VideoCameraIcon } from "@heroicons/react/24/outline"; +import { + SparklesIcon, + PaperAirplaneIcon, + TrophyIcon, + XMarkIcon, + VideoCameraIcon, + GiftIcon +} from "@heroicons/react/24/outline"; import { useAccount } from "wagmi"; - - interface Message { text: string; isUser: boolean; blockchainInsights?: any; + isNFTMinted?: boolean; } const ChatSearchBar: FC = () => { @@ -17,17 +23,16 @@ const ChatSearchBar: FC = () => { const [messages, setMessages] = useState([]); const [isLoading, setIsLoading] = useState(false); const [showCTA, setShowCTA] = useState(false); + const [showNFTButton, setShowNFTButton] = useState(false); const { address } = useAccount(); - const stepCount = 2000; - useEffect(() => { - // Show CTA after 2 seconds const timer = setTimeout(() => setShowCTA(true), 2000); return () => clearTimeout(timer); }, []); + const dailyChallenges = `Today's Challenges 🏋️‍♂️:\n 1. 10 Push-ups\n 2. 20 Sit-ups\n @@ -47,6 +52,12 @@ Just Upload your video to participate`; }, ]); }; + + const handleViewNFT = () => { + // Replace with your NFT marketplace URL + window.open('https://your-nft-marketplace.com', '_blank'); + }; + const handleSubmit = async (e: React.FormEvent) => { setInputText(""); e.preventDefault(); @@ -56,27 +67,34 @@ Just Upload your video to participate`; setMessages(prev => [...prev, { text: inputText, isUser: true }]); try { - // Update inputText with appended information - setInputText(`${inputText}(my address=${address} my steps=${stepCount} USE ONLY IF RELEVENT)`); + const enhancedInput = `${inputText}(my address=${address} my steps=${stepCount} USE ONLY IF RELEVENT)`; const response = await fetch("http://ai.thearnab.tech:8000/chat", { method: "POST", headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ message: inputText }), + body: JSON.stringify({ message: enhancedInput }), }); if (!response.ok) throw new Error("Network response was not ok"); const data = await response.json(); + const isNFTMinted = data.response.includes("NFT minted successfully"); + setMessages(prev => [ ...prev, { text: data.response, isUser: false, blockchainInsights: data.blockchain_insights, + isNFTMinted }, ]); + + if (isNFTMinted) { + setShowNFTButton(true); + } + } catch (error) { setMessages(prev => [...prev, { text: "Sorry, there was an error processing your request.", isUser: false }]); } finally { @@ -94,8 +112,9 @@ Just Upload your video to participate`; if (file) { const formData = new FormData(); formData.append('file', file); - formData.append('WalletAddress', address); + formData.append('WalletAddress', address || ''); formData.append('description', "Pushups rush!!"); + const imageUrls = [ 'https://walrus-ms.onrender.com/retrieve/PAnhlbndMMhGpbGYbJn24mbllXwYKXNzICe5oWACaYQ', 'https://walrus-ms.onrender.com/retrieve/KQ7VGN23gif1in3I0wVETV6tiqtwBmLF1vla8GNauH8', @@ -114,8 +133,6 @@ Just Upload your video to participate`; if (!response.ok) { throw new Error('File upload failed'); } - - // Handle successful upload console.log('File uploaded successfully'); } catch (error) { console.error('Error uploading file:', error); @@ -127,7 +144,6 @@ Just Upload your video to participate`; return ( <> - {/* Pointing Arrow CTA */} {showCTA && !isChat && ( - {/* Glow effect */}
-
- {/* Close button */} -

Daily Challenge is here! 💪

- {/* Arrow pointing down */}
@@ -177,11 +188,8 @@ Just Upload your video to participate`; )} -
- {/* Header when in chat mode */} + +
{isChat && (

Chat Assistant

@@ -191,15 +199,20 @@ Just Upload your video to participate`;
)} - {/* Chat Messages */}
{messages.map((message, index) => (
-
+
{message.text} + {message.isNFTMinted && ( + + )} {message.blockchainInsights && (

Blockchain Insights:

@@ -211,10 +224,8 @@ Just Upload your video to participate`; ))}
- {/* Input Bar */}
- {/* Daily Challenges Button */}
setInputText(e.target.value)} onFocus={() => setIsChat(true)} @@ -239,11 +249,12 @@ Just Upload your video to participate`; disabled={isLoading} /> {!isChat && ( - + )}
+ {isChat && ( -
+
- ) : ( -
- + {/* Right side - RainbowKit Connect Button */} + + {({ + account, + chain, + openAccountModal, + openChainModal, + openConnectModal, + mounted, + }) => { + const ready = mounted; + const connected = ready && account && chain; - {isWalletMenuOpen && ( -
{/* Full-screen overlay to handle clicks */} -
setIsWalletMenuOpen(false)}>
-
- {/* Network Selection */} -
-
Switch Network
- {networks.map(network => ( + return ( +
+ {(() => { + if (!connected) { + return ( - ))} -
+ ); + } - {/* Wallet Actions */} -
- -
-
+ return ( +
+ + + +
+ ); + })()}
- )} -
- )} + ); + }} +
); }; diff --git a/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx b/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx index 91870b7..23f7a21 100644 --- a/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx +++ b/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx @@ -1,7 +1,6 @@ "use client"; import { useEffect, useState } from "react"; -import { usePathname } from "next/navigation"; import { ApolloClient, ApolloProvider, InMemoryCache } from "@apollo/client"; import { RainbowKitProvider, darkTheme, lightTheme } from "@rainbow-me/rainbowkit"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; @@ -9,13 +8,27 @@ import { AppProgressBar as ProgressBar } from "next-nprogress-bar"; import { useTheme } from "next-themes"; import { Toaster } from "react-hot-toast"; import { WagmiProvider } from "wagmi"; -// import { BottomTabs } from "~~/components/BottomTabs"; import ChatSearchBar from "~~/components/ChatSearchBar"; -// import { Footer } from "~~/components/Footer"; import { NewHeader } from "~~/components/NewHeader"; import { BlockieAvatar } from "~~/components/scaffold-eth"; import { useInitializeNativeCurrencyPrice } from "~~/hooks/scaffold-eth"; -import { wagmiConfig } from "~~/services/web3/wagmiConfig"; +import { config } from "~~/utils/rainbowConfig"; +import { usePathname } from "next/navigation"; + +// Create clients outside component to prevent recreation +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + }, + }, +}); + +const subgraphUri = "http://localhost:8000/subgraphs/name/scaffold-eth/your-contract"; +const apolloClient = new ApolloClient({ + uri: subgraphUri, + cache: new InMemoryCache(), +}); const ScaffoldEthApp = ({ children }: { children: React.ReactNode }) => { useInitializeNativeCurrencyPrice(); @@ -34,20 +47,6 @@ const ScaffoldEthApp = ({ children }: { children: React.ReactNode }) => { ); }; -export const queryClient = new QueryClient({ - defaultOptions: { - queries: { - refetchOnWindowFocus: false, - }, - }, -}); - -const subgraphUri = "http://localhost:8000/subgraphs/name/scaffold-eth/your-contract"; -const apolloClient = new ApolloClient({ - uri: subgraphUri, - cache: new InMemoryCache(), -}); - export const ScaffoldEthAppWithProviders = ({ children }: { children: React.ReactNode }) => { const { resolvedTheme } = useTheme(); const isDarkMode = resolvedTheme === "dark"; @@ -58,7 +57,7 @@ export const ScaffoldEthAppWithProviders = ({ children }: { children: React.Reac }, []); return ( - + ); -}; +}; \ No newline at end of file diff --git a/packages/nextjs/utils/rainbowConfig.ts b/packages/nextjs/utils/rainbowConfig.ts new file mode 100644 index 0000000..58e1cf0 --- /dev/null +++ b/packages/nextjs/utils/rainbowConfig.ts @@ -0,0 +1,24 @@ +import { connectorsForWallets } from '@rainbow-me/rainbowkit'; +import { getDefaultConfig } from '@rainbow-me/rainbowkit'; +import { mainnet, base, baseSepolia, optimism, sepolia } from 'viem/chains'; +import scaffoldConfig from "~~/scaffold.config"; + +const targetNetworks = Object.values(scaffoldConfig.targetNetworks); + +const projectId = "0320c6b4b914f49872b81d4d7af430c1"; + +export const config = getDefaultConfig({ + appName: 'StakeFit', + projectId: '0320c6b4b914f49872b81d4d7af430c1', + chains: [ + mainnet, + base, + baseSepolia, + optimism, + sepolia, + ...targetNetworks, + ], + ssr: true, // Enable server-side rendering + }); + + export { targetNetworks as chains }; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 5659421..ed1fa96 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4296,6 +4296,27 @@ __metadata: languageName: node linkType: hard +"@rainbow-me/rainbowkit@npm:^2.2.1": + version: 2.2.1 + resolution: "@rainbow-me/rainbowkit@npm:2.2.1" + dependencies: + "@vanilla-extract/css": 1.15.5 + "@vanilla-extract/dynamic": 2.1.2 + "@vanilla-extract/sprinkles": 1.6.3 + clsx: 2.1.1 + qrcode: 1.5.4 + react-remove-scroll: 2.6.0 + ua-parser-js: ^1.0.37 + peerDependencies: + "@tanstack/react-query": ">=5.0.0" + react: ">=18" + react-dom: ">=18" + viem: 2.x + wagmi: ^2.9.0 + checksum: 0647344590fe2970b2d0446b08a4b4d29af015992df0e8da47c17388fd7e8d1334d3a7aae4e574306950bb0ce51faef11d8713ed557e04d8bd92627938d91915 + languageName: node + linkType: hard + "@repeaterjs/repeater@npm:^3.0.4, @repeaterjs/repeater@npm:^3.0.6": version: 3.0.6 resolution: "@repeaterjs/repeater@npm:3.0.6" @@ -4873,6 +4894,24 @@ __metadata: languageName: node linkType: hard +"@tanstack/query-core@npm:5.62.3": + version: 5.62.3 + resolution: "@tanstack/query-core@npm:5.62.3" + checksum: 6105d00fb6d6a5ffcec86f7781990d805d9d50092f52ae2fa92a0fdbecd55cac757059a1f38cd107c0abbe9a2bd0ce3b8f2ce354fecb1b73a014dea374990305 + languageName: node + linkType: hard + +"@tanstack/react-query@npm:^5.62.3": + version: 5.62.3 + resolution: "@tanstack/react-query@npm:5.62.3" + dependencies: + "@tanstack/query-core": 5.62.3 + peerDependencies: + react: ^18 || ^19 + checksum: dc7ead76788924193bdd791c3a6fe0b85aff51252a1067b87f6a78ebab08d09476c5941773a970afb3700f79077406ce5de81fb7fb6a1131581afe0d92626601 + languageName: node + linkType: hard + "@tanstack/react-query@npm:~5.59.15": version: 5.59.20 resolution: "@tanstack/react-query@npm:5.59.20" @@ -17541,6 +17580,8 @@ __metadata: "@apollo/experimental-nextjs-app-support": ^0.11.7 "@ethereum-attestation-service/eas-sdk": ^2.7.0 "@graphprotocol/graph-cli": ^0.91.1 + "@rainbow-me/rainbowkit": ^2.2.1 + "@tanstack/react-query": ^5.62.3 "@types/ethereum-blockies": ^0 axios: ^1.7.9 ethereum-blockies: ^0.1.1