Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions apps/demo-liquidity-widget/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"root": true,
"env": {
"browser": true,
"es2020": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
"prettier"
],
"ignorePatterns": [
"dist",
".eslintrc.json"
],
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint",
"react-hooks"
],
"rules": {}
}
4 changes: 4 additions & 0 deletions apps/demo-liquidity-widget/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.vercel
.certs
.yalc
yalc.lock
45 changes: 45 additions & 0 deletions apps/demo-liquidity-widget/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
## Getting Started

This demo shows how to integrate the `@goodsdks/liquidity-widget` web component
into a React app using [Reown AppKit](https://reown.com/) + [wagmi](https://wagmi.sh).

1. **Clone the Repository**

```bash
git clone https://github.com/GoodDollar/GoodSdks
```

2. **Install & Build**

From the monorepo root:

```bash
yarn install --immutable && yarn build
```

3. **Start the Development Server**

```bash
cd apps/demo-liquidity-widget
yarn dev
```

4. **Open the App**

Visit `http://localhost:3000`.

## Usage

The liquidity widget is a Lit-based web component registered as
`<gooddollar-liquidity-widget>`. See
[packages/liquidity-widget/REACT_DOCUMENT.md](../../packages/liquidity-widget/REACT_DOCUMENT.md)
for the full React integration guide.

This demo uses:

- `src/config.tsx` — Reown AppKit + wagmi setup (Celo only; the pool is on Celo).
- `src/components/LiquidityWidget.tsx` — Thin React wrapper around the web
component that sets the `web3Provider` and `connectWallet` JS properties via
`ref` (non-serializable props can't go through JSX attributes in React <19).
- `src/App.tsx` — Page layout + wagmi plumbing to pull the EIP-1193 provider
off the active connector and pass it to the widget.
13 changes: 13 additions & 0 deletions apps/demo-liquidity-widget/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>GoodDollar Liquidity Widget Demo</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
44 changes: 44 additions & 0 deletions apps/demo-liquidity-widget/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "demo-liquidity-widget",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "vite --port 3000",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint . --ext .ts,.tsx",
"format": "prettier --write ."
},
"dependencies": {
"@goodsdks/liquidity-widget": "*",
"@reown/appkit": "^1.7.2",
"@reown/appkit-adapter-wagmi": "^1.7.2",
"@reown/appkit-wallet": "^1.7.2",
"@tamagui/config": "^1.125.22",
"@tamagui/core": "^1.125.22",
"@tamagui/font-inter": "^1.125.22",
"@tamagui/vite-plugin": "^1.125.22",
"@tamagui/web": "^1.125.22",
"@tanstack/react-query": "^4.36.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"tamagui": "^1.125.22",
"viem": "^1.21.4",
"wagmi": "^1.4.13"
},
"devDependencies": {
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"@vitejs/plugin-react": "^4.3.4",
"cross-env": "^7.0.3",
"eslint": "^8.57.1",
"eslint-config-prettier": "^8.10.0",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^5.2.0",
"prettier": "^3.5.3",
"typescript": "^5.8.2",
"vite": "6.3.5"
}
}
1 change: 1 addition & 0 deletions apps/demo-liquidity-widget/public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
175 changes: 175 additions & 0 deletions apps/demo-liquidity-widget/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import React, { useEffect, useState } from "react"
import {
createTamagui,
TamaguiProvider,
View,
Text,
ScrollView,
YStack,
Anchor,
Stack,
} from "tamagui"
import { config } from "@tamagui/config/v3"
import { useAppKit } from "@reown/appkit/react"
import { celo } from "wagmi/chains"
import { useAccount, useChainId, useSwitchChain } from "wagmi"

import { LiquidityWidget } from "./components/LiquidityWidget"

const tamaguiConfig = createTamagui(config)

