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

Integrate ENS Record Setting in UI #256

Merged
merged 6 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 2 additions & 0 deletions packages/app/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ REACT_APP_SUBGRAPH_SEPOLIA=auryn-macmillan/tabula-sepolia
REACT_APP_SUBGRAPH_POLYGON=auryn-macmillan/tabula-polygon
REACT_APP_SUBGRAPH_ARBITRUM=auryn-macmillan/tabula-arbitrum
REACT_APP_SUBGRAPH_OPTIMISM=auryn-macmillan/tabula-optimism
REACT_APP_ENS_SUBGRAPH_MAINNET=ensdomains/ens
REACT_APP_ENS_SUBGRAPH_GOERLI=ensdomains/ensgoerli
REACT_APP_IPFS_GATEWAY=https://ipfs.io/ipfs
REACT_APP_SUBGRAPH_OPTIMISM_ON_GNOSIS_CHAIN=auryn-macmillan/tabula-optimism-on-gnosis-chain
REACT_APP_INFURA_API_KEY=
Expand Down
61 changes: 32 additions & 29 deletions packages/app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { PosterProvider } from "./services/poster/context"
import { WalletProvider } from "./connectors/WalletProvider"
import { RedirectOldRoute } from "./components/commons/RedicrectOldRoute"
import PreviewArticleView from "./components/views/publication/PreviewArticleView"
import { EnsProvider } from "./services/ens/context"

