Skip to content

Commit

Permalink
feat: show chain select in companion app (#501)
Browse files Browse the repository at this point in the history
* pull in chain select and add failing test

* update ser-kit

* shim process.env

* make chainSelect semi-controllable

* adjust spec
  • Loading branch information
frontendphil authored Jan 9, 2025
1 parent 0d80572 commit 4d1e29a
Show file tree
Hide file tree
Showing 15 changed files with 135 additions and 47 deletions.
40 changes: 40 additions & 0 deletions deployables/app/app/components/ChainSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { invariant } from '@epic-web/invariant'
import { CHAIN_NAME } from '@zodiac/chains'
import { Select } from '@zodiac/ui'
import type { ChainId } from 'ser-kit'

export interface Props {
value: ChainId | null | undefined
onChange(chainId: ChainId): void
}

interface Option {
value: ChainId
label: string
}

const options = Object.entries(CHAIN_NAME).map(([chainId, name]) => ({
value: parseInt(chainId) as ChainId,
label: name,
}))

export const ChainSelect = ({ value, onChange }: Props) => (
<Select
label="Chain"
isMulti={false}
options={options}
defaultValue={options.find((op) => op.value === value)}
onChange={(option) => {
invariant(option != null, 'Empty value selected as chain')

onChange(option.value)
}}
formatOptionLabel={ChainOptionLabel as any}
/>
)

const ChainOptionLabel = ({ value, label }: Option) => (
<div className="flex items-center gap-4 py-2">
<div className="pl-1">{label || `#${value}`}</div>
</div>
)
1 change: 1 addition & 0 deletions deployables/app/app/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ChainSelect } from './ChainSelect'
48 changes: 38 additions & 10 deletions deployables/app/app/routes/edit-route.spec.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,49 @@
import { render } from '@/test-utils'
import { screen } from '@testing-library/react'
import { createMockExecutionRoute } from '@zodiac/test-utils'
import { CHAIN_NAME } from '@zodiac/chains'
import {
createMockExecutionRoute,
randomPrefixedAddress,
} from '@zodiac/test-utils'
import type { ChainId } from 'ser-kit'
import { describe, expect, it } from 'vitest'
import EditRoute, { loader } from './edit-route'

