fix slider, submit and edit contribution screens
This commit is contained in:
parent
0ecbe23f41
commit
a55ea4ed74
|
@ -1,4 +1,37 @@
|
|||
import { FunctionComponent } from 'react'
|
||||
import styled from '@emotion/styled'
|
||||
import tw from 'twin.macro'
|
||||
|
||||
type StyledButtonProps = {
|
||||
secondary: boolean
|
||||
}
|
||||
|
||||
const StyledButton = styled.button<StyledButtonProps>`
|
||||
:before {
|
||||
${tw`absolute left-0 top-0 opacity-0 h-full w-full block bg-gradient-to-tl from-secondary-1-light via-secondary-1-dark to-secondary-2-light transition-opacity duration-500`}
|
||||
border-radius: inherit;
|
||||
content: '';
|
||||
z-index: -10;
|
||||
}
|
||||
|
||||
:hover {
|
||||
:before {
|
||||
${tw`opacity-100`};
|
||||
${({ disabled, secondary }) => (disabled || secondary) && tw`hidden`}
|
||||
}
|
||||
}
|
||||
|
||||
:focus {
|
||||
${tw`ring-4 ring-secondary-2-light ring-opacity-40`}
|
||||
${({ secondary }) => secondary && tw`ring-0`}
|
||||
}
|
||||
|
||||
:active {
|
||||
:before {
|
||||
${tw`ring-4 ring-secondary-2-light ring-opacity-40`}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
interface ButtonProps {
|
||||
onClick?: (x?) => void
|
||||
|
@ -16,20 +49,21 @@ const Button: FunctionComponent<ButtonProps> = ({
|
|||
...props
|
||||
}) => {
|
||||
return (
|
||||
<button
|
||||
<StyledButton
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
className={`${className} ${
|
||||
secondary || disabled
|
||||
? 'bg-bkg-4'
|
||||
: 'bg-gradient-to-br from-secondary-1-light via-secondary-1-dark to-secondary-2-light'
|
||||
} bg-bkg-4 border-none default-transition px-6 py-2 rounded-lg text-fgd-1
|
||||
active:border-primary hover:bg-bkg-3 focus:outline-none
|
||||
} relative z-10 bg-bkg-4 border-none default-transition px-6 py-2 rounded-lg text-fgd-1
|
||||
active:border-primary hover:bg-bkg-3 focus:outline-none
|
||||
disabled:cursor-not-allowed`}
|
||||
secondary={secondary}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
</StyledButton>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import { WALLET_PROVIDERS, DEFAULT_PROVIDER } from '../hooks/useWallet'
|
|||
import useLocalStorageState from '../hooks/useLocalStorageState'
|
||||
import WalletSelect from './WalletSelect'
|
||||
import WalletIcon from './WalletIcon'
|
||||
import Button from './Button'
|
||||
|
||||
const StyledWalletTypeLabel = styled.div`
|
||||
font-size: 0.6rem;
|
||||
|
@ -43,3 +44,15 @@ const ConnectWalletButton = () => {
|
|||
}
|
||||
|
||||
export default ConnectWalletButton
|
||||
|
||||
export const ConnectWalletButtonSmall = ({ children, onClick }) => (
|
||||
<div className="relative">
|
||||
<Button
|
||||
className="rounded-full h-9 w-44 z-30 relative"
|
||||
onClick={() => onClick()}
|
||||
>
|
||||
<div className="flex items-center justify-center text-sm">{children}</div>
|
||||
</Button>
|
||||
<div className="absolute animate-ping-small bg-secondary-2-light top-0 rounded-full h-9 w-44 z-20" />
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -1,24 +1,43 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import { LinkIcon } from '@heroicons/react/solid'
|
||||
import styled from '@emotion/styled'
|
||||
import tw from 'twin.macro'
|
||||
import {
|
||||
LinkIcon,
|
||||
LockClosedIcon,
|
||||
LockOpenIcon,
|
||||
} from '@heroicons/react/outline'
|
||||
import useWalletStore from '../stores/useWalletStore'
|
||||
import { getUsdcBalance } from '../utils'
|
||||
import Input from './Input'
|
||||
import Button from './Button'
|
||||
import { ConnectWalletButtonSmall } from './ConnectWalletButton'
|
||||
import Slider from './Slider'
|
||||
import Loading from './Loading'
|
||||
import WalletIcon from './WalletIcon'
|
||||
|
||||
const StyledModalWrapper = styled.div`
|
||||
height: 414px;
|
||||
${tw`bg-bkg-2 border border-bkg-3 flex flex-col items-center rounded-lg shadow-lg p-7 w-96`}
|
||||
}
|
||||
`
|
||||
|
||||
const ContributionModal = () => {
|
||||
const connected = useWalletStore((s) => s.connected)
|
||||
const wallet = useWalletStore((s) => s.current)
|
||||
const usdcBalance = getUsdcBalance()
|
||||
|
||||
const [contributionAmount, setContributionAmount] = useState(null)
|
||||
const [sliderPercentage, setSliderPercentage] = useState(null)
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
const [submitted, setSubmitted] = useState(false)
|
||||
const [editContribution, setEditContribution] = useState(false)
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
const handleConnectDisconnect = () => {
|
||||
if (connected) {
|
||||
setContributionAmount(null)
|
||||
setSubmitted(false)
|
||||
setEditContribution(false)
|
||||
wallet.disconnect()
|
||||
} else {
|
||||
wallet.connect()
|
||||
|
@ -27,6 +46,27 @@ const ContributionModal = () => {
|
|||
|
||||
const handleSetContribution = () => {
|
||||
setSubmitting(true)
|
||||
setEditContribution(false)
|
||||
}
|
||||
|
||||
const handleEditContribution = () => {
|
||||
setEditContribution(true)
|
||||
setSubmitted(false)
|
||||
}
|
||||
|
||||
const onChangeAmountInput = (amount) => {
|
||||
setContributionAmount(amount)
|
||||
setSliderPercentage((amount / usdcBalance) * 100)
|
||||
}
|
||||
|
||||
const onChangeSlider = (percentage) => {
|
||||
setContributionAmount((percentage / 100) * usdcBalance)
|
||||
setSliderPercentage(percentage)
|
||||
}
|
||||
|
||||
const handleMax = () => {
|
||||
setContributionAmount(usdcBalance)
|
||||
setSliderPercentage(100)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -37,107 +77,164 @@ const ContributionModal = () => {
|
|||
}, [usdcBalance])
|
||||
|
||||
useEffect(() => {
|
||||
const submitTimer = setTimeout(() => {
|
||||
setSubmitting(false)
|
||||
}, 1000)
|
||||
return () => clearTimeout(submitTimer)
|
||||
if (submitting) {
|
||||
const submitTimer = setTimeout(() => {
|
||||
setSubmitted(true)
|
||||
setSubmitting(false)
|
||||
}, 2000)
|
||||
return () => clearTimeout(submitTimer)
|
||||
}
|
||||
}, [submitting])
|
||||
|
||||
return (
|
||||
<div className="bg-bkg-2 border border-bkg-3 flex flex-col items-center rounded-lg shadow-lg p-7 w-96">
|
||||
<StyledModalWrapper>
|
||||
<div className="pb-4 text-center">
|
||||
<h2>Plant your seed</h2>
|
||||
<p>This is the start of something big.</p>
|
||||
{!submitted && !submitting && !editContribution ? (
|
||||
<>
|
||||
<h2>Plant your seed</h2>
|
||||
<p>This is the start of something big.</p>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{!submitted && submitting ? (
|
||||
<>
|
||||
<h2>Approve the transaction</h2>
|
||||
<p>Almost there...</p>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{submitted && !submitting ? (
|
||||
<>
|
||||
<h2>Your contribution amount</h2>
|
||||
<p>A new seed planted...</p>
|
||||
</>
|
||||
) : null}
|
||||
|
||||
{editContribution && !submitting ? (
|
||||
<>
|
||||
<h2>Funds unlocked</h2>
|
||||
<p>Increase or reduce your contribution...</p>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
<div
|
||||
className={`${
|
||||
connected ? 'opacity-100' : 'opacity-30'
|
||||
} pb-6 transiton-all duration-1000 w-full`}
|
||||
>
|
||||
<div className="pb-20">
|
||||
<div className="flex justify-between pb-2">
|
||||
<div className="flex items-center text-xs text-fgd-4">
|
||||
<WalletIcon className="w-4 h-4 mr-1 text-secondary-1-dark fill-current" />
|
||||
{connected ? (
|
||||
loading ? (
|
||||
<div className="bg-bkg-4 rounded w-10 h-4 animate-pulse" />
|
||||
{submitting ? (
|
||||
<div className="flex items-center h-full">
|
||||
<Loading className="h-6 w-6 mb-3 text-primary-light" />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
className={`${
|
||||
connected ? 'opacity-100' : 'opacity-30'
|
||||
} pb-6 transiton-all duration-1000 w-full`}
|
||||
>
|
||||
<div className="flex justify-between pb-2">
|
||||
<div className="flex items-center text-xs text-fgd-4">
|
||||
<WalletIcon className="w-4 h-4 mr-1 text-fgd-3 fill-current" />
|
||||
{connected ? (
|
||||
loading ? (
|
||||
<div className="bg-bkg-4 rounded w-10 h-4 animate-pulse" />
|
||||
) : (
|
||||
<span className="font-display text-fgd-1 ml-1">
|
||||
{usdcBalance}
|
||||
</span>
|
||||
)
|
||||
) : (
|
||||
<span className="font-display text-fgd-1 ml-1">
|
||||
{usdcBalance}
|
||||
</span>
|
||||
)
|
||||
) : (
|
||||
'----'
|
||||
)}
|
||||
<img
|
||||
alt=""
|
||||
width="16"
|
||||
height="16"
|
||||
src="/icons/usdc.svg"
|
||||
className={`ml-1`}
|
||||
'----'
|
||||
)}
|
||||
<img
|
||||
alt=""
|
||||
width="16"
|
||||
height="16"
|
||||
src="/icons/usdc.svg"
|
||||
className={`ml-1`}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex">
|
||||
{submitted ? (
|
||||
<Button
|
||||
className="bg-secondary-2-light hover:bg-secondary-2-dark font-normal rounded text-fgd-1 text-xs py-0.5 px-1.5 mr-2"
|
||||
disabled={!connected}
|
||||
onClick={() => handleEditContribution()}
|
||||
secondary
|
||||
>
|
||||
Unlock
|
||||
</Button>
|
||||
) : null}
|
||||
<Button
|
||||
className={`${
|
||||
submitted && 'opacity-30'
|
||||
} bg-bkg-4 font-normal rounded text-fgd-3 text-xs py-0.5 px-1.5`}
|
||||
disabled={!connected || submitted}
|
||||
onClick={() => handleMax()}
|
||||
secondary
|
||||
>
|
||||
Max
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center pb-4 relative">
|
||||
{submitted ? (
|
||||
<LockClosedIcon className="absolute text-secondary-2-light h-4 w-4 mb-0.5 left-2 z-10" />
|
||||
) : null}
|
||||
{editContribution ? (
|
||||
<LockOpenIcon className="absolute text-secondary-1-light h-4 w-4 mb-0.5 left-2 z-10" />
|
||||
) : null}
|
||||
<Input
|
||||
className={(submitted || editContribution) && 'pl-7'}
|
||||
disabled={!connected || submitted || loading}
|
||||
type="text"
|
||||
onChange={(e) => onChangeAmountInput(e.target.value)}
|
||||
value={loading ? '' : contributionAmount}
|
||||
suffix="USDC"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={`${
|
||||
!submitted ? 'opacity-100' : 'opacity-30'
|
||||
} transiton-all duration-1000`}
|
||||
>
|
||||
<div className="pb-20">
|
||||
<Slider
|
||||
disabled={submitted || !connected || loading}
|
||||
value={sliderPercentage}
|
||||
onChange={(v) => onChangeSlider(v)}
|
||||
step={1}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => handleSetContribution()}
|
||||
className="w-full py-2.5"
|
||||
disabled={!connected || submitted}
|
||||
>
|
||||
<div className={`flex items-center justify-center`}>
|
||||
Set Contribution
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{connected ? (
|
||||
<Button
|
||||
className="bg-bkg-4 font-normal rounded text-fgd-3 text-xs py-0.5 px-2"
|
||||
disabled={!connected}
|
||||
onClick={() => setContributionAmount(100)}
|
||||
className="rounded-full bg-bkg-4 text-fgd-3 font-normal"
|
||||
onClick={() => handleConnectDisconnect()}
|
||||
secondary
|
||||
>
|
||||
Max
|
||||
<div className="flex items-center text-sm">
|
||||
<LinkIcon className="h-4 w-4 mr-1" />
|
||||
Disconnect
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="pb-4">
|
||||
<Input
|
||||
disabled={!connected}
|
||||
type="text"
|
||||
onChange={(e) => setContributionAmount(e.target.value)}
|
||||
value={loading ? '' : usdcBalance * (contributionAmount / 100)}
|
||||
suffix="USDC"
|
||||
/>
|
||||
</div>
|
||||
<Slider
|
||||
value={contributionAmount}
|
||||
onChange={(v) => setContributionAmount(v)}
|
||||
step={usdcBalance / 100}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => handleSetContribution()}
|
||||
className="w-full py-2.5"
|
||||
disabled={!connected}
|
||||
>
|
||||
<div className={`flex items-center justify-center`}>
|
||||
{submitting && <Loading />}
|
||||
Set Contribution
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
{connected ? (
|
||||
<Button
|
||||
className="rounded-full bg-bkg-4 text-fgd-3 font-normal"
|
||||
onClick={() => handleConnectDisconnect()}
|
||||
secondary
|
||||
>
|
||||
<div className="flex items-center text-sm">
|
||||
<LinkIcon className="h-4 w-4 mr-1" />
|
||||
Disconnect
|
||||
</div>
|
||||
</Button>
|
||||
) : (
|
||||
<div className="relative">
|
||||
<Button
|
||||
className="rounded-full h-9 w-44 z-20 relative"
|
||||
onClick={() => handleConnectDisconnect()}
|
||||
>
|
||||
<div className="flex items-center justify-center text-sm">
|
||||
<LinkIcon className="h-4 w-4 mr-1" />
|
||||
Connect Wallet
|
||||
</div>
|
||||
</Button>
|
||||
<div className="absolute animate-ping-small bg-secondary-2-light top-0 rounded-full h-9 w-44 z-10" />
|
||||
</div>
|
||||
) : (
|
||||
<ConnectWalletButtonSmall onClick={handleConnectDisconnect}>
|
||||
<div className="flex items-center justify-center text-sm">
|
||||
<LinkIcon className="h-4 w-4 mr-1" />
|
||||
Connect Wallet
|
||||
</div>
|
||||
</ConnectWalletButtonSmall>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</StyledModalWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ const Input = ({
|
|||
className={`${className} font-display px-2 py-2 w-full bg-bkg-1 rounded text-fgd-1
|
||||
border border-fgd-4 default-transition hover:border-primary-dark
|
||||
focus:border-primary-light focus:outline-none
|
||||
${disabled ? 'cursor-not-allowed hover:border-fgd-4' : ''}
|
||||
${disabled ? 'cursor-not-allowed hover:border-fgd-4 text-fgd-3' : ''}
|
||||
${prefix ? 'rounded-l-none' : ''}`}
|
||||
disabled={disabled}
|
||||
{...props}
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
const Loading = () => {
|
||||
import { FunctionComponent } from 'react'
|
||||
|
||||
interface LoadingProps {
|
||||
className?: string
|
||||
}
|
||||
|
||||
const Loading: FunctionComponent<LoadingProps> = ({ className }) => {
|
||||
return (
|
||||
<svg
|
||||
className={`animate-spin -ml-1 mr-3 h-5 w-5`}
|
||||
className={`${className} animate-spin h-5 w-5`}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
|
@ -15,7 +21,7 @@ const Loading = () => {
|
|||
strokeWidth="4"
|
||||
></circle>
|
||||
<path
|
||||
className={`opacity-75`}
|
||||
className={`opacity-90`}
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
></path>
|
||||
|
|
|
@ -5,7 +5,8 @@ import Slider from 'rc-slider'
|
|||
import 'rc-slider/assets/index.css'
|
||||
|
||||
type StyledSliderProps = {
|
||||
enableTransition: boolean
|
||||
enableTransition?: boolean
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
const StyledSlider = styled(Slider)<StyledSliderProps>`
|
||||
|
@ -14,12 +15,10 @@ const StyledSlider = styled(Slider)<StyledSliderProps>`
|
|||
}
|
||||
|
||||
.rc-slider-track {
|
||||
${tw`bg-gradient-to-r from-secondary-1-light via-primary-light to-secondary-2-light h-2.5 rounded-full`}
|
||||
${tw`bg-gradient-to-r from-secondary-1-dark via-primary-light to-secondary-2-light h-2.5 rounded-full ring-1 ring-primary-light ring-inset`}
|
||||
|
||||
${({ enableTransition }) =>
|
||||
enableTransition && tw`transition-all duration-500`}
|
||||
|
||||
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.rc-slider-step {
|
||||
|
@ -29,11 +28,11 @@ const StyledSlider = styled(Slider)<StyledSliderProps>`
|
|||
.rc-slider-handle {
|
||||
${tw`bg-fgd-1 border-4 border-primary-dark h-4 w-4`}
|
||||
|
||||
${({ enableTransition }) =>
|
||||
enableTransition && tw`transition-all duration-500`}
|
||||
|
||||
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.3);
|
||||
margin-top: -3px;
|
||||
|
||||
${({ enableTransition }) =>
|
||||
enableTransition && tw`transition-all duration-500`}
|
||||
}
|
||||
|
||||
.rc-slider-mark-text {
|
||||
|
@ -52,12 +51,16 @@ const StyledSlider = styled(Slider)<StyledSliderProps>`
|
|||
.rc-slider-mark-text:last-of-type {
|
||||
padding-right: 24px;
|
||||
}
|
||||
|
||||
${({ disabled }) => disabled && 'background-color: transparent'}
|
||||
`
|
||||
|
||||
type SliderProps = {
|
||||
onChange: (...args: any[]) => any
|
||||
step: number
|
||||
value: number
|
||||
disabled: boolean
|
||||
max?: number
|
||||
}
|
||||
|
||||
const marks = {
|
||||
|
@ -72,12 +75,15 @@ const AmountSlider: FunctionComponent<SliderProps> = ({
|
|||
onChange,
|
||||
step,
|
||||
value,
|
||||
disabled,
|
||||
max,
|
||||
}) => {
|
||||
const [enableTransition, setEnableTransition] = useState(true)
|
||||
|
||||
return (
|
||||
<StyledSlider
|
||||
min={0}
|
||||
max={max}
|
||||
value={value || 0}
|
||||
onChange={onChange}
|
||||
step={step}
|
||||
|
@ -85,6 +91,7 @@ const AmountSlider: FunctionComponent<SliderProps> = ({
|
|||
enableTransition={enableTransition}
|
||||
onBeforeChange={() => setEnableTransition(false)}
|
||||
onAfterChange={() => setEnableTransition(true)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue