Skip to content

Commit

Permalink
Connect to Avventura API (#2)
Browse files Browse the repository at this point in the history
* set branding

* comment w3m

* adapt link

* rm contract

* fix button

* add API calls

* fix urls
  • Loading branch information
julienbrg authored Aug 1, 2024
1 parent b373643 commit e685ee2
Show file tree
Hide file tree
Showing 14 changed files with 323 additions and 150 deletions.
26 changes: 3 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
# Genji
# Avventura UI

A Next.js Web3 app template.
UI of Avventura.

## Features

- [Next.js](https://nextjs.org/)
- [Web3 Modal](https://web3modal.com/)
- [Ethers.js](https://ethers.org/) (v6)
- [Chakra UI](https://chakra-ui.com/)

View the [Solidity contract](https://github.com/w3hc/w3hc-hardhat-template/blob/main/contracts/Basic.sol) used in the example.

Web app live at [https://genji-app.netlify.app](https://genji-app.netlify.app).
API: https://github.com/strat-web3/avventura

## Install

Expand All @@ -33,13 +24,6 @@ Add your own keys in the `.env` file (you can get it in your [Wallet Connect das
pnpm dev
```

## Requirements

Here are the known minimal mobile hardware requirements:

- iOS: Safari 10+ (iOS 10+)
- Android: Chrome 51+ (Android 5.0+)

## Versions

- pnpm `v8.7.5`
Expand All @@ -48,7 +32,3 @@ Here are the known minimal mobile hardware requirements:
## Support

You can contact me via [Element](https://matrix.to/#/@julienbrg:matrix.org), [Farcaster](https://warpcast.com/julien-), [Telegram](https://t.me/julienbrg), [Twitter](https://twitter.com/julienbrg), [Discord](https://discordapp.com/users/julienbrg), or [LinkedIn](https://www.linkedin.com/in/julienberanger/).

## Credits

Special thanks to Wesley ([@wslyvh](https://github.com/wslyvh)) for building [Nexth](https://github.com/wslyvh/nexth). I also want to thank the [Wallet Connect](https://walletconnect.com/) team, [@glitch-txs](https://github.com/glitch-txs) in particular. And of course [@ricmoo](https://github.com/ricmoo) for maintaining [Ethers.js](https://ethers.org/)!
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "genji",
"description": "A Next.js Web3 app template",
"name": "avventura-ui",
"description": "Avventura UI",
"version": "0.1.0",
"scripts": {
"dev": "next dev",
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/Head.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function Head({ title, description }: Props) {
<meta property="og:url" content={origin} />
<meta name="twitter:card" content={img} />
<meta name="twitter:site" content="@W3HC8" />
<meta name="twitter:title" content="Genji" />
<meta name="twitter:title" content="Avventura" />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={img} />
</NextHead>
Expand Down
8 changes: 4 additions & 4 deletions src/components/layout/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ export function Header(props: Props) {
<Spacer />

<Flex alignItems="center" gap={4}>
<w3m-button />
{/* <w3m-button /> */}
<Flex alignItems="center">
<ThemeSwitcher />
<Box mt={2} ml={4}>
<Link href="https://github.com/w3hc/genji" isExternal>
{/* <Box mt={2} ml={4}>
<Link href="https://github.com/w3hc/avventura-ui" isExternal>
<Icon as={FaGithub} boxSize={5} _hover={{ color: 'blue.500' }} />
</Link>
</Box>
</Box> */}
</Flex>
</Flex>
</Flex>
Expand Down
20 changes: 18 additions & 2 deletions src/components/layout/LinkComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// In src/components/layout/LinkComponent.tsx

import React, { ReactNode } from 'react'
import NextLink from 'next/link'
import { Link, useColorModeValue } from '@chakra-ui/react'
Expand All @@ -8,6 +10,7 @@ interface Props {
children: ReactNode
isExternal?: boolean
className?: string
onClick?: () => void // Add this line
}

export function LinkComponent(props: Props) {
Expand All @@ -17,14 +20,27 @@ export function LinkComponent(props: Props) {

if (isExternal) {
return (
<Link className={className} _hover={{ color: '#8c1c84' }} href={props.href} target="_blank" rel="noopener noreferrer">
<Link
className={className}
_hover={{ color: '#8c1c84' }}
href={props.href}
target="_blank"
rel="noopener noreferrer"
onClick={props.onClick} // Add this line
>
{props.children}
</Link>
)
}

return (
<Link as={NextLink} className={className} _hover={{ color: color }} href={props.href}>
<Link
as={NextLink}
className={className}
_hover={{ color: color }}
href={props.href}
onClick={props.onClick} // Add this line
>
{props.children}
</Link>
)
Expand Down
6 changes: 3 additions & 3 deletions src/context/web3modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ const sepolia = {
}

const metadata = {
name: 'Genji',
description: 'Next.js + Web3 Modal + Ethers.js + Chakra UI',
url: 'https://genji.netlify.app',
name: 'Avventura',
description: 'Avvetura UI',
url: 'https://avventura.netlify.app',
icons: ['./favicon.ico'],
}

Expand Down
5 changes: 0 additions & 5 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import type { AppProps } from 'next/app'
import Layout from '../components/layout'
import { useEffect } from 'react'
import { ChakraProvider } from '@chakra-ui/react'
import { Seo } from '../components/layout/Seo'
import { ERC20_CONTRACT_ADDRESS } from '../utils/erc20'
import { useIsMounted } from '../hooks/useIsMounted'
import ErrorBoundary from '../components/layout/ErrorBoundary'

export default function App({ Component, pageProps }: AppProps) {
useEffect(() => {
console.log('contract address:', ERC20_CONTRACT_ADDRESS)
}, [])
const isMounted = useIsMounted()

return (
Expand Down
28 changes: 28 additions & 0 deletions src/pages/api/fetchCard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { NextApiRequest, NextApiResponse } from 'next'

type StoryCard = {
step: number
desc: string
options: string[]
paths: number[]
}

export default async function handler(req: NextApiRequest, res: NextApiResponse<StoryCard | { error: string }>) {
const { id } = req.query

if (!id || Array.isArray(id)) {
return res.status(400).json({ error: 'Invalid id parameter' })
}

try {
const response = await fetch(`https://avventura.jcloud-ver-jpe.ik-server.com/steps/${id}`)
if (!response.ok) {
throw new Error('Failed to fetch story card')
}
const data: StoryCard = await response.json()
res.status(200).json(data)
} catch (error) {
console.error('Error fetching story card:', error)
res.status(500).json({ error: 'Failed to fetch story card' })
}
}
26 changes: 26 additions & 0 deletions src/pages/api/getCurrentStep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { NextApiRequest, NextApiResponse } from 'next'

type CurrentStepResponse = {
currentStep: number
error?: string
}

export default async function handler(req: NextApiRequest, res: NextApiResponse<CurrentStepResponse>) {
if (req.method !== 'GET') {
return res.status(405).json({ currentStep: 0, error: 'Method not allowed' })
}

try {
// Call your Nest.js API to get the current game state
const response = await fetch('https://avventura.jcloud-ver-jpe.ik-server.com/games/1')
if (!response.ok) {
throw new Error('Failed to fetch game state')
}

const gameData = await response.json()
res.status(200).json({ currentStep: gameData.currentStep })
} catch (error) {
console.error('Error fetching current step:', error)
res.status(500).json({ currentStep: 0, error: 'Failed to fetch current step' })
}
}
38 changes: 38 additions & 0 deletions src/pages/api/updateGameStep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { NextApiRequest, NextApiResponse } from 'next'

type UpdateResponse = {
success: boolean
error?: string
}

export default async function handler(req: NextApiRequest, res: NextApiResponse<UpdateResponse>) {
if (req.method !== 'POST') {
return res.status(405).json({ success: false, error: 'Method not allowed' })
}

const { nextStep } = req.body

if (!nextStep || typeof nextStep !== 'number') {
return res.status(400).json({ success: false, error: 'Invalid nextStep' })
}

console.log('next step:', nextStep)
try {
const response = await fetch('https://avventura.jcloud-ver-jpe.ik-server.com/games/1/next-step', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ nextStep }),
})

if (!response.ok) {
throw new Error('Failed to update game state from API route')
}

res.status(200).json({ success: true })
} catch (error) {
console.error('Error updating game state:', error)
res.status(500).json({ success: false, error: 'Failed to update game state' })
}
}
113 changes: 6 additions & 107 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { HeadingComponent } from '../components/layout/HeadingComponent'
import { ethers } from 'ethers'
import { Head } from '../components/layout/Head'
import { SITE_NAME, SITE_DESCRIPTION } from '../utils/config'
import { ArrowForwardIcon } from '@chakra-ui/icons'

export default function Home() {
const [isLoading, setIsLoading] = useState<boolean>(false)
Expand All @@ -20,117 +21,15 @@ export default function Home() {
const provider: Eip1193Provider | undefined = walletProvider
const toast = useToast()

const getBal = async () => {
if (isConnected) {
const ethersProvider = new BrowserProvider(provider as any)
const signer = await ethersProvider.getSigner()
const balance = await ethersProvider.getBalance(address as any)
const ethBalance = ethers.formatEther(balance)
if (ethBalance !== '0') {
return Number(ethBalance)
} else {
return 0
}
} else {
return 0
}
}

const faucetTx = async () => {
const customProvider = new ethers.JsonRpcProvider(process.env.NEXT_PUBLIC_RPC_ENDPOINT_URL)
const pKey = process.env.NEXT_PUBLIC_SIGNER_PRIVATE_KEY || ''
const specialSigner = new ethers.Wallet(pKey, customProvider)
const tx = await specialSigner.sendTransaction({
to: address,
value: parseEther('0.0007'),
})
const receipt = await tx.wait(1)
return receipt
}

const doSomething = async () => {
try {
if (!isConnected) {
toast({
title: 'Not connected yet',
description: 'Please connect your wallet, my friend.',
status: 'error',
position: 'bottom',
variant: 'subtle',
duration: 9000,
isClosable: true,
})
return
}
let signer
if (provider) {
setIsLoading(true)
setTxHash('')
setTxLink('')
const ethersProvider = new BrowserProvider(provider)
signer = await ethersProvider.getSigner()

///// Send ETH if needed /////
const bal = await getBal()
console.log('bal:', bal)
if (bal < 0.0007) {
const faucet = await faucetTx()
console.log('faucet tx', faucet)
}

///// Call /////
const erc20 = new Contract(ERC20_CONTRACT_ADDRESS, ERC20_CONTRACT_ABI, signer)
const call = await erc20.mint(parseEther('10000'))
const receipt = await call.wait()

console.log('tx:', receipt)
setTxHash(receipt.hash)
setTxLink('https://sepolia.etherscan.io/tx/' + receipt.hash)
setIsLoading(false)
toast({
title: 'Successful tx',
description: 'Well done! 🎉',
status: 'success',
position: 'bottom',
variant: 'subtle',
duration: 20000,
isClosable: true,
})
}
} catch (e) {
setIsLoading(false)
console.log('error:', e)
toast({
title: 'Woops',
description: 'Something went wrong...',
status: 'error',
position: 'bottom',
variant: 'subtle',
duration: 9000,
isClosable: true,
})
}
}

return (
<>
<Head title={SITE_NAME} description={SITE_DESCRIPTION} />
<main>
<Button
colorScheme="blue"
variant="outline"
type="submit"
onClick={doSomething}
isLoading={isLoading}
loadingText="Minting..."
spinnerPlacement="end">
Mint
</Button>
{txHash && (
<Text py={4} fontSize="14px" color="#45a2f8">
<LinkComponent href={txLink ? txLink : ''}>{txHash}</LinkComponent>
</Text>
)}
<LinkComponent href="/play/1">
<Button mt={4} colorScheme="green" variant="outline" rightIcon={<ArrowForwardIcon />}>
Play
</Button>
</LinkComponent>
</main>
</>
)
Expand Down
Loading

0 comments on commit e685ee2

Please sign in to comment.