Skip to content

Commit

Permalink
fix: mf-6009 resend redpacket from history with password (#11319)
Browse files Browse the repository at this point in the history
* fix: mf-6009 resend redpacket from history with password

* fix: nft redpacket

* fix: fixup
  • Loading branch information
UncleBill authored and guanbinrui committed Jan 30, 2024
1 parent 5dc89e0 commit 30e06f9
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 179 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { TokenIcon } from '@masknet/shared'
import { NetworkPluginID } from '@masknet/shared-base'
import { useEverSeen } from '@masknet/shared-base-ui'
import { ActionButton, makeStyles } from '@masknet/theme'
import { ActionButton, ShadowRootTooltip, makeStyles } from '@masknet/theme'
import { useChainContext, useNetworkDescriptor } from '@masknet/web3-hooks-base'
import { type NftRedPacketJSONPayload } from '@masknet/web3-providers/types'
import { isSameAddress, type NonFungibleCollection } from '@masknet/web3-shared-base'
import type { ChainId, SchemaType } from '@masknet/web3-shared-evm'
import { Box, ListItem, Typography } from '@mui/material'
import { fill } from 'lodash-es'
import { memo, useCallback, useMemo, type MouseEventHandler } from 'react'
import { memo, useCallback, useMemo } from 'react'
import { RedPacketTrans, useRedPacketTrans } from '../locales/index.js'
import { useAvailabilityNftRedPacket } from './hooks/useAvailabilityNftRedPacket.js'
import { useCreateNftRedPacketReceipt } from './hooks/useCreateNftRedPacketReceipt.js'
Expand Down Expand Up @@ -163,14 +163,10 @@ interface NftRedPacketHistoryItemProps {
history: NftRedPacketJSONPayload
collections: Array<NonFungibleCollection<ChainId, SchemaType>>
onSend: (history: NftRedPacketJSONPayload, contract: NonFungibleCollection<ChainId, SchemaType>) => void
onShowPopover: (anchorEl: HTMLElement, text: string) => void
onHidePopover: () => void
}
export const NftRedPacketHistoryItem = memo(function NftRedPacketHistoryItem({
history,
onSend,
onShowPopover,
onHidePopover,
collections,
}: NftRedPacketHistoryItemProps) {
const { account, chainId } = useChainContext<NetworkPluginID.PLUGIN_EVM>()
Expand All @@ -191,28 +187,19 @@ export const NftRedPacketHistoryItem = memo(function NftRedPacketHistoryItem({
listItemBackgroundIcon: networkDescriptor ? `url("${networkDescriptor.icon}")` : undefined,
})

const { canSend, isPasswordValid } = useNftAvailabilityComputed(account, patchedHistory)
const { canSend, isPasswordValid, password } = useNftAvailabilityComputed(account, patchedHistory)

const collection = collections.find((x) => isSameAddress(x.address, patchedHistory.token_address))

const handleSend = useCallback(() => {
if (!(canSend && collection && isPasswordValid)) return
onSend(patchedHistory, collection)
}, [onSend, canSend, patchedHistory, collection, isPasswordValid])
onSend({ ...patchedHistory, password: patchedHistory.password || password }, collection)
}, [onSend, canSend, patchedHistory, collection, isPasswordValid, password])

const { data: redpacketStatus } = useAvailabilityNftRedPacket(rpid, account, patchedHistory.chainId)
const bitStatusList =
redpacketStatus ? redpacketStatus.bitStatusList : fill(Array(patchedHistory.token_ids.length), false)

const handleMouseEnter: MouseEventHandler<HTMLButtonElement> = (event) => {
if (canSend && !isPasswordValid) {
handleShowPopover(event.currentTarget)
}
}
const handleShowPopover = (anchor: HTMLElement) => {
onShowPopover(anchor, t.nft_data_broken())
}

return (
<ListItem className={classes.root}>
<section className={classes.contentItem} ref={ref}>
Expand Down Expand Up @@ -243,17 +230,19 @@ export const NftRedPacketHistoryItem = memo(function NftRedPacketHistoryItem({
</div>
</div>

{canSend ?
<ActionButton
onMouseEnter={handleMouseEnter}
onMouseLeave={onHidePopover}
onClick={handleSend}
disabled={!isPasswordValid}
className={classes.actionButton}
size="large">
{t.share()}
</ActionButton>
: null}
<ShadowRootTooltip
placement="top"
title={canSend && !isPasswordValid ? t.nft_data_broken() : ''}>
<span style={{ display: 'inline-block' }}>
<ActionButton
onClick={handleSend}
disabled={!isPasswordValid}
className={classes.actionButton}
size="large">
{t.share()}
</ActionButton>
</span>
</ShadowRootTooltip>
</section>

<section className={classes.footer}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import { useRef, useState } from 'react'
import { makeStyles } from '@masknet/theme'
import { EmptyStatus, LoadingStatus, useSharedTrans } from '@masknet/shared'
import { EMPTY_LIST, NetworkPluginID } from '@masknet/shared-base'
import { useChainContext, useNonFungibleCollections } from '@masknet/web3-hooks-base'
import type { NonFungibleCollection } from '@masknet/web3-shared-base'
import { SchemaType, type ChainId } from '@masknet/web3-shared-evm'
import { type NftRedPacketJSONPayload } from '@masknet/web3-providers/types'
import { List, Popper, Typography } from '@mui/material'
import { List } from '@mui/material'
import { useNftRedPacketHistory } from './hooks/useNftRedPacketHistory.js'
import { NftRedPacketHistoryItem } from './NftRedPacketHistoryItem.js'
import { useRedPacketTrans } from '../locales/index.js'

const useStyles = makeStyles<void, 'atBottom'>()((theme, _, refs) => {
const useStyles = makeStyles()((theme) => {
const smallQuery = `@media (max-width: ${theme.breakpoints.values.sm}px)`
return {
root: {
Expand All @@ -38,39 +37,6 @@ const useStyles = makeStyles<void, 'atBottom'>()((theme, _, refs) => {
height: 474,
margin: '0 auto',
},
popper: {
overflow: 'visible',
padding: 6,
},
popperContent: {
position: 'relative',
overflow: 'visible',
backgroundColor: theme.palette.mode === 'light' ? 'rgba(15, 20, 25, 1)' : '#fff',
borderRadius: 8,
padding: 10,
},
arrow: {
position: 'absolute',
bottom: 0,
right: 74,
width: 0,
height: 0,
borderLeft: '6px solid transparent',
borderRight: '6px solid transparent',
borderTop: `6px solid ${theme.palette.mode === 'light' ? 'rgba(15, 20, 25, 1)' : '#fff'}`,
transform: 'RedPacketTrans(-50%, 6px)',
[`&.${refs.atBottom}`]: {
bottom: 'auto',
top: 0,
transform: 'RedPacketTrans(-50%, -6px) rotate(180deg)',
},
},
atBottom: {},
popperText: {
cursor: 'default',
color: theme.palette.mode === 'light' ? '#fff' : 'rgba(15, 20, 25, 1)',
fontSize: 12,
},
}
})

Expand All @@ -79,27 +45,16 @@ interface Props {
}

export function NftRedPacketHistoryList({ onSend }: Props) {
const { classes, cx } = useStyles()
const { classes } = useStyles()
const t = useRedPacketTrans()
const sharedI18N = useSharedTrans()
const { account, chainId } = useChainContext<NetworkPluginID.PLUGIN_EVM>()
const { data: histories, isPending } = useNftRedPacketHistory(account, chainId)
const containerRef = useRef<HTMLDivElement>(null)
const [popperText, setPopperText] = useState('')
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null)
const { data: collections = EMPTY_LIST } = useNonFungibleCollections(NetworkPluginID.PLUGIN_EVM, {
chainId,
schemaType: SchemaType.ERC721,
})

const handleShowPopover = (anchor: HTMLElement, text: string) => {
setAnchorEl(anchor)
setPopperText(text)
}
const handleHidePopover = () => {
setAnchorEl(null)
}

if (isPending) {
return (
<LoadingStatus className={classes.placeholder} iconSize={30}>
Expand All @@ -117,37 +72,17 @@ export function NftRedPacketHistoryList({ onSend }: Props) {
}

return (
<>
<div ref={containerRef} className={classes.root}>
<List style={{ padding: '16px 0 0' }}>
{histories.map((history) => (
<NftRedPacketHistoryItem
key={history.txid}
collections={collections}
history={history}
onSend={onSend}
onShowPopover={handleShowPopover}
onHidePopover={handleHidePopover}
/>
))}
</List>
</div>
<Popper
placeholder={undefined}
className={classes.popper}
open={!!anchorEl}
placement="top"
anchorEl={anchorEl}
disablePortal>
{({ placement }) => {
return (
<div className={classes.popperContent}>
<Typography className={classes.popperText}>{popperText}</Typography>
<div className={cx(classes.arrow, placement === 'bottom' ? classes.atBottom : '')} />
</div>
)
}}
</Popper>
</>
<div className={classes.root}>
<List style={{ padding: '16px 0 0' }}>
{histories.map((history) => (
<NftRedPacketHistoryItem
key={history.txid}
collections={collections}
history={history}
onSend={onSend}
/>
))}
</List>
</div>
)
}
107 changes: 38 additions & 69 deletions packages/plugins/RedPacket/src/SiteAdaptor/RedPacketInHistoryList.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { TokenIcon } from '@masknet/shared'
import { NetworkPluginID } from '@masknet/shared-base'
import { ActionButton, makeStyles } from '@masknet/theme'
import { ActionButton, ShadowRootTooltip, makeStyles } from '@masknet/theme'
import { useChainContext, useFungibleToken, useNetworkDescriptor } from '@masknet/web3-hooks-base'
import {
RedPacketStatus,
Expand All @@ -9,9 +9,9 @@ import {
} from '@masknet/web3-providers/types'
import { formatBalance, minus, type FungibleToken } from '@masknet/web3-shared-base'
import { type ChainId, type SchemaType } from '@masknet/web3-shared-evm'
import { Box, ListItem, Popper, Typography, useMediaQuery, type Theme } from '@mui/material'
import { Box, ListItem, Typography, useMediaQuery, type Theme } from '@mui/material'
import { intervalToDuration, nextDay } from 'date-fns'
import { memo, useCallback, useMemo, useState, type MouseEvent } from 'react'
import { memo, useCallback, useMemo } from 'react'
import { useEverSeen } from '../../../../shared-base-ui/src/hooks/useEverSeen.js'
import { RedPacketTrans, useRedPacketTrans } from '../locales/index.js'
import { useAvailabilityComputed } from './hooks/useAvailabilityComputed.js'
Expand Down Expand Up @@ -149,25 +149,6 @@ const useStyles = makeStyles<{ listItemBackground?: string; listItemBackgroundIc
marginRight: 2,
},
},
popper: {
overflow: 'visible',
backgroundColor: theme.palette.maskColor.dark,
transform: 'RedPacketTrans(196px, 47px)',
borderRadius: 8,
width: 328,
padding: 10,
},
arrow: {
position: 'absolute',
top: -12,
right: 40,
width: 0,
height: 0,
borderLeft: '6px solid transparent',
borderRight: '6px solid transparent',
borderBottom: `6px solid ${theme.palette.maskColor.dark}`,
transform: 'RedPacketTransY(6px)',
},
popperText: {
cursor: 'default',
color: theme.palette.common.white,
Expand Down Expand Up @@ -224,6 +205,7 @@ export const RedPacketInHistoryList = memo(function RedPacketInHistoryList(props
const {
value: availability,
computed: { canRefund, canSend, listOfStatus, isPasswordValid },
password,
retry: revalidateAvailability,
} = useAvailabilityComputed(account, patchedHistory)

Expand Down Expand Up @@ -255,13 +237,8 @@ export const RedPacketInHistoryList = memo(function RedPacketInHistoryList(props
await refundCallback()
revalidateAvailability()
}
if (canSend) onSelect({ ...patchedHistory, token: historyToken })
}, [onSelect, refundCallback, canRefund, canSend, patchedHistory, historyToken])

// #region password lost tips
const [anchorEl, setAnchorEl] = useState<(EventTarget & HTMLButtonElement) | null>(null)
const openPopper = !!anchorEl
// #endregion
if (canSend) onSelect({ ...patchedHistory, password, token: historyToken })
}, [onSelect, refundCallback, canRefund, canSend, patchedHistory, historyToken, password])

// #region refund time
const refundDuration =
Expand Down Expand Up @@ -295,46 +272,38 @@ export const RedPacketInHistoryList = memo(function RedPacketInHistoryList(props
</div>
</div>
{canRefund || canSend || listOfStatus.includes(RedPacketStatus.empty) || refunded ?
<>
<ActionButton
loading={isRefunding}
fullWidth={isSmall}
onClick={canSend && !isPasswordValid ? undefined : onSendOrRefund}
onMouseEnter={(event: MouseEvent<HTMLButtonElement>) => {
canSend && !isPasswordValid ? setAnchorEl(event.currentTarget) : undefined
}}
onMouseLeave={() => {
canSend && !isPasswordValid ? setAnchorEl(null) : undefined
}}
disabled={
listOfStatus.includes(RedPacketStatus.empty) || refunded || isRefunding
}
className={cx(
classes.actionButton,
canSend && !isPasswordValid ? classes.disabledButton : '',
)}
size="large">
{canSend ?
t.share()
: isRefunding ?
t.refunding()
: listOfStatus.includes(RedPacketStatus.empty) || refunded ?
t.empty()
: t.refund()}
</ActionButton>
<Popper
placeholder={undefined}
className={classes.popper}
open={openPopper}
anchorEl={anchorEl}
transition
disablePortal>
<Typography className={classes.popperText}>
{t.data_broken({ duration: formatRefundDuration })}
</Typography>
<div className={classes.arrow} />
</Popper>
</>
<ShadowRootTooltip
placement="top"
title={
canSend && !isPasswordValid ?
<Typography className={classes.popperText}>
{t.data_broken({ duration: formatRefundDuration })}
</Typography>
: undefined
}>
<span style={{ display: 'inline-block' }}>
<ActionButton
loading={isRefunding}
fullWidth={isSmall}
onClick={canSend && !isPasswordValid ? undefined : onSendOrRefund}
disabled={
listOfStatus.includes(RedPacketStatus.empty) || refunded || isRefunding
}
className={cx(
classes.actionButton,
canSend && !isPasswordValid ? classes.disabledButton : '',
)}
size="large">
{canSend ?
t.share()
: isRefunding ?
t.refunding()
: listOfStatus.includes(RedPacketStatus.empty) || refunded ?
t.empty()
: t.refund()}
</ActionButton>
</span>
</ShadowRootTooltip>
: null}
</section>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export function useAvailabilityComputed(account: string, payload: RedPacketJSONP
return {
...asyncResult,
payload,
password,
computed: {
canClaim: false,
canRefund: false,
Expand All @@ -51,6 +52,7 @@ export function useAvailabilityComputed(account: string, payload: RedPacketJSONP
const isPasswordValid = !!(password && password !== 'PASSWORD INVALID')
return {
...asyncResult,
password,
computed: {
canClaim: !isExpired && !isEmpty && !isClaimed && isPasswordValid,
canRefund: isExpired && !isEmpty && isCreator,
Expand Down

0 comments on commit 30e06f9

Please sign in to comment.