const App: React.FC = () => {
const { open } = useAppKit()
const { address, isConnected, connector } = useAccount()
const chainId = useChainId()
const { switchChain } = useSwitchChain()

const [provider, setProvider] = useState<unknown | null>(null)

// Pull the EIP-1193 provider off the active connector.
useEffect(() => {
let cancelled = false
;(async () => {
if (!isConnected || !connector) {
setProvider(null)
return
}
const p = await connector.getProvider()
if (!cancelled) setProvider(p)
})()
return () => {
cancelled = true
}
}, [isConnected, connector, address])

// The G$/USDGLO pool is on Celo, so keep the user there.
useEffect(() => {
if (isConnected && chainId !== celo.id) {
switchChain({ chainId: celo.id })
}
}, [isConnected, chainId, switchChain])

return (
<TamaguiProvider config={tamaguiConfig}>
<ScrollView
flex={1}
padding={24}
backgroundColor="#F7FAFC"
alignItems="center"
>
<YStack maxWidth={600} width="100%" alignItems="center">
<Text
fontSize={26}
fontWeight="bold"
color="$text"
textAlign="center"
>
GoodDollar Liquidity Widget
</Text>

{/* Disclaimer Section */}
<YStack
padding="$3"
backgroundColor="#FFF8E1"
borderRadius="$4"
borderWidth={1}
borderColor="#FFD700"
marginVertical={16}
>
<Text fontSize={14} color="#664D03" textAlign="center">
<Text fontWeight="bold">Disclaimer: </Text>
This is a demo showing how to embed the{" "}
<Text fontFamily="$mono">{`<gooddollar-liquidity-widget>`}</Text>{" "}
web component in a React app. It provides liquidity to the
G$/USDGLO pool on Celo.{" "}
<Anchor
href="https://github.com/GoodDollar/GoodSdks"
color="#005AFF"
target="_blank"
>
Learn more about the SDK and how to integrate it here.
</Anchor>
</Text>
</YStack>

{/* Connect Section */}
<View
padding="$3"
backgroundColor="white"
borderRadius="$4"
borderWidth={1}
borderColor="#E2E8F0"
width="100%"
alignItems="center"
justifyContent="center"
marginBottom={16}
>
<Stack
justifyContent="center"
alignItems="center"
marginBottom={!isConnected ? 12 : 0}
>
{!isConnected ? (
<Text fontSize={16} color="$red10" marginBottom={12}>
Connect your wallet to add liquidity.
</Text>
) : null}
<appkit-button></appkit-button>
</Stack>
</View>

{/* Liquidity Widget */}
<View width="100%" alignItems="center">
<LiquidityWidget
web3Provider={provider}
connectWallet={() => open()}
defaultRange="full"
showPositions
onTxSubmitted={({ hash, step }) =>
console.log("[lw] submitted", step, hash)
}
onTxConfirmed={({ hash, step }) =>
console.log("[lw] confirmed", step, hash)
}
onTxFailed={({ hash, step, error }) =>
console.warn("[lw] failed", step, hash, error)
}
onPositionAdded={({ hash }) =>
console.log("[lw] position minted", hash)
}
theme={{ primaryColor: "#00BB7F", borderRadius: "16px" }}
/>
</View>

{/* Help Section */}
<YStack justifyContent="center" alignItems="center" marginTop={24}>
<Text fontSize={14} color="$gray10">
Need help? Visit our docs:{" "}
<Anchor
href="https://docs.gooddollar.org"
target="_blank"
color="#005AFF"
>
GoodDollar Docs
</Anchor>
.
</Text>
<Text fontSize={14} color="$gray10">
Or join our Developer Communities at:{" "}
<Anchor
href="https://ubi.gd/GoodBuildersDiscord"
target="_blank"
color="#005AFF"
>
GoodBuilders Discord
</Anchor>
.
</Text>
</YStack>
</YStack>
</ScrollView>
</TamaguiProvider>
)
}

export default App
71 changes: 71 additions & 0 deletions apps/demo-liquidity-widget/src/components/LiquidityWidget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import "@goodsdks/liquidity-widget"
import React, { useEffect, useRef } from "react"
import type { GooddollarLiquidityWidget } from "@goodsdks/liquidity-widget"

type WidgetTheme = {
primaryColor?: string
borderRadius?: string
fontFamily?: string
}

export type LiquidityWidgetProps = {
web3Provider: unknown | null
connectWallet?: () => void
explorerBaseUrl?: string
approvalBuffer?: number
defaultRange?: "full" | "wide" | "narrow"
showPositions?: boolean
refreshInterval?: number
theme?: WidgetTheme
onTxSubmitted?: (detail: { hash: string; step: string }) => void
onTxConfirmed?: (detail: { hash: string; step: string }) => void
onTxFailed?: (detail: { hash: string; step: string; error: string }) => void
onPositionAdded?: (detail: { hash: string }) => void
}

export const LiquidityWidget: React.FC<LiquidityWidgetProps> = (props) => {
const ref = useRef<GooddollarLiquidityWidget | null>(null)

useEffect(() => {
const el = ref.current
if (!el) return
el.web3Provider = props.web3Provider ?? null
el.connectWallet = props.connectWallet
el.theme = props.theme
}, [props.web3Provider, props.connectWallet, props.theme])

useEffect(() => {
const el = ref.current
if (!el) return
const s = (e: Event) => props.onTxSubmitted?.((e as CustomEvent).detail)
const c = (e: Event) => props.onTxConfirmed?.((e as CustomEvent).detail)
const f = (e: Event) => props.onTxFailed?.((e as CustomEvent).detail)
const p = (e: Event) => props.onPositionAdded?.((e as CustomEvent).detail)
el.addEventListener("lw-tx-submitted", s)
el.addEventListener("lw-tx-confirmed", c)
el.addEventListener("lw-tx-failed", f)
el.addEventListener("lw-position-added", p)
return () => {
el.removeEventListener("lw-tx-submitted", s)
el.removeEventListener("lw-tx-confirmed", c)
el.removeEventListener("lw-tx-failed", f)
el.removeEventListener("lw-position-added", p)
}
}, [
props.onTxSubmitted,
props.onTxConfirmed,
props.onTxFailed,
props.onPositionAdded,
])

return (
<gooddollar-liquidity-widget
ref={ref}
explorer-base-url={props.explorerBaseUrl}
approval-buffer={props.approvalBuffer}
default-range={props.defaultRange}
show-positions={props.showPositions ? "" : undefined}
refresh-interval={props.refreshInterval}
/>
)
}
Loading