feat: implement Collapse-related components

This commit is contained in:
jinhojang6 2024-10-30 00:50:01 +09:00
parent 7049314828
commit 8489ea85fe
No known key found for this signature in database
GPG Key ID: 1762F21FE8B543F8
9 changed files with 190 additions and 42 deletions

View File

@ -11,7 +11,11 @@ export const fetchData = async () => {
return await api.get('/epochs').then((res) => res.data)
}
const useGetEpochs = () => {
interface Props {
enabled: boolean
}
const useGetEpochs = ({ enabled }: Props) => {
const queryKey = ['getEpochs']
const queryClient = useQueryClient()
@ -22,6 +26,7 @@ const useGetEpochs = () => {
const response = useQuery({
queryKey: queryKey,
queryFn: fetchData,
enabled,
...useQueryOptions,
})

View File

@ -7,11 +7,15 @@ const useQueryOptions = {
retry: 1,
}
interface Props {
enabled: boolean
}
export const fetchData = async () => {
return await api.get('/user/xp').then((res) => res.data)
}
const useGetUserXP = () => {
const useGetUserXP = ({ enabled }: Props) => {
const queryKey = ['getUserXP']
const queryClient = useQueryClient()
@ -22,6 +26,7 @@ const useGetUserXP = () => {
const response = useQuery({
queryKey: queryKey,
queryFn: fetchData,
enabled,
...useQueryOptions,
})

View File

@ -0,0 +1,3 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.34999 7L4.66666 4.31667L5.48332 3.5L8.98332 7L5.48332 10.5L4.66666 9.68333L7.34999 7Z" fill="#260324"/>
</svg>

After

Width:  |  Height:  |  Size: 219 B

View File

@ -1,3 +1,5 @@
import CopyCode from '@/components/common/Collapse/CopyCode'
import EnterXPCode from '@/components/common/Collapse/EnterXPCode'
import { breakpoints } from '@/configs/ui.configs'
import { truncateString } from '@/utils/general.utils'
import styled from '@emotion/styled'
@ -136,10 +138,10 @@ const OperatorPanel: React.FC<OperatorPanelProps> = () => {
</BadgesSection>
</ProfileInfo> */}
{/* <Collapse
header="Refer Operators +100 XP"
content={truncateString('445f5slk1as4645sdf54')}
/> */}
<CollapseContainer>
<EnterXPCode />
<CopyCode />
</CollapseContainer>
</StyledPanel>
)
}
@ -160,6 +162,13 @@ const Profile = styled.div`
}
`
const CollapseContainer = styled.div`
display: flex;
flex-direction: column;
gap: 2px;
margin-top: 24px;
`
const OperatorImage = styled.img`
width: 100%;
aspect-ratio: 1;

View File

@ -4,7 +4,6 @@ import styled from '@emotion/styled'
import { useAtomValue } from 'jotai'
import React from 'react'
import useGetEpochs from '../../../../apis/general/useGetEpochs'
import useGetUserXP from '../../../../apis/general/useGetUserXP'
import { userInfoAtom } from '../../../../atoms/userInfo'
interface ProgressBarProps {
@ -16,10 +15,12 @@ const ProgressBar: React.FC<ProgressBarProps> = ({
progress = 0,
claimPosition = 76,
}) => {
const { data: epochs } = useGetEpochs()
const { data: userXP } = useGetUserXP()
console.log('userXP', userXP)
const user = useAtomValue(userInfoAtom)
const { data: epochs } = useGetEpochs({
enabled: user?.address?.length > 0,
})
// const { data: currentBlock } = useGetCurrentBTCBlock()
// const { data: pillars } = useGetPillars()

View File

@ -3,26 +3,16 @@ import React, { useState } from 'react'
interface CollapsibleProps {
header: string
content: string
enableCopy?: boolean
children: React.ReactNode
}
const Collapse: React.FC<CollapsibleProps> = ({
header,
content,
enableCopy = true,
}) => {
const Collapse: React.FC<CollapsibleProps> = ({ header, children }) => {
const [isOpen, setIsOpen] = useState(false)
const toggleOpen = () => {
setIsOpen(!isOpen)
}
const copyToClipboard = () => {
navigator.clipboard.writeText(content)
alert('Copied to clipboard!')
}
return (
<Container>
<Header onClick={toggleOpen}>
@ -35,14 +25,7 @@ const Collapse: React.FC<CollapsibleProps> = ({
)}
</Chevron>
</Header>
<Body isOpen={isOpen}>
{content}
{enableCopy && (
<CopyButton onClick={copyToClipboard}>
<img src="/assets/file-copy-purple.svg" alt="file copy" />
</CopyButton>
)}
</Body>
<Body isOpen={isOpen}>{children}</Body>
</Container>
)
}
@ -50,7 +33,6 @@ const Collapse: React.FC<CollapsibleProps> = ({
const Container = styled.div`
background-color: #320430;
border-radius: 8px;
margin: 10px 0;
color: #f29ae9;
cursor: pointer;
`
@ -70,23 +52,14 @@ const Body = styled.div<{ isOpen: boolean }>`
max-height: ${({ isOpen }) => (isOpen ? '100px' : '0')};
overflow: hidden;
transition: max-height 0.3s ease;
background-color: #320430;
padding: 20px 16px 20px 8px;
background-color: #260324;
padding: 16px 8px;
font-size: 14px;
line-height: 20px;
color: #f29ae9;
letter-spacing: 0.14px;
`
const CopyButton = styled.button`
background: none;
border: none;
color: #f29ae9;
cursor: pointer;
font-size: 14px;
margin-left: 10px;
`
const Chevron = styled.span<{ isExpanded: boolean }>`
display: inline-flex;
transition: transform 0.3s ease;

View File

@ -0,0 +1,43 @@
import styled from '@emotion/styled'
import React from 'react'
import Collapse from './Collapse'
const CopyCode: React.FC = () => {
const content = '445f5..4645sdf54'
const copyToClipboard = () => {
navigator.clipboard.writeText(content)
alert('Copied to clipboard!')
}
return (
<Collapse header="Refer Operators +100 XP">
<Wrapper>
<div>{content}</div>
<CopyButton onClick={copyToClipboard}>
<img src="/assets/file-copy-purple.svg" alt="file copy" />
</CopyButton>
</Wrapper>
</Collapse>
)
}
const CopyButton = styled.button`
background: none;
border: none;
color: #f29ae9;
cursor: pointer;
font-size: 14px;
margin-left: 10px;
`
const Wrapper = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
width: 100%;
height: 28px;
`
export default CopyCode

View File

@ -0,0 +1,102 @@
import styled from '@emotion/styled'
import React, { useState } from 'react'
import { api } from '../../../../common/api'
import Collapse from './Collapse'
const EnterXPCode: React.FC = () => {
const [code, setCode] = useState('')
const [message, setMessage] = useState(null)
const [isSuccess, setIsSuccess] = useState(true)
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setCode(e.target.value)
}
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
api
.post('/user/exit-code', { exit_code: code })
.then((res) => {
setMessage(res.data.message)
setIsSuccess(true)
})
.catch((err) => {
console.log(err)
setMessage(err.message || 'Something went wrong')
setIsSuccess(false)
})
}
return (
<Collapse header="Enter XP Code">
<Wrapper>
<Form onSubmit={handleSubmit}>
<Input onChange={handleChange} placeholder="XP Code" />
<button type="submit">
<img src="/icons/chevron-right-dark-purple.svg" alt="submit" />
</button>
</Form>
{message && <Message isSuccess={isSuccess}>{message}</Message>}
</Wrapper>
</Collapse>
)
}
const Wrapper = styled.div`
display: flex;
flex-direction: column;
gap: 16px;
width: 100%;
`
const Form = styled.form`
display: flex;
width: 100%;
button {
display: flex;
width: 40px;
height: 40px;
padding: 13px;
justify-content: center;
align-items: center;
border: none;
background: #f29ae9;
box-sizing: border-box;
cursor: pointer;
}
`
const Input = styled.input`
color: #f29ae9;
width: 100%;
font-size: 14px;
line-height: 20px;
letter-spacing: 0.14px;
height: 40px;
padding: 10px 14px;
background: transparent;
border: none;
border-bottom: 1px solid #f29ae9;
&::placeholder {
color: #f29ae9;
opacity: 0.5;
}
&:focus {
outline: none;
}
`
const Message = styled.span<{ isSuccess: boolean }>`
color: ${({ isSuccess }) => (isSuccess ? '#8FFFB6' : '#F26969')};
font-size: 12px;
line-height: 16px;
letter-spacing: 0.12px;
opacity: 0.6;
`
export default EnterXPCode

View File

@ -5,6 +5,7 @@ import { breakpoints } from '@/configs/ui.configs'
import styled from '@emotion/styled'
import { useAtom, useSetAtom } from 'jotai'
import React, { useEffect } from 'react'
import useGetUserXP from '../../../apis/general/useGetUserXP'
import useGetUserInfo from '../../../apis/operators/useGetUserInfo'
import { userInfoAtom } from '../../../atoms/userInfo'
import { walletAddressAtom } from '../../../atoms/wallet'
@ -43,6 +44,12 @@ const DashboardContainer: React.FC<DashboardPageProps> = ({
const processedOperators = processMyOperators(userInfoData?.operators)
const { data: userXP } = useGetUserXP({
enabled: !!walletAddress && walletAddress.length > 0,
})
// console.log('userXP', userXP)
return (
<Container {...props}>
<Wrapper>