Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Updates wagmi/viem and related ecosystem #11

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
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
21 changes: 10 additions & 11 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
/** @type {import('eslint').Linter.Config} */
module.exports = {
extends: ['@remix-run/eslint-config', '@remix-run/eslint-config/node'],
rules: {
// Defensive programming - Ensure that objects dont result in false positives when used in conditionals
'@typescript-eslint/strict-boolean-expressions': [
'error',
{
allowNullableBoolean: true,
allowNullableString: true,
allowNullableNumber: true,
},
],
root: true,
plugins: ['@typescript-eslint'], // Use the TypeScript plugin
parser: '@typescript-eslint/parser', // Use the TypeScript parser for ESLint,
parserOptions: {
project: './tsconfig.json', // Set the TS-config file
},
extends: [
'@remix-run/eslint-config',
'@remix-run/eslint-config/node',
// 'plugin:@typescript-eslint/recommended', // Use TypeScript recommended rules
],
}
28 changes: 28 additions & 0 deletions app/.server/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* This is used in both `entry.server.ts` and `root.tsx` to ensure that
* the environment variables are set and globally available before the app is
* started.
*
* NOTE: Do *not* add any environment variables in here that you do not wish to
* be included in the client.
* @returns all public ENV variables
*/
export function getEnv() {
return {
MODE: process.env.NODE_ENV,
WALLETCONNECT_PROJECT_ID: process.env.WALLETCONNECT_PROJECT_ID,
ALCHEMY_MAINNET_RPC_URL: process.env.ALCHEMY_MAINNET_RPC_URL,
ALCHEMY_BASE_SEPOLIA_RPC_URL: process.env.ALCHEMY_BASE_SEPOLIA_RPC_URL,
ALCHEMY_BASE_RPC_URL: process.env.ALCHEMY_BASE_RPC_URL
}
}

type ENV = ReturnType<typeof getEnv>

declare global {
var ENV: ENV

interface Window {
ENV: ENV
}
}
24 changes: 24 additions & 0 deletions app/.server/session.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { createCookieSessionStorage } from '@remix-run/node'
import process from 'process'

// export async function loader() {
// const sessionSecret = process.env.SESSION_SECRET
// }

// const sessionSecret = process.env.SESSION_SECRET
// if (!sessionSecret) throw new Error('SESSION_SECRET is not set')

export let sessionStorage = createCookieSessionStorage({
cookie: {
name: '_session', // use any name you want here
sameSite: 'lax', // this helps with CSRF
path: '/', // remember to add this so the cookie will work in all routes
httpOnly: true, // for security reasons, make this cookie http only
secrets: ['s3cr3t'], // replace this with an actual secret
secure: process.env.NODE_ENV === 'production', // enable this in prod only,
maxAge: 60 * 60 * 24 * 30, // 30 days
},
})

// you can also export the methods individually for your own usage
export let { getSession, commitSession, destroySession } = sessionStorage
98 changes: 43 additions & 55 deletions app/components/account-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,60 +3,58 @@ import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
DropdownMenuTrigger
} from '@/components/ui/dropdown-menu'
import { cn } from '@/lib/utils/misc'
import { ConnectButton } from '@rainbow-me/rainbowkit'
import { LogOut } from 'lucide-react'
import type { User } from 'types/user'
import { optimismSepolia } from 'viem/chains'
import { useSwitchNetwork } from 'wagmi'
import { MetaMaskAvatar } from 'react-metamask-avatar'
import { baseSepolia } from 'viem/chains'
import { useSwitchChain } from 'wagmi'
import { NavLink } from '@remix-run/react'

interface AccountButtonProps {
user?: User | null
size?: 'sm' | 'default' | 'lg'
handleSignOut: () => void
className?: string
}

