diff --git a/packages/atlas/src/components/_crt/RevenueShareParticipationWidget.tsx b/packages/atlas/src/components/_crt/RevenueShareParticipationWidget.tsx index f3af6e7c0e..dddcce6d45 100644 --- a/packages/atlas/src/components/_crt/RevenueShareParticipationWidget.tsx +++ b/packages/atlas/src/components/_crt/RevenueShareParticipationWidget.tsx @@ -17,6 +17,7 @@ import { useSnackbar } from '@/providers/snackbars' import { useTransaction } from '@/providers/transactions/transactions.hooks' import { useUser } from '@/providers/user/user.hooks' import { cVar } from '@/styles' +import { getRevenueShareStatusForMember } from '@/utils/crts' import { SentryLogger } from '@/utils/logs' import { formatNumber } from '@/utils/number' @@ -38,6 +39,15 @@ export const RevenueShareParticipationWidget = ({ const { displaySnackbar } = useSnackbar() const handleTransaction = useTransaction() const navigate = useNavigate() + const status = revenueShare + ? getRevenueShareStatusForMember({ + currentBlock, + isFinalized: revenueShare.finalized, + hasMemberStaked: revenueShare.stakers.some((staker) => staker.account.member.id === memberId), + endingAt: revenueShare.endsAt, + startingAt: revenueShare.startingAt, + }) + : 'inactive' const handleExitRevenueShare = async () => { if (!joystream || !token || !memberId) { @@ -74,30 +84,27 @@ export const RevenueShareParticipationWidget = ({ } const actionNode = () => { - const hasStaked = revenueShare.stakers.some((staker) => staker.account.member.id === memberId) - if (!hasEnded) { - if (hasStaked) { - return <StyledPill icon={<SvgActionCheck />} size="large" label="Staked your tokens" /> - } else { + switch (status) { + case 'active': return ( <Button size="small" variant="secondary" onClick={onClaimShare}> Stake your tokens </Button> ) - } - } - if (!hasStaked) return null - - const hasClaimed = false - if (hasClaimed) { - return <StyledPill icon={<SvgActionCheck />} size="large" label="Tokens claimed" /> + case 'unlock': + return ( + <Button size="small" onClick={handleExitRevenueShare}> + Claim tokens + </Button> + ) + case 'locked': + return <StyledPill icon={<SvgActionCheck />} size="large" label="Staked your tokens" /> + case 'past': + return <StyledPill icon={<SvgActionCheck />} size="large" label="Tokens claimed" /> + case 'inactive': + case 'finalized': + return null } - - return ( - <Button size="small" onClick={handleExitRevenueShare}> - Claim tokens - </Button> - ) } return ( diff --git a/packages/atlas/src/components/_crt/RevenueShareStateWidget/RevenueShareStateWidget.tsx b/packages/atlas/src/components/_crt/RevenueShareStateWidget/RevenueShareStateWidget.tsx index abb2c86a37..cd08a00ccb 100644 --- a/packages/atlas/src/components/_crt/RevenueShareStateWidget/RevenueShareStateWidget.tsx +++ b/packages/atlas/src/components/_crt/RevenueShareStateWidget/RevenueShareStateWidget.tsx @@ -33,18 +33,23 @@ export const RevenueShareStateWidget = ({ }: RevenueShareStateWidgetProps) => { const { startingAt, endsAt, stakers } = revenueShare ?? { startingAt: 0, endsAt: 0 } const [openClaimShareModal, setOpenClaimShareModal] = useState(false) - const { convertBlockToMsTimestamp } = useBlockTimeEstimation() + const { convertBlockToMsTimestamp, currentBlock } = useBlockTimeEstimation() const endingBlockTimestamp = convertBlockToMsTimestamp(endsAt ?? 0) + const startingBlockTimestamp = convertBlockToMsTimestamp(startingAt ?? 0) const endingDate = endingBlockTimestamp ? new Date(endingBlockTimestamp) : null - const { currentBlock } = useBlockTimeEstimation() + const startingDate = startingBlockTimestamp ? new Date(startingBlockTimestamp) : null const unlockStakeTx = useUnlockTokenStake() const memberStake = stakers?.find((stakers) => stakers.account.member.id === memberId) - const status: 'active' | 'past' | 'inactive' = !endingBlockTimestamp - ? 'inactive' - : endingBlockTimestamp < Date.now() - ? 'past' - : 'active' + const status = revenueShare + ? getRevenueShareStatusForMember({ + currentBlock, + isFinalized: revenueShare.finalized, + hasMemberStaked: false, + endingAt: endsAt, + startingAt: startingAt, + }) + : 'inactive' const memberStatus = getRevenueShareStatusForMember({ startingAt, @@ -111,32 +116,42 @@ export const RevenueShareStateWidget = ({ ? 'REVENUE SHARE STATE' : status === 'past' ? 'REVENUE SHARE ENDED ON' + : status === 'upcoming' + ? 'REVENUE SHARE STARTS IN' : 'REVENUE SHARE ENDS IN' } customNode={ - status !== 'inactive' && endsAt ? ( - <FlexBox justifyContent="space-between" alignItems="center" width="100%"> - {status === 'past' ? ( - <Text variant="h500" as="h5" margin={{ bottom: 4 }}> + <FlexBox justifyContent="space-between" alignItems="center" width="100%"> + {status === 'inactive' ? ( + <Text variant="h500" as="h5" margin={{ bottom: 4 }}> + No active share + </Text> + ) : status === 'past' ? ( + <Text variant="h500" as="h5" margin={{ bottom: 4 }}> + {endingDate ? formatDateTime(endingDate).replace(',', ' at') : 'N/A'} + </Text> + ) : status === 'upcoming' ? ( + <FlexBox flow="column"> + <Text variant="h500" as="h5"> + {startingDate ? formatDurationShort(Math.round((startingDate.getTime() - Date.now()) / 1000)) : 'N/A'} + </Text> + <Text variant="t100" as="p" color="colorText"> + {startingDate ? formatDateTime(startingDate).replace(',', ' at') : 'N/A'} + </Text> + </FlexBox> + ) : ( + <FlexBox flow="column"> + <Text variant="h500" as="h5"> + {endingDate ? formatDurationShort(Math.round((endingDate.getTime() - Date.now()) / 1000)) : 'N/A'} + </Text> + <Text variant="t100" as="p" color="colorText"> {endingDate ? formatDateTime(endingDate).replace(',', ' at') : 'N/A'} </Text> - ) : ( - <FlexBox flow="column"> - <Text variant="h500" as="h5"> - {endingDate ? formatDurationShort(Math.round((endingDate.getTime() - Date.now()) / 1000)) : 'N/A'} - </Text> - <Text variant="t100" as="p" color="colorText"> - {endingDate ? formatDateTime(endingDate).replace(',', ' at') : 'N/A'} - </Text> - </FlexBox> - )} - <div style={{ marginLeft: 'auto' }}>{memberActionNode}</div> - </FlexBox> - ) : ( - <Text variant="h500" as="h5" margin={{ bottom: 4 }}> - No active share - </Text> - ) + </FlexBox> + )} + + <div style={{ marginLeft: 'auto' }}>{memberActionNode}</div> + </FlexBox> } customTopRightNode={withLink ? <TextButton to={absoluteRoutes.viewer.portfolio()} /> : undefined} tooltip={ diff --git a/packages/atlas/src/components/_crt/StartRevenueShareModal/StartRevenueShareModal.tsx b/packages/atlas/src/components/_crt/StartRevenueShareModal/StartRevenueShareModal.tsx index 98b30f3420..9522d69fce 100644 --- a/packages/atlas/src/components/_crt/StartRevenueShareModal/StartRevenueShareModal.tsx +++ b/packages/atlas/src/components/_crt/StartRevenueShareModal/StartRevenueShareModal.tsx @@ -84,8 +84,8 @@ export const StartRevenueShare = ({ token, onClose, show }: StartRevenueSharePro }) const [startDate, endDate] = watch(['startDate', 'endDate']) const endDateTimestamp = useMemo(() => { - const rawStartDate = startDate?.type === 'date' ? startDate.date : new Date() - + // we need to create new date object to aviod modifying it in addDaystoDate + const rawStartDate = startDate?.type === 'date' ? new Date(startDate.date.getTime()) : new Date() return endDate?.type === 'date' ? endDate.date : endDate?.durationDays @@ -95,7 +95,7 @@ export const StartRevenueShare = ({ token, onClose, show }: StartRevenueSharePro const onSubmit = () => handleSubmit((data) => { - const rawStartDate = data.startDate?.type === 'date' ? data.startDate.date : new Date() + const rawStartDate = startDate?.type === 'date' ? new Date(startDate.date.getTime()) : new Date() const startBlock = convertMsTimestampToBlock(rawStartDate.getTime()) if (channelBalance?.lten(0)) { @@ -332,7 +332,11 @@ export const StartRevenueShare = ({ token, onClose, show }: StartRevenueSharePro ]} onChange={(value) => { onChange(value) - if (endDate?.type === 'date') { + if ( + endDate?.type === 'date' && + value?.type === 'date' && + value.date.getTime() > endDate.date.getTime() + ) { resetField('endDate', { defaultValue: { type: 'duration', durationDays: 7 } }) } trigger('startDate') diff --git a/packages/atlas/src/utils/time.ts b/packages/atlas/src/utils/time.ts index 62dfba015b..c3ffc1459c 100644 --- a/packages/atlas/src/utils/time.ts +++ b/packages/atlas/src/utils/time.ts @@ -36,6 +36,7 @@ export const daysToMilliseconds = (days: number) => { return days * 24 * 60 * 60 * 1000 } +// Warning: this function will modify received date as a ref export const addDaysToDate = (daysToAdd: number, date = new Date()) => { date.setDate(date.getDate() + daysToAdd) return date