describe('Edit route', () => {
it('shows the name of a route', async () => {
const route = createMockExecutionRoute({ label: 'Test route' })
describe('Label', () => {
it('shows the name of a route', async () => {
const route = createMockExecutionRoute({ label: 'Test route' })

await render<typeof import('./edit-route')>(
'/edit-route',
{ path: '/edit-route', Component: EditRoute, loader },
{ searchParams: { route: btoa(JSON.stringify(route)) } },
)
await render<typeof import('./edit-route')>(
'/edit-route',
{ path: '/edit-route', Component: EditRoute, loader },
{ searchParams: { route: btoa(JSON.stringify(route)) } },
)

expect(screen.getByRole('textbox', { name: 'Label' })).toHaveValue(
'Test route',
)
})
})

describe('Chain', () => {
it.each(Object.entries(CHAIN_NAME))(
'shows chainId "%s" as "%s"',
async (chainId, name) => {
const route = createMockExecutionRoute({
avatar: randomPrefixedAddress({
chainId: parseInt(chainId) as ChainId,
}),
})

await render<typeof import('./edit-route')>(
'/edit-route',
{ path: '/edit-route', Component: EditRoute, loader },
{ searchParams: { route: btoa(JSON.stringify(route)) } },
)

expect(screen.getByRole('textbox', { name: 'Label' })).toHaveValue(
'Test route',
expect(screen.getByText(name)).toBeInTheDocument()
},
)
})
})
12 changes: 10 additions & 2 deletions deployables/app/app/routes/edit-route.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
import { ChainSelect } from '@/components'
import { invariantResponse } from '@epic-web/invariant'
import { executionRouteSchema } from '@zodiac/schema'
import { TextInput } from '@zodiac/ui'
import { splitPrefixedAddress } from 'ser-kit'
import type { Route } from './+types/edit-route'

export const loader = ({ request }: Route.LoaderArgs) => {
const url = new URL(request.url)

const routeData = url.searchParams.get('route')

console.log({ routeData })

invariantResponse(routeData != null, 'Missing "route" parameter')

const decodedData = Buffer.from(routeData, 'base64')

try {
const rawJson = JSON.parse(decodedData.toString())
const route = executionRouteSchema.parse(rawJson)

const [chainId] = splitPrefixedAddress(route.avatar)

return { route: executionRouteSchema.parse(rawJson) }
return { label: route.label, chainId }
} catch {
throw new Response(null, { status: 400 })
}
Expand All @@ -24,7 +31,8 @@ export const loader = ({ request }: Route.LoaderArgs) => {
const EditRoute = ({ loaderData }: Route.ComponentProps) => {
return (
<>
<TextInput label="Label" defaultValue={loaderData.route.label} />
<TextInput label="Label" defaultValue={loaderData.label} />
<ChainSelect value={loaderData.chainId} onChange={() => {}} />
</>
)
}
Expand Down
2 changes: 2 additions & 0 deletions deployables/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
"@epic-web/invariant": "^1.0.0",
"@react-router/node": "^7.1.1",
"@react-router/serve": "^7.1.1",
"@zodiac/chains": "workspace:*",
"@zodiac/schema": "workspace:*",
"@zodiac/ui": "workspace:*",
"isbot": "^5.1.17",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-router": "^7.1.1",
"ser-kit": "1.1.0",
"zod": "^3.23.8"
},
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions deployables/app/tsconfig.cloudflare.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
"baseUrl": ".",
"rootDirs": [".", "./.react-router/types"],
"paths": {
"~/*": ["./app/*"],
"@/test-utils": ["./test-utils/index.ts"]
"@/test-utils": ["./test-utils/index.ts"],
"@/components": ["./app/components/index.ts"]
},
"esModuleInterop": true,
"resolveJsonModule": true
Expand Down
3 changes: 2 additions & 1 deletion deployables/app/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
],
"compilerOptions": {
"paths": {
"@/test-utils": ["./test-utils/index.ts"]
"@/test-utils": ["./test-utils/index.ts"],
"@/components": ["./app/components/index.ts"]
}
}
}
16 changes: 4 additions & 12 deletions deployables/app/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export default defineConfig(({ isSsrBuild }) => ({
plugins: [tailwindcss, autoprefixer],
},
},
define: {
'process.env': {},
},
ssr: {
target: 'webworker',
// noExternal: true,
Expand All @@ -35,16 +38,5 @@ export default defineConfig(({ isSsrBuild }) => ({
],
},
},
plugins: [
cloudflareDevProxy(),
// vitePluginViteNodeMiniflare({
// entry: './workers/app.ts',
// miniflareOptions: (options) => {
// options.compatibilityDate = '2024-11-18'
// options.compatibilityFlags = ['nodejs_compat']
// },
// }),
reactRouter(),
tsconfigPaths(),
],
plugins: [cloudflareDevProxy(), reactRouter(), tsconfigPaths()],
}))
9 changes: 9 additions & 0 deletions deployables/app/vitest.setup.ts
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
import '@testing-library/jest-dom/vitest'
import { cleanup } from '@testing-library/react'
import { sleepTillIdle } from '@zodiac/test-utils'
import { afterEach } from 'vitest'

afterEach(async () => {
await sleepTillIdle()

cleanup()
})
2 changes: 1 addition & 1 deletion deployables/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"react-dom": "^19.0.0",
"react-select": "5.9.0",
"rimraf": "6.0.1",
"ser-kit": "1.0.7",
"ser-kit": "1.1.0",
"tailwindcss": "^3.4.14",
"typescript": "^5.5.4",
"vitest": "2.1.8",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const ChainSelect = ({ value, onChange }: Props) => (

onChange(option.value)
}}
formatOptionLabel={ChainOptionLabel as any}
formatOptionLabel={ChainOptionLabel}
/>
)

Expand Down
4 changes: 2 additions & 2 deletions packages/chains/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
"@zodiac/schema": "workspace:*"
},
"peerDependencies": {
"ser-kit": "1.0.7"
"ser-kit": "1.1.0"
},
"devDependencies": {
"@zodiac/eslint-config": "workspace:*",
"@zodiac/typescript-config": "workspace:*",
"eslint": "^9.7.0",
"ser-kit": "1.0.7"
"ser-kit": "1.1.0"
}
}
2 changes: 1 addition & 1 deletion packages/schema/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
}
},
"dependencies": {
"ser-kit": "1.0.7",
"ser-kit": "1.1.0",
"zod": "^3.23.8"
},
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions packages/test-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"peerDependencies": {
"react": "19.0.0",
"react-router": "7.1.1",
"ser-kit": "1.0.7"
"ser-kit": "1.1.0"
},
"devDependencies": {
"@types/node": "^22.10.5",
Expand All @@ -35,6 +35,6 @@
"@zodiac/eslint-config": "workspace:*",
"@zodiac/typescript-config": "workspace:*",
"eslint": "^9.7.0",
"ser-kit": "1.0.7"
"ser-kit": "1.1.0"
}
}
33 changes: 20 additions & 13 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 4d1e29a

Please sign in to comment.