export function AccountButton({
user,
size = 'default',
handleSignOut,
className,
}: AccountButtonProps) {
const { switchNetwork } = useSwitchNetwork()
export function AccountButton(props: AccountButtonProps) {
const { user, handleSignOut, className } = props
const { switchChain } = useSwitchChain()

const handleSwitch = () => {
if (switchNetwork) {
switchNetwork(optimismSepolia.id)
if (switchChain) {
switchChain({
// chainId: CURRENT_ENV === 'production' ? mainnet.id : baseSepolia.id, // change this back when we fully go to prod
chainId: baseSepolia.id
})
}
}

return (
<ConnectButton.Custom>
{({
account,
chain,
openConnectModal,
authenticationStatus,
mounted,
}) => {
account,
chain,
authenticationStatus,
mounted
}) => {
const ready = mounted && authenticationStatus !== 'loading'
const connected =
ready &&
account &&
chain &&
(!authenticationStatus || authenticationStatus === 'authenticated')

if (connected && chain?.id !== optimismSepolia.id) {
if (
connected &&
chain?.id !== baseSepolia.id
// (CURRENT_ENV === 'production' ? mainnet.id : baseSepolia.id)
) {
return (
<Button
size={size}
variant="outline"
variant="default"
className={cn(className)}
onClick={handleSwitch}
>
Expand All @@ -71,42 +69,32 @@ export function AccountButton({
style: {
opacity: 0,
pointerEvents: 'none',
userSelect: 'none',
},
userSelect: 'none'
}
})}
>
{connected && !!user ? (
<div className="flex gap-2 rounded-full p-1">
{connected && !!user && (
<div className="flex gap-2 rounded-full">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
size={'lg-icon'}
variant="ghost"
className={cn(
className,
'h-10 w-10 overflow-hidden rounded-full transition-transform hover:scale-105',
)}
>
<div className="flex items-center gap-1">
<MetaMaskAvatar
address={account?.address || ''}
size={40}
className="rounded-full"
/>
</div>
</Button>
<span>
<Button className={cn(className)}>
{user?.ensName ?? account?.displayName}
</Button>
</span>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="bg-popover w-48">
<DropdownMenuLabel className="flex items-center gap-2">
<div className="space-y-1">
<div className="text-sm font-normal text-primary-500">
Signed in as:
</div>
<div className="font-semibold">
<DropdownMenuContent align="end" className="w-48 bg-popover">
<DropdownMenuItem className="flex items-center gap-2">
<NavLink to={`/profile`} className="font-semibold">
<div className="space-y-1">
<div className="text-sm font-normal text-secondary-foreground">
Signed in as:
</div>

{account?.displayName}
</div>
</div>
</DropdownMenuLabel>
</NavLink>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
onSelect={(e) => {
Expand All @@ -124,7 +112,7 @@ export function AccountButton({
</DropdownMenuContent>
</DropdownMenu>
</div>
) : null}
)}
</div>
)
}}
Expand Down
73 changes: 35 additions & 38 deletions app/components/connect-button.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,40 @@
import { Button } from '@/components/ui/button'
import { cn } from '@/lib/utils/misc'
import { ConnectButton as RainbowkitConnectButton } from '@rainbow-me/rainbowkit'
import { Loader2Icon } from 'lucide-react'
import type { User } from 'types/user'
import { optimismSepolia } from 'viem/chains'
import { useSwitchNetwork } from 'wagmi'
import { type Cookie } from '@remix-run/node'
import { type User } from 'types/user'
import { baseSepolia } from 'viem/chains'
import { useSwitchChain } from 'wagmi'

interface ConnectButtonProps {
user?: User | null
size?: 'sm' | 'default' | 'lg'
className?: string
tosCookie?: Cookie
setShowTOSModal?: (value: boolean) => void
}

export function ConnectButton({
user,
size = 'default',
className,
}: ConnectButtonProps) {
const { switchNetwork } = useSwitchNetwork()
export const ConnectButton = (props: ConnectButtonProps) => {
const { user, className, tosCookie, setShowTOSModal } = props
const { switchChain } = useSwitchChain()

const handleSwitch = () => {
if (switchNetwork) {
switchNetwork(optimismSepolia.id)
if (switchChain) {
switchChain({
// chainId: CURRENT_ENV === 'production' ? mainnet.id : baseSepolia.id,
chainId: baseSepolia.id,
})
}
}

return (
<RainbowkitConnectButton.Custom>
{({
account,
chain,
openConnectModal,
authenticationStatus,
mounted,
}) => {
account,
chain,
openConnectModal,
openAccountModal,
authenticationStatus,
mounted,
}) => {
const ready = mounted && authenticationStatus !== 'loading'
const connected =
ready &&
Expand All @@ -54,33 +55,29 @@ export function ConnectButton({
>
{!connected ? (
<Button
size={size}
className={className}
variant="connect"
className={cn(className)}
onClick={openConnectModal}
onClick={
tosCookie
? openConnectModal
: () => setShowTOSModal && setShowTOSModal(true)
}
>
Connect Wallet
</Button>
) : !user?.didSession ? (
<Button
disabled
size={size}
variant="connect"
className={cn(className)}
>
<Loader2Icon className="mr-1 h-5 w-5 animate-spin" /> Signing...
<Button className={className}>
Signing...
</Button>
) : chain?.id !== optimismSepolia.id ? (
<Button
size={size}
variant="connect"
className={cn(className)}
onClick={handleSwitch}
>
) : chain?.id !== baseSepolia.id ? (
// (CURRENT_ENV === 'production' ? mainnet.id : baseSepolia.id) ? ( // add this back in when we fully go to prod
<Button className={className} onClick={handleSwitch}>
Wrong Network
</Button>
) : (
<div>{account?.displayName}</div>
<Button className={className} onClick={openAccountModal}>
{user?.ensName ?? account?.displayName}
</Button>
)}
</div>
)
Expand Down
13 changes: 7 additions & 6 deletions app/entry.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@
* For more information, see https://remix.run/file-conventions/entry.client
*/

import { RemixBrowser } from "@remix-run/react";
import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";
import './polyfills'
import { RemixBrowser } from '@remix-run/react'
import { startTransition, StrictMode } from 'react'
import { hydrateRoot } from 'react-dom/client'

startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RemixBrowser />
</StrictMode>
);
});
</StrictMode>,
)
})
Loading