mirror of
https://github.com/acid-info/logos-ordinals-dashboard.git
synced 2025-01-11 22:24:24 +00:00
feat: implement Collapse-related components
This commit is contained in:
parent
7049314828
commit
8489ea85fe
@ -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,
|
||||
})
|
||||
|
||||
|
@ -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,
|
||||
})
|
||||
|
||||
|
3
public/icons/chevron-right-dark-purple.svg
Normal file
3
public/icons/chevron-right-dark-purple.svg
Normal 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 |
@ -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;
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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;
|
||||
|
43
src/components/common/Collapse/CopyCode.tsx
Normal file
43
src/components/common/Collapse/CopyCode.tsx
Normal 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
|
102
src/components/common/Collapse/EnterXPCode.tsx
Normal file
102
src/components/common/Collapse/EnterXPCode.tsx
Normal 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
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user