diff --git a/src/components/Sponsor/Web3.tsx b/src/components/Sponsor/Web3.tsx
index 6ef6d10c..ce8e1ca5 100644
--- a/src/components/Sponsor/Web3.tsx
+++ b/src/components/Sponsor/Web3.tsx
@@ -2,7 +2,7 @@ import Web3Donation from './Web3Donation'
import config from '@config/blog.config'
import { RainbowKitProvider } from '@rainbow-me/rainbowkit'
import { WagmiConfig } from 'wagmi'
-import { wagmiConfig, chains, theme } from '@lib/rainbowkit'
+import { wagmiConfig, chains, theme } from './Web3Donation/lib/rainbowkit'
import type { ReactElement } from 'react'
export default function Web3(): ReactElement {
diff --git a/src/components/Sponsor/Web3Donation/InputGroup.tsx b/src/components/Sponsor/Web3Donation/InputGroup.tsx
deleted file mode 100644
index ad192a94..00000000
--- a/src/components/Sponsor/Web3Donation/InputGroup.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import { type ReactElement } from 'react'
-import Input from '@components/Input'
-import Conversion from './Conversion'
-import styles from './InputGroup.module.css'
-
-export default function InputGroup({
- amount,
- isDisabled,
- symbol,
- setAmount
-}: {
- amount: string
- isDisabled: boolean
- symbol: string
- setAmount(amount: string): void
-}): ReactElement {
- return (
- <>
-
-
-
setAmount(e.target.value)}
- className={styles.inputInput}
- disabled={isDisabled}
- />
-
- {symbol}
-
-
-
-
-
- >
- )
-}
diff --git a/src/components/Sponsor/Web3Donation/api/getBalance.ts b/src/components/Sponsor/Web3Donation/api/getBalance.ts
new file mode 100644
index 00000000..5e608b97
--- /dev/null
+++ b/src/components/Sponsor/Web3Donation/api/getBalance.ts
@@ -0,0 +1,9 @@
+export async function getBalance(address: `0x${string}` | undefined) {
+ const url = `http://localhost:3000/api/balance?address=${address}`
+ // const url = `https://web3-api-kremalicious.vercel.app/api/balance?address=${address}`
+ const response = await fetch(url)
+ const json = await response.json()
+
+ if (!json) console.error(response.statusText)
+ return json
+}
diff --git a/src/components/Sponsor/Web3Donation/api/getFiat.ts b/src/components/Sponsor/Web3Donation/api/getFiat.ts
new file mode 100644
index 00000000..ff5987f5
--- /dev/null
+++ b/src/components/Sponsor/Web3Donation/api/getFiat.ts
@@ -0,0 +1,18 @@
+export async function getFiat({
+ amount,
+ tokenId = 'ethereum'
+}: {
+ amount: number
+ tokenId?: string
+}): Promise<{ [key: string]: string }> {
+ const url = `https://api.coingecko.com/api/v3/simple/price?ids=${tokenId}&vs_currencies=eur%2Cusd`
+ const response = await fetch(url)
+ const json = await response.json()
+
+ if (!json) console.error(response.statusText)
+ const { usd, eur } = json[tokenId]
+ const dollar = (amount * usd).toFixed(2)
+ const euro = (amount * eur).toFixed(2)
+
+ return { dollar, euro }
+}
diff --git a/src/components/Sponsor/Web3Donation/Alert.module.css b/src/components/Sponsor/Web3Donation/components/Alert/Alert.module.css
similarity index 100%
rename from src/components/Sponsor/Web3Donation/Alert.module.css
rename to src/components/Sponsor/Web3Donation/components/Alert/Alert.module.css
diff --git a/src/components/Sponsor/Web3Donation/Alert.test.tsx b/src/components/Sponsor/Web3Donation/components/Alert/Alert.test.tsx
similarity index 100%
rename from src/components/Sponsor/Web3Donation/Alert.test.tsx
rename to src/components/Sponsor/Web3Donation/components/Alert/Alert.test.tsx
diff --git a/src/components/Sponsor/Web3Donation/Alert.tsx b/src/components/Sponsor/Web3Donation/components/Alert/Alert.tsx
similarity index 100%
rename from src/components/Sponsor/Web3Donation/Alert.tsx
rename to src/components/Sponsor/Web3Donation/components/Alert/Alert.tsx
diff --git a/src/components/Sponsor/Web3Donation/Conversion.module.css b/src/components/Sponsor/Web3Donation/components/Conversion/Conversion.module.css
similarity index 100%
rename from src/components/Sponsor/Web3Donation/Conversion.module.css
rename to src/components/Sponsor/Web3Donation/components/Conversion/Conversion.module.css
diff --git a/src/components/Sponsor/Web3Donation/Conversion.test.tsx b/src/components/Sponsor/Web3Donation/components/Conversion/Conversion.test.tsx
similarity index 84%
rename from src/components/Sponsor/Web3Donation/Conversion.test.tsx
rename to src/components/Sponsor/Web3Donation/components/Conversion/Conversion.test.tsx
index 6f386b8d..3f2710ef 100644
--- a/src/components/Sponsor/Web3Donation/Conversion.test.tsx
+++ b/src/components/Sponsor/Web3Donation/components/Conversion/Conversion.test.tsx
@@ -1,6 +1,6 @@
import { render } from '@testing-library/react'
import { describe, it } from 'vitest'
-import Conversion from './Conversion'
+import { Conversion } from './Conversion'
describe('Conversion', () => {
it('renders without crashing', async () => {
diff --git a/src/components/Sponsor/Web3Donation/Conversion.tsx b/src/components/Sponsor/Web3Donation/components/Conversion/Conversion.tsx
similarity index 62%
rename from src/components/Sponsor/Web3Donation/Conversion.tsx
rename to src/components/Sponsor/Web3Donation/components/Conversion/Conversion.tsx
index bcabaa04..9371c1ea 100644
--- a/src/components/Sponsor/Web3Donation/Conversion.tsx
+++ b/src/components/Sponsor/Web3Donation/components/Conversion/Conversion.tsx
@@ -1,26 +1,8 @@
import { type ReactElement, useEffect, useState } from 'react'
import styles from './Conversion.module.css'
+import { getFiat } from '../../api/getFiat'
-export async function getFiat({
- amount,
- tokenId = 'ethereum'
-}: {
- amount: number
- tokenId?: string
-}): Promise<{ [key: string]: string }> {
- const url = `https://api.coingecko.com/api/v3/simple/price?ids=${tokenId}&vs_currencies=eur%2Cusd`
- const response = await fetch(url)
- const json = await response.json()
-
- if (!json) console.error(response.statusText)
- const { usd, eur } = json[tokenId]
- const dollar = (amount * usd).toFixed(2)
- const euro = (amount * eur).toFixed(2)
-
- return { dollar, euro }
-}
-
-export default function Conversion({
+export function Conversion({
amount,
symbol
}: {
diff --git a/src/components/Sponsor/Web3Donation/components/Conversion/index.tsx b/src/components/Sponsor/Web3Donation/components/Conversion/index.tsx
new file mode 100644
index 00000000..289752d5
--- /dev/null
+++ b/src/components/Sponsor/Web3Donation/components/Conversion/index.tsx
@@ -0,0 +1 @@
+export * from './Conversion'
diff --git a/src/components/Sponsor/Web3Donation/InputGroup.module.css b/src/components/Sponsor/Web3Donation/components/Input/InputGroup.module.css
similarity index 63%
rename from src/components/Sponsor/Web3Donation/InputGroup.module.css
rename to src/components/Sponsor/Web3Donation/components/Input/InputGroup.module.css
index 9e1d324c..5fa03a57 100644
--- a/src/components/Sponsor/Web3Donation/InputGroup.module.css
+++ b/src/components/Sponsor/Web3Donation/components/Input/InputGroup.module.css
@@ -3,48 +3,28 @@
position: relative;
animation: fadeIn 0.8s ease-out backwards;
margin-top: var(--spacer);
+ display: flex;
}
-@media (min-width: 40rem) {
+/* @media (min-width: 40rem) {
.inputGroup {
display: flex;
flex-wrap: wrap;
}
-}
+} */
-.inputGroup button {
- width: 100%;
- border-top-left-radius: 0;
- border-top-right-radius: 0;
- border-color: var(--border-color);
-}
+/* .currency {
+} */
-@media (min-width: 40rem) {
- .inputGroup button {
- width: 40%;
- border-top-right-radius: var(--border-radius);
- border-top-left-radius: 0;
- border-bottom-left-radius: 0;
- border-left: 0;
- }
-}
-
-.input {
- position: relative;
-}
-
-@media (min-width: 40rem) {
- .input {
- width: 60%;
- }
+:global([data-theme='dark']) .currency {
+ border-right-color: #000;
}
.inputInput {
text-align: center;
border: 1px solid var(--border-color);
font-size: var(--font-size-large);
- padding: calc(var(--spacer) / 3) calc(var(--spacer) / 3)
- calc(var(--spacer) / 3) calc(var(--spacer) * 1.7);
+ padding: calc(var(--spacer) / 4);
border-bottom: 0;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
@@ -68,27 +48,25 @@
border-color: var(--border-color);
}
-.currency {
- position: absolute;
- top: 1px;
- bottom: 1px;
- left: 1px;
- font-size: var(--font-size-small);
- padding: calc(var(--spacer) / 3);
- background: var(--box-background-color);
- border-right: 1px solid var(--text-color-dimmed);
- border-top-left-radius: var(--border-radius);
- border-bottom-left-radius: var(--border-radius);
- display: flex;
- align-items: center;
+.submit {
+ width: 100%;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-color: var(--border-color);
}
-:global([data-theme='dark']) .currency {
- border-right-color: #000;
+@media (min-width: 40rem) {
+ .submit {
+ width: fit-content;
+ border-top-right-radius: var(--border-radius);
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ border-left: 0;
+ }
}
.message {
- composes: message from './index.module.css';
+ composes: message from '../../index.module.css';
}
@keyframes fadeIn {
diff --git a/src/components/Sponsor/Web3Donation/InputGroup.test.tsx b/src/components/Sponsor/Web3Donation/components/Input/InputGroup.test.tsx
similarity index 96%
rename from src/components/Sponsor/Web3Donation/InputGroup.test.tsx
rename to src/components/Sponsor/Web3Donation/components/Input/InputGroup.test.tsx
index bf735179..67734af0 100644
--- a/src/components/Sponsor/Web3Donation/InputGroup.test.tsx
+++ b/src/components/Sponsor/Web3Donation/components/Input/InputGroup.test.tsx
@@ -1,6 +1,6 @@
import { fireEvent, render, screen } from '@testing-library/react'
import { describe, it, expect, vi } from 'vitest'
-import InputGroup from './InputGroup'
+import { InputGroup } from '.'
const setAmount = vi.fn()
diff --git a/src/components/Sponsor/Web3Donation/components/Input/InputGroup.tsx b/src/components/Sponsor/Web3Donation/components/Input/InputGroup.tsx
new file mode 100644
index 00000000..0dc0e909
--- /dev/null
+++ b/src/components/Sponsor/Web3Donation/components/Input/InputGroup.tsx
@@ -0,0 +1,43 @@
+import { type ReactElement } from 'react'
+import Input from '@components/Input'
+import { Conversion } from '../Conversion'
+import styles from './InputGroup.module.css'
+import { TokenSelect } from '../Tokens'
+
+export function InputGroup({
+ amount,
+ isDisabled,
+ symbol,
+ setAmount
+}: {
+ amount: string
+ isDisabled: boolean
+ symbol: string
+ setAmount(amount: string): void
+}): ReactElement {
+ return (
+ <>
+
+
+
+
+
setAmount(e.target.value)}
+ className={styles.inputInput}
+ disabled={isDisabled}
+ />
+
+
+
+ >
+ )
+}
diff --git a/src/components/Sponsor/Web3Donation/components/Input/index.tsx b/src/components/Sponsor/Web3Donation/components/Input/index.tsx
new file mode 100644
index 00000000..c5658db9
--- /dev/null
+++ b/src/components/Sponsor/Web3Donation/components/Input/index.tsx
@@ -0,0 +1 @@
+export * from './InputGroup'
diff --git a/src/components/Sponsor/Web3Donation/components/Tokens/Select.css b/src/components/Sponsor/Web3Donation/components/Tokens/Select.css
new file mode 100644
index 00000000..78487447
--- /dev/null
+++ b/src/components/Sponsor/Web3Donation/components/Tokens/Select.css
@@ -0,0 +1,67 @@
+/* reset */
+button {
+ all: unset;
+}
+
+.SelectTrigger {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 70px;
+ height: 100%;
+ font-size: var(--font-size-small);
+ line-height: 1;
+ padding: 0 calc(var(--spacer) / 4);
+ background: var(--box-background-color);
+ border-right: 1px solid var(--text-color-dimmed);
+ border-top-left-radius: var(--border-radius);
+ border-bottom-left-radius: var(--border-radius);
+}
+
+.SelectTrigger:hover {
+ background-color: whitesmoke;
+}
+
+.SelectTrigger:focus {
+ box-shadow: 0 0 0 2px blue;
+}
+
+.SelectTrigger[data-disabled] {
+ opacity: 0.5;
+ pointer-events: none;
+}
+
+.SelectContent {
+ overflow: hidden;
+ background-color: var(--body-background-color);
+ border-radius: var(--border-radius);
+ box-shadow: var(--box-shadow);
+}
+
+.SelectViewport {
+ padding: 0;
+}
+
+.SelectLabel {
+ padding: 0 25px;
+ font-size: var(--font-size-small);
+ color: var(--text-color-light);
+ text-transform: capitalize;
+ border-bottom: 1px solid var(--border-color);
+}
+
+.SelectSeparator {
+ height: 1px;
+ background-color: var(--border-color);
+ margin: 5px;
+}
+
+.SelectScrollButton {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 25px;
+ background-color: var(--body-background-color);
+ color: var(--text-color);
+ cursor: default;
+}
diff --git a/src/components/Sponsor/Web3Donation/components/Tokens/Select.tsx b/src/components/Sponsor/Web3Donation/components/Tokens/Select.tsx
new file mode 100644
index 00000000..27a86b53
--- /dev/null
+++ b/src/components/Sponsor/Web3Donation/components/Tokens/Select.tsx
@@ -0,0 +1,70 @@
+import * as Select from '@radix-ui/react-select'
+import './Select.css'
+import { SelectItem } from './SelectItem'
+import { ChevronDown, ChevronsDown, ChevronsUp } from '@images/components/react'
+import { useEffect, useState } from 'react'
+import { getBalance } from '../../api/getBalance'
+import { useAccount, useNetwork } from 'wagmi'
+
+export function TokenSelect() {
+ const { address } = useAccount()
+ const { chain } = useNetwork()
+
+ const [tokens, setTokens] = useState()
+
+ useEffect(() => {
+ if (!address || !chain) return
+
+ async function getTokens() {
+ try {
+ const response = await getBalance(address)
+ const tokens = response.filter(
+ (token: any) => parseInt(token.chainId) === chain?.id
+ )
+ setTokens(tokens)
+ } catch (error) {
+ console.error((error as Error).message)
+ }
+ }
+ getTokens()
+ }, [address, chain])
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ In Your Wallet
+
+
+ {tokens?.map((token: any) => (
+
+ {token.name}
+
+ ))}
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/components/Sponsor/Web3Donation/components/Tokens/SelectItem.css b/src/components/Sponsor/Web3Donation/components/Tokens/SelectItem.css
new file mode 100644
index 00000000..319cc838
--- /dev/null
+++ b/src/components/Sponsor/Web3Donation/components/Tokens/SelectItem.css
@@ -0,0 +1,52 @@
+.SelectItem {
+ font-size: var(--font-size-small);
+ line-height: 1;
+ color: var(--text-color);
+ display: flex;
+ align-items: center;
+ padding: calc(var(--spacer) / 4) calc(var(--spacer) / 4)
+ calc(var(--spacer) / 4) 25px;
+ position: relative;
+ user-select: none;
+}
+
+.SelectItem[data-disabled] {
+ opacity: 0.5;
+ pointer-events: none;
+}
+
+.SelectItem[data-highlighted] {
+ outline: none;
+ background-color: var(--text-color);
+ color: var(--body-background-color);
+}
+
+.SelectItem,
+.Token {
+ display: flex;
+ align-items: center;
+ position: relative;
+}
+
+.Token {
+ min-width: 200px;
+}
+
+.Token img {
+ width: 32px;
+ height: 32px;
+ margin: 0;
+ margin-right: calc(var(--spacer) / 4);
+ border-radius: 50%;
+ border: 1px solid var(--border-color);
+ background: var(--border-color);
+}
+
+.SelectItemIndicator {
+ position: absolute;
+ left: 0;
+ width: 25px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+}
diff --git a/src/components/Sponsor/Web3Donation/components/Tokens/SelectItem.tsx b/src/components/Sponsor/Web3Donation/components/Tokens/SelectItem.tsx
new file mode 100644
index 00000000..4828e099
--- /dev/null
+++ b/src/components/Sponsor/Web3Donation/components/Tokens/SelectItem.tsx
@@ -0,0 +1,33 @@
+import { forwardRef, type HTMLAttributes } from 'react'
+import * as Select from '@radix-ui/react-select'
+import classnames from 'classnames'
+import './SelectItem.css'
+import { Check } from '@images/components/react'
+
+interface SelectItemProps extends HTMLAttributes {
+ value: string
+ icon: string
+}
+
+export const SelectItem = forwardRef(
+ ({ children, className, value, icon, ...props }, forwardedRef) => {
+ return (
+
+
+
+
+
+
{children}
+
+
+
+
+
+ )
+ }
+)
diff --git a/src/components/Sponsor/Web3Donation/components/Tokens/index.tsx b/src/components/Sponsor/Web3Donation/components/Tokens/index.tsx
new file mode 100644
index 00000000..3e383f07
--- /dev/null
+++ b/src/components/Sponsor/Web3Donation/components/Tokens/index.tsx
@@ -0,0 +1 @@
+export * from './Select'
diff --git a/src/components/Sponsor/Web3Donation/index.tsx b/src/components/Sponsor/Web3Donation/index.tsx
index 01f5a8f0..d3188f46 100644
--- a/src/components/Sponsor/Web3Donation/index.tsx
+++ b/src/components/Sponsor/Web3Donation/index.tsx
@@ -9,8 +9,8 @@ import {
} from 'wagmi'
import { ConnectButton } from '@rainbow-me/rainbowkit'
-import Alert, { getTransactionMessage } from './Alert'
-import InputGroup from './InputGroup'
+import Alert, { getTransactionMessage } from './components/Alert/Alert'
+import { InputGroup } from './components/Input'
import styles from './index.module.css'
export default function Web3Donation({
diff --git a/src/lib/rainbowkit.ts b/src/components/Sponsor/Web3Donation/lib/rainbowkit.ts
similarity index 96%
rename from src/lib/rainbowkit.ts
rename to src/components/Sponsor/Web3Donation/lib/rainbowkit.ts
index 3eb488de..9a4b2be1 100644
--- a/src/lib/rainbowkit.ts
+++ b/src/components/Sponsor/Web3Donation/lib/rainbowkit.ts
@@ -1,6 +1,6 @@
import { type Theme, getDefaultWallets } from '@rainbow-me/rainbowkit'
import { configureChains, createConfig } from 'wagmi'
-import { mainnet, polygon } from 'wagmi/chains'
+import { mainnet, polygon, base, bsc } from 'wagmi/chains'
import { infuraProvider } from 'wagmi/providers/infura'
import { publicProvider } from 'wagmi/providers/public'
@@ -13,7 +13,7 @@ if (isProduction && (!PUBLIC_INFURA_ID || !PUBLIC_WALLETCONNECT_ID)) {
}
export const { chains, publicClient } = configureChains(
- [mainnet, polygon],
+ [mainnet, polygon, base, bsc],
[infuraProvider({ apiKey: PUBLIC_INFURA_ID }), publicProvider()]
)
diff --git a/src/pages/thanks.astro b/src/pages/thanks.astro
index 44322a0b..3bad5f00 100644
--- a/src/pages/thanks.astro
+++ b/src/pages/thanks.astro
@@ -33,7 +33,7 @@ const coins = Object.entries(config.author).filter(
}
-
+