Skip to content

Commit

Permalink
Merge branch 'main' into fix-create-dao-address-validaton
Browse files Browse the repository at this point in the history
  • Loading branch information
neokry committed Mar 28, 2023
2 parents 2843879 + 09d2ff0 commit af2cd6c
Show file tree
Hide file tree
Showing 10 changed files with 553 additions and 184 deletions.
11 changes: 11 additions & 0 deletions apps/web/src/components/Icon/assets/info-16.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions apps/web/src/components/Icon/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import External from './assets/external-16.svg'
import Github from './assets/github.svg'
import Globe from './assets/globe.svg'
import HandlebarCircle from './assets/handlebar-circle.svg'
import Info16 from './assets/info-16.svg'
import Move from './assets/move.svg'
import NewWindow from './assets/new-window.svg'
import NounsConnect from './assets/nouns-connect.svg'
Expand Down Expand Up @@ -56,6 +57,7 @@ export const icons = {
github: Github,
eth: Eth,
handlebarCircle: HandlebarCircle,
'info-16': Info16,
globe: Globe,
move: Move,
newWindow: NewWindow,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const validateAddress = async (

export const deboucedValidateAddress = debounce(validateAddress, 500)

const allocationSchema = Yup.object().shape({
export const allocationSchema = Yup.object().shape({
founderAddress: Yup.string()
.test(
'isValidAddress',
Expand All @@ -28,12 +28,12 @@ const allocationSchema = Yup.object().shape({
allocationPercentage: Yup.number()
.transform((value) => (isNaN(value) ? undefined : value))
.required('*')
.integer('Must be whole number')
.max(100, '< 100')
.when('admin', (admin, schema) => {
if (!admin) return schema.min(1, '> 0') // (condition, errorMessage) - allocation represented as % must be greater than or equal to 0
return schema
})
.max(100, '< 100')
.integer('Must be whole number'),
}),
endDate: Yup.string()
.required('*')
.test('isDateInFuture', 'Must be in future', (value: string | undefined) => {
Expand Down
25 changes: 20 additions & 5 deletions apps/web/src/modules/dao/components/About/About.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Flex, Text } from '@zoralabs/zord'
import { Box, Flex, Grid, Text } from '@zoralabs/zord'
import HtmlReactParser from 'html-react-parser'
import { getFetchableUrl } from 'ipfs-service'
import Image from 'next/legacy/image'
Expand All @@ -11,19 +11,22 @@ import { CHAIN } from 'src/constants/network'
import SWR_KEYS from 'src/constants/swrKeys'
import { metadataAbi, tokenAbi } from 'src/data/contract/abis'
import { sdk } from 'src/data/graphql/client'
import { useLayoutStore } from 'src/stores'
import { about, daoDescription, daoInfo, daoName } from 'src/styles/About.css'
import { unpackOptionalArray } from 'src/utils/helpers'
import { formatCryptoVal } from 'src/utils/numbers'

import { useDaoStore } from '../../stores'
import { parseContractURI } from '../../utils'
import { ExternalLinks } from './ExternalLinks'
import { Founder } from './Founder'
import { Statistic } from './Statistic'

export const About: React.FC = () => {
const {
addresses: { token, treasury, metadata },
} = useDaoStore()
const { isMobile } = useLayoutStore()

const tokenContractParams = {
abi: tokenAbi,
Expand All @@ -38,16 +41,15 @@ export const About: React.FC = () => {
contracts: [
{ ...tokenContractParams, functionName: 'name' },
{ ...tokenContractParams, functionName: 'totalSupply' },
{ ...tokenContractParams, functionName: 'getFounders' },
{ ...metadataContractParams, functionName: 'contractImage' },
{ ...metadataContractParams, functionName: 'description' },
{ ...metadataContractParams, functionName: 'contractURI' },
],
})

const [name, totalSupply, daoImage, description, contractURI] = unpackOptionalArray(
contractData,
5
)
const [name, totalSupply, founders, daoImage, description, contractURI] =
unpackOptionalArray(contractData, 6)
const parsedContractURI = parseContractURI(contractURI)

const { data: balance } = useBalance({ address: treasury as Address })
Expand Down Expand Up @@ -133,6 +135,19 @@ export const About: React.FC = () => {
>
<ExternalLinks links={{ website: parsedContractURI?.external_url }} />
</Box>

{typeof founders !== 'undefined' && founders.length > 0 ? (
<>
<Text variant="heading-xs" mt="x16" style={{ fontWeight: 800 }}>
Founders
</Text>
<Grid columns={isMobile ? 1 : 2} mt="x6" gap="x4">
{founders.map((founder) => (
<Founder {...founder} />
))}
</Grid>
</>
) : null}
</Box>
)
}
69 changes: 69 additions & 0 deletions apps/web/src/modules/dao/components/About/Founder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Box, Flex, PopUp, Text } from '@zoralabs/zord'
import { useState } from 'react'

import { Avatar } from 'src/components/Avatar'
import { Icon } from 'src/components/Icon'
import { ETHERSCAN_BASE_URL } from 'src/constants/etherscan'
import { useEnsData } from 'src/hooks'
import { AddressType } from 'src/typings'

interface FounderProps {
wallet: AddressType
ownershipPct: number
vestExpiry: number
}

export const Founder: React.FC<FounderProps> = ({ wallet, ownershipPct, vestExpiry }) => {
const [showTooltip, setShowTooltip] = useState(false)
const { displayName, ensAvatar } = useEnsData(wallet as string)
const vestDate = new Date(vestExpiry * 1000).toLocaleDateString(undefined, {
year: 'numeric',
month: 'short',
day: 'numeric',
})
return (
<Flex
direction={'row'}
align={'center'}
justify={'space-between'}
w={'100%'}
borderStyle="solid"
borderColor="border"
borderWidth="normal"
borderRadius="curved"
p="x4"
px="x6"
>
<Flex direction={'row'} align={'center'}>
<Avatar address={wallet} src={ensAvatar} size={'40'} />
<Flex direction={'column'} ml={'x2'}>
<Text
as="a"
target="_blank"
rel="noreferrer noopener"
href={`${ETHERSCAN_BASE_URL}/address/${wallet}`}
fontWeight={'display'}
>
{displayName}
</Text>
</Flex>
</Flex>
<Flex align={'center'} justify="center">
<Text fontWeight={'display'} mr="x2">
{ownershipPct}%
</Text>
<Box
cursor="pointer"
style={{ zIndex: 102 }}
onMouseOver={() => setShowTooltip(true)}
onMouseLeave={() => setShowTooltip(false)}
>
<Icon id="info-16" size="sm" />
</Box>
<PopUp open={showTooltip} trigger={<></>}>
<Box>{`In effect until ${vestDate}`}</Box>
</PopUp>
</Flex>
</Flex>
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Provider } from '@ethersproject/abstract-provider'
import * as Yup from 'yup'

import { auctionSettingsValidationSchema } from 'src/modules/create-dao'
import { TokenAllocation, auctionSettingsValidationSchema } from 'src/modules/create-dao'
import { allocationSchema } from 'src/modules/create-dao/components/AllocationForm/AllocationForm.schema'
import { Duration } from 'src/typings'
import { isValidAddress } from 'src/utils/ens'
import { durationValidationSchema, urlValidationSchema } from 'src/utils/yup'
Expand All @@ -17,6 +18,7 @@ export interface AdminFormValues {
quorumThreshold: number
votingPeriod: Duration
votingDelay: Duration
founderAllocation: TokenAllocation[]
vetoPower: boolean
vetoer: string
}
Expand Down Expand Up @@ -48,6 +50,16 @@ export const adminValidationSchema = (provider: Provider | undefined) =>
{ value: tenMinutes, description: '10 minutes' },
{ value: twentyFourWeeks, description: '24 weeks' }
),
founderAllocation: Yup.array()
.of(allocationSchema)
.test(
'unique',
'Founder allocation addresses should be unique.',
function (values) {
const addresses = values?.map((v) => v.founderAddress)
return values?.length === new Set(addresses)?.size
}
),
vetoPower: Yup.bool().required('*'),
})
)
Loading

0 comments on commit af2cd6c

Please sign in to comment.