Skip to content
This repository has been archived by the owner on Oct 4, 2023. It is now read-only.

Commit

Permalink
[C-892] Fix multiple menus open at once (#1889)
Browse files Browse the repository at this point in the history
* opening an actions menu now closes all others
  • Loading branch information
amendelsohn committed Sep 12, 2022
1 parent 1cca57c commit f3c02b6
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 105 deletions.
28 changes: 15 additions & 13 deletions packages/web/src/components/card/desktop/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MouseEvent, useState, useEffect, useCallback, ReactNode } from 'react'
import { useState, useEffect, useCallback, ReactNode, useRef } from 'react'

import {
ID,
Expand All @@ -20,6 +20,7 @@ import RepostFavoritesStats, {
import UserBadges from 'components/user-badges/UserBadges'
import { useCollectionCoverArt } from 'hooks/useCollectionCoverArt'
import { useUserProfilePicture } from 'hooks/useUserProfilePicture'
import { isDescendantElementOf } from 'utils/domUtils'

import styles from './Card.module.css'

Expand Down Expand Up @@ -150,6 +151,16 @@ const Card = ({
// The card is considered `setDidLoad` (and calls it) if the artwork has loaded and its
// parent is no longer telling it that it is loading. This allows ordered loading.
const [artworkLoaded, setArtworkLoaded] = useState(false)

const menuActionsRef = useRef<HTMLDivElement>(null)
const handleClick = useCallback(
(e) => {
if (isDescendantElementOf(e?.target, menuActionsRef.current)) return
onClick()
},
[menuActionsRef, onClick]
)

useEffect(() => {
if (artworkLoaded && setDidLoad) {
setDidLoad(index!)
Expand All @@ -160,18 +171,12 @@ const Card = ({
setArtworkLoaded(true)
}, [setArtworkLoaded])

const onBottomActionsClick = (e: MouseEvent) => {
e.stopPropagation()
}
const sizeStyles = cardSizeStyles[size]

let bottomActions = null
if (menu && (size === 'large' || size === 'medium')) {
bottomActions = (
<div
className={sizeStyles.actionsContainer}
onClick={onBottomActionsClick}
>
<div className={sizeStyles.actionsContainer} ref={menuActionsRef}>
<ActionsTab
handle={handle}
standalone
Expand All @@ -189,10 +194,7 @@ const Card = ({
)
} else if (menu && size === 'small') {
bottomActions = (
<div
className={sizeStyles.actionsContainer}
onClick={onBottomActionsClick}
>
<div className={sizeStyles.actionsContainer} ref={menuActionsRef}>
<Menu menu={menu}>
{(ref, triggerPopup) => (
<div className={styles.iconContainer} onClick={triggerPopup}>
Expand All @@ -212,7 +214,7 @@ const Card = ({
return (
<div
className={cn(className, styles.cardContainer, sizeStyles.cardContainer)}
onClick={onClick}
onClick={handleClick}
>
<div
className={cn(styles.coverArt, sizeStyles.coverArt, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export const TestCollectiblesPlaylistTable = ({
)

const handleClickRow = useCallback(
(rowInfo, index: number) => {
(e, rowInfo, index: number) => {
const collectible = rowInfo.original
onClickRow?.(collectible, index)
},
Expand Down
4 changes: 2 additions & 2 deletions packages/web/src/components/test-table/TestTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ type TestTableProps = {
isVirtualized?: boolean
loading?: boolean
maxRowNum?: number
onClickRow?: (rowInfo: any, index: number) => void
onClickRow?: (e: MouseEvent, rowInfo: any, index: number) => void
onReorder?: (source: number, destination: number) => void
onSort?: (sortProps: {
column: { sorter: (a: any, b: any) => number }
Expand Down Expand Up @@ -230,7 +230,7 @@ export const TestTable = ({
)}
{...props}
key={key}
onClick={() => onClickRow?.(row, row.index)}
onClick={(e: MouseEvent) => onClickRow?.(e, row, row.index)}
>
{row.cells.map(renderCell)}
</tr>
Expand Down
73 changes: 38 additions & 35 deletions packages/web/src/components/test-tracks-table/TestTracksTable.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useCallback, useMemo } from 'react'
import { useCallback, useMemo, useRef } from 'react'

import { formatCount, formatSeconds } from '@audius/common'
import cn from 'classnames'
Expand All @@ -18,6 +18,7 @@ import {
} from 'components/test-table'
import Tooltip from 'components/tooltip/Tooltip'
import UserBadges from 'components/user-badges/UserBadges'
import { isDescendantElementOf } from 'utils/domUtils'

import styles from './TestTracksTable.module.css'

Expand Down Expand Up @@ -222,6 +223,7 @@ export const TestTracksTable = ({
return moment(track.dateListened).format('M/D/YY')
}, [])

const favoriteButtonRef = useRef<HTMLDivElement>(null)
const renderFavoriteButtonCell = useCallback(
(cellInfo) => {
const track = cellInfo.row.original
Expand All @@ -233,15 +235,12 @@ export const TestTracksTable = ({
<Tooltip
text={track.has_current_user_saved ? 'Unfavorite' : 'Favorite'}
>
<div>
<div ref={favoriteButtonRef}>
<TableFavoriteButton
className={cn(styles.tableActionButton, {
[styles.active]: track.has_current_user_saved
})}
onClick={(e: any) => {
e.stopPropagation()
onClickFavorite?.(track)
}}
onClick={() => onClickFavorite?.(track)}
favorited={track.has_current_user_saved}
/>
</div>
Expand All @@ -251,6 +250,7 @@ export const TestTracksTable = ({
[onClickFavorite, userId]
)

const repostButtonRef = useRef<HTMLDivElement>(null)
const renderRepostButtonCell = useCallback(
(cellInfo) => {
const track = cellInfo.row.original
Expand All @@ -259,15 +259,12 @@ export const TestTracksTable = ({
const isOwner = track.owner_id === userId
return isOwner ? null : (
<Tooltip text={track.has_current_user_reposted ? 'Unrepost' : 'Repost'}>
<div>
<div ref={repostButtonRef}>
<TableRepostButton
className={cn(styles.tableActionButton, {
[styles.active]: track.has_current_user_reposted
})}
onClick={(e: any) => {
e.stopPropagation()
onClickRepost?.(track)
}}
onClick={() => onClickRepost?.(track)}
reposted={track.has_current_user_reposted}
/>
</div>
Expand All @@ -277,33 +274,33 @@ export const TestTracksTable = ({
[onClickRepost, userId]
)

const overflowMenuRef = useRef<HTMLDivElement>(null)
const renderOverflowMenuCell = useCallback(
(cellInfo) => {
const track = cellInfo.row.original
const deleted = track.is_delete || !!track.user.is_deactivated
return (
<OverflowMenuButton
className={styles.tableActionButton}
onClick={(e: any) => {
e.stopPropagation()
}}
isDeleted={deleted}
onRemove={onClickRemove}
removeText={removeText}
handle={track.handle}
trackId={track.track_id}
uid={track.uid}
date={track.date}
isFavorited={track.has_current_user_saved}
isOwner={track.owner_id === userId}
isOwnerDeactivated={!!track.user.is_deactivated}
isArtistPick={track.user._artist_pick === track.track_id}
index={cellInfo.row.index}
trackTitle={track.name}
albumId={null}
albumName={null}
trackPermalink={track.permalink}
/>
<div ref={overflowMenuRef}>
<OverflowMenuButton
className={styles.tableActionButton}
isDeleted={deleted}
onRemove={onClickRemove}
removeText={removeText}
handle={track.handle}
trackId={track.track_id}
uid={track.uid}
date={track.date}
isFavorited={track.has_current_user_saved}
isOwner={track.owner_id === userId}
isOwnerDeactivated={!!track.user.is_deactivated}
isArtistPick={track.user._artist_pick === track.track_id}
index={cellInfo.row.index}
trackTitle={track.name}
albumId={null}
albumName={null}
trackPermalink={track.permalink}
/>
</div>
)
},
[onClickRemove, removeText, userId]
Expand Down Expand Up @@ -440,10 +437,16 @@ export const TestTracksTable = ({
)

const handleClickRow = useCallback(
(rowInfo, index: number) => {
(e, rowInfo, index: number) => {
const track = rowInfo.original
const deleted = track.is_delete || track.user?.is_deactivated
if (deleted) return
const clickedActionButton = [
favoriteButtonRef,
repostButtonRef,
overflowMenuRef
].some((ref) => isDescendantElementOf(e?.target, ref.current))

if (deleted || clickedActionButton) return
onClickRow?.(track, index)
},
[onClickRow]
Expand Down

0 comments on commit f3c02b6

Please sign in to comment.