feat: implement wallet connect dropdown

This commit is contained in:
jinhojang6 2024-10-22 01:13:17 +09:00
parent e9cd02826d
commit 5e75d92dbb
No known key found for this signature in database
GPG Key ID: 1762F21FE8B543F8
4 changed files with 286 additions and 153 deletions

View File

@ -1,4 +1,3 @@
import { Collapse } from '@/components/common/Collapse'
import { breakpoints } from '@/configs/ui.configs'
import { truncateString } from '@/utils/general.utils'
import styled from '@emotion/styled'
@ -9,33 +8,33 @@ import useGetPillars from '../../../../apis/general/useGetPillars'
interface OperatorPanelProps {}
const TEMP_BADGES = [
{
id: 1,
image: '/dashboard/badges/1-year-streak.svg',
},
{
id: 2,
image: '/dashboard/badges/10-day-streak.svg',
},
{
id: 3,
image: '/dashboard/badges/100-days-streak.svg',
},
{
id: 4,
image: '/dashboard/badges/badege-placeholder.svg',
},
]
// const TEMP_BADGES = [
// {
// id: 1,
// image: '/dashboard/badges/1-year-streak.svg',
// },
// {
// id: 2,
// image: '/dashboard/badges/10-day-streak.svg',
// },
// {
// id: 3,
// image: '/dashboard/badges/100-days-streak.svg',
// },
// {
// id: 4,
// image: '/dashboard/badges/badege-placeholder.svg',
// },
// ]
const OperatorPanel: React.FC<OperatorPanelProps> = () => {
const { data: currentBlock } = useGetCurrentBTCBlock()
const { data: epochs } = useGetEpochs()
const { data: pillars } = useGetPillars()
console.log('currentBlock', currentBlock)
console.log('epochs', epochs)
console.log('pillars', pillars)
// console.log('currentBlock', currentBlock)
// console.log('epochs', epochs)
// console.log('pillars', pillars)
return (
<StyledPanel>
@ -79,7 +78,7 @@ const OperatorPanel: React.FC<OperatorPanelProps> = () => {
</InfoRow>
</CallSignContainer>
<ProfileInfo>
{/* <ProfileInfo>
<BadgesSection>
<BadgeTitle>
<Label>Badges</Label>
@ -95,12 +94,12 @@ const OperatorPanel: React.FC<OperatorPanelProps> = () => {
))}
</BadgeList>
</BadgesSection>
</ProfileInfo>
</ProfileInfo> */}
<Collapse
{/* <Collapse
header="Refer Operators +100 XP"
content={truncateString('445f5slk1as4645sdf54')}
/>
/> */}
</StyledPanel>
)
}
@ -159,11 +158,11 @@ const InfoRow = styled.div`
background-color: var(--grey-900);
`
const ProfileInfo = styled.div`
display: flex;
flex-direction: column;
gap: 2px;
`
// const ProfileInfo = styled.div`
// display: flex;
// flex-direction: column;
// gap: 2px;
// `
const CallSignContainer = styled.div`
margin-top: 24px;
@ -187,38 +186,38 @@ const Value = styled.span`
}
`
const BadgesSection = styled.div`
display: flex;
flex-direction: column;
background-color: var(--grey-900);
padding: 16px 8px;
`
// const BadgesSection = styled.div`
// display: flex;
// flex-direction: column;
// background-color: var(--grey-900);
// padding: 16px 8px;
// `
const BadgeTitle = styled.div`
display: flex;
align-items: center;
margin-bottom: 16px;
width: 100%;
`
// const BadgeTitle = styled.div`
// display: flex;
// align-items: center;
// margin-bottom: 16px;
// width: 100%;
// `
const BadgeIcon = styled.img`
width: 14px;
height: 14px;
// const BadgeIcon = styled.img`
// width: 14px;
// height: 14px;
margin-left: auto;
`
// margin-left: auto;
// `
const BadgeList = styled.div`
display: flex;
flex-wrap: wrap;
gap: 16px;
`
// const BadgeList = styled.div`
// display: flex;
// flex-wrap: wrap;
// gap: 16px;
// `
const Badge = styled.img`
width: 52px;
height: 52px;
object-fit: contain;
`
// const Badge = styled.img`
// width: 52px;
// height: 52px;
// object-fit: contain;
// `
const ActionButton = styled.button`
display: flex;

View File

@ -1,11 +1,9 @@
import HamburguerMenu from '@/components/HamburgerMenu/HamburgerMenu'
import { WalletConnect } from '@/components/WalletConnect'
import { breakpoints } from '@/configs/ui.configs'
import { truncateString } from '@/utils/general.utils'
import styled from '@emotion/styled'
import Link from 'next/link'
import React, { useState } from 'react'
import { api } from '../../../../common/api'
import { WALLET_SIGN_MESSAGE_REQUEST } from '../../../../constants/wallet'
import React from 'react'
import { Navbar } from '../Navbar'
declare global {
@ -18,42 +16,6 @@ declare global {
interface NavbarProps {}
const Header: React.FC<NavbarProps> = () => {
const [walletAddress, setWalletAddress] = useState<string | null>(null)
const connectWallet = async () => {
try {
if (walletAddress) {
setWalletAddress(null)
alert('Wallet disconnected.')
} else {
if (window.okxwallet) {
// DOCS: https://www.okx.com/web3/build/docs/sdks/chains/bitcoin/provider#connect
const result = await window.okxwallet.bitcoin.connect()
const address = result.address
setWalletAddress(address)
// Docs: https://www.okx.com/web3/build/docs/sdks/chains/bitcoin/provider#signmessage
const signature = await window.okxwallet.bitcoin.signMessage(
WALLET_SIGN_MESSAGE_REQUEST,
'bip322-simple',
)
const response = await api.post('/token/pair', {
address,
signature,
})
console.log('Token pair response:', response)
} else {
alert('No Bitcoin wallet found. Please install OKX Wallet.')
}
}
} catch (error) {
console.error('Failed to connect or disconnect wallet:', error)
}
}
return (
<Container>
<Link href="/">
@ -72,7 +34,7 @@ const Header: React.FC<NavbarProps> = () => {
<span>Gitbook</span>
</GitbookButton>
</Link>
<Link
{/* <Link
href="https://discord.com/invite/logosnetwork"
passHref
target="_blank"
@ -81,18 +43,9 @@ const Header: React.FC<NavbarProps> = () => {
<span>Join our Discord</span>
<Icon src="/icons/discord-white.svg" alt="Discord" />
</SocialButton>
</Link>
</Link> */}
<WalletConnect />
<HamburguerMenu />
<WalletButton onClick={connectWallet}>
<WalletAddress>
{walletAddress ? truncateString(walletAddress) : 'Connect'}
</WalletAddress>
{/* <Icon src="/assets/btc.svg" alt="Wallet icon" /> */}
</WalletButton>
{/* <PointsButton>
<PointsValue>4,278</PointsValue>
<Icon src="/assets/star.png" alt="Points icon" />
</PointsButton> */}
</UserActions>
</Container>
)
@ -129,30 +82,15 @@ const UserActions = styled.div`
}
`
const Button = styled.button`
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 12px;
height: 28px;
font-weight: 400;
font-size: 12px;
line-height: 16px;
border: 1px solid rgb(var(--lsd-border-primary));
background: transparent;
color: rgb(var(--lsd-text-primary));
cursor: pointer;
`
// const SocialButton = styled(Button)`
// width: 142px;
// box-sizing: border-box;
// gap: 12px;
const SocialButton = styled(Button)`
width: 142px;
box-sizing: border-box;
gap: 12px;
span {
white-space: nowrap;
}
`
// span {
// white-space: nowrap;
// }
// `
const DesktopNavbar = styled.div`
position: absolute;
@ -164,26 +102,6 @@ const DesktopNavbar = styled.div`
}
`
const WalletButton = styled(Button)`
width: fit-content;
`
const WalletAddress = styled.span`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`
// const PointsButton = styled(Button)`
// width: 83px;
// `
// const PointsValue = styled.span``
const Icon = styled.img`
padding: 0;
`
const GitbookButton = styled.button`
display: flex;
padding: 6px 12px;

View File

@ -0,0 +1,215 @@
import { truncateString } from '@/utils/general.utils'
import styled from '@emotion/styled'
import React, { useEffect, useRef, useState } from 'react'
import { api } from '../../../common/api'
import { WALLET_SIGN_MESSAGE_REQUEST } from '../../../constants/wallet'
const options = [
{ label: 'Multiplass', value: 'multiplass' },
{ label: 'Unisat', value: 'unisat' },
{ label: 'Magic Eden', value: 'magic-eden' },
{ label: 'Phantom', value: 'phantom' },
{ label: 'OKX', value: 'okx' },
]
const Dropdown: React.FC = () => {
const [isExpanded, setIsExpanded] = useState(false)
const [walletAddress, setWalletAddress] = useState<string | null>(null)
const connectWallet = async (wallet: string) => {
try {
if (walletAddress) {
setWalletAddress(null)
alert('Wallet disconnected.')
} else {
if (wallet === 'okx' && window.okxwallet) {
// Docs: https://www.okx.com/web3/build/docs/sdks/chains/bitcoin/provider#connect
const result = await window.okxwallet.bitcoin.connect()
const address = result.address
setWalletAddress(address)
// Docs: https://www.okx.com/web3/build/docs/sdks/chains/bitcoin/provider#signmessage
const signature = await window.okxwallet.bitcoin.signMessage(
WALLET_SIGN_MESSAGE_REQUEST,
'bip322-simple',
)
const response = await api.post('/token/pair', {
address,
signature,
})
console.log('Token pair response:', response)
} else {
alert('Only OKX wallet is supported for now.')
}
}
} catch (error) {
console.error('Failed to connect or disconnect wallet:', error)
}
}
const dropdownRef = useRef<HTMLDivElement>(null)
const toggleDropdown = () => {
setIsExpanded(!isExpanded)
}
const handleClickOutside = (event: MouseEvent) => {
if (
dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node)
) {
setIsExpanded(false)
}
}
useEffect(() => {
if (isExpanded) {
document.addEventListener('mousedown', handleClickOutside)
} else {
document.removeEventListener('mousedown', handleClickOutside)
}
return () => {
document.removeEventListener('mousedown', handleClickOutside)
}
}, [isExpanded])
return (
<DropdownContainer ref={dropdownRef}>
<DropdownHeader onClick={toggleDropdown} isExpanded={isExpanded}>
<div>
<WalletButton>
<WalletAddress>
{walletAddress ? truncateString(walletAddress) : 'Connect Wallet'}
</WalletAddress>
<Icon src="/assets/chevron-down.svg" alt="Wallet icon" />
</WalletButton>
{isExpanded && (
<DropdownContent>
<ScrollDiv>
{options.map((option, index) => (
<WalletName
onClick={() => connectWallet(option.value)}
key={'wallet-' + index}
>
{option.label}
</WalletName>
))}
</ScrollDiv>
</DropdownContent>
)}
</div>
{walletAddress && (
<PointsButton>
<PointsValue>4,278 XP</PointsValue>
</PointsButton>
)}
</DropdownHeader>
</DropdownContainer>
)
}
const DropdownContainer = styled.div`
position: relative;
display: inline-block;
@media (max-width: 768px) {
width: 100%;
}
`
const DropdownHeader = styled.div<{ isExpanded: boolean }>`
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
font-size: 14px;
line-height: 20px;
`
const ScrollDiv = styled.div`
box-sizing: border-box;
`
const WalletName = styled.div`
font-size: 12px;
line-height: 16px;
border-bottom: 1px solid rgb(var(--lsd-border-primary));
display: flex;
padding: 6px 10px 6px 12px;
align-items: center;
align-self: stretch;
cursor: pointer;
&:last-of-type {
border-bottom: none;
}
`
const WalletButton = styled.button`
width: fit-content;
padding: 0 10px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 12px;
height: 28px;
font-size: 12px;
line-height: 16px;
border: 1px solid rgb(var(--lsd-border-primary));
background: transparent;
color: rgb(var(--lsd-text-primary));
cursor: pointer;
`
const WalletAddress = styled.span`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-width: 90px;
`
const Icon = styled.img`
padding: 0;
margin-left: 10px;
`
const DropdownContent = styled.div`
position: absolute;
top: 28px;
left: 0;
width: 100%;
background-color: black;
border: 1px solid white;
border-top: none;
z-index: 10;
box-sizing: border-box;
`
const PointsButton = styled.button`
display: flex;
align-items: center;
justify-content: center;
width: fit-content;
position: absolute;
background-color: transparent;
cursor: pointer;
height: 28px;
border: 1px solid rgb(var(--lsd-border-primary));
padding: 8px 12px;
top: 36px;
right: 0;
`
const PointsValue = styled.span`
font-size: 12px;
line-height: 16px;
white-space: nowrap;
color: white;
`
export default Dropdown

View File

@ -0,0 +1 @@
export { default as WalletConnect } from './WalletConnect'