Skip to content

Commit

Permalink
Merge pull request #2867 from JoinColony/fix/2834-pending-button-open…
Browse files Browse the repository at this point in the history
…s-tx
  • Loading branch information
chmanie authored Aug 8, 2024
2 parents 27a199c + 653c3a6 commit dc1f3a1
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 91 deletions.
30 changes: 16 additions & 14 deletions src/components/common/Extensions/UserHub/UserHub.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ import CryptoToFiatTab from './partials/CryptoToFiatTab/CryptoToFiatTab.tsx';
import ReputationTab from './partials/ReputationTab/index.ts';
import StakesTab from './partials/StakesTab/index.ts';
import TransactionsTab from './partials/TransactionsTab/index.ts';
import { type UserHubProps, UserHubTabs } from './types.ts';
import { UserHubTab } from './types.ts';

// @BETA: Disabled for now
// import { COLONY_HOME_ROUTE } from '~routes';
// @BETA: Disabled for now
// import ButtonLink from '~v5/shared/Button/ButtonLink';

interface Props {
initialOpenTab?: UserHubTab;
}

const displayName = 'common.Extensions.UserHub.partials.UserHub';

const MSG = defineMessages({
Expand All @@ -33,12 +37,10 @@ const MSG = defineMessages({
},
});

const UserHub: FC<UserHubProps> = ({
defaultOpenedTab = UserHubTabs.Balance,
}) => {
const UserHub: FC<Props> = ({ initialOpenTab = UserHubTab.Balance }) => {
const isMobile = useMobile();
const featureFlags = useContext(FeatureFlagsContext);
const [selectedTab, setSelectedTab] = useState(defaultOpenedTab);
const [selectedTab, setSelectedTab] = useState(initialOpenTab);

const filteredTabList = tabList.filter(
(tabItem) =>
Expand All @@ -47,7 +49,7 @@ const UserHub: FC<UserHubProps> = ({
featureFlags[tabItem.featureFlag]?.isEnabled),
);

const handleTabChange = (newTab: UserHubTabs) => {
const handleTabChange = (newTab: UserHubTab) => {
setSelectedTab(newTab);
};

Expand All @@ -62,9 +64,9 @@ const UserHub: FC<UserHubProps> = ({
<div
className={clsx('flex h-full flex-col sm:w-[42.625rem] sm:flex-row', {
'sm:h-[27.75rem]':
selectedTab !== UserHubTabs.Balance &&
selectedTab !== UserHubTabs.CryptoToFiat,
'sm:min-h-[27.75rem]': selectedTab === UserHubTabs.Balance,
selectedTab !== UserHubTab.Balance &&
selectedTab !== UserHubTab.CryptoToFiat,
'sm:min-h-[27.75rem]': selectedTab === UserHubTab.Balance,
})}
>
<div className="sticky left-0 right-0 top-0 flex shrink-0 flex-col justify-between border-b border-b-gray-200 bg-base-white px-6 pb-6 pt-4 sm:static sm:left-auto sm:right-auto sm:top-auto sm:w-[13.85rem] sm:border-b-0 sm:border-r sm:border-gray-100 sm:bg-transparent sm:p-6 sm:px-6">
Expand All @@ -73,7 +75,7 @@ const UserHub: FC<UserHubProps> = ({
options={filteredTabList}
defaultValue={selectedTab}
value={selectedTab}
onChange={(value) => handleTabChange(value?.value as UserHubTabs)}
onChange={(value) => handleTabChange(value?.value as UserHubTab)}
className="w-full"
hideSelectedOptions
/>
Expand Down Expand Up @@ -124,14 +126,14 @@ const UserHub: FC<UserHubProps> = ({
)}
</div>
<div className="relative h-full w-full min-w-0">
{selectedTab === UserHubTabs.Balance && (
{selectedTab === UserHubTab.Balance && (
<ReputationTab onTabChange={handleTabChange} />
)}
{selectedTab === UserHubTabs.Stakes && <StakesTab />}
{selectedTab === UserHubTabs.Transactions && (
{selectedTab === UserHubTab.Stakes && <StakesTab />}
{selectedTab === UserHubTab.Transactions && (
<TransactionsTab appearance={{ interactive: true }} />
)}
{selectedTab === UserHubTabs.CryptoToFiat && <CryptoToFiatTab />}
{selectedTab === UserHubTab.CryptoToFiat && <CryptoToFiatTab />}
</div>
{/* @BETA: Disabled for now */}
{/* {isMobile && ( */}
Expand Down
18 changes: 9 additions & 9 deletions src/components/common/Extensions/UserHub/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { defineMessages } from 'react-intl';
import { FeatureFlag } from '~context/FeatureFlagsContext/types.ts';
import { formatText } from '~utils/intl.ts';

import { type UserHubTabList, UserHubTabs } from './types.ts';
import { type UserHubTabList, UserHubTab } from './types.ts';

export const menuMessages = defineMessages({
balance: {
Expand All @@ -32,27 +32,27 @@ export const menuMessages = defineMessages({

export const tabList: UserHubTabList = [
{
id: UserHubTabs.Balance,
id: UserHubTab.Balance,
label: formatText(menuMessages.balance),
value: UserHubTabs.Balance,
value: UserHubTab.Balance,
icon: Invoice,
},
{
id: UserHubTabs.Stakes,
id: UserHubTab.Stakes,
label: formatText(menuMessages.stakes),
value: UserHubTabs.Stakes,
value: UserHubTab.Stakes,
icon: CoinVertical,
},
{
id: UserHubTabs.Transactions,
id: UserHubTab.Transactions,
label: formatText(menuMessages.transactions),
value: UserHubTabs.Transactions,
value: UserHubTab.Transactions,
icon: Receipt,
},
{
id: UserHubTabs.CryptoToFiat,
id: UserHubTab.CryptoToFiat,
label: formatText(menuMessages.cryptoToFiat),
value: UserHubTabs.CryptoToFiat,
value: UserHubTab.CryptoToFiat,
icon: CreditCard,
featureFlag: FeatureFlag.CRYPTO_TO_FIAT_WITHDRAWALS,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
import React, { type FC, useMemo } from 'react';
import { defineMessages, useIntl } from 'react-intl';

import { UserHubTabs } from '~common/Extensions/UserHub/types.ts';
import { UserHubTab } from '~common/Extensions/UserHub/types.ts';
import { useColonyContext } from '~context/ColonyContext/ColonyContext.ts';
import { useTokensModalContext } from '~context/TokensModalContext/TokensModalContext.ts';
import { useGetUserTokenBalanceQuery } from '~gql';
Expand Down Expand Up @@ -170,7 +170,7 @@ const Balance: FC<BalanceProps> = ({ nativeToken, wallet, onTabChange }) => {
</span>
{!isMobile && (
<ViewStakedButton
onClick={() => onTabChange(UserHubTabs.Stakes)}
onClick={() => onTabChange(UserHubTab.Stakes)}
/>
)}
</div>
Expand All @@ -185,7 +185,7 @@ const Balance: FC<BalanceProps> = ({ nativeToken, wallet, onTabChange }) => {
{isMobile && (
<div className="mt-3">
<ViewStakedButton
onClick={() => onTabChange(UserHubTabs.Stakes)}
onClick={() => onTabChange(UserHubTab.Stakes)}
isFullSize
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { type Token } from '~types/graphql.ts';
import { type ColonyWallet } from '~types/wallet.ts';

import { type UserHubTabs } from '../../types.ts';
import { type UserHubTab } from '../../types.ts';

export interface ReputationTabProps {
onTabChange: (newTab: UserHubTabs) => void;
onTabChange: (newTab: UserHubTab) => void;
}

export interface BalanceProps extends Pick<ReputationTabProps, 'onTabChange'> {
Expand Down
10 changes: 3 additions & 7 deletions src/components/common/Extensions/UserHub/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,16 @@ import { type Icon } from '@phosphor-icons/react';
import { type FeatureFlag } from '~context/FeatureFlagsContext/types.ts';

export type UserHubTabList = {
id: UserHubTabs;
id: UserHubTab;
label: string;
value: UserHubTabs;
value: UserHubTab;
icon: Icon;
featureFlag?: FeatureFlag;
}[];

export enum UserHubTabs {
export enum UserHubTab {
Balance = 0,
Stakes = 1,
Transactions = 2,
CryptoToFiat = 3,
}

export interface UserHubProps {
defaultOpenedTab?: UserHubTabs;
}
98 changes: 52 additions & 46 deletions src/components/common/Extensions/UserHubButton/UserHubButton.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import clsx from 'clsx';
import React, { type FC, useState, useEffect } from 'react';
import React, { type FC, useState, useEffect, useCallback } from 'react';
import { usePopperTooltip } from 'react-popper-tooltip';
import { useSearchParams } from 'react-router-dom';

Expand All @@ -12,7 +12,6 @@ import { useColonyContext } from '~context/ColonyContext/ColonyContext.ts';
import { useTokensModalContext } from '~context/TokensModalContext/TokensModalContext.ts';
import { TransactionStatus } from '~gql';
import { useMobile } from '~hooks/index.ts';
import useDetectClickOutside from '~hooks/useDetectClickOutside.ts';
import useDisableBodyScroll from '~hooks/useDisableBodyScroll/index.ts';
import usePrevious from '~hooks/usePrevious.ts';
import { TX_SEARCH_PARAM } from '~routes';
Expand All @@ -26,19 +25,23 @@ import Button from '~v5/shared/Button/index.ts';
import PopoverBase from '~v5/shared/PopoverBase/index.ts';
import UserAvatar from '~v5/shared/UserAvatar/index.ts';

import { UserHubTabs } from '../UserHub/types.ts';
import { UserHubTab } from '../UserHub/types.ts';

import { OPEN_USER_HUB_EVENT } from './consts.ts';

interface Props {
openTab?: UserHubTab;
onOpen: () => void;
}

const displayName = 'common.Extensions.UserNavigation.partials.UserHubButton';

const UserHubButton: FC = () => {
const UserHubButton: FC<Props> = ({ openTab, onOpen }) => {
const isMobile = useMobile();
const {
colony: { colonyAddress },
} = useColonyContext();
const { wallet, user } = useAppContext();
const [isUserHubOpen, setIsUserHubOpen] = useState(false);
const { transactions } = useGroupedTransactions();
const [prevGroupStatus, setPrevGroupStatus] = useState<
TransactionStatus | undefined
Expand All @@ -52,21 +55,14 @@ const UserHubButton: FC = () => {

const { setOpenItemIndex, mobileMenuToggle } = useNavigationSidebarContext();
const { isTokensModalOpen } = useTokensModalContext();
// Note that this will change once we have a better modal transaction experience
const prevIsTokensModalOpen = usePrevious(isTokensModalOpen);

const [, { toggleOff }] = mobileMenuToggle;

const popperTooltipOffset = isMobile ? [0, 1] : [0, 8];

const ref = useDetectClickOutside({
onTriggered: (e) => {
// This stops the hub closing when clicking the pending button (which is outside)
if (!(e.target as HTMLElement)?.getAttribute('data-openhubifclicked')) {
setIsUserHubOpen(false);
} else {
setIsUserHubOpen(true);
}
},
});
const [initialOpenTab, setInitialOpenTab] = useState<UserHubTab>();

const { getTooltipProps, setTooltipRef, setTriggerRef, triggerRef, visible } =
usePopperTooltip(
Expand All @@ -76,7 +72,6 @@ const UserHubButton: FC = () => {
placement: isMobile ? 'bottom' : 'bottom-end',
trigger: 'click',
interactive: true,
onVisibleChange: () => {},
closeOnOutsideClick: true,
},
{
Expand All @@ -91,35 +86,50 @@ const UserHubButton: FC = () => {
},
);

// If visible is not true, then clicking buttons within the popover will close it
// So if isUserHubOpen is true, trigger a triggerRef click to ensure visible is true
useEffect(() => {
if (isUserHubOpen && !visible) {
// This is how we should open the userhub now, from this file. It keeps the state in popper
// Important! The user hub can't be closed from outside programmatically!
const openUserHub = useCallback(
(tab?: UserHubTab) => {
if (!visible) {
setInitialOpenTab(tab);
triggerRef?.click();
}
},
[triggerRef, visible],
);

const closeUserHub = useCallback(() => {
if (visible) {
triggerRef?.click();
}
}, [isUserHubOpen, visible, triggerRef]);
}, [visible, triggerRef]);

useEffect(() => {
if (transactionId !== previousTransactionId && (visible || isUserHubOpen)) {
triggerRef?.click();
setIsUserHubOpen(false);
// openTab signals that we want to open the UserHub from outside with a specific tab
// This immediately gets reset (onOpen) once the UserHub is open to prevent recursion
if (openTab) {
openUserHub(openTab);
onOpen();
}
}, [
transactionId,
triggerRef,
previousTransactionId,
visible,
isUserHubOpen,
]);
// once it's visible, we clear out the initial open tab again to open it with the default tab the next time
if (!openTab && visible) {
setInitialOpenTab(undefined);
}
}, [setInitialOpenTab, onOpen, openUserHub, openTab, triggerRef, visible]);

useEffect(() => {
if (isTokensModalOpen) {
triggerRef?.click();
setIsUserHubOpen(false);
if (transactionId !== previousTransactionId) {
closeUserHub();
}
}, [transactionId, previousTransactionId, closeUserHub]);

useEffect(() => {
if (isTokensModalOpen && isTokensModalOpen !== prevIsTokensModalOpen) {
closeUserHub();
}
}, [isTokensModalOpen, triggerRef]);
}, [isTokensModalOpen, prevIsTokensModalOpen, closeUserHub]);

useDisableBodyScroll(visible && isMobile);
useDisableBodyScroll(isMobile && visible);

const handleButtonClick = () => {
trackEvent(OPEN_USER_HUB_EVENT);
Expand All @@ -137,27 +147,27 @@ const UserHubButton: FC = () => {
(prevGroupStatus === TransactionStatus.Pending ||
prevGroupStatus === TransactionStatus.Ready)
) {
setIsUserHubOpen(true);
openUserHub(UserHubTab.Transactions);
}
if (groupStatus !== prevGroupStatus) {
setPrevGroupStatus(groupStatus);
}
}, [transactions, prevGroupStatus]);
}, [transactions, prevGroupStatus, openUserHub]);

const userName =
user?.profile?.displayName ??
splitWalletAddress(walletAddress ?? ADDRESS_ZERO);

return (
<div ref={ref} className="flex-shrink-0">
<div className="flex-shrink-0">
<Button
mode="tertiary"
size="large"
isFullRounded
ref={setTriggerRef}
className={clsx(
{
'!border-blue-400': visible || isUserHubOpen,
'!border-blue-400': visible,
},
'min-w-[3rem] md:hover:!border-blue-400',
)}
Expand Down Expand Up @@ -192,7 +202,7 @@ const UserHubButton: FC = () => {
) : null}
</div>
</Button>
{(visible || isUserHubOpen) && (
{visible && (
<PopoverBase
setTooltipRef={setTooltipRef}
tooltipProps={getTooltipProps}
Expand All @@ -204,11 +214,7 @@ const UserHubButton: FC = () => {
},
)}
>
<UserHub
defaultOpenedTab={
isUserHubOpen ? UserHubTabs.Transactions : undefined
}
/>
<UserHub initialOpenTab={initialOpenTab} />
</PopoverBase>
)}
</div>
Expand Down
Loading

0 comments on commit dc1f3a1

Please sign in to comment.