const App: React.FC = () => {
// the chainId should be from the publication if its present
Expand All @@ -44,39 +45,41 @@ const App: React.FC = () => {
<SnackbarProvider maxSnack={1}>
<UrqlProvider value={currentSubgraphClient}>
<WalletProvider>
<PublicationProvider>
<ArticleProvider>
<PosterProvider>
<ScrollToTop />
<Routes>
{" "}
<Route path="/" element={<LandingView />} />
<Route path="/wallet" element={<WalletView />} />
<Route path="/publications" element={<PublicationsView updateChainId={updateChainId} />} />
<Route path=":publicationSlug" element={<PublicationView updateChainId={updateChainId} />} />
{/* Redirect old routes to new routes */}
<Route path="/goerli/*" element={<RedirectOldRoute />} />
<Route path="/mainnet/*" element={<RedirectOldRoute />} />
<Route path="/gnosis_chain/*" element={<RedirectOldRoute />} />
<Route path="/polygon/*" element={<RedirectOldRoute />} />
<Route path="/arbitrum/*" element={<RedirectOldRoute />} />
<Route path="/optimism/*" element={<RedirectOldRoute />} />
{/* New routes */}
<Route path=":publicationSlug">
<Route path="permissions/:type" element={<PermissionView />} />
<EnsProvider>
<PublicationProvider>
<ArticleProvider>
<PosterProvider>
<ScrollToTop />
<Routes>
{" "}
<Route path="/" element={<LandingView />} />
<Route path="/wallet" element={<WalletView />} />
<Route path="/publications" element={<PublicationsView updateChainId={updateChainId} />} />
<Route path=":publicationSlug" element={<PublicationView updateChainId={updateChainId} />} />
{/* Redirect old routes to new routes */}
<Route path="/goerli/*" element={<RedirectOldRoute />} />
<Route path="/mainnet/*" element={<RedirectOldRoute />} />
<Route path="/gnosis_chain/*" element={<RedirectOldRoute />} />
<Route path="/polygon/*" element={<RedirectOldRoute />} />
<Route path="/arbitrum/*" element={<RedirectOldRoute />} />
<Route path="/optimism/*" element={<RedirectOldRoute />} />
{/* New routes */}
<Route path=":publicationSlug">
<Route path="permissions/:type" element={<PermissionView />} />

<Route path="new" element={<CreateArticleView type="new" />} />
<Route path="new" element={<CreateArticleView type="new" />} />

<Route path=":type/preview" element={<PreviewArticleView />} />
<Route path=":type/preview" element={<PreviewArticleView />} />

<Route path=":articleId" element={<ArticleView updateChainId={updateChainId} />} />
<Route path=":articleId" element={<ArticleView updateChainId={updateChainId} />} />

<Route path=":articleId/edit" element={<CreateArticleView type="edit" />} />
</Route>
</Routes>
</PosterProvider>
</ArticleProvider>
</PublicationProvider>
<Route path=":articleId/edit" element={<CreateArticleView type="edit" />} />
</Route>
</Routes>
</PosterProvider>
</ArticleProvider>
</PublicationProvider>
</EnsProvider>
</WalletProvider>
</UrqlProvider>
</SnackbarProvider>
Expand Down
111 changes: 111 additions & 0 deletions packages/app/src/components/commons/NetworkModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { Button, CircularProgress, Grid, Modal, Typography, styled } from "@mui/material"
import React, { useRef, useState } from "react"
import { palette, typography } from "../../theme"
import { ViewContainer } from "./ViewContainer"
import CloseIcon from "@mui/icons-material/Close"
import { useWeb3React } from "@web3-react/core"
import { useNotification } from "../../hooks/useNotification"

type NetworkError = {
code: number
message: string
stack: string
}

const ModalContainer = styled(ViewContainer)({
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
borderRadius: 8,
width: 648,
background: palette.whites[1000],
padding: 24,
})

const NetworkModal: React.FC<any> = ({ open, handleClose }) => {
juliopavila marked this conversation as resolved.
Show resolved Hide resolved
const ref = useRef(null)
const openNotification = useNotification()
const { library } = useWeb3React()
const [loading, setLoading] = useState<boolean>(false)

const handleSwitch = async () => {
if (library) {
try {
setLoading(true)
await library.send("wallet_switchEthereumChain", [{ chainId: "0x1" }])
handleClose({}, "escapeKeyDown")
juliopavila marked this conversation as resolved.
Show resolved Hide resolved
} catch (switchError: unknown) {
const error = switchError as NetworkError
setLoading(false)
openNotification({
message: error.message,
variant: "error",
})
if (error && error.code === 4902) {
setLoading(false)
try {
await library.send("wallet_addEthereumChain", [
{
chainId: "0x1",
},
])
} catch (addError) {
console.error(addError)
setLoading(false)
}
}
}
}
}
return (
<Modal open={open} onClose={handleClose}>
<ModalContainer maxWidth="md" ref={ref}>
<Grid container spacing={3} py={3} px={4} flexDirection="column">
<Grid item>
<Grid container justifyContent="space-between" alignItems="center">
<Grid item>
<Typography
fontFamily={typography.fontFamilies.sans}
variant="h5"
sx={{ margin: 0 }}
color={palette.grays[1000]}
>
Network Switch Required
</Typography>
</Grid>
<Grid item>
<CloseIcon
style={{ cursor: "pointer" }}
onClick={() => {
!loading && handleClose({}, "escapeKeyDown")
}}
/>
</Grid>
</Grid>
</Grid>

<Grid item>
<Grid container gap={1}>
<Typography fontFamily={typography.fontFamilies.sans}>
<p>
You are currently connected to a network other than mainnet. To proceed with transactions involving
ENS domains, please switch to mainnet.
</p>
</Typography>
</Grid>
</Grid>

<Grid item>
<Button variant="contained" type="submit" onClick={handleSwitch} disabled={loading}>
{loading && <CircularProgress size={20} sx={{ marginRight: 1 }} />}
Switch Network
</Button>
</Grid>
</Grid>
</ModalContainer>
</Modal>
)
}

export default NetworkModal
14 changes: 8 additions & 6 deletions packages/app/src/components/commons/WalletBadge.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React, { useEffect, useState } from "react"
import React, { useEffect } from "react"

import { Avatar } from "@mui/material"
import * as blockies from "blockies-ts"

import { useNotification } from "../../hooks/useNotification"
import { useWeb3React } from "@web3-react/core"
import { lookupAddress } from "../../services/ens"
import { useEnsContext } from "../../services/ens/context"
import useENS from "../../services/ens/hooks/useENS"

type WalletBadgeProps = {
copyable?: boolean
Expand All @@ -14,25 +15,26 @@ type WalletBadgeProps = {
}

export const WalletBadge: React.FC<WalletBadgeProps> = ({ address, hover, copyable }) => {
const { lookupAddress } = useENS()
const avatarSrc = blockies.create({ seed: address.toLowerCase() }).toDataURL()
const { connector, active, chainId } = useWeb3React()
const { setEnsName } = useEnsContext()

const [ensName, setEnsName] = useState<string>()
const openNotification = useNotification()

useEffect(() => {
const fetchData = async () => {
if (address && active) {
const provider = await connector?.getProvider()
if (provider != null) {
const ensName = await lookupAddress(provider, address)
setEnsName(ensName ?? undefined)
const ens = await lookupAddress(provider, address)
setEnsName(ens)
}
}
}

fetchData().catch(console.error)
}, [active, address, connector, ensName, chainId])
}, [active, address, connector, chainId, setEnsName, lookupAddress])

const handleAddressClick = async () => {
if (copyable) {
Expand Down
123 changes: 123 additions & 0 deletions packages/app/src/components/views/publication/components/EnsModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { Button, CircularProgress, Grid, Modal, ModalProps, Typography, styled } from "@mui/material"
import React, { useEffect, useRef, useState } from "react"
import { palette, typography } from "../../../../theme"
import { ViewContainer } from "../../../commons/ViewContainer"
import CloseIcon from "@mui/icons-material/Close"
import { useEnsContext } from "../../../../services/ens/context"
import { useWeb3React } from "@web3-react/core"
import useENS from "../../../../services/ens/hooks/useENS"
import { Dropdown } from "../../../commons/Dropdown"

interface EnsModalProps extends Omit<ModalProps, "children"> {
publicationId: string
}

const ModalContainer = styled(ViewContainer)({
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
borderRadius: 8,
width: 648,
background: palette.whites[1000],
padding: 24,
})

const EnsModal: React.FC<EnsModalProps> = ({ publicationId, ...props }) => {
const { setTextRecord, loading, transactionCompleted } = useENS()
const { connector, chainId } = useWeb3React()
const ref = useRef(null)
const { ensNameList } = useEnsContext()
const [ensNameSelected, setEnsNameSelected] = useState<string>("")

useEffect(() => {
if (transactionCompleted) {
props.onClose && props.onClose({}, "backdropClick")
}
}, [props, transactionCompleted])

const handleEnsRecord = async () => {
const provider = await connector?.getProvider()
if (provider !== null && ensNameSelected && chainId) {
await setTextRecord(provider, publicationId, ensNameSelected, chainId)
}
}

return (
<Modal
open={props.open}
onClose={() => {
if (!loading) {
props.onClose && props.onClose({}, "backdropClick")
}
}}
>
<ModalContainer maxWidth="md" ref={ref}>
<Grid container spacing={3} py={3} px={4} flexDirection="column">
<Grid item>
<Grid container justifyContent="space-between" alignItems="center">
<Grid item>
<Typography
fontFamily={typography.fontFamilies.sans}
variant="h5"
sx={{ margin: 0 }}
color={palette.grays[1000]}
>
Linking Your Publication to Your ENS Name
</Typography>
</Grid>
<Grid item>
<CloseIcon
style={{ cursor: "pointer" }}
onClick={() => {
if (!loading) {
props.onClose && props.onClose({}, "escapeKeyDown")
}
}}
/>
</Grid>
</Grid>
</Grid>

<Grid item>
<Dropdown
title="Select an ENS name"
options={ensNameList}
onSelected={(e) => {
setEnsNameSelected(e.value)
}}
/>
</Grid>

<Grid item>
<Grid container gap={1}>
<Typography fontFamily={typography.fontFamilies.sans}>
We're registering a record to your ENS name with the publication ID. This allows direct access to your
publication via{" "}
<span
style={{
color: palette.secondary[1000],
textDecoration: "underline",
cursor: "pointer",
}}
>
tabula.gg/#/{ensNameSelected ?? "yourENS"}
</span>
.
</Typography>
</Grid>
</Grid>

<Grid item>
<Button variant="contained" type="submit" onClick={handleEnsRecord} disabled={loading || !ensNameSelected}>
{loading && <CircularProgress size={20} sx={{ marginRight: 1 }} />}
Continue
</Button>
</Grid>
</Grid>
</ModalContainer>
</Modal>
)
}

export default EnsModal
Loading
Loading