Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tooltip for deactivated AddProposalButton (#3909) #3916

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/ui/src/common/components/Tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export interface TooltipPopupProps {
forBig?: boolean
hideOnComponentLeave?: boolean
boundaryClassName?: string
placement?: 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end'
}

export interface DarkTooltipInnerItemProps {
Expand All @@ -54,14 +55,15 @@ export const Tooltip = ({
offset,
hideOnComponentLeave,
boundaryClassName,
placement = 'bottom-start',
}: TooltipProps) => {
const [isTooltipActive, setTooltipActive] = useState(tooltipOpen)
const [referenceElementRef, setReferenceElementRef] = useState<HTMLElement | null>(null)
const [popperElementRef, setPopperElementRef] = useState<HTMLDivElement | null>(null)
const [boundaryElement, setBoundaryElement] = useState<HTMLElement | null>(null)

const { styles, attributes } = usePopper(referenceElementRef, popperElementRef, {
placement: 'bottom-start',
placement,
modifiers: [
{
name: 'offset',
Expand Down
53 changes: 31 additions & 22 deletions packages/ui/src/proposals/components/AddProposalButton.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,46 @@
import React, { useCallback } from 'react'
import React, { useCallback, useMemo } from 'react'

import { useApi } from '@/api/hooks/useApi'
import { TransactionButton } from '@/common/components/buttons/TransactionButton'
import { PlusIcon } from '@/common/components/icons/PlusIcon'
import { Tooltip } from '@/common/components/Tooltip'
import { useFirstObservableValue } from '@/common/hooks/useFirstObservableValue'
import { useModal } from '@/common/hooks/useModal'
import { AddNewProposalModalCall } from '@/proposals/modals/AddNewProposal'

export const AddProposalButton = () => {
const { api } = useApi()
const { showModal } = useModal()
const addNewProposalModal = useCallback(() => {
showModal<AddNewProposalModalCall>({
modal: 'AddNewProposalModal',
})
}, [])
const addProposalModal = useCallback(() => showModal<AddNewProposalModalCall>({ modal: 'AddNewProposalModal' }), [])

const { api } = useApi()
const maxProposals = api?.consts.proposalsEngine.maxActiveProposalLimit
const currentProposals = useFirstObservableValue(
() => api?.query.proposalsEngine.activeProposalCount(),
[api?.isConnected]
)
const areProposalSlotsAvailable = api && maxProposals && currentProposals?.lt(maxProposals)
const maxProposals = useMemo(() => api?.consts.proposalsEngine.maxActiveProposalLimit, [api?.isConnected])
const proposals = useFirstObservableValue(() => api?.query.proposalsEngine.activeProposalCount(), [api?.isConnected])
const availableSlots = useMemo(() => Number(maxProposals) - Number(proposals), [proposals, maxProposals])

const tooltipProps = useMemo(() => {
if (!api?.isConnected) return { tooltipText: 'Connecting to api' }
if (!api?.isConnected || availableSlots > 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!api?.isConnected || availableSlots > 0) {
if (availableSlots > 0) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new logic is that until connection is established and when there are slots the default tooltip is shown. Without the first condition a user would see the error "Max active proposals limit reached" during loading.

return {
tooltipText: 'Use the proposal engine to suggest a change to the Council.',
tooltipLinkText: 'Learn about the Proposal System',
tooltipLinkURL: 'https://joystream.gitbook.io/testnet-workspace/system/proposal-system',
}
} else {
return {
tooltipTitle: 'Max active proposals limit reached',
tooltipText: `The creation of proposals is currently disabled because the number of deciding or gracing proposals reached the limit of ${maxProposals}.`,
tooltipLinkText: 'Proposal System Constants',
tooltipLinkURL: 'https://joystream.gitbook.io/testnet-workspace/system/proposal-system#constants',
}
}
}, [api?.isConnected, availableSlots])

return (
<TransactionButton
style="primary"
size="medium"
onClick={addNewProposalModal}
disabled={!areProposalSlotsAvailable}
>
<PlusIcon />
Add new proposal
</TransactionButton>
<Tooltip placement="bottom-end" {...tooltipProps}>
<TransactionButton style="primary" size="medium" onClick={addProposalModal} disabled={!availableSlots}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TransactionButton also renders a Tooltip when a transaction is pending. As a result in case of a pending transaction, this will result in the Tooltip beeing nested (I'm not sure what will actually be shown). To avoid this situation, TransactionButton could accept TooltipContentProp:

  • If these are defined ⇒ display the Tooltip
  • If a transaction is pending ⇒ display the: "Please wait until the current transaction is over" regardless of whether a different tooltip text was passed.

WDYT ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense.

<PlusIcon />
Add new proposal
</TransactionButton>
</Tooltip>
)
}