mirror of
https://github.com/AtHeartEngineering/bandada.git
synced 2026-01-10 00:48:41 -05:00
@@ -2,11 +2,11 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Client</title>
|
<title>Bandada Demo</title>
|
||||||
<base href="/" />
|
<base href="/" />
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
<link rel="icon" type="image/x-icon" href="./src/assets/favicon.ico" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -8,17 +8,21 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@bandada/api-sdk": "0.12.0",
|
||||||
"@bandada/utils": "0.12.0",
|
"@bandada/utils": "0.12.0",
|
||||||
"@chakra-ui/react": "^2.5.1",
|
"@chakra-ui/react": "^2.5.1",
|
||||||
|
"@chakra-ui/theme-tools": "^2.0.16",
|
||||||
"@emotion/react": "^11.10.6",
|
"@emotion/react": "^11.10.6",
|
||||||
"@emotion/styled": "^11.10.6",
|
"@emotion/styled": "^11.10.6",
|
||||||
"@semaphore-protocol/identity": "3.4.0",
|
"@fontsource-variable/unbounded": "^5.0.5",
|
||||||
|
"@semaphore-protocol/identity": "3.10.1",
|
||||||
"@web3-react/core": "^6.1.9",
|
"@web3-react/core": "^6.1.9",
|
||||||
"@web3-react/injected-connector": "^6.0.7",
|
"@web3-react/injected-connector": "^6.0.7",
|
||||||
"ethers": "^5.4.7",
|
"ethers": "^5.4.7",
|
||||||
"framer-motion": "^10.0.1",
|
"framer-motion": "^10.0.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
"react-icons": "^4.10.1",
|
||||||
"react-router-dom": "^6.8.1",
|
"react-router-dom": "^6.8.1",
|
||||||
"regenerator-runtime": "^0.13.11"
|
"regenerator-runtime": "^0.13.11"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
import { ChakraProvider } from "@chakra-ui/react"
|
|
||||||
import { Web3ReactProvider } from "@web3-react/core"
|
|
||||||
import { providers } from "ethers"
|
|
||||||
import { Route, Routes } from "react-router-dom"
|
|
||||||
import NavBar from "./components/navbar"
|
|
||||||
import Home from "./pages/home"
|
|
||||||
import PermissionedGroup from "./pages/permissioned-group"
|
|
||||||
|
|
||||||
export default function App() {
|
|
||||||
function getLibrary(provider: any) {
|
|
||||||
return new providers.Web3Provider(provider)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Web3ReactProvider getLibrary={(provider) => getLibrary(provider)}>
|
|
||||||
<ChakraProvider>
|
|
||||||
<NavBar />
|
|
||||||
<Routes>
|
|
||||||
<Route path="/" element={<Home />} />
|
|
||||||
<Route
|
|
||||||
path="/invites/:inviteCode"
|
|
||||||
element={<PermissionedGroup />}
|
|
||||||
/>
|
|
||||||
</Routes>
|
|
||||||
</ChakraProvider>
|
|
||||||
</Web3ReactProvider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
BIN
apps/client/src/assets/favicon.ico
Normal file
BIN
apps/client/src/assets/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
19
apps/client/src/assets/icon1.svg
Normal file
19
apps/client/src/assets/icon1.svg
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<svg width="56" height="56" viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6.85986 31.7156L12.428 29.2313L14.6872 31.3369L12.428 42.6567L20.0723 39.2482C20.0723 39.2482 21.7049 31.0121 22.2124 29.4087L23.8409 29.0187L25.9719 27.2784L23.8409 25.6719L22.2124 25.3496C21.2387 21.9958 20.0723 16.7251 20.0723 16.7251L12.428 12.4799L14.6872 22.9001L12.428 25.3496L7.28614 22.9001L6.85986 31.7156Z" fill="url(#paint0_linear_1655_9972)"/>
|
||||||
|
<path d="M42.7496 44.6115L37.8229 41.0443L38.5191 38.041L49.4436 34.335L42.6819 29.4368C42.6819 29.4368 34.7389 32.1428 33.098 32.5057L31.9484 31.2943L29.3795 30.3237L29.0515 32.9668L29.5845 34.5342C27.167 37.0512 23.1864 40.6925 23.1864 40.6925L23.3233 49.4156L31.2164 42.2572L34.4631 42.9841L34.9066 48.6488L42.7496 44.6115Z" fill="url(#paint1_linear_1655_9972)"/>
|
||||||
|
<path d="M42.4825 11.0984L37.6129 14.7431L38.3565 17.735L49.3382 21.2677L42.6548 26.2722C42.6548 26.2722 34.67 23.6922 33.0235 23.3553L31.8933 24.5847L29.3401 25.5959L28.9703 22.9582L29.4785 21.3826C27.0215 18.9042 22.9837 15.3262 22.9837 15.3262L22.9827 6.60203L30.988 13.6348L34.2228 12.8566L34.5767 7.18561L42.4825 11.0984Z" fill="url(#paint2_linear_1655_9972)"/>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="paint0_linear_1655_9972" x1="9.91778" y1="12.4799" x2="26.216" y2="13.47" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#FF5242"/>
|
||||||
|
<stop offset="1" stop-color="#EB179B"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_1655_9972" x1="24.5749" y1="51.5835" x2="17.3016" y2="37.0154" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#FF5242"/>
|
||||||
|
<stop offset="1" stop-color="#EB179B"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_1655_9972" x1="24.1999" y1="4.41463" x2="17.1578" y2="19.0959" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#FF5242"/>
|
||||||
|
<stop offset="1" stop-color="#EB179B"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -1,74 +0,0 @@
|
|||||||
import {
|
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Center,
|
|
||||||
Container,
|
|
||||||
Flex,
|
|
||||||
Spacer,
|
|
||||||
Text,
|
|
||||||
Tooltip,
|
|
||||||
useClipboard
|
|
||||||
} from "@chakra-ui/react"
|
|
||||||
import { useWeb3React } from "@web3-react/core"
|
|
||||||
import { InjectedConnector } from "@web3-react/injected-connector"
|
|
||||||
import { shortenAddress } from "@bandada/utils"
|
|
||||||
import { providers } from "ethers"
|
|
||||||
import { useEffect } from "react"
|
|
||||||
import { Link } from "react-router-dom"
|
|
||||||
|
|
||||||
const injectedConnector = new InjectedConnector({})
|
|
||||||
|
|
||||||
export default function NavBar(): JSX.Element {
|
|
||||||
const { activate, account } = useWeb3React<providers.Web3Provider>()
|
|
||||||
const { hasCopied, onCopy } = useClipboard(account || "")
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
;(async () => {
|
|
||||||
if (await injectedConnector.isAuthorized()) {
|
|
||||||
await activate(injectedConnector)
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
}, [activate])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Box bgColor="#F8F9FF" borderBottom="1px" borderColor="gray.200">
|
|
||||||
<Container maxWidth="container.xl">
|
|
||||||
<Flex h="100px">
|
|
||||||
<Center>
|
|
||||||
<Link to="/">
|
|
||||||
<Text fontSize="lg" fontWeight="bold">
|
|
||||||
Bandada
|
|
||||||
</Text>
|
|
||||||
</Link>
|
|
||||||
</Center>
|
|
||||||
<Spacer />
|
|
||||||
<Center>
|
|
||||||
{account ? (
|
|
||||||
<Tooltip
|
|
||||||
label={hasCopied ? "Copied" : "Copy"}
|
|
||||||
closeOnClick={false}
|
|
||||||
hasArrow
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
color="primary"
|
|
||||||
onClick={onCopy}
|
|
||||||
sx={{ marginRight: 10 }}
|
|
||||||
>
|
|
||||||
{shortenAddress(account)}
|
|
||||||
</Button>
|
|
||||||
</Tooltip>
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
mr="10px"
|
|
||||||
onClick={() => activate(injectedConnector)}
|
|
||||||
>
|
|
||||||
Connect wallet
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Center>
|
|
||||||
</Flex>
|
|
||||||
</Container>
|
|
||||||
</Box>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
import { Identity } from "@semaphore-protocol/identity"
|
|
||||||
import { request } from "@bandada/utils"
|
|
||||||
import { Signer } from "ethers"
|
|
||||||
import { useCallback, useState } from "react"
|
|
||||||
import { Invite } from "../types/invite"
|
|
||||||
|
|
||||||
type ReturnParameters = {
|
|
||||||
getInvite: (inviteCode: string | undefined) => Promise<Invite>
|
|
||||||
generateIdentityCommitment: (
|
|
||||||
signer: Signer,
|
|
||||||
groupId: string,
|
|
||||||
groupName: string
|
|
||||||
) => Promise<string | null>
|
|
||||||
addMember: (
|
|
||||||
groupId: string,
|
|
||||||
idCommitment: string,
|
|
||||||
inviteCode: string
|
|
||||||
) => Promise<void>
|
|
||||||
hasjoined: boolean
|
|
||||||
loading: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function usePermissionedGroups(): ReturnParameters {
|
|
||||||
const [_loading, setLoading] = useState<boolean>(false)
|
|
||||||
const [_hasJoined, setHasjoined] = useState<boolean>(false)
|
|
||||||
|
|
||||||
const getInvite = useCallback(
|
|
||||||
async (inviteCode: string | undefined): Promise<Invite> => {
|
|
||||||
const codeInfo = await request(
|
|
||||||
`${import.meta.env.VITE_API_URL}/invites/${inviteCode}`
|
|
||||||
)
|
|
||||||
|
|
||||||
return codeInfo
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
|
|
||||||
const generateIdentityCommitment = useCallback(
|
|
||||||
async (
|
|
||||||
signer: Signer,
|
|
||||||
groupId: string,
|
|
||||||
groupName: string
|
|
||||||
): Promise<string | null> => {
|
|
||||||
setLoading(true)
|
|
||||||
const nonce = 0
|
|
||||||
const message = `Sign this message to generate your ${groupName} Semaphore identity with key nonce: ${nonce}.`
|
|
||||||
const identity = new Identity(await signer.signMessage(message))
|
|
||||||
const identityCommitment = identity.getCommitment().toString()
|
|
||||||
const hasJoined = await request(
|
|
||||||
`${
|
|
||||||
import.meta.env.VITE_API_URL
|
|
||||||
}/groups/${groupId}/members/${identityCommitment}`
|
|
||||||
)
|
|
||||||
setHasjoined(hasJoined)
|
|
||||||
setLoading(false)
|
|
||||||
return identityCommitment
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
|
|
||||||
const addMember = useCallback(
|
|
||||||
async (
|
|
||||||
groupId: string,
|
|
||||||
idCommitment: string,
|
|
||||||
inviteCode: string
|
|
||||||
): Promise<void> => {
|
|
||||||
await request(
|
|
||||||
`${
|
|
||||||
import.meta.env.VITE_API_URL
|
|
||||||
}/groups/${groupId}/members/${idCommitment}`,
|
|
||||||
{
|
|
||||||
method: "post",
|
|
||||||
data: {
|
|
||||||
inviteCode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
|
||||||
getInvite,
|
|
||||||
generateIdentityCommitment,
|
|
||||||
addMember,
|
|
||||||
hasjoined: _hasJoined,
|
|
||||||
loading: _loading
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { useEffect, useState } from "react"
|
|
||||||
import { useWeb3React } from "@web3-react/core"
|
|
||||||
import { providers, Signer } from "ethers"
|
|
||||||
|
|
||||||
const useSigner = () => {
|
|
||||||
const [signer, setSigner] = useState<Signer>()
|
|
||||||
const { account, library } = useWeb3React<providers.Web3Provider>()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!library || !account) return
|
|
||||||
|
|
||||||
setSigner(library.getSigner(account))
|
|
||||||
}, [account, library])
|
|
||||||
|
|
||||||
return signer
|
|
||||||
}
|
|
||||||
|
|
||||||
export default useSigner
|
|
||||||
@@ -1,16 +1,19 @@
|
|||||||
import { StrictMode } from "react"
|
|
||||||
import * as ReactDOM from "react-dom/client"
|
|
||||||
import { BrowserRouter } from "react-router-dom"
|
|
||||||
import { ChakraProvider } from "@chakra-ui/react"
|
import { ChakraProvider } from "@chakra-ui/react"
|
||||||
import App from "./app"
|
import "@fontsource-variable/unbounded"
|
||||||
|
import { Web3ReactProvider } from "@web3-react/core"
|
||||||
|
import { providers } from "ethers"
|
||||||
|
import * as ReactDOM from "react-dom/client"
|
||||||
|
import Routes from "./routes"
|
||||||
|
import theme from "./styles"
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement)
|
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement)
|
||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
<StrictMode>
|
<Web3ReactProvider
|
||||||
<BrowserRouter basename={import.meta.env.BASE_URL || ""}>
|
getLibrary={(provider) => new providers.Web3Provider(provider)}
|
||||||
<ChakraProvider>
|
>
|
||||||
<App />
|
<ChakraProvider theme={theme}>
|
||||||
</ChakraProvider>
|
<Routes />
|
||||||
</BrowserRouter>
|
</ChakraProvider>
|
||||||
</StrictMode>
|
</Web3ReactProvider>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,16 +1,176 @@
|
|||||||
import { Container, Heading } from "@chakra-ui/react"
|
import { request } from "@bandada/utils"
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Container,
|
||||||
|
Heading,
|
||||||
|
HStack,
|
||||||
|
Icon,
|
||||||
|
Image,
|
||||||
|
Input,
|
||||||
|
Link,
|
||||||
|
Text,
|
||||||
|
VStack
|
||||||
|
} from "@chakra-ui/react"
|
||||||
|
import { Identity } from "@semaphore-protocol/identity"
|
||||||
|
import { useWeb3React } from "@web3-react/core"
|
||||||
|
import { InjectedConnector } from "@web3-react/injected-connector"
|
||||||
|
import { providers } from "ethers"
|
||||||
|
import { useCallback, useEffect, useState } from "react"
|
||||||
|
import { FiGithub } from "react-icons/fi"
|
||||||
|
import { useSearchParams } from "react-router-dom"
|
||||||
|
import icon1Image from "../assets/icon1.svg"
|
||||||
|
|
||||||
|
const injectedConnector = new InjectedConnector({})
|
||||||
|
|
||||||
|
export default function HomePage(): JSX.Element {
|
||||||
|
const [_inviteCode, setInviteCode] = useState<string>("")
|
||||||
|
const [_loading, setLoading] = useState<boolean>(false)
|
||||||
|
const { activate, active, library, account } =
|
||||||
|
useWeb3React<providers.Web3Provider>()
|
||||||
|
const [_searchParams] = useSearchParams()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
;(async () => {
|
||||||
|
if (await injectedConnector.isAuthorized()) {
|
||||||
|
await activate(injectedConnector)
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}, [activate])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const inviteCode = _searchParams.get("inviteCode")
|
||||||
|
|
||||||
|
if (inviteCode) {
|
||||||
|
setInviteCode(inviteCode)
|
||||||
|
}
|
||||||
|
}, [_searchParams])
|
||||||
|
|
||||||
|
const joinGroupByInvite = useCallback(
|
||||||
|
async (inviteCode: string) => {
|
||||||
|
if (account && library) {
|
||||||
|
setLoading(true)
|
||||||
|
|
||||||
|
const invite = await request(
|
||||||
|
`${import.meta.env.VITE_API_URL}/invites/${inviteCode}`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!invite) {
|
||||||
|
alert("Some error occurred!")
|
||||||
|
setLoading(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const signer = library.getSigner(account)
|
||||||
|
|
||||||
|
const message = `Sign this message to generate your Semaphore identity.`
|
||||||
|
const identity = new Identity(await signer.signMessage(message))
|
||||||
|
const identityCommitment = identity.getCommitment().toString()
|
||||||
|
const hasJoined = await request(
|
||||||
|
`${import.meta.env.VITE_API_URL}/groups/${
|
||||||
|
invite.groupId
|
||||||
|
}/members/${identityCommitment}`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (hasJoined) {
|
||||||
|
alert("You have already joined this group")
|
||||||
|
setLoading(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await request(
|
||||||
|
`${import.meta.env.VITE_API_URL}/groups/${
|
||||||
|
invite.groupId
|
||||||
|
}/members/${identityCommitment}`,
|
||||||
|
{
|
||||||
|
method: "post",
|
||||||
|
data: {
|
||||||
|
inviteCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
alert("You have joined the group!")
|
||||||
|
setInviteCode("")
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[account, library]
|
||||||
|
)
|
||||||
|
|
||||||
export default function Home(): JSX.Element {
|
|
||||||
return (
|
return (
|
||||||
<Container
|
<Container maxW="container.xl" pt="20" pb="20" px="8" centerContent>
|
||||||
textAlign="center"
|
<VStack spacing="20" pb="30px">
|
||||||
flex="1"
|
<HStack mb="60px" justify="space-between" w="100%">
|
||||||
mb="80px"
|
<HStack spacing="1">
|
||||||
mt="300px"
|
<Image
|
||||||
px="80px"
|
src={icon1Image}
|
||||||
maxW="container.lg"
|
htmlWidth="32px"
|
||||||
>
|
alt="Bandada icon"
|
||||||
<Heading fontSize="150px">Client App</Heading>
|
/>
|
||||||
|
<Heading fontSize="22px" as="h1">
|
||||||
|
bandada
|
||||||
|
</Heading>
|
||||||
|
</HStack>
|
||||||
|
|
||||||
|
<HStack spacing="5">
|
||||||
|
<Link
|
||||||
|
href="https://github.com/privacy-scaling-explorations/bandada"
|
||||||
|
isExternal
|
||||||
|
>
|
||||||
|
<HStack spacing="1">
|
||||||
|
<Icon boxSize={5} as={FiGithub} />
|
||||||
|
<Text textDecoration="underline">Github</Text>
|
||||||
|
</HStack>
|
||||||
|
</Link>
|
||||||
|
</HStack>
|
||||||
|
</HStack>
|
||||||
|
|
||||||
|
<Heading
|
||||||
|
fontSize="40px"
|
||||||
|
as="h1"
|
||||||
|
lineHeight="67px"
|
||||||
|
textAlign="center"
|
||||||
|
>
|
||||||
|
Join Bandada groups
|
||||||
|
<br />
|
||||||
|
by invite .
|
||||||
|
</Heading>
|
||||||
|
|
||||||
|
{!active ? (
|
||||||
|
<Button
|
||||||
|
colorScheme="secondary"
|
||||||
|
variant="solid"
|
||||||
|
onClick={() => activate(injectedConnector)}
|
||||||
|
>
|
||||||
|
Connect Metamask
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<VStack w="400px" spacing="5">
|
||||||
|
<VStack align="left" w="100%">
|
||||||
|
<Text>Invite code</Text>
|
||||||
|
<Input
|
||||||
|
size="lg"
|
||||||
|
value={_inviteCode}
|
||||||
|
placeholder="Paste your code here"
|
||||||
|
onChange={(event) =>
|
||||||
|
setInviteCode(event.target.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</VStack>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
width="100%"
|
||||||
|
colorScheme="secondary"
|
||||||
|
variant="solid"
|
||||||
|
onClick={() => joinGroupByInvite(_inviteCode)}
|
||||||
|
isDisabled={!_inviteCode}
|
||||||
|
isLoading={_loading}
|
||||||
|
>
|
||||||
|
Join group
|
||||||
|
</Button>
|
||||||
|
</VStack>
|
||||||
|
)}
|
||||||
|
</VStack>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
13
apps/client/src/routes.tsx
Normal file
13
apps/client/src/routes.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { createBrowserRouter, RouterProvider } from "react-router-dom"
|
||||||
|
import HomePage from "./pages/home"
|
||||||
|
|
||||||
|
export default function Routes(): JSX.Element {
|
||||||
|
const router = createBrowserRouter([
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
element: <HomePage />
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
return <RouterProvider router={router} />
|
||||||
|
}
|
||||||
43
apps/client/src/styles/colors.ts
Normal file
43
apps/client/src/styles/colors.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
const colors = {
|
||||||
|
balticSea: {
|
||||||
|
50: "#f8f7f8",
|
||||||
|
100: "#F6EDF4",
|
||||||
|
200: "#ded9de",
|
||||||
|
300: "#c0b8c1",
|
||||||
|
400: "#9d919f",
|
||||||
|
500: "#827384",
|
||||||
|
600: "#6b5d6c",
|
||||||
|
700: "#574c58",
|
||||||
|
800: "#4b414b",
|
||||||
|
900: "#413941",
|
||||||
|
950: "#231f23"
|
||||||
|
},
|
||||||
|
sunsetOrange: {
|
||||||
|
50: "#fff2f1",
|
||||||
|
100: "#ffe2df",
|
||||||
|
200: "#ffcac5",
|
||||||
|
300: "#ffa59d",
|
||||||
|
400: "#ff7164",
|
||||||
|
500: "#ff5242",
|
||||||
|
600: "#ed2715",
|
||||||
|
700: "#c81d0d",
|
||||||
|
800: "#a51c0f",
|
||||||
|
900: "#881e14",
|
||||||
|
950: "#4b0a04"
|
||||||
|
},
|
||||||
|
classicRose: {
|
||||||
|
50: "#fef1fa",
|
||||||
|
100: "#fee5f7",
|
||||||
|
200: "#ffccf2",
|
||||||
|
300: "#ffa1e6",
|
||||||
|
400: "#ff66d2",
|
||||||
|
500: "#fb39bb",
|
||||||
|
600: "#eb179b",
|
||||||
|
700: "#cd097d",
|
||||||
|
800: "#a90b67",
|
||||||
|
900: "#8d0e57",
|
||||||
|
950: "#570032"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default colors
|
||||||
136
apps/client/src/styles/components/button.ts
Normal file
136
apps/client/src/styles/components/button.ts
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
import { SystemStyleObject } from "@chakra-ui/react"
|
||||||
|
import { GlobalStyleProps } from "@chakra-ui/theme-tools"
|
||||||
|
|
||||||
|
const height = "48px"
|
||||||
|
const paddingX = "16px"
|
||||||
|
const paddingY = "12px"
|
||||||
|
|
||||||
|
const Button = {
|
||||||
|
baseStyle: {
|
||||||
|
_focus: {
|
||||||
|
boxShadow: "none"
|
||||||
|
},
|
||||||
|
fontFamily: "DM Sans, sans-serif",
|
||||||
|
borderRadius: 8,
|
||||||
|
fontWeight: 500
|
||||||
|
},
|
||||||
|
variants: {
|
||||||
|
outline: (): SystemStyleObject => ({
|
||||||
|
height,
|
||||||
|
paddingX,
|
||||||
|
paddingY
|
||||||
|
}),
|
||||||
|
solid: (props: GlobalStyleProps): SystemStyleObject => {
|
||||||
|
const { colorScheme: c } = props
|
||||||
|
|
||||||
|
if (c === "primary") {
|
||||||
|
const bgGradient =
|
||||||
|
"linear(to-r, sunsetOrange.500, classicRose.600)"
|
||||||
|
const color = "balticSea.50"
|
||||||
|
|
||||||
|
return {
|
||||||
|
bgGradient,
|
||||||
|
color,
|
||||||
|
height,
|
||||||
|
paddingX,
|
||||||
|
paddingY,
|
||||||
|
_hover: {
|
||||||
|
bgGradient:
|
||||||
|
"linear(to-r, sunsetOrange.600, classicRose.700)",
|
||||||
|
_disabled: {
|
||||||
|
bgGradient
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_active: {
|
||||||
|
bgGradient:
|
||||||
|
"linear(to-r, sunsetOrange.700, classicRose.800)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c === "secondary") {
|
||||||
|
const bg = "balticSea.950"
|
||||||
|
const color = "balticSea.100"
|
||||||
|
|
||||||
|
return {
|
||||||
|
bg,
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: "13px",
|
||||||
|
color,
|
||||||
|
paddingX,
|
||||||
|
paddingY,
|
||||||
|
_hover: {
|
||||||
|
bg: "balticSea.900",
|
||||||
|
_disabled: {
|
||||||
|
bg
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_active: { bg: "balticSea.700" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c === "tertiary") {
|
||||||
|
const bg = "balticSea.100"
|
||||||
|
const color = "balticSea.900"
|
||||||
|
|
||||||
|
return {
|
||||||
|
bg,
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: "13px",
|
||||||
|
color,
|
||||||
|
height,
|
||||||
|
paddingX,
|
||||||
|
paddingY,
|
||||||
|
_hover: {
|
||||||
|
bg: "balticSea.200",
|
||||||
|
_disabled: {
|
||||||
|
bg
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_active: { bg: "balticSea.300" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c === "danger") {
|
||||||
|
const bg = "sunsetOrange.200"
|
||||||
|
const color = "sunsetOrange.950"
|
||||||
|
|
||||||
|
return {
|
||||||
|
bg,
|
||||||
|
fontWeight: 600,
|
||||||
|
fontSize: "13px",
|
||||||
|
color,
|
||||||
|
height,
|
||||||
|
paddingX,
|
||||||
|
paddingY,
|
||||||
|
_hover: {
|
||||||
|
bg: "sunsetOrange.300",
|
||||||
|
_disabled: {
|
||||||
|
bg
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_active: { bg: "sunsetOrange.400" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bg = "rgba(0,0,0,0)"
|
||||||
|
|
||||||
|
return {
|
||||||
|
bg,
|
||||||
|
color: `${c}.800`,
|
||||||
|
height,
|
||||||
|
paddingX,
|
||||||
|
paddingY,
|
||||||
|
_hover: {
|
||||||
|
bg: `${c}.200`,
|
||||||
|
_disabled: {
|
||||||
|
bg
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_active: { bg: `${c}.300` }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Button
|
||||||
5
apps/client/src/styles/components/index.ts
Normal file
5
apps/client/src/styles/components/index.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import Button from "./button"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Button
|
||||||
|
}
|
||||||
16
apps/client/src/styles/index.ts
Normal file
16
apps/client/src/styles/index.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { extendTheme } from "@chakra-ui/react"
|
||||||
|
import styles from "./styles"
|
||||||
|
import colors from "./colors"
|
||||||
|
import components from "./components"
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
fonts: {
|
||||||
|
heading: "Unbounded Variable, sans-serif",
|
||||||
|
body: "DM Sans, sans-serif"
|
||||||
|
},
|
||||||
|
colors,
|
||||||
|
styles,
|
||||||
|
components
|
||||||
|
}
|
||||||
|
|
||||||
|
export default extendTheme(config)
|
||||||
26
apps/client/src/styles/styles.ts
Normal file
26
apps/client/src/styles/styles.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { SystemStyleObject } from "@chakra-ui/react"
|
||||||
|
import { Styles } from "@chakra-ui/theme-tools"
|
||||||
|
|
||||||
|
const styles: Styles = {
|
||||||
|
global: (): SystemStyleObject => ({
|
||||||
|
body: {},
|
||||||
|
"body, #root, #root > div": {
|
||||||
|
minHeight: "100vh"
|
||||||
|
},
|
||||||
|
"#root > div": {
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column"
|
||||||
|
},
|
||||||
|
h1: {
|
||||||
|
fontWeight: "400 !important"
|
||||||
|
},
|
||||||
|
"h2, h3": {
|
||||||
|
fontWeight: "500 !important"
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
fontSize: "16px !important"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default styles
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export type Group = {
|
|
||||||
name: string
|
|
||||||
description: string
|
|
||||||
treeDepth: number
|
|
||||||
members: string[]
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import { Invite } from "./invite"
|
|
||||||
import { Group } from "./group"
|
|
||||||
|
|
||||||
export type { Invite, Group }
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
import { Group } from "./group"
|
|
||||||
|
|
||||||
export type Invite = {
|
|
||||||
code: string
|
|
||||||
isRedeemed: boolean
|
|
||||||
groupName: string
|
|
||||||
groupId: string
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# This file contains build time variables for dev env.
|
# This file contains build time variables for dev env.
|
||||||
|
|
||||||
VITE_API_URL=http://localhost:3000
|
VITE_API_URL=http://localhost:3000
|
||||||
VITE_CLIENT_INVITES_URL=http://localhost:3002/invites/\
|
VITE_CLIENT_INVITES_URL=http://localhost:3002?inviteCode=\
|
||||||
VITE_ETHEREUM_NETWORK=goerli
|
VITE_ETHEREUM_NETWORK=goerli
|
||||||
VITE_GITHUB_CLIENT_ID=a83a8b014ef38270fb22
|
VITE_GITHUB_CLIENT_ID=a83a8b014ef38270fb22
|
||||||
VITE_TWITTER_CLIENT_ID=NV82Mm85NWlSZ1llZkpLMl9vN3A6MTpjaQ
|
VITE_TWITTER_CLIENT_ID=NV82Mm85NWlSZ1llZkpLMl9vN3A6MTpjaQ
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# This file contains build time variables for prod env.
|
# This file contains build time variables for prod env.
|
||||||
|
|
||||||
VITE_API_URL=https://api.bandada.appliedzkp.org
|
VITE_API_URL=https://api.bandada.appliedzkp.org
|
||||||
VITE_CLIENT_INVITES_URL=https://client.bandada.appliedzkp.org/invites/\
|
VITE_CLIENT_INVITES_URL=https://client.bandada.appliedzkp.org?inviteCode=\
|
||||||
VITE_ETHEREUM_NETWORK=goerli
|
VITE_ETHEREUM_NETWORK=goerli
|
||||||
VITE_GITHUB_CLIENT_ID=6ccd7b93e84260e353f9
|
VITE_GITHUB_CLIENT_ID=6ccd7b93e84260e353f9
|
||||||
VITE_TWITTER_CLIENT_ID=NV82Mm85NWlSZ1llZkpLMl9vN3A6MTpjaQ
|
VITE_TWITTER_CLIENT_ID=NV82Mm85NWlSZ1llZkpLMl9vN3A6MTpjaQ
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { SiweMessage } from "siwe"
|
|||||||
import { Group } from "../types"
|
import { Group } from "../types"
|
||||||
|
|
||||||
const API_URL = import.meta.env.VITE_API_URL
|
const API_URL = import.meta.env.VITE_API_URL
|
||||||
const CLIENT_URL = import.meta.env.VITE_CLIENT_INVITES_URL
|
const CLIENT_INVITES_URL = import.meta.env.VITE_CLIENT_INVITES_URL
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* It generates a magic link with a valid invite code
|
* It generates a magic link with a valid invite code
|
||||||
@@ -26,7 +26,7 @@ export async function generateMagicLink(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return (clientUrl || CLIENT_URL).replace("\\", code)
|
return (clientUrl || CLIENT_INVITES_URL).replace("\\", code)
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
|
|
||||||
|
|||||||
16
yarn.lock
16
yarn.lock
@@ -783,7 +783,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@bandada/api-sdk@workspace:libs/api-sdk":
|
"@bandada/api-sdk@0.12.0, @bandada/api-sdk@workspace:libs/api-sdk":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@bandada/api-sdk@workspace:libs/api-sdk"
|
resolution: "@bandada/api-sdk@workspace:libs/api-sdk"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -5109,16 +5109,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@semaphore-protocol/identity@npm:3.4.0":
|
"@semaphore-protocol/identity@npm:3.10.1":
|
||||||
version: 3.4.0
|
version: 3.10.1
|
||||||
resolution: "@semaphore-protocol/identity@npm:3.4.0"
|
resolution: "@semaphore-protocol/identity@npm:3.10.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@ethersproject/bignumber": ^5.5.0
|
"@ethersproject/bignumber": ^5.5.0
|
||||||
"@ethersproject/keccak256": ^5.7.0
|
"@ethersproject/keccak256": ^5.7.0
|
||||||
"@ethersproject/random": ^5.5.1
|
"@ethersproject/random": ^5.5.1
|
||||||
"@ethersproject/strings": ^5.6.1
|
"@ethersproject/strings": ^5.6.1
|
||||||
js-sha512: ^0.8.0
|
js-sha512: ^0.8.0
|
||||||
checksum: ac1c621196d972f8698591cf5fb9e60146f3223a87f77208f2931fc56749e68a14fbc01b7bc2a6abb69bbe69192f579c17db971f55381ba5fa50a561e232c57b
|
checksum: cb00d3bfea550500aa20ffba9a569c10dbe4f32356bff867f5429c2d0fa74f285c0334a10305407d6797308f8398ca23b8bd3170a0f418acca9461f034791682
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -9114,11 +9114,14 @@ __metadata:
|
|||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "client@workspace:apps/client"
|
resolution: "client@workspace:apps/client"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
"@bandada/api-sdk": 0.12.0
|
||||||
"@bandada/utils": 0.12.0
|
"@bandada/utils": 0.12.0
|
||||||
"@chakra-ui/react": ^2.5.1
|
"@chakra-ui/react": ^2.5.1
|
||||||
|
"@chakra-ui/theme-tools": ^2.0.16
|
||||||
"@emotion/react": ^11.10.6
|
"@emotion/react": ^11.10.6
|
||||||
"@emotion/styled": ^11.10.6
|
"@emotion/styled": ^11.10.6
|
||||||
"@semaphore-protocol/identity": 3.4.0
|
"@fontsource-variable/unbounded": ^5.0.5
|
||||||
|
"@semaphore-protocol/identity": 3.10.1
|
||||||
"@types/react": ^18.0.27
|
"@types/react": ^18.0.27
|
||||||
"@types/react-dom": ^18.0.10
|
"@types/react-dom": ^18.0.10
|
||||||
"@vitejs/plugin-react": ^3.1.0
|
"@vitejs/plugin-react": ^3.1.0
|
||||||
@@ -9128,6 +9131,7 @@ __metadata:
|
|||||||
framer-motion: ^10.0.1
|
framer-motion: ^10.0.1
|
||||||
react: ^18.2.0
|
react: ^18.2.0
|
||||||
react-dom: ^18.2.0
|
react-dom: ^18.2.0
|
||||||
|
react-icons: ^4.10.1
|
||||||
react-router-dom: ^6.8.1
|
react-router-dom: ^6.8.1
|
||||||
regenerator-runtime: ^0.13.11
|
regenerator-runtime: ^0.13.11
|
||||||
typescript: ^4.9.3
|
typescript: ^4.9.3
|
||||||
|
|||||||
Reference in New Issue
Block a user